| 1 package gnu.math; 2 import java.io.*; 3 4 public class Duration extends Quantity implements Externalizable 5 { 6 public Unit unit; 7 8 9 int months; 10 11 16 long seconds; 17 18 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 str, Unit unit) 49 { 50 Duration d = Duration.valueOf(str, unit); 51 if (d == null) 52 throw new IllegalArgumentException ("not a valid "+unit.getName()+" duration: '"+str+"'"); 53 return d; 54 } 55 56 public static Duration parseDuration (String str) 57 { 58 return parse(str, Unit.duration); 59 } 60 61 public static Duration parseYearMonthDuration (String str) 62 { 63 return parse(str, Unit.month); 64 } 65 66 67 public static Duration parseDayTimeDuration (String str) 68 { 69 return parse(str, Unit.second); 70 } 71 72 75 public static Duration valueOf (String 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 } 128 else if (str.charAt(pos) != 'T' || ++pos == len) 129 return null; 130 else { 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 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 (); 199 } 200 201 public Numeric mul (Object 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 (); 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 ("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 ("divide of incompatible durations"); 234 } 235 236 public Numeric div (Object 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 ("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 long nanos = x.seconds * 1000000000L + (long) x.nanos 256 + k * (y.seconds * 1000000000L + y.nanos); 257 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 ("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 ("cannot multiply general duration"); 273 double months = x.months * y; 274 if (Double.isInfinite(months) || Double.isNaN(months)) 275 throw new ArithmeticException ("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 obj) 300 { 301 if (obj instanceof Duration) 302 return compare(this, (Duration) obj); 303 throw new IllegalArgumentException (); 305 } 306 307 public String toString () 308 { 309 StringBuffer sbuf = new StringBuffer (); 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 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 391 private static long scanPart (String 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; } 410 return val < 0 ? (start << 16) : -1; 411 } 412 413 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  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 ("number needs to be implemented!"); 500 } 501 502 public int hashCode () 503 { 504 return months ^ (int) seconds ^ nanos; 505 } 506 507 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 520 public boolean equals (Object obj) 521 { 522 if (obj == null || ! (obj instanceof Duration)) 523 return false; 524 return Duration.equals (this, (Duration) obj); 525 } 526 } 527 | Popular Tags |