KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > service > cmr > repository > datatype > Duration


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.service.cmr.repository.datatype;
18
19 import java.io.IOException JavaDoc;
20 import java.io.Serializable JavaDoc;
21 import java.io.StreamTokenizer JavaDoc;
22 import java.io.StringReader JavaDoc;
23 import java.math.BigDecimal JavaDoc;
24 import java.text.DateFormat JavaDoc;
25 import java.text.NumberFormat JavaDoc;
26 import java.text.ParsePosition JavaDoc;
27 import java.util.Calendar JavaDoc;
28 import java.util.Date JavaDoc;
29
30 import org.alfresco.util.CachingDateFormat;
31
32 /**
33  * This data type represents duration/interval/period as defined by the XMLSchema type
34  * duration.
35  *
36  * The lexical representation of duration is
37  * PnYnMnDTnHnMnS.
38  *
39  * P is a literal value that starts the expression
40  * nY is an integer number of years followed by the literal Y
41  * nM is an integer number of months followed by the literal M
42  * nD is an integer number of days followed by the literal D
43  * T is the literal that separates the date and time
44  * nH is an integer number of hours followed by a literal H
45  * nM is an integer number of minutes followed by a literal M
46  * nS is a decimal number of seconds followed by a literal S
47  *
48  * Any numbers and designator may be absent if the value is zero.
49  * A minus sign may appear before the literal P to indicate a negative duration.
50  * If no time items are present the literal T must not appear.
51  *
52  *
53  * This implementation is immutable and thread safe.
54  *
55  * There are two forms of duration common on database types.
56  * The code contains warnings wheer these are relevant.
57  *
58  * @author andyh
59  */

