001 package edu.nrao.sss.measure; 002 003 import java.math.BigDecimal; 004 import java.text.ParseException; 005 import java.text.SimpleDateFormat; 006 import java.util.Date; 007 008 import javax.xml.bind.annotation.XmlElement; 009 import javax.xml.bind.annotation.XmlType; 010 011 import static edu.nrao.sss.util.FormatString.ISO8601_DATE_TIME_TIMEZONE; 012 import static edu.nrao.sss.util.FormatString.ISO8601_TIME_INTERVAL_SEPARATOR; 013 014 import edu.nrao.sss.util.DateUtility; 015 016 /** 017 * An interval from one point in time to another. 018 * <p> 019 * This interval is half-open; it includes the starting point 020 * but does <i>not</i> include the ending point.</p> 021 * <p> 022 * <b><u>Caveat</u></b><br/><tt> 023 * July 2006. It might be that some of the query methods that compare 024 * one interval to another, or to a point, are not accurate for the 025 * degenerate case where one or both intervals have zero length. 026 * This possibility will be tested, and corrected, in the future. 027 * --DMH</tt></p> 028 * <p> 029 * <b>Version Info:</b> 030 * <table style="margin-left:2em"> 031 * <tr><td>$Revision: 1708 $</td></tr> 032 * <tr><td>$Date: 2008-11-14 10:31:42 -0700 (Fri, 14 Nov 2008) $</td></tr> 033 * <tr><td>$Author: dharland $</td></tr> 034 * </table></p> 035 * 036 * @author David M. Harland 037 * @since 2006-03-24 038 */ 039 @XmlType(propOrder= {"start","end"}) 040 public class TimeInterval 041 implements Cloneable, Comparable<TimeInterval> 042 { 043 private static final long DEFAULT_START_TIME = 044 DateUtility.createEarlyDate().getTime(); 045 046 private static final long DEFAULT_END_TIME = 047 DateUtility.createLateDate().getTime(); 048 049 @XmlElement private Date start; 050 @XmlElement private Date end; 051 052 //=========================================================================== 053 // CONSTRUCTORS 054 //=========================================================================== 055 056 /** 057 * Creates a new large interval. 058 * The newly created interval begins prior to the current century 059 * and ends after the current millenium. 060 */ 061 public TimeInterval() 062 { 063 start = new Date(DEFAULT_START_TIME); 064 end = new Date(DEFAULT_END_TIME); 065 } 066 067 /** 068 * Creates a new interval using the given times. 069 * <p> 070 * The description of the {@link #set(Date, Date)} method applies 071 * to this constructor as well.</p> 072 * 073 * @param from the starting point of this interval. The starting 074 * point is included in the interval. 075 * 076 * @param to the ending point of this interval. The ending 077 * point is <i>not</i> included in the interval. 078 */ 079 public TimeInterval(Date from, Date to) 080 { 081 setInterval(from, to); 082 } 083 084 /** 085 * Resets this interval to its initial state. 086 * <p> 087 * A reset interval has the same state as one newly created by 088 * the {@link #TimeInterval() no-argument constructor}.</p> 089 */ 090 public void reset() 091 { 092 start.setTime(DEFAULT_START_TIME); 093 end.setTime(DEFAULT_END_TIME); 094 } 095 096 //=========================================================================== 097 // GETTING & SETTING THE PROPERTIES 098 //=========================================================================== 099 100 /** 101 * Sets the starting and ending points of this interval. 102 * <p> 103 * By convention, the earlier date should be passed as 104 * the {@code from} parameter. However, this method will 105 * correct the situation where {@code from} is later than 106 * {@code to}, and 107 * use the earlier of the two parameters as the starting 108 * point of this interval. The later of the two 109 * times will be used as the ending point. 110 * Note that this range goes up to, but does not include, 111 * the ending point. That is, this interval is half-open, 112 * with the ending point excluded from the interval.</p> 113 * <p> 114 * If either parameter is <i>null</i>, a 115 * {@code IllegalArgumentException} will be thrown.</p> 116 * <p> 117 * Note that this method makes copies of the parameters; it 118 * does not maintain a reference to either parameter. This 119 * is done in order to maintain the integrity of the relationship 120 * between the starting and ending points of this interval.</p> 121 * 122 * @param from the starting point of this interval. The starting 123 * point is included in the interval. 124 * 125 * @param to the ending point of this interval. The ending 126 * point is <i>not</i> included in the interval. 127 */ 128 public void set(Date from, Date to) 129 { 130 setInterval(from, to); 131 } 132 133 /** 134 * Sets the endpoints of this interval based on {@code intervalText}. 135 * If {@code intervalText} is <i>null</i> or <tt>""</tt> (the empty string), 136 * the {@link #reset()} method is called. Otherwise, the parsing is 137 * delegated to {@link #parse(String, String, String)}. See that method 138 * for details related to parsing. 139 */ 140 public void set(String intervalText, String dateFormat, String separator) 141 { 142 if (intervalText == null || intervalText.equals("")) 143 { 144 reset(); 145 } 146 else 147 { 148 try { 149 parseInterval(intervalText, dateFormat, separator); 150 } 151 catch (IllegalArgumentException ex) { 152 //If the parseInterval method threw an exception it never reached 153 //the point of updating this interval, so we don't need to restore 154 //to pre-parsing values. 155 throw ex; 156 } 157 } 158 } 159 160 public void set(String iso8601Interval) 161 { 162 if (iso8601Interval == null || iso8601Interval.equals("")) 163 { 164 reset(); 165 } 166 else 167 { 168 try { 169 parseInterval(iso8601Interval, ISO8601_DATE_TIME_TIMEZONE, 170 ISO8601_TIME_INTERVAL_SEPARATOR); 171 } 172 catch (IllegalArgumentException ex) { 173 //If the parseInterval method threw an exception it never reached 174 //the point of updating this interval, so we don't need to restore 175 //to pre-parsing values. 176 throw ex; 177 } 178 } 179 } 180 181 /** Called from constructor & public set method. */ 182 private void setInterval(Date time1, Date time2) 183 { 184 if ((time1 == null) || (time2 == null)) 185 throw new IllegalArgumentException("Cannot configure TimeInterval with null Date."); 186 187 if (time2.before(time1)) 188 { 189 start = (Date)time2.clone(); 190 end = (Date)time1.clone(); 191 } 192 else 193 { 194 start = (Date)time1.clone(); 195 end = (Date)time2.clone(); 196 } 197 } 198 199 /** 200 * Returns a copy of this interval's starting time. 201 * Note that the start time is included in this interval. 202 * 203 * @return a copy of this interval's starting time. 204 * 205 * @see #set(Date, Date) 206 */ 207 public Date getStart() 208 { 209 return (Date)start.clone(); 210 } 211 212 /** 213 * Returns a copy of this interval's ending time. 214 * Note that the end time is <i>not</i> included in this interval. 215 * 216 * @return a copy of this interval's ending time. 217 * 218 * @see #set(Date, Date) 219 */ 220 public Date getEnd() 221 { 222 return (Date)end.clone(); 223 } 224 225 //=========================================================================== 226 // DERIVED QUERIES 227 //=========================================================================== 228 229 /** 230 * Returns the time that is midway between the endpoints of this interval. 231 * @return the center of this interval. 232 */ 233 public Date getCenterTime() 234 { 235 double center = (double)(end.getTime() + start.getTime()) / 2.0; 236 237 return new Date(Math.round(center)); 238 } 239 240 /** 241 * Returns the time duration represented by this interval. 242 * @return the time duration represented by this interval. 243 */ 244 public TimeDuration getDuration() 245 { 246 TimeDuration td = new TimeDuration(); 247 248 td.set(new BigDecimal(end.getTime() - start.getTime()), 249 TimeUnits.MILLISECOND); 250 251 return td; 252 } 253 254 /** 255 * Returns <i>true</i> if {@code time} is contained in this interval. 256 * <p> 257 * Note that this interval is half-open; it does not include its 258 * ending point.</p> 259 * 260 * @param time the time to be tested for containment. 261 * 262 * @return <i>true</i> if {@code time} is contained in this interval. 263 */ 264 public boolean contains(Date time) 265 { 266 return (time.equals(start) || time.after(start)) && time.before(end); 267 } 268 269 /** 270 * Returns <i>true</i> if this interval contains {@code other}. 271 * <p> 272 * Note that an interval that is equal to this one is <i>not</i> 273 * contained by this one. The best analogy is that of a rigid box 274 * with infinitely thin walls: a box that is exactly the same as 275 * another cannot fit inside it.</p> 276 * 277 * @param other an interval that might be contained by this one. 278 * 279 * @return <i>true</i> if this interval contains {@code other}. 280 */ 281 public boolean contains(TimeInterval other) 282 { 283 if (this.equals(other)) 284 return false; 285 else 286 return (start.equals(other.start) || start.before(other.start)) && 287 (end.equals(other.end) || end.after(other.end)); 288 } 289 290 /** 291 * Returns <i>true</i> if the {@code other} interval contains this one. 292 * <p> 293 * See {@link #contains(TimeInterval)} for the definition of containment.</p> 294 * 295 * @param other a time interval that might contain this one. 296 * 297 * @return <i>true</i> if the {@code other} interval contains this one. 298 */ 299 public boolean isContainedBy(TimeInterval other) 300 { 301 return other.contains(this); 302 } 303 304 /** 305 * Returns <i>true</i> if this interval ends before the {@code other} 306 * one starts. 307 * @param other an interval that might come after this one. 308 * @return <i>true</i> if this interval ends before {@code other} starts. 309 */ 310 public boolean isBefore(TimeInterval other) 311 { 312 //Remember that the starting point of an interval is IN the interval, 313 //while the ending point is OUTSIDE the interval. This means that 314 //if other has a start that equals this interval's end, it is after 315 //this one. 316 317 return isBefore(other.start); 318 } 319 320 /** 321 * Returns <i>true</i> if this interval starts after the {@code other} 322 * one ends. 323 * @param other an interval that might come after this one. 324 * @return <i>true</i> if this interval starts after {@code other} ends. 325 */ 326 public boolean isAfter(TimeInterval other) 327 { 328 //Remember that the starting point of an interval is IN the interval, 329 //while the ending point is OUTSIDE the interval. This means that 330 //if other has a start that equals this interval's end, it is after 331 //this one. 332 333 //Don't use isAfter(Date) because other.end is NOT actually in the 334 //other interval. We would need to pass other.end less epsilon. 335 return this.start.after(other.end) || this.start.equals(other.end); 336 } 337 338 /** 339 * Returns <i>true</i> if this interval ends before the given time. 340 * @param time a point in time that might come after this interval. 341 * @return <i>true</i> if this interval ends before the given time. 342 */ 343 public boolean isBefore(Date time) 344 { 345 //Remember that the ending point of an interval is OUTSIDE the interval. 346 //This means that if time is exactly equal to the ending point, it 347 //is after the interval. 348 349 return this.end.before(time) || this.end.equals(time); 350 } 351 352 /** 353 * Returns <i>true</i> if this interval starts after the given time. 354 * @param time a point in time that might come after this interval. 355 * @return <i>true</i> if this interval starts after the given time. 356 */ 357 public boolean isAfter(Date time) 358 { 359 //Remember that the starting point of an interval is IN the interval. 360 //This means that if time is exactly equal to the starting point, 361 //it is NOT before the interval. 362 363 return this.start.after(time); 364 } 365 366 /** 367 * Returns <i>true</i> if this interval and the {@code other} form a contiguous 368 * non-overlapping time interval. Since a time interval is half open, this 369 * method returns <i>true</i> when either this interval starts at the same time 370 * the other one ends, or ends at the same time the other starts. 371 * 372 * @param other an interval that might be contiguous with this one. 373 * 374 * @return <i>true</i> if this interval and the {@code other} form a contiguous 375 * non-overlapping time interval. 376 */ 377 public boolean isContiguousWith(TimeInterval other) 378 { 379 return this.start.equals(other.end) || this.end.equals(other.start); 380 } 381 382 /** 383 * Returns <i>true</i> if this interval overlaps the {@code other} interval. 384 * <p> 385 * Note that equal intervals overlap, as do intervals that have a 386 * container-contained relationship.</p> 387 * 388 * @param other an interval that might overlap this one. 389 * 390 * @return <i>true</i> if this interval overlaps the {@code other} interval. 391 */ 392 public boolean overlaps(TimeInterval other) 393 { 394 TimeInterval early, late; 395 396 //This bit of ordering makes the subsequent if statement easier to read 397 if (other.start.before(this.start)) 398 { 399 early = other; 400 late = this; 401 } 402 else 403 { 404 early = this; 405 late = other; 406 } 407 408 //Remember that the starting point of an interval is IN the interval, 409 //while the ending point is OUTSIDE the interval. This means that 410 //if the starting point of one interval is the same as the ending 411 //point of another, they do NOT overlap. 412 413 return late.start.before(early.end); 414 } 415 416 /** 417 * Returns <i>true</i> if this interval is in its default state, 418 * no matter how it got there. 419 * <p> 420 * An interval is in its <i>default state</i> if both its endpoints 421 * are the same as those of an interval newly created via 422 * the {@link #TimeInterval() no-argument constructor}. 423 * An interval whose most recent update came via the 424 * {@link #reset() reset} method is also in its default state.</p> 425 * 426 * @return <i>true</i> if this interval is in its default state. 427 */ 428 public boolean isInDefaultState() 429 { 430 return start.getTime() == DEFAULT_START_TIME && 431 end.getTime() == DEFAULT_END_TIME; 432 } 433 434 //=========================================================================== 435 // CONVERSION TO, AND EXPRESSION IN, OTHER FORMS 436 //=========================================================================== 437 438 /** 439 * Returns two new intervals that were formed by splitting this one at the 440 * given point. This interval is not altered by this method. 441 * <p> 442 * <b>Scenario One.</b> If this interval contains {@code pointOfSplit}, then 443 * the first interval in the array runs from this interval's starting point 444 * to {@code pointOfSplit}, and the second interval runs from 445 * {@code pointOfSplit} to this interval's ending point.</p> 446 * <p> 447 * <b>Scenario Two.</b> If this interval does not contain 448 * {@code pointOfSplit}, then the first interval in the array will be equal 449 * to this one, and the second interval will be a zero length interval whose 450 * starting and ending endpoints are both {@code pointOfSplit}.</p> 451 * 452 * @param pointOfSplit the point at which to split this interval in two. 453 * 454 * @return an array of two intervals whose combined length equals this 455 * interval's length. 456 */ 457 public TimeInterval[] split(Date pointOfSplit) 458 { 459 TimeInterval[] result = new TimeInterval[2]; 460 461 result[0] = new TimeInterval(); 462 result[1] = new TimeInterval(); 463 464 if (this.contains(pointOfSplit)) 465 { 466 result[0].set(this.start, pointOfSplit); 467 result[1].set(pointOfSplit, this.end); 468 } 469 else //can't use point to split, as its not in this interval 470 { 471 result[0].set(this.start, this.end); 472 result[1].set(pointOfSplit, pointOfSplit); 473 } 474 475 return result; 476 } 477 478 /** 479 * Returns a new time interval that exactly plugs the gap between this 480 * interval and the {@code other}. 481 * <p> 482 * If this interval is contiguous with, or overlaps, {@code other}, 483 * <i>null</i> is returned. Otherwise, a new interval is created 484 * and valued such that it fills the gap between this interval and 485 * the other. Note that the gap is filled regardless of whether 486 * {@code other} is before or after this interval.</p> 487 * 488 * @param other an interval that might not overlap, or be contiguous with, 489 * this interval, and for which a gap-filling interval is sought. 490 * 491 * @return a new interval that fills the gap between this one and 492 * {@code other}, or <i>null</i> if there is no gap. 493 */ 494 public TimeInterval makeGapFiller(TimeInterval other) 495 { 496 TimeInterval gapFiller = null; 497 498 //Test for gap 499 if (this.isAfter(other) || this.isBefore(other)) 500 { 501 Date gapStart = this.end.before(other.end) ? this.end : other.end; 502 Date gapEnd = this.start.after(other.start) ? this.start : other.start; 503 504 gapFiller = new TimeInterval(gapStart, gapEnd); 505 } 506 507 return gapFiller; 508 } 509 510 //=========================================================================== 511 // PARSING 512 //=========================================================================== 513 514 /** 515 * Creates a new time interval based on the parameter text. 516 * <p> 517 * This is a convenience method that is equivalent to:<pre> 518 * parse(iso8601Interval, FormatString.ISO8601_DATE_TIME_TIMEZONE, 519 * FormatString.ISO8601_TIME_INTERVAL_SEPARATOR);</pre> 520 * 521 * @param iso8601Interval the text to be parsed and converted into a time 522 * interval. 523 * 524 * @return a new time interval based on {@code iso8601Interval}. If 525 * {@code iso8601Interval} is <i>null</i> or <tt>""</tt> (the empty 526 * string), a new time interval of length zero is returned. 527 * 528 * @see #parse(String, String, String) 529 */ 530 public static TimeInterval parse(String iso8601Interval) 531 { 532 return parse(iso8601Interval, ISO8601_DATE_TIME_TIMEZONE, 533 ISO8601_TIME_INTERVAL_SEPARATOR); 534 } 535 536 /** 537 * Creates a new time interval by parsing {@code interval} with the given 538 * formatter and separator. The general form is 539 * <tt>StartDateSeparatorEndDate</tt>, with the particulars of the date 540 * format determined by {@code dateFormat}. 541 * 542 * @param interval the text to be parsed and converted into a time 543 * interval. If this value is <i>null</i> or <tt>""</tt> (the empty 544 * string), a new time interval of length zero is returned. 545 * 546 * @param dateFormat the text that determines the format of the start and end 547 * dates in {@code interval}. These are the same formats 548 * used in {@link java.text.SimpleDateFormat}. A list of 549 * ISO 8601 format strings may be found in 550 * {@link edu.nrao.sss.util.FormatString}. 551 * 552 * @param separator the text that separates the start date from the end date 553 * in {@code interval}. 554 * 555 * @return a new time interval based on the text of {@code interval}. 556 * 557 * @throws IllegalArgument if {@code interval} cannot be parsed using 558 * {@code dateFormat} and {@code separator}. 559 */ 560 public static TimeInterval parse(String interval, String dateFormat, 561 String separator) 562 { 563 TimeInterval newInterval = new TimeInterval(); 564 565 //null & "" are permissible 566 if ((interval != null) && !interval.equals("")) 567 { 568 try { 569 newInterval.parseInterval(interval, dateFormat, separator); 570 } 571 catch (IllegalArgumentException ex) { 572 throw ex; 573 } 574 } 575 576 return newInterval; 577 } 578 579 /** Does the actual parsing. */ 580 private void parseInterval(String interval, 581 String dateFormat, 582 String separator) 583 { 584 String errMsg = null; 585 586 //Find the endpoints of the interval 587 String[] endPoints = interval.split(separator, -1); 588 589 if (endPoints.length == 2) 590 { 591 //Parse the endpoints and set the interval 592 SimpleDateFormat parser = new SimpleDateFormat(dateFormat); 593 594 try 595 { 596 setInterval(parser.parse(endPoints[0]), parser.parse(endPoints[1])); 597 } 598 catch (ParseException ex) 599 { 600 errMsg = ex.getMessage(); 601 } 602 603 } 604 else //bad # of endpoints 605 { 606 errMsg = "Found " + endPoints.length + " endpoints. There should be 2."; 607 } 608 609 //Error message 610 if (errMsg != null) 611 { 612 errMsg = errMsg + " [Params: interval=" + interval + ", dateFormat=" + 613 dateFormat + ", separator=" + separator + "]"; 614 615 throw new IllegalArgumentException(errMsg); 616 } 617 } 618 619 //=========================================================================== 620 // UTILITY METHODS 621 //=========================================================================== 622 623 /** 624 * Creates a text representation of this time interval. 625 * The format of the returned string is the full ISO 8601 626 * representation of a time interval and looks something like this: 627 * <tt>yyyy-mm-ddThh:mm:ss.sss+zzzz/yyyy-mm-ddThh:mm:ss.sss+zzzz</tt>, 628 * where the 'T' and '/' are literals and the '+' is either a '+' or '-'. 629 * <p> 630 * A call to this method is equivalent to:<pre> 631 * toString(FormatString.ISO8601_DATE_TIME_TIMEZONE, 632 * FormatString.ISO8601_TIME_INTERVAL_SEPARATOR);</pre></p> 633 */ 634 public String toString() 635 { 636 return toString(ISO8601_DATE_TIME_TIMEZONE, 637 ISO8601_TIME_INTERVAL_SEPARATOR); 638 } 639 640 /** 641 * Returns a text representation of this interval based on the 642 * formatting parameters. For a description of these parameters, 643 * see {@link #parse(String, String, String)}. 644 */ 645 public String toString(String dateFormat, String separator) 646 { 647 SimpleDateFormat df = new SimpleDateFormat(dateFormat); 648 649 StringBuilder buff = new StringBuilder(); 650 651 buff.append(df.format(start)).append(separator).append(df.format(end)); 652 653 return buff.toString(); 654 } 655 656 /** 657 * Returns a time interval that is equal to this one. 658 * <p> 659 * If anything goes wrong during the cloning procedure, 660 * a {@code RuntimeException} will be thrown.</p> 661 */ 662 public TimeInterval clone() 663 { 664 TimeInterval clone = null; 665 666 try 667 { 668 //This line takes care of the primitive fields properly 669 clone = (TimeInterval)super.clone(); 670 671 clone.start = (Date)this.start.clone(); 672 clone.end = (Date)this.end.clone(); 673 } 674 catch (Exception ex) 675 { 676 throw new RuntimeException(ex); 677 } 678 679 return clone; 680 } 681 682 /** Returns <i>true</i> if {@code o} is equal to this time interval. */ 683 public boolean equals(Object o) 684 { 685 //Quick exit if o is this 686 if (o == this) 687 return true; 688 689 //Quick exit if o is null 690 if (o == null) 691 return false; 692 693 //Quick exit if classes are different 694 if (!o.getClass().equals(this.getClass())) 695 return false; 696 697 TimeInterval otherTime = (TimeInterval)o; 698 699 return otherTime.start.equals(this.start) && 700 otherTime.end.equals(this.end); 701 } 702 703 /** Returns a hash code value for this time interval. */ 704 public int hashCode() 705 { 706 //Taken from the Effective Java book by Joshua Bloch. 707 //The constants 17 & 37 are arbitrary & carry no meaning. 708 int result = 17; 709 710 result = 37 * result + start.hashCode(); 711 result = 37 * result + end.hashCode(); 712 713 return result; 714 } 715 716 /** 717 * Compares this interval to {@code other} for order. 718 * <p> 719 * One interval is deemed to be "less than" the other if it begins 720 * before the other. In the case that two intervals start at the 721 * same time, the one that ends first is considered to be less 722 * than the other.</p> 723 * 724 * @param other the time interval to which this one is compared. 725 * 726 * @return a negative integer, zero, or a positive integer as this interval 727 * is less than, equal to, or greater than the other interval. 728 */ 729 public int compareTo(TimeInterval other) 730 { 731 int answer = this.start.compareTo(other.start); 732 733 //If the intervals start at the same time, compare the end times 734 if (answer == 0) 735 answer = this.end.compareTo(other.end); 736 737 return answer; 738 } 739 740 /*public static void main(String[] args) 741 { 742 TimeInterval time = new TimeInterval(); 743 744 time.set(new Date(), new Date()); 745 746 System.out.println(time.toString()); 747 System.out.println(time.toString(FormatString.ISO8601_CALENDAR_DATE, " - ")); 748 System.out.println(time.toString(FormatString.ISO8601_DATE_TIME, " - ")); 749 System.out.println(time.toString(FormatString.ISO8601_HOUR_MIN_SEC, " - ")); 750 System.out.println(time.toString(FormatString.ISO8601_HOUR_MIN_SEC_MILLI, " - ")); 751 System.out.println(time.toString()); 752 System.out.println(); 753 754 try { 755 time = TimeInterval.parse("2006-07-03T01:02:03.04-0600/2006-09-16T01:23:45.678-0600"); 756 System.out.println(time); 757 } 758 catch (Exception ex) { System.out.println(ex.getMessage()); } 759 760 try { 761 time = TimeInterval.parse("2006-07-03T01:02:03.04-0600 TO 2006-09-16T01:23:45.678-0600", FormatString.ISO8601_CALENDAR_DATE, " TO "); 762 System.out.println(time); 763 } 764 catch (Exception ex) { System.out.println(ex.getMessage()); } 765 766 try { 767 time = TimeInterval.parse("2006-07-03T01:02:03.04-0600 TO 2006-09-16T01:23:45.678-0600", FormatString.ISO8601_DATE_TIME, " TO "); 768 System.out.println(time); 769 } 770 catch (Exception ex) { System.out.println(ex.getMessage()); } 771 772 try { 773 time = TimeInterval.parse("01:02:03.04 TO 01:23:45.678", FormatString.ISO8601_HOUR_MIN_SEC, " TO "); 774 System.out.println(time); 775 } 776 catch (Exception ex) { System.out.println(ex.getMessage()); } 777 778 try { 779 time = TimeInterval.parse("01:02:03.04 TO 01:23:45.678", FormatString.ISO8601_HOUR_MIN_SEC_MILLI, " TO "); 780 System.out.println(time); 781 } 782 catch (Exception ex) { System.out.println(ex.getMessage()); } 783 784 785 try { 786 time = TimeInterval.parse("2006-07-03T01:02:03.04-0600/2006-09-16T01:23:45.678-0600"); 787 System.out.println(time); 788 } 789 catch (Exception ex) { System.out.println(ex.getMessage()); } 790 System.out.println(); 791 System.out.println(time.toString()); 792 System.out.println(time.toString(FormatString.ISO8601_HOUR_MIN_SEC, "...")); 793 System.out.println(time.toString(FormatString.ISO8601_HOUR_MIN_SEC_MILLI, " - ")); 794 System.out.println(time.toString(FormatString.ISO8601_CALENDAR_DATE, " until ")); 795 System.out.println(time.toString(FormatString.ISO8601_DATE_TIME, "~")); 796 System.out.println(time.toString(FormatString.ISO8601_DATE_TIME_TIMEZONE, " all the way to ")); 797 798 System.out.println(); 799 time.set("2006-11-05 to 2007-01-01", FormatString.ISO8601_CALENDAR_DATE, " to "); 800 System.out.println(time); 801 }*/ 802 }