1 17 package org.alfresco.service.cmr.repository.datatype; 18 19 import java.io.IOException ; 20 import java.io.Serializable ; 21 import java.io.StreamTokenizer ; 22 import java.io.StringReader ; 23 import java.math.BigDecimal ; 24 import java.text.DateFormat ; 25 import java.text.NumberFormat ; 26 import java.text.ParsePosition ; 27 import java.util.Calendar ; 28 import java.util.Date ; 29 30 import org.alfresco.util.CachingDateFormat; 31 32 60 public class Duration implements Comparable , Serializable 61 { 62 63 static final long serialVersionUID = 3274526442325176068L; 64 65 public static final String XML_DAY = "P1D"; 66 public static final String XML_WEEK = "P7D"; 67 public static final String XML_TWO_WEEKS = "P14D"; 68 public static final String XML_MONTH = "P1M"; 69 public static final String XML_QUARTER = "P3M"; 70 public static final String XML_SIX_MONTHS = "P6M"; 71 public static final String 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 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 94 101 public static Date add(Date date, Duration duration) 102 { 103 Calendar 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 122 123 public static Date subtract(Date date, Duration duration) 124 { 125 return add(date, duration.unaryMinus()); 126 } 127 128 129 130 133 134 public Duration() 135 { 136 super(); 137 } 138 139 142 143 public Duration(String duration) 144 { 145 146 if (duration.equals("P")) 147 { 148 throw new RuntimeException ("Invalid period: P"); 149 } 150 151 if (!duration.startsWith("P") && !duration.startsWith("-P")) 152 { 153 throw new RuntimeException ("Invalid period: must start with P or -P"); 154 } 155 else 156 { 157 boolean dateMode = true; 158 int last = -1; 159 Double nval = null; 160 StringReader reader = new StringReader (duration); 161 StreamTokenizer tok = new StreamTokenizer (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 (tok.nval); 183 } 184 else if (token == StreamTokenizer.TT_EOF) 185 { 186 throw new RuntimeException ("Invalid EOF in Duration"); 187 } 188 else if (token == StreamTokenizer.TT_EOL) 189 { 190 throw new RuntimeException ("Invalid EOL in Duration"); 191 } 192 else if (token == StreamTokenizer.TT_WORD) 193 { 194 throw new RuntimeException ("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 } 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 ("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 ("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 ("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 ("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 ("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 ("IO Error parsing Duration: " + duration); 293 } 294 nval = null; 295 } 296 else 297 { 298 throw new RuntimeException ("IO Error parsing Duration: " + duration); 299 } 300 } 301 } 302 } 303 catch (IOException e) 304 { 305 throw new RuntimeException ("IO Error parsing Duration: " + duration); 306 } 307 catch (RuntimeException e) 308 { 309 throw new RuntimeException ("IO Error parsing Duration: " + duration, e); 310 } 311 } 312 } 313 314 317 318 private int checkIndex(int last, String search) 319 { 320 if ((search == null) || (search.length() == 0)) 321 { 322 throw new RuntimeException ("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 ("Illegal position for identifier " + search); 332 } 333 } 334 335 341 342 public Duration(Date date) 343 { 344 this(date, new Date ()); 345 } 346 347 354 355 public Duration(String start, String end) 356 { 357 this(parseDate(start), parseDate(end)); 358 } 359 360 361 366 private static Date parseDate(String stringDate) 367 { 368 DateFormat df = CachingDateFormat.getDateFormat(); 369 df.setLenient(true); 370 Date date; 371 372 ParsePosition pp = new ParsePosition (0); 373 date = df.parse(stringDate, pp); 374 if ((pp.getIndex() < stringDate.length()) || (date == null)) 375 { 376 date = new Date (); 377 } 378 return date; 379 380 } 381 382 388 public Duration(Date start_in, Date end_in) 389 { 390 boolean positive = true; 391 Date start; 392 Date 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 cstart = Calendar.getInstance(); 406 cstart.setTime(start); 407 Calendar 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 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 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 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 495 if ((months < 0) && (seconds + nanos < 0)) 496 { 497 positive = !positive; 499 months = -months; 500 seconds = -seconds; 501 nanos = -nanos; 502 } 503 else if ((months == 0) && (seconds + nanos < 0)) 504 { 505 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 ("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 ("Can not convert to period - incompatible signs for year_to_momth and day_to_second elements"); 518 } 519 else 520 { 521 } 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 542 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 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 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 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 607 608 private long getTotalMonths() 609 { 610 return m_years * 12 + m_months; 611 } 612 613 616 617 private long getTotalSeconds() 618 { 619 return m_seconds + m_mins * 60 + m_hours * 3600 + m_days * 3600 * 24; 620 } 621 622 625 626 private long getTotalNanos() 627 { 628 return m_nanos; 629 } 630 631 634 635 public boolean isYearToMonth() 636 { 637 return (m_years != 0) || (m_months != 0); 638 } 639 640 643 644 public boolean isDayToSec() 645 { 646 return ((m_years == 0) && (m_months == 0)); 647 } 648 649 652 653 public boolean hasTime() 654 { 655 return (m_hours != 0) || (m_mins != 0) || (m_seconds != 0) || (m_nanos != 0); 656 } 657 658 661 662 public Duration getYearToMonth() 663 { 664 Duration result = new Duration(m_positive, getTotalMonths(), 0, 0); 665 return result; 666 } 667 668 671 672 public Duration getDayToYear() 673 { 674 Duration result = new Duration(m_positive, 0, getTotalSeconds(), getTotalNanos()); 675 return result; 676 } 677 678 681 682 public int compareTo(Object o) 683 { 684 if (!(o instanceof Duration)) 685 { 686 throw new RuntimeException ("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 716 717 public boolean equals(Object 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 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 747 748 public String toString() 749 { 750 StringBuffer buffer = new StringBuffer (128); 751 if (!m_positive) 752 { 753 buffer.append("-"); 754 } 755 buffer.append("P"); 756 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 a = new BigDecimal (m_seconds); 781 BigDecimal b = new BigDecimal (m_nanos); 782 a = a.add(b.divide(new BigDecimal (1000000000), 9, BigDecimal.ROUND_HALF_EVEN)); 783 NumberFormat nf = NumberFormat.getInstance(); 784 buffer.append(nf.format(a)); 785 buffer.append("S"); 786 } 787 788 } 789 790 return buffer.toString(); 791 } 792 793 798 799 public String formattedString() 800 { 801 StringBuffer buffer = new StringBuffer (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 a = new BigDecimal (m_seconds); 849 BigDecimal b = new BigDecimal (m_nanos); 850 a = a.add(b.divide(new BigDecimal (1000000000), 9, BigDecimal.ROUND_HALF_EVEN)); 851 NumberFormat nf = NumberFormat.getInstance(); 852 String 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 868 public static void main(String [] 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 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 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 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 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 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 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 e) 939 { 940 e.printStackTrace(); 941 } 942 943 Date now = new Date (); 944 Calendar 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 1000 } 1001} 1002 | Popular Tags |