KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > math > Duration


1 package gnu.math;
2 import java.io.*;
3
4 public class Duration extends Quantity implements Externalizable
5 {
6   public Unit unit;
7
8   /** Number of whole months. May be negative. */
9   int months;
10
11   /** Does not include any leap seconds.
12    * I.e. @code{sign * ((24 * days + hours) * 60 + minutes) * 60 + seconds},
13    * where {@code hours >= 0 && hours < 24 && minutes >= 0 && minutes < 60
14    * && secconds >= 0 && minutes > 60}.
15    */

16   long seconds;
17
18   /** Number of nanoseconds.
19    * We could possibly include leap seconds in here. */

20   int nanos;
21
22   public static Duration make (int months, long seconds, int nanos, Unit unit)
23   {
24     Duration d = new Duration();
25     d.months = months;
26     d.seconds = seconds;
27     d.nanos = nanos;
28     d.unit = unit;
29     return d;
30   }
31
32   public static Duration makeMonths(int months)
33   {
34     Duration d = new Duration();
35     d.unit = Unit.month;
36     d.months = months;
37     return d;
38   }
39
40   public static Duration makeMinutes (int minutes)
41   {
42     Duration d = new Duration();
43     d.unit = Unit.second;
44     d.seconds = 60 * minutes;
45     return d;
46   }
47
48   public static Duration parse (String JavaDoc str, Unit unit)
49   {
50     Duration d = Duration.valueOf(str, unit);
51     if (d == null)
52       throw new IllegalArgumentException JavaDoc("not a valid "+unit.getName()+" duration: '"+str+"'");
53     return d;
54   }
55
56   public static Duration parseDuration (String JavaDoc str)
57   {
58     return parse(str, Unit.duration);
59   }
60
61   public static Duration parseYearMonthDuration (String JavaDoc str)
62   {
63     return parse(str, Unit.month);
64   }
65
66
67   public static Duration parseDayTimeDuration (String JavaDoc str)
68   {
69     return parse(str, Unit.second);
70   }
71
72   /** Parse a duration lexical value as specified by XML Schama.
73    * Return null if invalid syntax.
74    */

75   public static Duration valueOf (String JavaDoc str, Unit unit)
76   {
77     str = str.trim();
78     int pos = 0;
79     int len = str.length();
80     boolean negative;
81     if (pos < len && str.charAt(pos) == '-')
82       {
83         negative = true;
84         pos++;
85       }
86     else
87       negative = false;
88     if (pos + 1 >= len || str.charAt(pos) != 'P')
89       return null;
90     pos++;
91     int months = 0, nanos = 0;
92     long seconds = 0;
93     long part = scanPart(str, pos);
94     pos = ((int) part) >> 16;
95     char ch = (char) part;
96     if (unit == Unit.second && (ch == 'Y' || ch == 'M'))
97       return null;
98     if (ch == 'Y')
99       {
100         months = 12 * (int) (part >> 32);
101         pos = ((int) part) >> 16;
102         part = scanPart(str, pos);
103         ch = (char) part;
104       }
105     if (ch == 'M')
106       {
107         months += (part >> 32);
108         pos = ((int) part) >> 16;
109         part = scanPart(str, pos);
110         ch = (char) part;
111       }
112     if (unit == Unit.month && pos != len)
113       return null;
114     if (ch == 'D')
115       {
116         if (unit == Unit.month)
117           return null;
118         seconds = (long) (24 * 60 * 60) * (int) (part >> 32);
119         pos = ((int) part) >> 16;
120         part = scanPart (str, pos);
121       }
122     if (part != (pos << 16))
123       return null;
124     if (pos == len)
125       {
126         // No time part
127
}
128     else if (str.charAt(pos) != 'T' || ++pos == len)
129       return null;
130     else // saw 'T'
131
{
132         if (unit == Unit.month)
133           return null;
134         part = scanPart (str, pos);
135         ch = (char) part;
136         if (ch == 'H')
137           {
138             seconds += (60 * 60) * (int) (part >> 32);
139             pos = ((int) part) >> 16;
140             part = scanPart (str, pos);
141             ch = (char) part;
142           }
143         if (ch == 'M')
144           {
145             seconds += 60 * (int) (part >> 32);
146             pos = ((int) part) >> 16;
147             part = scanPart (str, pos);
148             ch = (char) part;
149           }
150         if (ch == 'S' || ch == '.')
151           {
152             seconds += (int) (part >> 32);
153             pos = ((int) part) >> 16;
154           }
155         if (ch == '.' && pos + 1 < len
156             && Character.digit(str.charAt(pos), 10) >= 0)
157           {
158             int nfrac = 0;
159             for (; pos < len; nfrac++)
160               {
161                 ch = str.charAt(pos++);
162                 int dig = Character.digit(ch, 10);
163                 if (dig < 0)
164                   break;
165                 if (nfrac < 9)
166                   nanos = 10 * nanos + dig;
167                 else if (nfrac == 9 && dig >= 5)
168                   nanos++;
169               }
170             while (nfrac++ < 9)
171               nanos = 10 * nanos;
172             if (ch != 'S')
173               return null;
174           }
175       }
176     if (pos != len)
177       return null;
178     Duration d = new Duration();
179     if (negative)
180       {
181         months = -months;
182         seconds = -seconds;
183         nanos = -nanos;
184       }
185     d.months = months;
186     d.seconds = seconds;
187     d.nanos = nanos;
188     d.unit = unit;
189     return d;
190   }
191
192   public Numeric add (Object JavaDoc y, int k)
193   {
194     if (y instanceof Duration)
195       return Duration.add (this, (Duration) y, k);
196     if (y instanceof DateTime && k == 1)
197       return DateTime.add((DateTime) y, this, 1);
198     throw new IllegalArgumentException JavaDoc ();
199   }
200
201   public Numeric mul (Object JavaDoc y)
202   {
203     if (y instanceof RealNum)
204       return Duration.times(this, ((RealNum) y).doubleValue());
205     return ((Numeric)y).mulReversed (this);
206   }
207
208   public Numeric mulReversed (Numeric x)
209   {
210     if (! (x instanceof RealNum))
211       throw new IllegalArgumentException JavaDoc ();
212     return Duration.times(this, ((RealNum) x).doubleValue());
213   }
214
215   public static double div (Duration dur1, Duration dur2)
216   {
217     int months1 = dur1.months;
218     int months2 = dur2.months;
219     double sec1 = (double) dur1.seconds + dur1.nanos * 0.000000001;
220     double sec2 = (double) dur2.seconds + dur1.nanos * 0.000000001;
221     if (months2 == 0 && sec2 == 0)
222       throw new ArithmeticException JavaDoc("divide duration by zero");
223     if (months2 == 0)
224       {
225         if (months1 == 0)
226           return sec1 /sec2;
227       }
228     else if (sec2 == 0)
229       {
230         if (sec1 == 0)
231           return (double) months1 / (double) months2;
232       }
233     throw new ArithmeticException JavaDoc("divide of incompatible durations");
234   }
235
236   public Numeric div (Object JavaDoc y)
237   {
238     if (y instanceof RealNum)
239       {
240         double dy = ((RealNum) y).doubleValue();
241         if (dy == 0 || Double.isNaN(dy))
242           throw new ArithmeticException JavaDoc("divide of duration by 0 or NaN");
243         return Duration.times(this, 1.0 / dy);
244       }
245     if (y instanceof Duration)
246       return new DFloNum(div(this, (Duration) y));
247     return ((Numeric)y).divReversed (this);
248   }
249
250   public static Duration add (Duration x, Duration y, int k)
251   {
252     long months = (long) x.months + k * (long) y.months;
253     // FIXME does not handle leap-seconds represented as multiples of
254
// 10^9 in the nanos field.
255
long nanos = x.seconds * 1000000000L + (long) x.nanos
256       + k * (y.seconds * 1000000000L + y.nanos);
257     // FIXME check for overflow
258
// FIXME handle inconsistent signs.
259
Duration d = new Duration();
260     d.months = (int) months;
261     d.seconds = (int) (nanos / 1000000000L);
262     d.nanos = (int) (nanos % 1000000000L);
263     if (x.unit != y.unit || x.unit == Unit.duration)
264       throw new ArithmeticException JavaDoc("cannot add these duration types");
265     d.unit = x.unit;
266     return d;
267   }
268
269   public static Duration times (Duration x, double y)
270   {
271     if (x.unit == Unit.duration)
272       throw new IllegalArgumentException JavaDoc("cannot multiply general duration");
273     double months = x.months * y;
274     if (Double.isInfinite(months) || Double.isNaN(months))
275       throw new ArithmeticException JavaDoc("overflow/NaN when multiplying a duration");
276     double nanos = (x.seconds * 1000000000L + x.nanos) * y;
277     Duration d = new Duration();
278     d.months = (int) Math.floor(months + 0.5);
279     d.seconds = (int) (nanos / 1000000000L);
280     d.nanos = (int) (nanos % 1000000000L);
281     d.unit = x.unit;
282     return d;
283   }
284
285   public static int compare (Duration x, Duration y)
286   {
287     long months = (long) x.months - (long) y.months;
288     long nanos = x.seconds * 1000000000L + (long) x.nanos
289       - (y.seconds * 1000000000L + y.nanos);
290     if (months < 0 && nanos <= 0)
291       return -1;
292     if (months > 0 && nanos >= 0)
293       return 1;
294     if (months == 0)
295       return nanos < 0 ? -1 : nanos > 0 ? 1 : 0;
296     return -2;
297   }
298
299   public int compare (Object JavaDoc obj)
300   {
301     if (obj instanceof Duration)
302       return compare(this, (Duration) obj);
303     // Could also compare other Quanties if units match appropriately. FIXME.
304
throw new IllegalArgumentException JavaDoc ();
305   }
306
307   public String JavaDoc toString ()
308   {
309     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
310     int m = months;
311     long s = seconds;
312     int n = nanos;
313     boolean neg = m < 0 || s < 0 || n < 0;
314     if (neg)
315       {
316         m = -m;
317         s = -s;
318         n = -n;
319         sbuf.append('-');
320       }
321     sbuf.append('P');
322     int y = m / 12;
323     if (y != 0)
324       {
325         sbuf.append(y);
326         sbuf.append('Y');
327         m -= y * 12;
328       }
329     if (m != 0)
330       {
331         sbuf.append(m);
332         sbuf.append('M');
333       }
334     long d = s / (24 * 60 * 60);
335     if (d != 0)
336       {
337         sbuf.append(d);
338         sbuf.append('D');
339         s -= 24 * 60 * 60 * d;
340       }
341     if (s != 0 || n != 0)
342       {
343         sbuf.append('T');
344         long hr = s / (60 * 60);
345         if (hr != 0)
346           {
347             sbuf.append(hr);
348             sbuf.append('H');
349             s -= 60 * 60 * hr;
350           }
351         long mn = s / 60;
352         if (mn != 0)
353           {
354             sbuf.append(mn);
355             sbuf.append('M');
356             s -= 60 * mn;
357           }
358         if (s != 0 || n != 0)
359           {
360             sbuf.append(s);
361             appendNanoSeconds(n, sbuf);
362             sbuf.append('S');
363           }
364       }
365     else if (sbuf.length() == 1)
366       sbuf.append(unit == Unit.month ? "0M" : "T0S");
367     return sbuf.toString();
368   }
369
370   static void appendNanoSeconds (int nanoSeconds, StringBuffer JavaDoc sbuf)
371   {
372     if (nanoSeconds == 0)
373       return;
374     sbuf.append('.');
375     int pos = sbuf.length();
376     sbuf.append(nanoSeconds);
377     int len = sbuf.length();
378     int pad = pos + 9 - len;
379     while (--pad >= 0)
380       sbuf.insert(pos, '0');
381     len = pos + 9;
382     do { --len; } while (sbuf.charAt(len) == '0');
383     sbuf.setLength(len+1);
384   }
385
386   /** Parse digits following by a terminator char
387    * @return {@code (VALUE << 32)|(FOLLOWING_POS<<16)|FOLLOWING_CHAR}.
388    * If there are no digits return @code{START<<16}.
389    * Otherwise, on overflow or digits followed by end-of-string, return -1.
390    */

391   private static long scanPart (String JavaDoc str, int start)
392   {
393     int i = start;
394     long val = -1;
395     int len = str.length();
396     while (i < len)
397       {
398         char ch = str.charAt(i);
399         i++;
400         int dig = Character.digit(ch, 10);
401         if (dig < 0)
402           {
403             if (val < 0) return start << 16;
404             return (val << 32) | (i << 16) | ((int) ch);
405           }
406         val = val < 0 ? dig : 10 * val + dig;
407         if (val > Integer.MAX_VALUE)
408           return -1; // overflow
409
}
410     return val < 0 ? (start << 16) : -1;
411   }
412
413   /** The number of years in the canonical representation. */
414   public int getYears ()
415   {
416     return months / 12;
417   }
418
419   public int getMonths()
420   {
421     return months % 12;
422   }
423
424   public int getDays ()
425   {
426     return (int) (seconds / (24 * 60 * 60));
427   }
428
429   public int getHours ()
430   {
431     return (int) ((seconds / (60 * 60)) % 24);
432   }
433
434   public int getMinutes ()
435   {
436     return (int) ((seconds / 60) % 60);
437   }
438
439   public int getSecondsOnly ()
440   {
441     return (int) (seconds % 60);
442   }
443
444   public int getNanoSecondsOnly ()
445   {
446     return nanos;
447   }
448
449   public int getTotalMonths ()
450   {
451     return months;
452   }
453
454   public long getTotalSeconds ()
455   {
456     return seconds;
457   }
458
459   public long getTotalMinutes ()
460   {
461     return seconds / 60;
462   }
463
464   public long getNanoSeconds ()
465   {
466     return seconds * 1000000000L + nanos;
467   }
468
469   public boolean isZero ()
470   {
471     return months == 0 && seconds == 0 && nanos == 0;
472   }
473
474   public boolean isExact ()
475   {
476     return false;
477   }
478
479   public void writeExternal(ObjectOutput out) throws IOException
480   {
481     out.writeInt(months);
482     out.writeLong(seconds);
483     out.writeInt(nanos);
484     out.writeObject(unit);
485   }
486
487   public void readExternal(ObjectInput in)
488     throws IOException, ClassNotFoundException JavaDoc
489   {
490     months = in.readInt();
491     seconds = in.readLong();
492     nanos = in.readInt();
493     unit = (Unit) in.readObject();
494   }
495
496   public Unit unit() { return unit; }
497   public Complex number ()
498   {
499     throw new Error JavaDoc("number needs to be implemented!");
500   }
501
502   public int hashCode ()
503   {
504     return months ^ (int) seconds ^ nanos;
505   }
506
507   /** Compare for equality.
508    * Ignores unit.
509    */

510   public static boolean equals (Duration x, Duration y)
511   {
512     return x.months == y.months
513       && x.seconds == y.seconds
514       && x.nanos == y.nanos;
515   }
516
517   /** Compare for equality.
518    * Ignores unit.
519    */

520   public boolean equals (Object JavaDoc obj)
521   {
522     if (obj == null || ! (obj instanceof Duration))
523       return false;
524     return Duration.equals (this, (Duration) obj);
525   }
526 }
527
Popular Tags