60 public class Duration implements Comparable JavaDoc, Serializable JavaDoc
61 {
62
63    static final long serialVersionUID = 3274526442325176068L;
64
65    public static final String JavaDoc XML_DAY = "P1D";
66    public static final String JavaDoc XML_WEEK = "P7D";
67    public static final String JavaDoc XML_TWO_WEEKS = "P14D";
68    public static final String JavaDoc XML_MONTH = "P1M";
69    public static final String JavaDoc XML_QUARTER = "P3M";
70    public static final String JavaDoc XML_SIX_MONTHS = "P6M";
71    public static final String JavaDoc XML_YEAR = "P1Y";
72
73    public static final Duration DAY = new Duration(XML_DAY);
74    public static final Duration WEEK = new Duration(XML_WEEK);
75    public static final Duration TWO_WEEKS = new Duration(XML_TWO_WEEKS);
76    public static final Duration MONTH = new Duration(XML_MONTH);
77    public static final Duration QUARTER = new Duration(XML_QUARTER);
78    public static final Duration SIX_MONTHS = new Duration(XML_SIX_MONTHS);
79    public static final Duration YEAR = new Duration(XML_YEAR);
80
81    private static final String JavaDoc s_parse = "-PYMDTHmS";
82
83    private boolean m_positive = true;
84    private int m_years = 0;
85    private int m_months = 0;
86    private int m_days = 0;
87    private int m_hours = 0;
88    private int m_mins = 0;
89    private int m_seconds = 0;
90    private int m_nanos = 0;
91
92    // Date duration arithmetic
93

94    /**
95     * Add a duration to a date and return the date plus the specified increment.
96     *
97     * @param date - the initial date
98     * @param duration - the duration to add on to the date (the duration may be negative)
99     * @return the adjusted date.
100     */

101    public static Date JavaDoc add(Date JavaDoc date, Duration duration)
102    {
103       Calendar JavaDoc c = Calendar.getInstance();
104       c.setTime(date);
105       c.add(Calendar.YEAR, (duration.m_positive ? 1 : -1) * duration.m_years);
106       c.add(Calendar.MONTH, (duration.m_positive ? 1 : -1) * duration.m_months);
107       c.add(Calendar.DATE, (duration.m_positive ? 1 : -1) * duration.m_days);
108       c.add(Calendar.HOUR_OF_DAY, (duration.m_positive ? 1 : -1) * duration.m_hours);
109       c.add(Calendar.MINUTE, (duration.m_positive ? 1 : -1) * duration.m_mins);
110       c.add(Calendar.SECOND, (duration.m_positive ? 1 : -1) * duration.m_seconds);
111       c.add(Calendar.MILLISECOND, (duration.m_positive ? 1 : -1) * duration.m_nanos / 1000000);
112       return c.getTime();
113    }
114
115    /**
116     * Subtract a period for a given date
117     *
118     * @param date - the intial date
119     * @param duration - the diration to subtract
120     * @return the adjusted date.
121     */

122    
123    public static Date JavaDoc subtract(Date JavaDoc date, Duration duration)
124    {
125       return add(date, duration.unaryMinus());
126    }
127
128    
129
130    /**
131     * Constructor for Duration - a zero value duration
132     */

133
134    public Duration()
135    {
136       super();
137    }
138
139    /**
140     * Construct a Duration from the XMLSchema definition
141     */

142
143    public Duration(String JavaDoc duration)
144    {
145
146       if (duration.equals("P"))
147       {
148          throw new RuntimeException JavaDoc("Invalid period: P");
149       }
150
151       if (!duration.startsWith("P") && !duration.startsWith("-P"))
152       {
153          throw new RuntimeException JavaDoc("Invalid period: must start with P or -P");
154       }
155       else
156       {
157          boolean dateMode = true;
158          int last = -1;
159          Double JavaDoc nval = null;
160          StringReader JavaDoc reader = new StringReader JavaDoc(duration);
161          StreamTokenizer JavaDoc tok = new StreamTokenizer JavaDoc(reader);
162          tok.resetSyntax();
163          tok.eolIsSignificant(true);
164          tok.parseNumbers();
165          tok.ordinaryChars('-', '-');
166          tok.ordinaryChars('P', 'P');
167          tok.ordinaryChars('Y', 'Y');
168          tok.ordinaryChars('M', 'M');
169          tok.ordinaryChars('D', 'D');
170          tok.ordinaryChars('T', 'T');
171          tok.ordinaryChars('H', 'H');
172          tok.ordinaryChars('m', 'm');
173          tok.ordinaryChars('S', 'S');
174
175          int token;
176          try
177          {
178             while ((token = tok.nextToken()) != StreamTokenizer.TT_EOF)
179             {
180                if (token == StreamTokenizer.TT_NUMBER)
181                {
182                   nval = new Double JavaDoc(tok.nval);
183                }
184                else if (token == StreamTokenizer.TT_EOF)
185                {
186                   throw new RuntimeException JavaDoc("Invalid EOF in Duration");
187                }
188                else if (token == StreamTokenizer.TT_EOL)
189                {
190                   throw new RuntimeException JavaDoc("Invalid EOL in Duration");
191                }
192                else if (token == StreamTokenizer.TT_WORD)
193                {
194                   throw new RuntimeException JavaDoc("Invalid text in Duration: " + tok.sval);
195                }
196                else
197                {
198                   if (tok.ttype == '-')
199                   {
200                      last = checkIndex(last, "-");
201                      m_positive = false;
202                   }
203                   else if (tok.ttype == 'P')
204                   {
205                      last = checkIndex(last, "P");
206                      // nothing
207
}
208                   else if (tok.ttype == 'Y')
209                   {
210                      last = checkIndex(last, "Y");
211                      if (nval != null)
212                      {
213                         m_years = nval.intValue();
214                      }
215                      else
216                      {
217                         throw new RuntimeException JavaDoc("IO Error parsing Duration: " + duration);
218                      }
219                      nval = null;
220                   }
221                   else if (tok.ttype == 'M')
222                   {
223                      if (dateMode)
224                      {
225                         last = checkIndex(last, "M");
226                         if (nval != null)
227                         {
228                            m_months = nval.intValue();
229                         }
230                         else
231                         {
232                            throw new RuntimeException JavaDoc("IO Error parsing Duration: " + duration);
233                         }
234                         nval = null;
235                      }
236                      else
237                      {
238                         last = checkIndex(last, "m");
239                         if (nval != null)
240                         {
241                            m_mins = nval.intValue();
242                         }
243                         else
244                         {
245                            throw new RuntimeException JavaDoc("IO Error parsing Duration: " + duration);
246                         }
247                         nval = null;
248                      }
249                   }
250                   else if (tok.ttype == 'D')
251                   {
252                      last = checkIndex(last, "D");
253                      if (nval != null)
254                      {
255                         m_days = nval.intValue();
256                      }
257                      else
258                      {
259                         throw new RuntimeException JavaDoc("IO Error parsing Duration: " + duration);
260                      }
261                      nval = null;
262                   }
263                   else if (tok.ttype == 'T')
264                   {
265                      last = checkIndex(last, "T");
266                      dateMode = false;
267                      nval = null;
268                   }
269                   else if (tok.ttype == 'H')
270                   {
271                      last = checkIndex(last, "H");
272                      if (nval != null)
273                      {
274                         m_hours = nval.intValue();
275                      }
276                      else
277                      {
278                         throw new RuntimeException JavaDoc("IO Error parsing Duration: " + duration);
279                      }
280                      nval = null;
281                   }
282                   else if (tok.ttype == 'S')
283                   {
284                      last = checkIndex(last, "S");
285                      if (nval != null)
286                      {
287                         m_seconds = nval.intValue();
288                         m_nanos = (int) ((long) (nval.doubleValue() * 1000000000) % 1000000000);
289                      }
290                      else
291                      {
292                         throw new RuntimeException JavaDoc("IO Error parsing Duration: " + duration);
293                      }
294                      nval = null;
295                   }
296                   else
297                   {
298                      throw new RuntimeException JavaDoc("IO Error parsing Duration: " + duration);
299                   }
300                }
301             }
302          }
303          catch (IOException JavaDoc e)
304          {
305             throw new RuntimeException JavaDoc("IO Error parsing Duration: " + duration);
306          }
307          catch (RuntimeException JavaDoc e)
308          {
309             throw new RuntimeException JavaDoc("IO Error parsing Duration: " + duration, e);
310          }
311       }
312    }
313
314    /**
315     * Simple index to check identifiers appear in order
316     */

317
318    private int checkIndex(int last, String JavaDoc search)
319    {
320       if ((search == null) || (search.length() == 0))
321       {
322          throw new RuntimeException JavaDoc("Null or zero length serach");
323       }
324       int index = s_parse.indexOf(search);
325       if (index > last)
326       {
327          return index;
328       }
329       else
330       {
331          throw new RuntimeException JavaDoc("Illegal position for identifier " + search);
332       }
333    }
334
335    /**
336     * Create a duration given a date. The duration is between the two dates provided.
337     *
338     * Sadly, it works out the duration by incrementing the lower calendar until it matches
339     * the higher.
340     */

341
342    public Duration(Date JavaDoc date)
343    {
344       this(date, new Date JavaDoc());
345    }
346
347    /**
348     * Create a duration betweeen two dates expressed as strings.
349     * Uses the standard XML date form.
350     *
351     * @param start - the date at the start of the period
352     * @param end - the date at the end of the period
353     */

354    
355    public Duration(String JavaDoc start, String JavaDoc end)
356    {
357       this(parseDate(start), parseDate(end));
358    }
359
360    
361    /**
362     * Helper method to parse eaets from strings
363     * @param stringDate
364     * @return
365     */

366    private static Date JavaDoc parseDate(String JavaDoc stringDate)
367    {
368       DateFormat JavaDoc df = CachingDateFormat.getDateFormat();
369       df.setLenient(true);
370       Date JavaDoc date;
371
372       ParsePosition JavaDoc pp = new ParsePosition JavaDoc(0);
373       date = df.parse(stringDate, pp);
374       if ((pp.getIndex() < stringDate.length()) || (date == null))
375       {
376          date = new Date JavaDoc();
377       }
378       return date;
379
380    }
381
382    /**
383     * Construct a preiod between the two given dates
384     *
385     * @param start_in
386     * @param end_in
387     */

388    public Duration(Date JavaDoc start_in, Date JavaDoc end_in)
389    {
390       boolean positive = true;
391       Date JavaDoc start;
392       Date JavaDoc end;
393       if (start_in.before(end_in))
394       {
395          start = start_in;
396          end = end_in;
397          positive = true;
398       }
399       else
400       {
401          start = end_in;
402          end = start_in;
403          positive = false;
404       }
405       Calendar JavaDoc cstart = Calendar.getInstance();
406       cstart.setTime(start);
407       Calendar JavaDoc cend = Calendar.getInstance();
408       cend.setTime(end);
409
410       int millis = cend.get(Calendar.MILLISECOND) - cstart.get(Calendar.MILLISECOND);
411       if (millis < 0)
412       {
413          millis += cstart.getActualMaximum(Calendar.MILLISECOND)+1;
414       }
415       cstart.add(Calendar.MILLISECOND, millis);
416
417       int seconds = cend.get(Calendar.SECOND) - cstart.get(Calendar.SECOND);
418       if (seconds < 0)
419       {
420          seconds += cstart.getActualMaximum(Calendar.SECOND)+1;
421       }
422       cstart.add(Calendar.SECOND, seconds);
423
424       int minutes = cend.get(Calendar.MINUTE) - cstart.get(Calendar.MINUTE);
425       if (minutes < 0)
426       {
427          minutes += cstart.getActualMaximum(Calendar.MINUTE)+1;
428       }
429       cstart.add(Calendar.MINUTE, minutes);
430
431       int hours = cend.get(Calendar.HOUR_OF_DAY) - cstart.get(Calendar.HOUR_OF_DAY);
432       if (hours < 0)
433       {
434          hours += cstart.getActualMaximum(Calendar.HOUR_OF_DAY)+1;
435       }
436       cstart.add(Calendar.HOUR_OF_DAY, hours);
437
438       int days = cend.get(Calendar.DAY_OF_MONTH) - cstart.get(Calendar.DAY_OF_MONTH);
439       if (days < 0)
440       {
441          days += cstart.getActualMaximum(Calendar.DAY_OF_MONTH)+1;
442       }
443       cstart.add(Calendar.DAY_OF_MONTH, days);
444
445       int months = cend.get(Calendar.MONTH) - cstart.get(Calendar.MONTH);
446       if (months < 0)
447       {
448          months += cstart.getActualMaximum(Calendar.MONTH)+1;
449       }
450       cstart.add(Calendar.MONTH, months);
451
452       int years = cend.get(Calendar.YEAR) - cstart.get(Calendar.YEAR);
453       //cstart.add(Calendar.YEAR, years);
454

455       m_positive = positive;
456       m_years = years;
457       m_months = months;
458       m_days = days;
459       m_hours = hours;
460       m_mins = minutes;
461       m_seconds = seconds;
462       m_nanos = millis * 1000000;
463
464    }
465
466    /**
467     * Construct a duration from months seconds and nanos
468     * Checks sign and fixes up seconds and nano.
469     * Treats year-month abd day-sec as separate chunks
470     */

471
472    public Duration(boolean positive_in, long months_in, long seconds_in, long nanos_in)
473    {
474
475       boolean positive = positive_in;
476       long months = months_in;
477       long seconds = seconds_in + nanos_in / 1000000000;
478       long nanos = nanos_in % 1000000000;
479
480       // Fix up seconds and nanos to be of the same sign
481

482       if ((seconds > 0) && (nanos < 0))
483       {
484          seconds -= 1;
485          nanos += 1000000000;
486       }
487       else if ((seconds < 0) && (nanos > 0))
488       {
489          seconds += 1;
490          nanos -= 1000000000;
491       }
492
493       // seconds and nanos now the same sign - sum to test overall sign
494

495       if ((months < 0) && (seconds + nanos < 0))
496       {
497          // switch sign
498
positive = !positive;
499          months = -months;
500          seconds = -seconds;
501          nanos = -nanos;
502       }
503       else if ((months == 0) && (seconds + nanos < 0))
504       {
505          // switch sign
506
positive = !positive;
507          months = -months;
508          seconds = -seconds;
509          nanos = -nanos;
510       }
511       else if ((months > 0) && (seconds + nanos < 0))
512       {
513          throw new RuntimeException JavaDoc("Can not convert to period - incompatible signs for year_to_momth and day_to_second elements");
514       }
515       else if ((months < 0) && (seconds + nanos > 0))
516       {
517          throw new RuntimeException JavaDoc("Can not convert to period - incompatible signs for year_to_momth and day_to_second elements");
518       }
519       else
520       {
521          // All +ve
522
}
523
524       m_positive = positive;
525       m_years = (int) (months / 12);
526       m_months = (int) (months % 12);
527
528       m_days = (int) (seconds / (3600 * 24));
529       seconds -= m_days * 3600 * 24;
530       m_hours = (int) (seconds / 3600);
531       seconds -= m_hours * 3600;
532       m_mins = (int) (seconds / 60);
533       seconds -= m_mins * 60;
534       m_seconds = (int) seconds;
535       m_nanos = (int) nanos;
536
537    }
538
539    
540    // Duration arithmetic
541

542    /**
543     * Add two durations together
544     */

545
546    public Duration add(Duration add)
547    {
548
549       long months = (this.m_positive ? 1 : -1) * this.getTotalMonths() + (add.m_positive ? 1 : -1) * add.getTotalMonths();
550       long seconds = (this.m_positive ? 1 : -1) * this.getTotalSeconds() + (add.m_positive ? 1 : -1) * add.getTotalSeconds();
551       long nanos = (this.m_positive ? 1 : -1) * this.getTotalNanos() + (add.m_positive ? 1 : -1) * add.getTotalNanos();
552
553       Duration result = new Duration(true, months, seconds, nanos);
554       return result;
555    }
556
557    /**
558     * Subtract one duration from another
559     */

560
561    public Duration subtract(Duration sub)
562    {
563       long months = (this.m_positive ? 1 : -1) * this.getTotalMonths() - (sub.m_positive ? 1 : -1) * sub.getTotalMonths();
564       long seconds = (this.m_positive ? 1 : -1) * this.getTotalSeconds() - (sub.m_positive ? 1 : -1) * sub.getTotalSeconds();
565       long nanos = (this.m_positive ? 1 : -1) * this.getTotalNanos() - (sub.m_positive ? 1 : -1) * sub.getTotalNanos();
566       Duration result = new Duration(true, months, seconds, nanos);
567       return result;
568    }
569
570    /**
571     * Negate the duration
572     */

573
574    public Duration unaryMinus()
575    {
576       Duration result = new Duration(!this.m_positive, this.getTotalMonths(), this.getTotalSeconds(), this.getTotalNanos());
577       return result;
578    }
579
580    /**
581     * Divide the duration - if year-month drops the day-second part of the duration
582     */

583
584    public Duration divide(int d)
585    {
586       if (isYearToMonth())
587       {
588          long months = getTotalMonths();
589          months /= d;
590          Duration result = new Duration(m_positive, months, 0, 0);
591          return result;
592       }
593       else
594       {
595          long seconds = getTotalSeconds();
596          long nanos = (seconds * (1000000000 / d)) % 1000000000;
597          nanos += getTotalNanos() / d;
598          seconds /= d;
599          Duration result = new Duration(m_positive, 0, seconds, nanos);
600          return result;
601       }
602    }
603
604    /**
605     * Helper method to get the total number of months - year-month
606     */

607
608    private long getTotalMonths()
609    {
610       return m_years * 12 + m_months;
611    }
612
613    /**
614     * Helper method to get the total number of seconds
615     */

616
617    private long getTotalSeconds()
618    {
619       return m_seconds + m_mins * 60 + m_hours * 3600 + m_days * 3600 * 24;
620    }
621
622    /**
623     * Helper method to get the total number of nanos (does not include seconds_
624     */

625
626    private long getTotalNanos()
627    {
628       return m_nanos;
629    }
630
631    /**
632     * Check if is year-month
633     */

634
635    public boolean isYearToMonth()
636    {
637       return (m_years != 0) || (m_months != 0);
638    }
639
640    /**
641     * Check if is day-sec
642     */

643
644    public boolean isDayToSec()
645    {
646       return ((m_years == 0) && (m_months == 0));
647    }
648
649    /**
650     * Check if it includes time
651     */

652
653    public boolean hasTime()
654    {
655       return (m_hours != 0) || (m_mins != 0) || (m_seconds != 0) || (m_nanos != 0);
656    }
657
658    /**
659     * Extract the year to month part
660     */

661
662    public Duration getYearToMonth()
663    {
664       Duration result = new Duration(m_positive, getTotalMonths(), 0, 0);
665       return result;
666    }
667
668    /**
669     * Extract the day to sec part.
670     */

671
672    public Duration getDayToYear()
673    {
674       Duration result = new Duration(m_positive, 0, getTotalSeconds(), getTotalNanos());
675       return result;
676    }
677
678    /**
679     * Compare two durations
680     */

681
682    public int compareTo(Object JavaDoc o)
683    {
684       if (!(o instanceof Duration))
685       {
686          throw new RuntimeException JavaDoc("Can not compare Duration and " + o.getClass().getName());
687       }
688
689       Duration d = (Duration) o;
690       if (this.m_positive != d.m_positive)
691       {
692          return (m_positive ? 1 : -1);
693       }
694
695       if (this.getTotalMonths() != d.getTotalMonths())
696       {
697          return (m_positive ? 1 : -1) * ((int) (this.getTotalMonths() - d.getTotalMonths()));
698       }
699       else if (this.getTotalSeconds() != d.getTotalSeconds())
700       {
701          return (m_positive ? 1 : -1) * ((int) (this.getTotalSeconds() - d.getTotalSeconds()));
702       }
703       else if (this.getTotalNanos() != d.getTotalNanos())
704       {
705          return (m_positive ? 1 : -1) * ((int) (this.getTotalNanos() - d.getTotalNanos()));
706       }
707       else
708       {
709          return 0;
710       }
711    }
712
713    /**
714     * @see java.lang.Object#equals(Object)
715     */

716
717    public boolean equals(Object JavaDoc o)
718    {
719       if (this == o)
720          return true;
721       if (!(o instanceof Duration))
722          return false;
723       Duration d = (Duration) o;
724       return (this.m_positive == d.m_positive) && (this.getTotalMonths() == d.getTotalMonths()) && (this.getTotalSeconds() == d.getTotalSeconds()) && (this.getTotalNanos() == d.getTotalNanos());
725
726    }
727
728    /**
729     * @see java.lang.Object#hashCode()
730     */

731
732    public int hashCode()
733    {
734       int hash = 17;
735       hash = 37 * hash + (m_positive ? 1 : -1);
736       hash = 37 * hash + (int) getTotalMonths();
737       hash = 37 * hash + (int) getTotalSeconds();
738       hash = 37 * hash + (int) getTotalNanos();
739       return hash;
740    }
741
742    /**
743     * Produce the XML Schema string
744     *
745     * @see java.lang.Object#toString()
746     */

747
748    public String JavaDoc toString()
749    {
750       StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(128);
751       if (!m_positive)
752       {
753          buffer.append("-");
754       }
755       buffer.append("P");
756       // Always include years as just P on its own is invalid
757
buffer.append(m_years).append("Y");
758
759       if (m_months != 0)
760       {
761          buffer.append(m_months).append("M");
762       }
763       if (m_days != 0)
764       {
765          buffer.append(m_days).append("D");
766       }
767       if (hasTime())
768       {
769          buffer.append("T");
770          if (m_hours != 0)
771          {
772             buffer.append(m_hours).append("H");
773          }
774          if (m_mins != 0)
775          {
776             buffer.append(m_mins).append("M");
777          }
778          if ((m_seconds != 0) || (m_nanos != 0))
779          {
780             BigDecimal JavaDoc a = new BigDecimal JavaDoc(m_seconds);
781             BigDecimal JavaDoc b = new BigDecimal JavaDoc(m_nanos);
782             a = a.add(b.divide(new BigDecimal JavaDoc(1000000000), 9, BigDecimal.ROUND_HALF_EVEN));
783             NumberFormat JavaDoc nf = NumberFormat.getInstance();
784             buffer.append(nf.format(a));
785             buffer.append("S");
786          }
787
788       }
789
790       return buffer.toString();
791    }
792
793    /**
794     * Format in human readable form
795     *
796     * TODO: I18n
797     */

798
799    public String JavaDoc formattedString()
800    {
801       StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(128);
802       if (!m_positive)
803       {
804          buffer.append("-");
805       }
806       if (m_years != 0)
807       {
808          if (buffer.length() > 0)
809             buffer.append(" ");
810          buffer.append(m_years);
811          buffer.append((m_years == 1) ? " Year" : " Years");
812
813       }
814       if (m_months != 0)
815       {
816          if (buffer.length() > 0)
817             buffer.append(" ");
818          buffer.append(m_months);
819          buffer.append((m_months == 1) ? " Month" : " Months");
820       }
821       if (m_days != 0)
822       {
823          if (buffer.length() > 0)
824             buffer.append(" ");
825          buffer.append(m_days);
826          buffer.append((m_days == 1) ? " Day" : " Days");
827       }
828       if (hasTime())
829       {
830          if (m_hours != 0)
831          {
832             if (buffer.length() > 0)
833                buffer.append(" ");
834             buffer.append(m_hours);
835             buffer.append((m_hours == 1) ? " Hour" : " Hours");
836          }
837          if (m_mins != 0)
838          {
839             if (buffer.length() > 0)
840                buffer.append(" ");
841             buffer.append(m_mins);
842             buffer.append((m_mins == 1) ? " Minute" : " Minutes");
843          }
844          if ((m_seconds != 0) || (m_nanos != 0))
845          {
846             if (buffer.length() > 0)
847                buffer.append(" ");
848             BigDecimal JavaDoc a = new BigDecimal JavaDoc(m_seconds);
849             BigDecimal JavaDoc b = new BigDecimal JavaDoc(m_nanos);
850             a = a.add(b.divide(new BigDecimal JavaDoc(1000000000), 9, BigDecimal.ROUND_HALF_EVEN));
851             NumberFormat JavaDoc nf = NumberFormat.getInstance();
852             String JavaDoc formatted = nf.format(a);
853             buffer.append(formatted);
854             buffer.append(formatted.equals("1") ? " Second" : " Seconds");
855          }
856
857       }
858
859       return buffer.toString();
860    }
861
862    
863    /**
864     * TODO: Tests that should be moved into a unit test
865     *
866     * @param args
867     */

868    public static void main(String JavaDoc[] args)
869    {
870       Duration diff = new Duration("2002-04-02T01:01:01", "2003-03-01T00:00:00");
871       System.out.println("Diff " + diff);
872
873       try
874       {
875          Duration test = new Duration("P");
876          System.out.println("Just P" + test);
877       }
878       catch (RuntimeException JavaDoc e)
879       {
880          e.printStackTrace();
881       }
882
883       try
884       {
885          Duration test2 = new Duration("P Jones");
886          System.out.println("P Jones" + test2);
887       }
888       catch (RuntimeException JavaDoc e)
889       {
890          e.printStackTrace();
891       }
892
893       try
894       {
895          Duration test2 = new Duration("P12Y Jones");
896          System.out.println("P Jones" + test2);
897       }
898       catch (RuntimeException JavaDoc e)
899       {
900          e.printStackTrace();
901       }
902
903       try
904       {
905          Duration test = new Duration("PPPPPPPPPPPPPP");
906          System.out.println("Just many P" + test);
907       }
908       catch (RuntimeException JavaDoc e)
909       {
910          e.printStackTrace();
911       }
912
913       try
914       {
915          Duration test = new Duration("PY");
916          System.out.println("PY" + test);
917       }
918       catch (RuntimeException JavaDoc e)
919       {
920          e.printStackTrace();
921       }
922
923       try
924       {
925          Duration test = new Duration("PM");
926          System.out.println("PM" + test);
927       }
928       catch (RuntimeException JavaDoc e)
929       {
930          e.printStackTrace();
931       }
932
933       try
934       {
935          Duration test = new Duration("PP");
936          System.out.println("PP" + test);
937       }
938       catch (RuntimeException JavaDoc e)
939       {
940          e.printStackTrace();
941       }
942
943       Date JavaDoc now = new Date JavaDoc();
944       Calendar JavaDoc c = Calendar.getInstance();
945       c.setTime(now);
946       c.add(Calendar.YEAR, -1);
947       c.add(Calendar.MONTH, +2);
948       c.add(Calendar.DAY_OF_MONTH, -3);
949       c.add(Calendar.HOUR_OF_DAY, +4);
950       c.add(Calendar.MINUTE, -5);
951       c.add(Calendar.SECOND, +6);
952       c.add(Calendar.MILLISECOND, -7);
953
954       diff = new Duration(c.getTime(), now);
955       System.out.println("V: " + diff);
956
957       Duration diff2 = new Duration(now, c.getTime());
958       System.out.println("V: " + diff2);
959
960       Duration a1 = new Duration("P2Y6M");
961       Duration a2 = new Duration("P1DT2H3M1.5S");
962
963       Duration d = new Duration("P2Y6M5DT12H35M30.100S");
964       System.out.println("V: " + d);
965       System.out.println("F: " + d.formattedString());
966       System.out.println(" D: " + d.divide(2));
967       System.out.println(" +: " + d.add(a1));
968       System.out.println(" +: " + d.add(a1.add(a2)));
969       d = new Duration("P1DT2H3M1.5S");
970       System.out.println("V: " + d);
971       System.out.println("F: " + d.formattedString());
972       System.out.println(" D: " + d.divide(2));
973       System.out.println(" +: " + d.add(a1));
974       System.out.println(" +: " + d.add(a1.add(a2)));
975       d = new Duration("PT1.5S");
976       System.out.println("V: " + d);
977       System.out.println("F: " + d.formattedString());
978       System.out.println(" D: " + d.divide(2));
979       System.out.println(" +: " + d.add(a1));
980       System.out.println(" +: " + d.add(a1.add(a2)));
981       d = new Duration("P20M");
982       System.out.println("V: " + d);
983       System.out.println("F: " + d.formattedString());
984       System.out.println(" D: " + d.divide(2));
985       System.out.println(" +: " + d.add(a1));
986       System.out.println(" +: " + d.add(a1.add(a2)));
987       d = new Duration("P0Y20M0D");
988       System.out.println("V: " + d);
989       System.out.println("F: " + d.formattedString());
990       System.out.println(" D: " + d.divide(2));
991       System.out.println(" +: " + d.add(a1));
992       System.out.println(" +: " + d.add(a1.add(a2)));
993       d = new Duration("-P60D");
994       System.out.println("V: " + d);
995       System.out.println("F: " + d.formattedString());
996       System.out.println(" D: " + d.divide(10));
997       System.out.println(" +: " + d.add(a2));
998       //System.out.println(" +: " + d.add(a1));
999

1000   }
1001}
1002
Popular Tags