001 package edu.nrao.sss.measure; 002 003 import java.math.BigDecimal; 004 import java.math.RoundingMode; 005 import java.util.Calendar; 006 import java.util.Date; 007 import java.util.GregorianCalendar; 008 import java.util.TimeZone; 009 010 import static edu.nrao.sss.math.MathUtil.MC_INTERM_CALCS; 011 012 import edu.nrao.sss.util.StringUtil; 013 014 /** 015 * A Julian Date. 016 * <p/> 017 * <a href="http://en.wikipedia.org/wiki/Julian_date">Wikipedia</a>'s 018 * definition: 019 * <blockquote><i> 020 * The <b>Julian day</b> or <b>Julian day number (JDN)</b> 021 * is the integer number of days that 022 * have elapsed since the initial epoch defined as noon Universal Time (UT) 023 * Monday, January 1, 4713 BC in the proleptic Julian calendar...The <b>Julian 024 * date (JD)</b> is a continuous count of days and fractions elapsed since the 025 * same initial epoch. 026 * </i></blockquote> 027 * <p> 028 * As is the case with the {@link java.util.Date} class, this class models 029 * a date/time concept, not a pure date.</p> 030 * <p> 031 * <b>Note on the use of the Gregorian Calendar</b><br/> 032 * This class uses java's {@link java.util.GregorianCalendar} class to handle 033 * historical oddities in day tracking. That class sets the year for the 034 * switch over from the Julian to the Gregorian calendar as 1582; England 035 * and its colonies, including America, did not convert until 1752. That 036 * class also uses the Julian calendar for dates prior to the change to 037 * the Gregorian, and then a proleptic Julian for dates prior to 1 March 4 AD. 038 * What this means for us is that the conversion of a Julian Date to the 039 * more familiar form may not produce the expected results for dates prior 040 * to 1753. Since our main use for this class is for more recent dates, and 041 * since this class is backed by java's standard calendar, we should not 042 * be overly concerned with conversion of dates in the distant past.</p> 043 * <p> 044 * <b>Note on Precision</b><br/> 045 * The java {@link java.util.Date Date} class has a resolution of one 046 * millisecond (1ms). This class employs techniques to keep the resolution 047 * of this class as close to that of <tt>Date</tt> as possible. The goal 048 * is to make code like this work without complaint.</p> 049 * <pre> 050 * Date origDate = someFuncThatReturnsDate(); 051 * JulianDate jd1 = new JulianDate(origDate); 052 * JulianDate jd2 = new JulianDate(jd1.value()); 053 * Date otherDate = jd2.toDate(); 054 * 055 * if (!origDate.equals(otherDate)) 056 * complainVigorously(); 057 * </pre> 058 * <p> 059 * Without taking pains in the class to make certain the above works 060 * properly, the two times could have been off by a millisecond.</p> 061 * <p> 062 * <b>Version Info:</b> 063 * <table style="margin-left:2em"> 064 * <tr><td>$Revision: 1578 $</td></tr> 065 * <tr><td>$Date: 2008-09-24 13:34:32 -0600 (Wed, 24 Sep 2008) $</td></tr> 066 * <tr><td>$Author: dharland $ (last person to modify)</td></tr> 067 * </table></p> 068 * 069 * @author David M. Harland 070 * @since 2007-08-01 071 */ 072 //TODO deal w/ infinity 073 public class JulianDate 074 implements Cloneable, Comparable<JulianDate> 075 { 076 private static final BigDecimal JULIAN_DATE_AT_MJD_ZERO = new BigDecimal("2400000.5"); 077 private static final Date UTC_DATE_AT_MJD_ZERO; 078 private static final long MILLISECONDS_AT_MJD_ZERO; 079 080 //If we ever want to do threading, these calendar variables 081 //could be changed to instance variables. 082 private static final GregorianCalendar GREGORIAN_UTC_CALENDAR = 083 new GregorianCalendar(TimeZone.getTimeZone("GMT+0")); 084 085 private static final Calendar LOCAL_CALENDAR = Calendar.getInstance(); 086 private static final Calendar CALENDAR = Calendar.getInstance(); 087 088 static 089 { 090 //November 17, 1858 (rem: java uses Jan=0,...,Nov=10,...) 091 GREGORIAN_UTC_CALENDAR.clear(); //Lets us set milliseconds to zero. 092 GREGORIAN_UTC_CALENDAR.set(1858, 10, 17, 0, 0, 0); 093 094 UTC_DATE_AT_MJD_ZERO = GREGORIAN_UTC_CALENDAR.getTime(); 095 MILLISECONDS_AT_MJD_ZERO = UTC_DATE_AT_MJD_ZERO.getTime(); 096 } 097 098 private Date gd; 099 private BigDecimal jd; 100 private BigDecimal mjd; 101 102 /** 103 * Creates a new instance for the current time. 104 * 105 * See the {@link JulianDate class comments} for an explanation of 106 * the use of the {@link java.util.Date} class. 107 */ 108 public JulianDate() 109 { 110 this(new Date()); 111 } 112 113 /** 114 * Creates a new instance for the given Gregorian calendar date. 115 * 116 * See the {@link JulianDate class comments} for an explanation of 117 * the use of the {@link java.util.Date} class. 118 */ 119 public JulianDate(Date gregorianCalendarDate) 120 { 121 setValues(gregorianCalendarDate); 122 } 123 124 /** 125 * Creates a new instance for the given Julian Date. 126 * <p> 127 * The actual value used by this object may differ from the parameter value 128 * by as much as 10<sup>-7</sup>. This is because this class attempts to 129 * mimic the millisecond resolution of java's <tt>Date</tt> class. 130 * See the {@link JulianDate class comments} for a longer explanation.</p> 131 */ 132 public JulianDate(BigDecimal julianDate) 133 { 134 setValues(julianDate); 135 } 136 137 /** 138 * Creates a new instance for the given Julian Date. 139 * <p> 140 * The actual value used by this object may differ from the parameter value 141 * by as much as 10<sup>-7</sup>. This is because this class attempts to 142 * mimic the millisecond resolution of java's <tt>Date</tt> class. 143 * See the {@link JulianDate class comments} for a longer explanation.</p> 144 * 145 * @since 2008-08-14 146 */ 147 public JulianDate(String julianDate) 148 { 149 setValues(julianDate); 150 } 151 152 /** Creates a new instance for the given Julian Day Number. */ 153 public JulianDate(int julianDayNumber) 154 { 155 setValues(julianDayNumber); 156 } 157 158 /** 159 * Returns a new <tt>JulianDate</tt> whose time is set to the instance 160 * that MJD equals zero. 161 * 162 * @return 163 * a <tt>JulianDate</tt> where the {@link #modifiedValue()} is zero. 164 * 165 * @since 166 * 2008-09-23 167 */ 168 public static JulianDate makeMjdZero() 169 { 170 return new JulianDate(JULIAN_DATE_AT_MJD_ZERO); 171 } 172 173 private static JulianDate CLONE_BASE = null; 174 175 /** 176 * Returns a new <tt>JulianDate</tt> for the given MJD. 177 * 178 * @param modifiedJulianDate 179 * the intial MJD for this Julian Date. 180 * 181 * @return 182 * a new <tt>JulianDate</tt> for the given MJD. 183 * 184 * @since 2008-09-23 185 */ 186 public static JulianDate makeFromMjd(BigDecimal modifiedJulianDate) 187 { 188 if (CLONE_BASE == null) 189 CLONE_BASE = new JulianDate(); 190 191 JulianDate jd = CLONE_BASE.clone(); 192 193 return jd.setFromMjd(modifiedJulianDate); 194 } 195 196 /** 197 * Returns a new <tt>JulianDate</tt> for the given MJD. 198 * 199 * @param modifiedJulianDate 200 * the intial MJD for this Julian Date. 201 * 202 * @return 203 * a new <tt>JulianDate</tt> for the given MJD. 204 * 205 * @since 2008-09-23 206 */ 207 public static JulianDate makeFromMjd(String modifiedJulianDate) 208 { 209 if (CLONE_BASE == null) 210 CLONE_BASE = new JulianDate(); 211 212 JulianDate jd = CLONE_BASE.clone(); 213 214 return jd.setFromMjd(modifiedJulianDate); 215 } 216 217 //============================================================================ 218 // SETTING THE DATE 219 //============================================================================ 220 221 /** 222 * Sets this date to the current time. 223 * 224 * See the {@link JulianDate class comments} for an explanation of 225 * the use of the {@link java.util.Date} class. 226 */ 227 public JulianDate set() 228 { 229 return set(new Date()); 230 } 231 232 /** 233 * Sets this date to the given time. 234 * 235 * See the {@link JulianDate class comments} for an explanation of 236 * the use of the {@link java.util.Date} class. 237 * 238 * @param gregorianCalendarDate the common form of a date. 239 * 240 * @return this date. 241 */ 242 public JulianDate set(Date gregorianCalendarDate) 243 { 244 setValues(gregorianCalendarDate); 245 return this; 246 } 247 248 /** 249 * Sets this date to the given time. 250 * 251 * @param julianDayNumber an integral representation of a Julian Date. 252 * 253 * @return this date. 254 */ 255 public JulianDate set(int julianDayNumber) 256 { 257 setValues(julianDayNumber); 258 return this; 259 } 260 261 /** 262 * Sets this date to the given time. 263 * <p> 264 * The actual value used by this object may differ from the parameter value 265 * by as much as 10<sup>-7</sup>. This is because this class attempts to 266 * mimic the millisecond resolution of java's <tt>Date</tt> class. 267 * See the {@link JulianDate class comments} for a longer explanation.</p> 268 * 269 * @param julianDate 270 * a real number representation of a Julian Date. 271 * 272 * @return 273 * this date. 274 */ 275 public JulianDate set(BigDecimal julianDate) 276 { 277 setValues(julianDate); 278 return this; 279 } 280 281 /** 282 * Sets this date to the given time. 283 * <p> 284 * The actual value used by this object may differ from the parameter value 285 * by as much as 10<sup>-7</sup>. This is because this class attempts to 286 * mimic the millisecond resolution of java's <tt>Date</tt> class. 287 * See the {@link JulianDate class comments} for a longer explanation.</p> 288 * 289 * @param julianDate 290 * a real number representation, in text form, of a Julian Date. 291 * 292 * @return 293 * this date. 294 * 295 * @since 2008-08-14 296 */ 297 public JulianDate set(String julianDate) 298 { 299 setValues(julianDate); 300 return this; 301 } 302 303 /** 304 * Sets this date to the given time. 305 * <p> 306 * The actual value used by this object may differ from the parameter value 307 * by as much as 10<sup>-7</sup>. This is because this class attempts to 308 * mimic the millisecond resolution of java's <tt>Date</tt> class. 309 * See the {@link JulianDate class comments} for a longer explanation.</p> 310 * 311 * @param modifiedJulianDate 312 * a real number representation of a Modified Julian Date. 313 * 314 * @return 315 * this date. 316 * 317 * @since 2008-09-23 318 */ 319 public JulianDate setFromMjd(BigDecimal modifiedJulianDate) 320 { 321 BigDecimal julianDate = modifiedJulianDate.add(JULIAN_DATE_AT_MJD_ZERO); 322 return set(julianDate); 323 } 324 325 /** 326 * Sets this date to the given time. 327 * <p> 328 * The actual value used by this object may differ from the parameter value 329 * by as much as 10<sup>-7</sup>. This is because this class attempts to 330 * mimic the millisecond resolution of java's <tt>Date</tt> class. 331 * See the {@link JulianDate class comments} for a longer explanation.</p> 332 * 333 * @param modifiedJulianDate 334 * a real number representation, in text form, of a Modified Julian Date. 335 * 336 * @return 337 * this date. 338 * 339 * @since 2008-09-23 340 */ 341 public JulianDate setFromMjd(String modifiedJulianDate) 342 { 343 return setFromMjd(new BigDecimal(modifiedJulianDate)); 344 } 345 346 //============================================================================ 347 // ARITHMETIC 348 //============================================================================ 349 350 /** 351 * Increments this date by the whole and fractional {@code days}. 352 * @param days the number of whole and fractional days to add to this date. 353 * @return this date, after the addition. 354 */ 355 public JulianDate add(BigDecimal days) 356 { 357 setValues(jd.add(days)); 358 return this; 359 } 360 361 /** 362 * Increments this date by the given amount of time. 363 * @param duration the amount by which to increment this date. 364 * @return this date, after the addition. 365 */ 366 public JulianDate add(TimeDuration duration) 367 { 368 return add(duration.toUnits(TimeUnits.DAY)); 369 } 370 371 /** 372 * Decrements this date by the whole and fractional {@code days}. 373 * @param days the number of whole and fractional days to subtract 374 * from this date. 375 * @return this date, after the subtraction. 376 */ 377 public JulianDate subtract(BigDecimal days) 378 { 379 setValues(jd.subtract(days)); 380 return this; 381 } 382 383 /** 384 * Decrements this date by the given amount of time. 385 * @param duration the amount by which to decrement this date. 386 * @return this date, after the subtraction. 387 */ 388 public JulianDate subtract(TimeDuration duration) 389 { 390 return subtract(duration.toUnits(TimeUnits.DAY)); 391 } 392 393 //============================================================================ 394 // QUERIES 395 //============================================================================ 396 397 /** 398 * Returns a real number representation of this date. 399 * @return a real number representation of this date. 400 */ 401 public BigDecimal value() 402 { 403 return jd; 404 } 405 406 /** 407 * Returns the Julian Day Number for this date. 408 * This is the integer portion of the 409 * {@link #value() real number representation} of this date. 410 * 411 * @return the Julian Day Number for this date. 412 */ 413 public int dayNumber() 414 { 415 return jd.intValue(); 416 } 417 418 /** 419 * Returns the fractional portion of the value of this date. 420 * <p> 421 * For example, if {@link #value()} returns <tt>2,456,789.0123</tt>, 422 * {@link #dayNumber()} will return <tt>2,456,789</tt> and 423 * this method will return <tt>0.0123</tt>.</p> 424 * 425 * @return 426 * the fractional portion of the value of this date. 427 */ 428 public BigDecimal fraction() 429 { 430 return jd.subtract(new BigDecimal(dayNumber())); 431 } 432 433 /** 434 * Returns the real number representation of the Modified 435 * Julian Date (MJD) corresponding this date. 436 * The MJD is 2,400,000.5 days less than the JD. 437 * 438 * @return the modified julian date. 439 */ 440 public BigDecimal modifiedValue() 441 { 442 return mjd; 443 } 444 445 /** 446 * Returns the Modified Julian Day Number for this date. 447 * This is the integer portion of the 448 * {@link #modifiedValue() real number representation} of 449 * the MJD corresponding to this date. 450 * 451 * @return the Julian Day Number for this date. 452 */ 453 public int modifiedDayNumber() 454 { 455 return mjd.intValue(); 456 } 457 458 /** 459 * Returns the fractional portion of the modified value of this date. 460 * <p> 461 * For example, if {@link #modifiedValue()} returns <tt>56,789.0123</tt>, 462 * {@link #modifiedDayNumber()} will return <tt>56,789</tt> and 463 * this method will return <tt>0.0123</tt>.</p> 464 * 465 * @return 466 * the fractional portion of the modified value of this date. 467 */ 468 public BigDecimal modifiedFraction() 469 { 470 return mjd.subtract(new BigDecimal(modifiedDayNumber())); 471 } 472 473 /** 474 * Returns <i>true</i> if this date is earlier than {@code other}. 475 * @param other the date to be tested against this one. 476 * @return <i>true</i> if this date is earlier than {@code other}. 477 */ 478 public boolean isBefore(JulianDate other) 479 { 480 return this.compareTo(other) < 0; 481 } 482 483 /** 484 * Returns <i>true</i> if this date is later than {@code other}. 485 * @param other the date to be tested against this one. 486 * @return <i>true</i> if this date is later than {@code other}. 487 */ 488 public boolean isAfter(JulianDate other) 489 { 490 return this.compareTo(other) > 0; 491 } 492 493 //============================================================================ 494 // TO OTHER FORMS 495 //============================================================================ 496 497 /** 498 * Returns a date in the Gregorian, Julian, or proleptic Julian calendar 499 * corresponding to this date. The date returned is a copy of the one used 500 * internally by this object, so subsequent changes to it 501 * will <i>not</i> be reflected herein. 502 * <p> 503 * See the {@link JulianDate class comments} for more information on 504 * the use of the Gregorian and Julian calendars made by this class.</p> 505 * 506 * @return a date in the proleptic Gregorian calendar. 507 */ 508 public Date toDate() 509 { 510 return (Date)gd.clone(); 511 } 512 513 private static final BigDecimal JULIAN_DATE_AT_EPOCH_2000 = new BigDecimal("2451545.0"); 514 private static final BigDecimal JULIAN_YEAR_IN_DAYS = new BigDecimal("365.25"); 515 private static final BigDecimal TWO_THOUSAND = new BigDecimal("2000.0"); 516 517 /** 518 * Returns the 519 * <a href="http://scienceworld.wolfram.com/astronomy/JulianEpoch.html"> 520 * Julian Epoch</a> for this date. 521 * <p> 522 * For example, the Julian Epoch for JD 2451545.0 is 2000.0.</p> 523 * 524 * @return 525 * the Julian Epoch for this date. 526 * 527 * @since 2008-09-19 528 */ 529 public BigDecimal toEpoch() 530 { 531 return value().subtract(JULIAN_DATE_AT_EPOCH_2000) 532 .divide(JULIAN_YEAR_IN_DAYS, MC_INTERM_CALCS) 533 .add(TWO_THOUSAND); 534 } 535 536 /** 537 * Returns the time of day, in the local time zone, for this Julian Date. 538 * @return the time of day, in the local time zone, for this Julian Date. 539 * 540 * @since 2008-08-14 541 */ 542 public TimeOfDay toTimeOfDayLocal() 543 { 544 return makeTimeOfDay(LOCAL_CALENDAR); 545 } 546 547 /** 548 * Returns the UTC time of day for this Julian Date. 549 * @return the UTC time of day for this Julian Date. 550 * 551 * @since 2008-08-14 552 */ 553 public TimeOfDay toTimeOfDayUtc() 554 { 555 return makeTimeOfDay(GREGORIAN_UTC_CALENDAR); 556 } 557 558 /** 559 * Returns the time of day, in the given time zone, for this Julian Date. 560 * 561 * @param timeZone 562 * the time zone for which the returne time of day is applicable. 563 * 564 * @return 565 * the time of day, in the given time zone, for this Julian Date. 566 * 567 * @since 2008-08-14 568 */ 569 public TimeOfDay toTimeOfDay(TimeZone timeZone) 570 { 571 CALENDAR.setTimeZone(timeZone); 572 return makeTimeOfDay(CALENDAR); 573 } 574 575 private TimeOfDay makeTimeOfDay(Calendar cal) 576 { 577 TimeOfDay tod = new TimeOfDay(); 578 579 cal.setTime(gd); 580 581 int hour = cal.get(Calendar.HOUR_OF_DAY); 582 int minute = cal.get(Calendar.MINUTE); 583 int sec = cal.get(Calendar.SECOND); 584 int milli = cal.get(Calendar.MILLISECOND); 585 586 String second = Integer.toString(sec) + "." + Integer.toString(milli); 587 588 tod.set(hour, minute, second); 589 590 return tod; 591 } 592 593 /* (non-Javadoc) 594 * @see java.lang.Object#toString() 595 */ 596 @Override 597 public String toString() 598 { 599 return StringUtil.getInstance().formatNoScientificNotation(jd); 600 } 601 602 /** 603 * Returns a text representation of this Julian Date. 604 * 605 * @param minFracDigits the minimum number of places after the decimal point. 606 * 607 * @param maxFracDigits the maximum number of places after the decimal point. 608 * 609 * @return a text representation of this Julian Date. 610 */ 611 public String toString(int minFracDigits, int maxFracDigits) 612 { 613 return StringUtil.getInstance().formatNoScientificNotation(jd, 614 minFracDigits, 615 maxFracDigits); 616 } 617 618 //============================================================================ 619 // CALCULATIONS 620 //============================================================================ 621 622 private void setValues(int julianDayNumber) 623 { 624 jd = new BigDecimal(julianDayNumber); 625 mjd = jd.subtract(JULIAN_DATE_AT_MJD_ZERO); 626 gd = calcGregorianDate(jd); 627 } 628 629 private void setValues(BigDecimal julianDate) 630 { 631 //The Date class has only millisecond resolution. We will attempt 632 //to keep the resolution of this class about the same. The important 633 //thing is if we create JD1 w/ a Date, then create JD2 from JD1.value, 634 //then ask JD2 for its date, we get the original date. That is why 635 //we go through a couple calcs here instead of just one. 636 gd = calcGregorianDate(julianDate); 637 638 jd = calcJulianDate(gd); 639 mjd = jd.subtract(JULIAN_DATE_AT_MJD_ZERO); 640 } 641 642 private void setValues(Date gregorianCalendarDate) 643 { 644 gd = gregorianCalendarDate; 645 jd = calcJulianDate(gd); 646 mjd = jd.subtract(JULIAN_DATE_AT_MJD_ZERO); 647 } 648 649 private void setValues(String julianDate) 650 { 651 setValues(new BigDecimal(julianDate)); 652 } 653 654 private static final BigDecimal MS_PER_DAY = 655 TimeUnits.DAY.toUnits(TimeUnits.MILLISECOND); 656 657 private static final BigDecimal DAYS_PER_MS = 658 TimeUnits.MILLISECOND.toUnits(TimeUnits.DAY); 659 660 //1ms ~ 10^-8 days, thus the "8" below 661 private static final int DAY_SCALE = 8; 662 663 /** 664 * Calculates a Julian Date for a Gregorian Date using java's 665 * calendar logic and a point in time where both the 666 * JD and UTC times are known. 667 * 668 * @param gregDate a date in the proleptic Gregorian calendar. 669 * 670 * @return the Julian Date for {@code gregDate}. 671 */ 672 private BigDecimal calcJulianDate(Date gregDate) 673 { 674 //Let the GregorianCalendar class handle leap years and such. 675 //Milliseconds elapsed since (or before) our zero point. 676 BigDecimal deltaMs = 677 new BigDecimal(gregDate.getTime() - MILLISECONDS_AT_MJD_ZERO); 678 679 //Days elapsed since (or before) our zero point. 680 //(Do we need to deal with leap seconds?) 681 BigDecimal deltaDays = DAYS_PER_MS.multiply(deltaMs); 682 683 //Convert to roughly millisecond resolution 684 deltaDays = deltaDays.setScale(DAY_SCALE, RoundingMode.HALF_UP); 685 686 return JULIAN_DATE_AT_MJD_ZERO.add(deltaDays); 687 } 688 689 /** 690 * Calculates a Gregorian Date for a Julian Date using java's 691 * calendar logic and a point in time where both the 692 * JD and UTC times are known. 693 * 694 * @param julianDate a Julian Date 695 * 696 * @return a date in the proleptic Gregorian calendar for {@code gregDate}. 697 */ 698 private Date calcGregorianDate(BigDecimal julianDate) 699 { 700 //Days elapsed since (or before) our zero point. 701 BigDecimal deltaDays = julianDate.subtract(JULIAN_DATE_AT_MJD_ZERO); 702 703 //Milliseconds elapsed since (or before) our zero point. 704 BigDecimal deltaMs = MS_PER_DAY.multiply(deltaDays); 705 706 long ms = MILLISECONDS_AT_MJD_ZERO + Math.round(deltaMs.doubleValue()); 707 708 GREGORIAN_UTC_CALENDAR.setTimeInMillis(ms); 709 710 return GREGORIAN_UTC_CALENDAR.getTime(); 711 } 712 713 //============================================================================ 714 // 715 //============================================================================ 716 717 /** 718 * Returns a copy of this date. 719 * <p> 720 * If anything goes wrong during the cloning procedure, 721 * a {@code RuntimeException} will be thrown.</p> 722 */ 723 @Override 724 public JulianDate clone() 725 { 726 JulianDate clone = null; 727 728 try 729 { 730 //This line takes care of the primitive fields properly 731 clone = (JulianDate)super.clone(); 732 } 733 catch (Exception ex) 734 { 735 throw new RuntimeException(ex); 736 } 737 738 return clone; 739 } 740 741 /** Returns <i>true</i> if {@code o} is equal to this Julian date. */ 742 @Override 743 public boolean equals(Object o) 744 { 745 //Quick exit if o is this 746 if (o == this) 747 return true; 748 749 //Quick exit if o is null 750 if (o == null) 751 return false; 752 753 //Quick exit if classes are different 754 if (!o.getClass().equals(this.getClass())) 755 return false; 756 757 JulianDate other = (JulianDate)o; 758 759 return compareTo(other) == 0; 760 } 761 762 /** Returns a hash code value for this Julian date. */ 763 @Override 764 public int hashCode() 765 { 766 //Taken from the Effective Java book by Joshua Bloch. 767 //The constants 17 & 37 are arbitrary & carry no meaning. 768 int result = 17; 769 770 result = 37 * result + jd.hashCode(); 771 772 return result; 773 } 774 775 /* (non-Javadoc) 776 * @see java.lang.Comparable#compareTo(java.lang.Object) 777 */ 778 public int compareTo(JulianDate otherDate) 779 { 780 return this.jd.compareTo(otherDate.jd); 781 } 782 783 //============================================================================ 784 // 785 //============================================================================ 786 787 //Here for quick testing 788 /* 789 public static void main(String[] args) throws Exception 790 { 791 JulianDate mjd = JulianDate.makeFromMjd("50000"); 792 System.out.println("mjd 50,000 = " + mjd.toDate()); 793 794 Date date = new Date(); 795 JulianDate jd = new JulianDate(date); 796 797 System.out.println("java date = " + date); 798 System.out.println("julian date = " + jd); 799 System.out.println("jd.toTimeOfDayLocal = " + jd.toTimeOfDayLocal()); 800 System.out.println("jd.toTimeOfDayUtc = " + jd.toTimeOfDayUtc()); 801 } 802 */ 803 /* 804 public static void main(String[] args) throws Exception 805 { 806 JulianDate jd = new JulianDate("2456789.0123"); 807 System.out.println(jd); 808 System.out.println(jd.value()); 809 System.out.println(jd.dayNumber()); 810 System.out.println(jd.fraction()); 811 System.out.println(jd.toEpoch().doubleValue()); 812 813 System.out.println(); 814 815 jd = new JulianDate("2456789.5123"); 816 System.out.println(jd); 817 System.out.println(jd.modifiedValue()); 818 System.out.println(jd.modifiedDayNumber()); 819 System.out.println(jd.modifiedFraction()); 820 } 821 */ 822 /* 823 public static void main(String[] args) throws Exception 824 { 825 boolean inputIsDate = false; 826 827 SimpleDateFormat df = new SimpleDateFormat(); 828 df.setTimeZone(TimeZone.getTimeZone("GMT")); 829 df.applyPattern("G yyyy MMMM dd HH:mm:ss.S"); 830 831 for (String arg : args) 832 { 833 if (!arg.startsWith("-")) 834 { 835 if (inputIsDate) 836 processDate(arg, df); 837 else 838 processReal(arg, df); 839 } 840 else 841 inputIsDate = arg.equalsIgnoreCase("-utc"); 842 } 843 } 844 845 private static void processDate(String dateText, SimpleDateFormat df) 846 throws Exception 847 { 848 System.out.print("The Julian Date for UTC date/time "); 849 System.out.print(dateText + " is "); 850 851 Date date = df.parse(dateText); 852 853 System.out.println(new JulianDate(date)); 854 } 855 856 private static void processReal(String numText, SimpleDateFormat df) 857 { 858 System.out.print("The UTC date/time for JD "); 859 System.out.print(numText + " is "); 860 861 double jd = Double.parseDouble(numText); 862 863 System.out.println(df.format(new JulianDate(jd).toDate())); 864 } 865 */ 866 /* 867 //Show consequence of millisecond resolution 868 public static void main(String... args) throws Exception 869 { 870 Calendar cal = Calendar.getInstance(); 871 BigDecimal currVal=null, priorVal=null; 872 JulianDate jd = new JulianDate(); 873 for (int i=1; i <= 20; i++) 874 { 875 jd.set(cal.getTime()); 876 877 currVal = jd.value(); 878 System.out.print(currVal.setScale(10, RoundingMode.HALF_UP)); 879 System.out.print(", " + cal.getTimeInMillis()); 880 881 System.out.println(); 882 883 if (priorVal != null) 884 { 885 BigDecimal midVal = currVal.add(priorVal).divide(new BigDecimal("2")); 886 jd.set(midVal); 887 System.out.print(jd.value().setScale(10, RoundingMode.HALF_UP)); 888 System.out.print(", " + midVal.setScale(10, RoundingMode.HALF_UP)); 889 System.out.println(); 890 } 891 892 priorVal = currVal; 893 894 cal.add(Calendar.MILLISECOND, 1); 895 } 896 } 897 */ 898 }