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.TimeZone; 008 009 import static edu.nrao.sss.math.MathUtil.MC_FINAL_CALC; 010 import static edu.nrao.sss.math.MathUtil.MC_INTERM_CALCS; 011 012 /** 013 * Local sidereal time (LST). 014 * See <a href="http://en.wikipedia.org/wiki/Sidereal_time">Wikipedia</a> 015 * or other places on the web for more information. 016 * <p> 017 * Note that this LST functions as a date/time, like the 018 * {@link java.util.Date} class, not as a dateless time, like the 019 * {@link TimeOfDay} class. This means, for example, that two 020 * LSTs of 12:34:56.789 on different days are <i>not</i> equal. 021 * Clients who wish to work only with the LST time-of-day may 022 * get a <tt>TimeOfDay</tt> instance from the 023 * {@link #toTimeOfDay()} method.</p> 024 * <p> 025 * Currently this class represents local <i>mean</i> sidereal time; 026 * it could be upgraded to allow for the calculation of local 027 * <i>apparent</i> sidereal time in the future, if clients find 028 * that useful.</p> 029 * <p> 030 * The LST may be constructed for any location, but by default 031 * is set up to use the VLA's longitude (-107d 37' 03.819").</p> 032 * <p> 033 * <b>Version Info:</b> 034 * <table style="margin-left:2em"> 035 * <tr><td>$Revision: 1669 $</td></tr> 036 * <tr><td>$Date: 2008-11-05 11:08:04 -0700 (Wed, 05 Nov 2008) $</td></tr> 037 * <tr><td>$Author: dharland $ (last person to modify)</td></tr> 038 * </table></p> 039 * 040 * @author David M. Harland 041 * @since 2007-08-02 042 */ 043 public class LocalSiderealTime 044 implements Cloneable, Comparable<LocalSiderealTime> 045 { 046 //These variables are used internally in VLA location calculations 047 private static final Longitude VLA_LOCATION = 048 Longitude.parse("-107d 37' 03.819\""); 049 050 private static final TimeZone VLA_TIME_ZONE = 051 TimeZone.getTimeZone("US/Mountain"); 052 053 /** 054 * The number of mean sidereal units in one solar unit. 055 * For example, if the unit is "day", there are about 056 * 1.0027 sidereal days in one solar day. 057 */ 058 static final BigDecimal MEAN_SIDEREAL_PER_SOLAR = new BigDecimal("1.00273790935"); 059 060 //============================================================================ 061 // INSTANCE VARIABLES & CONSTRUCTORS 062 //============================================================================ 063 064 private Longitude location; 065 private TimeZone timeZone; 066 067 private JulianDate julianDate; 068 private TimeOfDay gmst; //24-hr day, but sec/min/hr are sidereal, not solar 069 private TimeOfDay lmst; //same as above 070 071 private BigDecimal gmstDay; //helps calc of lmstDay#; not publicly available 072 private int lmstDayNumber; //a VLA-specific concept 073 074 private Calendar calendar; //helps set(int,int,...,int) method 075 076 /** 077 * Creates a new local sidereal time based on the current solar time and the 078 * longitude and time zone of the VLA. 079 */ 080 public LocalSiderealTime() 081 { 082 initialize(null, null, VLA_LOCATION, VLA_TIME_ZONE); 083 } 084 085 /** 086 * Creates a new local sidereal time based on the given solar time and the 087 * longitude and time zone of the VLA. 088 * 089 * @param gregorianCalendarDate 090 * a solar time based on the Gregorian calendar. 091 * A value of <i>null</i> will be intrepeted as the current system time. 092 */ 093 public LocalSiderealTime(Date gregorianCalendarDate) 094 { 095 initialize(gregorianCalendarDate, null, VLA_LOCATION, VLA_TIME_ZONE); 096 } 097 098 /** 099 * Creates a new local sidereal time based on the given solar time and the 100 * longitude and time zone of the VLA. 101 * 102 * @param julianDate 103 * a solar time in Julian Date form. 104 * A value of <i>null</i> will be intrepeted as the current system time. 105 */ 106 public LocalSiderealTime(JulianDate julianDate) 107 { 108 initialize(null, julianDate, VLA_LOCATION, VLA_TIME_ZONE); 109 } 110 111 /** 112 * @param localSiderealDay 113 * @param localSiderealTime 114 */ 115 public LocalSiderealTime(int localSiderealDay, TimeOfDay localSiderealTime) 116 { 117 initialize(null, null, VLA_LOCATION, VLA_TIME_ZONE); 118 119 setSiderealTime(localSiderealDay, localSiderealTime); 120 } 121 122 /** 123 * Creates a new local sidereal time based on the given parameters 124 * 125 * @param gregorianCalendarDate 126 * a solar time based on the Gregorian calendar. 127 * A value of <i>null</i> will be intrepeted as the current system time. 128 * 129 * @param longitude 130 * the longitude for which this LST applies. 131 * A value of <i>null</i> will result in a <tt>NullPointerException</tt>. 132 * 133 * @param timeZone 134 * the time zone at the location for which this LST applies. 135 * A value of <i>null</i> will result in a <tt>NullPointerException</tt>. 136 */ 137 public LocalSiderealTime(Date gregorianCalendarDate, 138 Longitude longitude, 139 TimeZone timeZone) 140 { 141 initialize(gregorianCalendarDate, null, longitude, timeZone); 142 } 143 144 /** Creates and initializes instance variables for constructors. */ 145 private void initialize(Date initGD, JulianDate initJD, 146 Longitude loc, TimeZone tz) 147 { 148 timeZone = (TimeZone)tz.clone(); 149 calendar = Calendar.getInstance(timeZone); 150 location = loc.clone(); 151 152 if (initJD != null) 153 { 154 julianDate = initJD.clone(); 155 } 156 else 157 { 158 Date gd = (initGD == null) ? new Date() : (Date)initGD.clone(); 159 julianDate = new JulianDate(gd); 160 } 161 162 gmst = new TimeOfDay(); 163 lmst = new TimeOfDay(); 164 165 //Calculates GMST and LMST based on above values 166 updateGmst(); 167 } 168 169 //============================================================================ 170 // CHANGING THE LOCATION & TIME 171 //============================================================================ 172 173 /** 174 * Changes the location and time zone for which this LST is valid. 175 * 176 * @param newLongitude 177 * the new location on which this LST is based. 178 * A value of <i>null</i> will result in a <tt>NullPointerException</tt>. 179 * 180 * @param newTimeZone 181 * the time zone corresponding to the new location. 182 * A value of <i>null</i> will result in a <tt>NullPointerException</tt>. 183 * 184 * @return this LST. 185 */ 186 public LocalSiderealTime setLocationAndTimeZone(Longitude newLongitude, 187 TimeZone newTimeZone) 188 { 189 timeZone = (TimeZone)newTimeZone.clone(); 190 191 calendar.setTimeZone(timeZone); 192 193 updateLocation(newLongitude); 194 195 return this; 196 } 197 198 /** 199 * Sets the solar time on which this LST is based to 200 * the current system time. 201 * 202 * @return this LST. 203 */ 204 public LocalSiderealTime setSolarTime() 205 { 206 return setSolarTime(new Date()); 207 } 208 209 /** 210 * Sets the solar time on which this LST is based to 211 * the given time. 212 * 213 * @param gregorianCalendarDate a solar time based on the Gregorian calendar. 214 * 215 * @return this LST. 216 */ 217 public LocalSiderealTime setSolarTime(Date gregorianCalendarDate) 218 { 219 updateSolarDate(gregorianCalendarDate); 220 221 return this; 222 } 223 224 /** 225 * Sets the solar time on which this LST is based to 226 * the given time. 227 * 228 * @param julianDate a solar time in Julian Date form. 229 * 230 * @return this LST. 231 */ 232 public LocalSiderealTime setSolarTime(JulianDate julianDate) 233 { 234 updateSolarDate(julianDate); 235 236 return this; 237 } 238 239 /** 240 * Sets this LST to the given day and time of day. 241 * 242 * @param localSiderealDay 243 * the sidereal day to which this LST should be set. Remember that 244 * this class is similar to java's <tt>Date</tt> class in that it 245 * is real a date/timestamp class. This value is based on the VLA 246 * {@link #getDayNumber() LST-day} concept, but is not specific to 247 * that longitude. The UTC corresponding to local sidereal day zero 248 * and local sidereal time zero varies with longitude, but is on 249 * December 6 or 7 of 1840, arrived at empirically. Day / time 250 * zero is just an arbitrary epoch for beginning a count of sidereal 251 * time. 252 * 253 * @param localSiderealTime 254 * the local sidereal time of day. 255 * 256 * @return this LST. 257 * 258 * @since 2008-09-25 259 */ 260 public final LocalSiderealTime setSiderealTime(int localSiderealDay, 261 TimeOfDay localSiderealTime) 262 { 263 //STRATEGY: Rather than rework the algorithms to let us go "backward" from 264 // LST to UTC / JD, we use our current LST-DAY and LST values, 265 // comparing them to the parameters. We can easily figure out 266 // how far in the sidereal future or past the parameter values 267 // are. We then add this duration to our current values. 268 269 //The next two values below are in number of days since epoch 270 BigDecimal now = new BigDecimal(lmstDayNumber).add(lmst.toFractionOfDay()); 271 272 BigDecimal other = 273 new BigDecimal(localSiderealDay).add(localSiderealTime.toFractionOfDay()); 274 275 BigDecimal deltaSiderealDays = other.subtract(now); 276 277 //TimeDuration has this dopey restriction on units -- DAY is illegal 278 BigDecimal deltaSiderealHours = 279 deltaSiderealDays.multiply(TimeUnits.DAY.toUnits(TimeUnits.HOUR)); 280 281 TimeDuration siderealDuration = new TimeDuration(deltaSiderealHours.abs()); 282 283 switch (deltaSiderealHours.signum()) 284 { 285 case -1: return subtractSidereal(siderealDuration); 286 case +1: return addSidereal(siderealDuration); 287 default: return this; 288 } 289 } 290 291 /** 292 * Sets this LST to the given day and time of day. 293 * The {@link #getDayNumber() local sidereal day} will not be changed. 294 * 295 * @param lst 296 * the local sidereal time of day. 297 * 298 * @return this LST. 299 * 300 * @since 2008-09-25 301 */ 302 public final LocalSiderealTime setSiderealTime(TimeOfDay lst) 303 { 304 return setSiderealTime(lmstDayNumber, lst); 305 } 306 307 /** 308 * Sets the local solar calendar date and the local sidereal time. 309 * <p> 310 * <b><u>Date Parameters</u></b><br/> 311 * The <tt>year</tt>, <tt>month</tt>, and <tt>day</tt> parameters 312 * all refer to our standard notion of a calendar date, 313 * such as February 22, 2008. This is a solar, not sidereal, date 314 * and is understood to refer to a date for the current time zone 315 * of this instance. 316 * (See {@link #setLocationAndTimeZone(Longitude, TimeZone)}.) 317 * The parameters follow the conventions set forth in 318 * {@link Calendar#set(int, int, int)}. This method will not 319 * check the values of these parameters, but will instead delegate 320 * that job to the <tt>Calendar.set</tt> method.</p> 321 * <p> 322 * <b><u>Time Parameters</u></b><br/> 323 * The <tt>lstHour</tt>, <tt>lstMinute</tt>, and <tt>lstSecond</tt> 324 * parameters are all local sidereal time values. This method will 325 * use {@link TimeOfDay#set(int, int, BigDecimal)} to validate these 326 * values and will rethrow any exceptions encountered.</p> 327 * <p> 328 * <b><u>Example</u></b><br/> 329 * Let's say you want to configure an instance of this class so that it is 330 * set to LST 12:34:56.789 on July 3, 2008 for the VLA. The default location 331 * and time zone for instances of this class are those of the VLA, so you need 332 * do nothing regarding longitude and time zone. The code set the date and 333 * time given above is: 334 * <pre> 335 * LocalSiderealTime schedTime = new LocalSiderealTime(); 336 * schedTime.set(2008, 6, 3, 12, 34, 56.789);</pre> 337 * Note that July is <tt>6</tt>, not <tt>7</tt>, due to the conventions 338 * of the <tt>Calendar</tt> class. If you were then to write this code: 339 * <pre> 340 * System.out.println(schedTime.toDate());</pre> 341 * You should see that if the date is expressed as a Mountain Daylight Time 342 * value, the date is July 3, 2008 and that the time of day is some value 343 * that in all likelihood is not 12:34:56.789.</p> 344 * <p> 345 * <b><u>Days That Contain Two of the Given LST Values</u></b><br/> 346 * Since a sidereal day is shorter than a solar day by about four minutes, 347 * there are about four minutes of an LST day that show up twice per 348 * solar day. This method will always return the earlier of these 349 * two times.</p> 350 * 351 * @param year 352 * the calendar year. 353 * @param month 354 * the calendar month. This is a zero-based value. 355 * @param day 356 * the day of the calendar month. 357 * @param lstHour 358 * the local sidereal hour. 359 * @param lstMinute 360 * the local sidereal minute. 361 * @param lstSecond 362 * the local sidereal second. 363 * 364 * @return this LST after the values have been set. 365 * 366 * @throws IllegalArgumentException 367 * if there are problems with the parameter values. 368 */ 369 public LocalSiderealTime set(int year, int month, int day, 370 int lstHour, int lstMinute, BigDecimal lstSecond) 371 { 372 //We do this first in case an exception is thrown in order to leave 373 //our state unchanged. 374 TimeOfDay lstDesired = new TimeOfDay(); 375 lstDesired.set(lstHour, lstMinute, lstSecond); 376 377 //Change the solar time to midnight of the given local time zone date 378 calendar.clear(); 379 calendar.set(year, month, day); 380 381 this.setSolarTime(calendar.getTime()); 382 383 //See what LST we have at solar midnight 384 TimeOfDay lstAtMidnight = this.toTimeOfDay(); 385 386 //Find out how far into the future the desired LST is 387 TimeDuration lstDelta = lstAtMidnight.timeUntil(lstDesired); 388 389 //Move this clock by the calculated amount 390 this.addSidereal(lstDelta); 391 392 return this; 393 } 394 395 /** 396 * Sets the local solar calendar date and the local sidereal time. 397 * See {@link #set(int, int, int, int, int, BigDecimal)} for 398 * more details. 399 * 400 * @return this LST after the values have been set. 401 */ 402 public LocalSiderealTime set(int year, int month, int day, 403 int lstHour, int lstMinute, String lstSecond) 404 { 405 return set(year, month, day, lstHour, lstMinute, new BigDecimal(lstSecond)); 406 } 407 408 //TODO? method for setting mean vs apparent? 409 410 //============================================================================ 411 // QUERIES 412 //============================================================================ 413 414 /** 415 * Returns a copy of the location on which this LST is based. 416 * @return a copy of the location on which this LST is based. 417 */ 418 public Longitude getLocation() 419 { 420 return location.clone(); 421 } 422 423 /** 424 * Returns a copy of the time zone on which this LST is based. 425 * @return a copy of the time zone on which this LST is based. 426 */ 427 public TimeZone getTimeZone() 428 { 429 return (TimeZone)timeZone.clone(); 430 } 431 432 /** 433 * Returns the VLA-scheduling day number for this LST. 434 * This concept is not universal, but is specific to the VLA. 435 * We probably will not need it once we completely replace the VLA 436 * with the EVLA. 437 * 438 * @return the VLA scheduler's idea of an LST day number. 439 */ 440 public int getDayNumber() 441 { 442 return lmstDayNumber; 443 } 444 445 /** 446 * Returns <i>true</i> if this LST is earlier than {@code other}. 447 * (Remember that this class treats LST as a date/time, not 448 * a dateless time.) 449 * 450 * @param other the LST to be tested against this one. 451 * @return <i>true</i> if this LST is earlier than {@code other}. 452 */ 453 public boolean isBefore(LocalSiderealTime other) 454 { 455 return this.compareTo(other) < 0; 456 } 457 458 /** 459 * Returns <i>true</i> if this LST is later than {@code other}. 460 * (Remember that this class treats LST as a date/time, not 461 * a dateless time.) 462 * 463 * @param other the LST to be tested against this one. 464 * @return <i>true</i> if this LST is later than {@code other}. 465 */ 466 public boolean isAfter(LocalSiderealTime other) 467 { 468 return this.compareTo(other) > 0; 469 } 470 471 /** 472 * Returns the hour angle for the given right ascension at this LST. 473 * 474 * @param rightAscension 475 * the right ascension for which an hour angle is desired. 476 * 477 * @return 478 * an hour angle that is equal to this LST minus 479 * {@code rightAscension}. 480 */ 481 public Longitude getHourAngle(Longitude rightAscension) 482 { 483 //HA = LST - RA 484 return Longitude.parse(lmst.toString()).subtract(rightAscension); 485 } 486 487 /** 488 * Returns the right ascension for the given hour angle at this LST. 489 * 490 * @param hourAngle 491 * the hour angle for which a right ascension is desired. 492 * 493 * @return 494 * a right ascension that is equal to this LST minus 495 * {@code hourAngle}. 496 */ 497 public Longitude getRightAscension(Longitude hourAngle) 498 { 499 //RA = LST - HA 500 return Longitude.parse(lmst.toString()).subtract(hourAngle); 501 } 502 503 //============================================================================ 504 // TO OTHER FORMS 505 //============================================================================ 506 507 /** 508 * Returns a copy of the Julian Date corresponding to this LST. 509 * @return a copy of the Julian Date corresponding to this LST. 510 */ 511 public JulianDate toJulianDate() 512 { 513 return julianDate.clone(); 514 } 515 516 /** 517 * Returns a copy of the solar date and time corresponding to this LST. 518 * @return a copy of the solar date and time corresponding to this LST. 519 */ 520 public Date toDate() 521 { 522 return julianDate.toDate(); 523 } 524 525 /** 526 * Returns this LST as a dateless object. 527 * The returned time of day is in sidereal units, with a 24 sidereal hour 528 * length of day. The returned time of day is not referenced by this 529 * LST, so changes made to it will <i>not</i> be reflected herein. 530 * 531 * @return the time portion of this LST. 532 */ 533 public TimeOfDay toTimeOfDay() 534 { 535 return lmst.clone(); 536 } 537 538 /** 539 * Returns the local solar time of day for this LST. 540 * @return the local solar time of day for this LST. 541 * 542 * @since 2008-08-14 543 */ 544 public TimeOfDay toTimeOfDaySolar() 545 { 546 return julianDate.toTimeOfDayLocal(); 547 } 548 549 /** 550 * Returns the UTC solar time of day for this LST. 551 * @return the UTC solar time of day for this LST. 552 * 553 * @since 2008-08-14 554 */ 555 public TimeOfDay toTimeOfDayUtc() 556 { 557 return julianDate.toTimeOfDayUtc(); 558 } 559 560 @Override 561 public String toString() 562 { 563 return lmst.toString() + " (VLA day #" + lmstDayNumber + ")"; 564 } 565 566 //============================================================================ 567 // ARITHMETIC 568 //============================================================================ 569 570 /** 571 * Advances this LST to the given time of day. 572 * <p> 573 * Immediately after this call a call to {@link #toTimeOfDay()} should 574 * return the same time of day as {@code lstTimeOfDay}, and a call to 575 * {@link #getDayNumber()} should show that either the day number is the 576 * same as it was prior to calling this method, or it has advanced by 577 * one day.</p> 578 * <p> 579 * Attempting to advance to the current time of day of this LST will 580 * leave this LST unchanged. For example, the following code would 581 * not change the state of <tt>myLst</tt>: 582 * <pre> 583 * myLst.advanceTo(myLst.toTimeOfDay());</pre> 584 * 585 * @param lstTimeOfDay 586 * the new time of day for this LST date/time object. 587 * 588 * @return 589 * this LST, after the advancement. 590 */ 591 public LocalSiderealTime advanceTo(TimeOfDay lstTimeOfDay) 592 { 593 //lmst is the current LST time-of-day for this date/time instance 594 return addSidereal(lmst.timeUntil(lstTimeOfDay)); 595 } 596 597 /** 598 * Increments this LST by the given amount of <i>sidereal</i> time. 599 * 600 * @param siderealDuration the amount of solar time by which to 601 * increment this LST. 602 * @return this LST, after the addition. 603 * 604 * @see #addSolar(TimeDuration) 605 */ 606 public LocalSiderealTime addSidereal(TimeDuration siderealDuration) 607 { 608 gmst.add(siderealDuration); 609 lmst.add(siderealDuration); 610 611 gmstDay = gmstDay.add(siderealDuration.toUnits(TimeUnits.DAY)); 612 updateLmstDayNumber(); 613 614 BigDecimal solarDays = 615 siderealToSolar(siderealDuration).toUnits(TimeUnits.DAY); 616 617 julianDate.add(solarDays); 618 619 return this; 620 } 621 622 /** 623 * Decrements this LST by the given amount of <i>sidereal</i> time. 624 * 625 * @param siderealDuration the amount of solar time by which to 626 * decrement this LST. 627 * @return this LST, after the subtraction. 628 * 629 * @see #subtractSolar(TimeDuration) 630 */ 631 public LocalSiderealTime subtractSidereal(TimeDuration siderealDuration) 632 { 633 gmst.subtract(siderealDuration); 634 lmst.subtract(siderealDuration); 635 636 gmstDay = gmstDay.subtract(siderealDuration.toUnits(TimeUnits.DAY)); 637 updateLmstDayNumber(); 638 639 BigDecimal solarDays = 640 siderealToSolar(siderealDuration).toUnits(TimeUnits.DAY); 641 642 julianDate.subtract(solarDays); 643 644 return this; 645 } 646 647 /** 648 * Increments this LST by the given amount of <i>solar</i> time. 649 * @param solarDuration the amount of solar time by which to 650 * increment this LST. 651 * @return this LST, after the addition. 652 * 653 * @see #addSidereal(TimeDuration) 654 */ 655 public LocalSiderealTime addSolar(TimeDuration solarDuration) 656 { 657 julianDate.add(solarDuration); 658 659 updateSolarDate(julianDate); 660 661 return this; 662 } 663 664 /** 665 * Decrements this LST by the given amount of <i>solar</i> time. 666 * @param solarDuration the amount of solar time by which to 667 * decrement this LST. 668 * @return this LST, after the subtraction. 669 * 670 * @see #subtractSidereal(TimeDuration) 671 */ 672 public LocalSiderealTime subtractSolar(TimeDuration solarDuration) 673 { 674 julianDate.subtract(solarDuration); 675 676 updateSolarDate(julianDate); 677 678 return this; 679 } 680 681 /** 682 * Returns a duration, in <i>sidereal time</i>, from this LST to 683 * {@code otherSidereal}. If this LST is after the other time, 684 * the returned duration will have zero length. (Remember that 685 * this LST is really a date/time, not a time-of-day.) 686 * <p> 687 * To get behavior similar to {@link TimeOfDay#timeUntil(TimeOfDay)}, 688 * use this pattern:</p><pre> 689 * TimeDuration lstDur = myLst.toTimeOfDay().timeUntil(yourLst.timeOfDay());</pre> 690 * 691 * @param otherSidereal 692 * another point in time, expressed in sidereal time. 693 * 694 * @return 695 * the amount of sidereal time from this LST to {@code otherSidereal}. 696 */ 697 public TimeDuration siderealTimeUntil(LocalSiderealTime otherSidereal) 698 { 699 return siderealTimeUntil(otherSidereal.julianDate); 700 } 701 702 /** 703 * Returns a duration, in <i>sidereal time</i>, from this LST to 704 * {@code otherSolar}. If this LST is after the other time, 705 * the returned duration will have zero length. (Remember that 706 * this LST is really a date/time, not a time-of-day.) 707 * 708 * @param otherSolar 709 * another point in time, expressed in solar time. 710 * 711 * @return 712 * the amount of sidereal time from this LST to {@code otherSolar}. 713 */ 714 public TimeDuration siderealTimeUntil(Date otherSolar) 715 { 716 return siderealTimeUntil(new JulianDate(otherSolar)); 717 } 718 719 /** 720 * Returns a duration, in <i>sidereal time</i>, from this LST to 721 * {@code otherSolar}. If this LST is after the other time, 722 * the returned duration will have zero length. (Remember that 723 * this LST is really a date/time, not a time-of-day.) 724 * 725 * @param otherSolar 726 * another point in time, expressed in solar time. 727 * 728 * @return 729 * the amount of sidereal time from this LST to {@code otherSolar}. 730 */ 731 public TimeDuration siderealTimeUntil(JulianDate otherSolar) 732 { 733 TimeDuration solarDuration = solarTimeUntil(otherSolar); 734 735 return solarToSidereal(solarDuration); 736 } 737 738 /** 739 * Returns a duration, in <i>solar time</i>, from this LST to 740 * {@code otherSidereal}. If this LST is after the other time, 741 * the returned duration will have zero length. (Remember that 742 * this LST is really a date/time, not a time-of-day.) 743 * 744 * @param otherSidereal 745 * another point in time, expressed in sidereal time. 746 * 747 * @return 748 * the amount of solar time from this LST to {@code otherSidereal}. 749 */ 750 public TimeDuration solarTimeUntil(LocalSiderealTime otherSidereal) 751 { 752 return solarTimeUntil(otherSidereal.julianDate); 753 } 754 755 /** 756 * Returns a duration, in <i>solar time</i>, from this LST to 757 * {@code otherSolar}. If this LST is after the other time, 758 * the returned duration will have zero length. (Remember that 759 * this LST is really a date/time, not a time-of-day.) 760 * 761 * @param otherSolar 762 * another point in time, expressed in solar time. 763 * 764 * @return 765 * the amount of solar time from this LST to {@code otherSolar}. 766 */ 767 public TimeDuration solarTimeUntil(Date otherSolar) 768 { 769 return solarTimeUntil(new JulianDate(otherSolar)); 770 } 771 772 /** 773 * Returns a duration, in <i>solar time</i>, from this LST to 774 * {@code otherSolar}. If this LST is after the other time, 775 * the returned duration will have zero length. (Remember that 776 * this LST is really a date/time, not a time-of-day.) 777 * 778 * @param otherSolar 779 * another point in time, expressed in solar time. 780 * 781 * @return 782 * the amount of solar time from this LST to {@code otherSolar}. 783 */ 784 public TimeDuration solarTimeUntil(JulianDate otherSolar) 785 { 786 TimeDuration answer = new TimeDuration(); 787 788 if (otherSolar.isAfter(julianDate)) 789 { 790 BigDecimal days = otherSolar.value().subtract(julianDate.value()); 791 BigDecimal ms = TimeUnits.DAY.convertTo(TimeUnits.MILLISECOND, days); 792 793 ms=ms.setScale(0, RoundingMode.HALF_UP); 794 795 answer.set(ms, TimeUnits.MILLISECOND); 796 } 797 798 return answer; 799 } 800 801 //============================================================================ 802 // SOLAR / SIDEREAL CONVERSION 803 //============================================================================ 804 805 /** 806 * Returns a duration in sidereal time that is equivalent to the given 807 * solar duration. 808 * 809 * @param solarDuration 810 * a duration whose units are based on solar time. 811 * 812 * @return 813 * a duration whose units are based on sidereal time and whose length 814 * is equivalent to that of {@code solarDuration}. 815 */ 816 public static TimeDuration solarToSidereal(TimeDuration solarDuration) 817 { 818 BigDecimal newValue = 819 solarDuration.getValue().multiply(MEAN_SIDEREAL_PER_SOLAR, MC_INTERM_CALCS); 820 821 TimeDuration sidereal = solarDuration.clone(); 822 sidereal.setValue(newValue); 823 return sidereal; 824 } 825 826 private static final BigDecimal MEAN_SOLAR_PER_SIDEREAL = 827 BigDecimal.ONE.divide(MEAN_SIDEREAL_PER_SOLAR, MC_INTERM_CALCS); 828 829 /** 830 * Returns a duration in solar time that is equivalent to the given 831 * sidereal duration. 832 * 833 * @param siderealDuration 834 * a duration whose units are based on sidereal time. 835 * 836 * @return 837 * a duration whose units are based on solar time and whose length 838 * is equivalent to that of {@code siderealDuration}. 839 */ 840 public static TimeDuration siderealToSolar(TimeDuration siderealDuration) 841 { 842 BigDecimal newValue = 843 siderealDuration.getValue().multiply(MEAN_SOLAR_PER_SIDEREAL, MC_INTERM_CALCS); 844 845 TimeDuration solar = siderealDuration.clone(); 846 solar.setValue(newValue); 847 return solar; 848 849 } 850 851 //============================================================================ 852 // CALCULATIONS 853 //============================================================================ 854 855 /** 856 * Updates this object's location and all internal variables 857 * that depend on it. 858 */ 859 private void updateLocation(Longitude newLongitude) 860 { 861 if (location != newLongitude) 862 location.set(newLongitude.getValue(), newLongitude.getUnits()); 863 864 updateLmst(); 865 } 866 867 /** 868 * Updates this object's solar date and all internal variables 869 * that depend on it. 870 */ 871 private void updateSolarDate(Date newDate) 872 { 873 julianDate.set(newDate); 874 875 updateSolarDate(julianDate); 876 } 877 878 /** 879 * Updates this object's solar date and all internal variables 880 * that depend on it. 881 */ 882 private void updateSolarDate(JulianDate newDate) 883 { 884 //No need to set self from self 885 if (julianDate != newDate) 886 julianDate.set(newDate.value()); 887 888 updateGmst(); 889 } 890 891 private static final BigDecimal HR_PER_DAY = 892 TimeUnits.DAY.toUnits(TimeUnits.HOUR); 893 894 //At this time the LST at Greenwich is 0:00:00. The particular day is Jan 1, 2000 GMT. 895 private static final BigDecimal GMST_DAY_ZERO = new BigDecimal("2451544.2230699"); 896 897 /** 898 * An arbitrary number arrived at empirically in order to match the 899 * VLA's "LST Day" concept. 900 * Steps taken: 901 * 902 * 1. Since the USNO alg uses 1/1/2000 as its base date, use that 903 * same date to get an arbitrary "GMST Day Zero". This will 904 * be the solar time at which the sidereal time is 0:00:00. 905 * Its value is in the GMST_DAY_ZERO constant, above. 906 * 907 * 2. Get ahold of a VLA schedule. Find these at: 908 * http://www.vla.nrao.edu/cgi-bin/schedules.cgi 909 * 910 * 3. Make a program and set up times to match the schedule. 911 * At this point the LST_DAY_NUMBER_OFFSET should be zero. 912 * 913 * 4. Compare the LST Day # reported by this class with that of 914 * the schedule and use the difference from here on out. 915 * The calculated # was 58,257. 916 */ 917 private static final int LST_DAY_NUMBER_OFFSET = 58257; 918 919 /** 920 * Updates this object's GMST and all internal variables 921 * that depend on it. 922 */ 923 private void updateGmst() 924 { 925 //Calc GMST as time of day 926 BigDecimal gmstHours = calcGmstHours(julianDate.value()); 927 gmstHours = normalizeHours(gmstHours); 928 929 BigDecimal gmstSeconds = TimeUnits.HOUR.convertTo(TimeUnits.SECOND, gmstHours); 930 931 gmst.set(gmstSeconds); 932 933 //Calc GMST day so that we can support VLA's "LST day number" 934 BigDecimal solarDaysSinceT0 = julianDate.value().subtract(GMST_DAY_ZERO); 935 gmstDay = solarDaysSinceT0.multiply(MEAN_SIDEREAL_PER_SOLAR); 936 937 //Update local times 938 updateLmst(); 939 updateLmstDayNumber(); 940 } 941 942 /** 943 * Updates the Local Mean Sidereal Time based on the current 944 * location and GMST. 945 */ 946 private void updateLmst() 947 { 948 lmst.set(gmst.getTimeSinceMidnight().toUnits(TimeUnits.SECOND)); 949 950 //The convert... method puts angle to +/-0.5 circles, instead of [0.0-1.0) 951 BigDecimal secondsFromGreenwich = 952 location.toAngle().convertToMinAbsValueNormal().toUnits(ArcUnits.SECOND); 953 954 lmst.add(secondsFromGreenwich, TimeUnits.SECOND); 955 } 956 957 private static final BigDecimal ONE_SECOND_IN_DAYS = 958 TimeUnits.SECOND.toUnits(TimeUnits.DAY); 959 960 private static final TimeDuration ONE_SECOND_DURATION = 961 new TimeDuration(BigDecimal.ONE, TimeUnits.SECOND); 962 963 /** 964 * Updates the LST Day Number from an already-up-to-date gmstDay value. 965 */ 966 private void updateLmstDayNumber() 967 { 968 lmstDayNumber = calcLmstDayNumber(gmstDay); 969 970 //We're having some trouble with rounding issues near LST midnight. 971 //Some test cases have shown that we don't change day numbers until 972 //a few milliseconds after midnight. I wouldn't be surprised if there 973 //were undiscovered cases where we change day numbers a few ms before 974 //midnight. This code aims to get the right day # near midnight. 975 976 //See if we're in 1st second of LST day 977 if (lmst.getTimeSinceMidnight().compareTo(ONE_SECOND_DURATION) < 0) 978 { 979 //Use day number from LST + 1.000s 980 lmstDayNumber = calcLmstDayNumber(gmstDay.add(ONE_SECOND_IN_DAYS)); 981 } 982 //See if we're in last second of LST day 983 else if (lmst.getTimeUntilMidnight().compareTo(ONE_SECOND_DURATION) < 0) 984 { 985 //Use day number from LST - 1.000s 986 lmstDayNumber = calcLmstDayNumber(gmstDay.subtract(ONE_SECOND_IN_DAYS)); 987 } 988 } 989 990 private int calcLmstDayNumber(BigDecimal greenwichMeanSiderealDay) 991 { 992 //The convert... method puts angle to +/-0.5 circles, instead of [0.0-1.0) 993 BigDecimal hoursFromGreenwich = 994 location.toAngle().convertToMinAbsValueNormal().toUnits(ArcUnits.HOUR); 995 996 BigDecimal lmstDay = hoursFromGreenwich.divide(HR_PER_DAY, RoundingMode.HALF_UP) 997 .add(greenwichMeanSiderealDay); 998 999 return lmstDay.intValue() + LST_DAY_NUMBER_OFFSET; 1000 } 1001 1002 //Constants used in USNO algorithm in calcGmstHours, below 1003 private static final BigDecimal USNO1 = new BigDecimal("6.697374558"); //meaning? 1004 private static final BigDecimal USNO2 = new BigDecimal("0.06570982441908"); //meaning? 1005 private static final BigDecimal USNO3 = MEAN_SIDEREAL_PER_SOLAR; 1006 private static final BigDecimal USNO4 = new BigDecimal("0.000026"); //meaning? 1007 1008 private static final BigDecimal DAYS_PER_CENT = new BigDecimal("36525.0"); 1009 private static final BigDecimal ONE_HALF = new BigDecimal( "0.5"); 1010 1011 /** 1012 * Uses the US Naval Observatory's 1013 * <a href="http://aa.usno.navy.mil/faq/docs/GAST.html"> 1014 * Approximate Sidereal Time 1015 * </a> 1016 * algorithm for calculating Greenwich Mean Sidereal Time for 1017 * the given date. 1018 * 1019 * @return GMST in hours. This result will usually need to be normalized 1020 * to fit in the range [0.0 - 24.0). 1021 */ 1022 private BigDecimal calcGmstHours(BigDecimal julianDate) 1023 { 1024 //January 1, 2000 12:00:00.0 UTC 1025 final BigDecimal JULIAN_DATE_TIME_ZERO = new BigDecimal("2451545.0"); 1026 1027 //Called "D" in USNO algorithm 1028 BigDecimal daysSinceTimeZero = julianDate.subtract(JULIAN_DATE_TIME_ZERO); 1029 1030 BigDecimal wholeDay = new BigDecimal(julianDate.longValue()); 1031 BigDecimal fractionalDay = julianDate.subtract(wholeDay); 1032 1033 //Called "JD0" (JD-zero) 1034 BigDecimal jdForPreviousMidnight = 1035 fractionalDay.compareTo(ONE_HALF) >= 0 ? wholeDay.add(ONE_HALF) 1036 : wholeDay.subtract(ONE_HALF); 1037 //Called "D0" (D-zero) 1038 BigDecimal daysSinceTimeZeroAtPrevMidnight = 1039 jdForPreviousMidnight.subtract(JULIAN_DATE_TIME_ZERO); 1040 1041 BigDecimal fracDaysSinceMidnight = julianDate.subtract(jdForPreviousMidnight); 1042 1043 //Called "H" 1044 BigDecimal hoursSinceMidnight = HR_PER_DAY.multiply(fracDaysSinceMidnight); 1045 1046 //Called "T" 1047 BigDecimal centuriesSinceTimeZero = 1048 daysSinceTimeZero.divide(DAYS_PER_CENT, RoundingMode.HALF_UP); 1049 1050 final BigDecimal part2 = USNO2.multiply(daysSinceTimeZeroAtPrevMidnight); 1051 final BigDecimal part3 = USNO3.multiply(hoursSinceMidnight); 1052 final BigDecimal part4 = USNO4.multiply(centuriesSinceTimeZero) 1053 .multiply(centuriesSinceTimeZero); 1054 1055 BigDecimal gmstHours = USNO1.add(part2).add(part3).add(part4); 1056 1057 return gmstHours; 1058 } 1059 1060 /** Takes a number of hours and puts it into the range [0 - 24). */ 1061 private BigDecimal normalizeHours(BigDecimal hours) 1062 { 1063 if (hours.signum() < 0) 1064 { 1065 //Mimic multiples = Math.ceil(hours / -24.0) 1066 BigDecimal[] divAndRem = 1067 hours.divideAndRemainder(HR_PER_DAY.negate(), MC_INTERM_CALCS); 1068 1069 BigDecimal multiples = divAndRem[0]; //equiv to floor(x) 1070 if (divAndRem[1].signum() < 0) 1071 multiples = multiples.add(BigDecimal.ONE); 1072 1073 hours = hours.add(HR_PER_DAY.multiply(multiples, MC_INTERM_CALCS), 1074 MC_FINAL_CALC); 1075 } 1076 else if (hours.compareTo(HR_PER_DAY) >= 0) 1077 { 1078 BigDecimal multiples = 1079 hours.divideToIntegralValue(HR_PER_DAY, MC_INTERM_CALCS); 1080 1081 hours = hours.subtract(HR_PER_DAY.multiply(multiples, MC_INTERM_CALCS), 1082 MC_FINAL_CALC); 1083 } 1084 1085 //Exactly hitting top of clock 1086 if (hours.compareTo(HR_PER_DAY) == 0) 1087 hours = BigDecimal.ZERO; 1088 1089 return hours; 1090 } 1091 1092 //============================================================================ 1093 // 1094 //============================================================================ 1095 1096 /** 1097 * Returns a copy of this LST. 1098 * <p> 1099 * If anything goes wrong during the cloning procedure, 1100 * a {@code RuntimeException} will be thrown.</p> 1101 */ 1102 @Override 1103 public LocalSiderealTime clone() 1104 { 1105 LocalSiderealTime clone = null; 1106 1107 try 1108 { 1109 //This line takes care of the primitive variables 1110 clone = (LocalSiderealTime)super.clone(); 1111 1112 clone.julianDate = this.julianDate.clone(); 1113 clone.location = this.location.clone(); 1114 clone.gmst = this.gmst.clone(); 1115 clone.lmst = this.lmst.clone(); 1116 } 1117 catch (Exception ex) 1118 { 1119 throw new RuntimeException(ex); 1120 } 1121 1122 return clone; 1123 } 1124 1125 /** Returns <i>true</i> if {@code o} is equal to this LST. */ 1126 @Override 1127 public boolean equals(Object o) 1128 { 1129 //Quick exit if o is this 1130 if (o == this) 1131 return true; 1132 1133 //Quick exit if o is null 1134 if (o == null) 1135 return false; 1136 1137 //Quick exit if classes are different 1138 if (!o.getClass().equals(this.getClass())) 1139 return false; 1140 1141 LocalSiderealTime other = (LocalSiderealTime)o; 1142 1143 //This treats LST not as time, but as date/time 1144 return other.julianDate.equals(this.julianDate); 1145 } 1146 1147 /** Returns a hash code value for this LST. */ 1148 @Override 1149 public int hashCode() 1150 { 1151 //This treats LST not as time, but as date/time 1152 return julianDate.hashCode(); 1153 } 1154 1155 /* (non-Javadoc) 1156 * @see java.lang.Comparable#compareTo(java.lang.Object) 1157 */ 1158 public int compareTo(LocalSiderealTime other) 1159 { 1160 //This treats LST not as time, but as date/time 1161 return this.julianDate.compareTo(other.julianDate); 1162 } 1163 1164 //============================================================================ 1165 // 1166 //============================================================================ 1167 /* 1168 public static void main(String[] args) throws Exception 1169 { 1170 LocalSiderealTime lst = new LocalSiderealTime(); 1171 1172 java.util.Calendar cal = java.util.Calendar.getInstance(); 1173 cal.setTimeZone(TimeZone.getTimeZone("GMT")); 1174 cal.clear(java.util.Calendar.MILLISECOND); 1175 cal.set(2000, 0, 1, 0, 0, 0); 1176 1177 for (int trial=1; trial <= 60; trial++) 1178 { 1179 Date d = cal.getTime(); 1180 lst.setSolarTime(d); 1181 System.out.print("LST at VLA at time " + d + " = " + lst.toTimeOfDay()); 1182 System.out.print(", DAY # = " + lst.getDayNumber()); 1183 System.out.println(); 1184 //cal.roll(java.util.Calendar.SECOND, true); 1185 cal.add(java.util.Calendar.HOUR, 1); 1186 } 1187 1188 Longitude ra = Longitude.parse("07:00:00.0"); 1189 1190 System.out.println(); 1191 System.out.println("lst.set(2000, 0, 2, 5, 38, 16.097)"); 1192 lst.set(2000, 0, 2, 5, 38, new BigDecimal("16.097")); 1193 System.out.println("lst.toDate = " + lst.toDate()); 1194 System.out.println("lst.toTimeOfDay = " + lst.toTimeOfDay()); 1195 System.out.println("HA for RA of " + ra.toStringHms() + 1196 " = " + lst.getHourAngle(ra).toStringHms(0,3)); 1197 System.out.println("HA for RA of " + ra.toStringHms() + 1198 " = " + lst.getHourAngle(ra).toAngle().convertToMinAbsValueNormal().toUnits(ArcUnits.HOUR)); 1199 1200 System.out.println(); 1201 System.out.println("lst.set(2000, 0, 3, 10, 39, 5.380)"); 1202 lst.set(2000, 0, 3, 10, 39, new BigDecimal("5.380")); 1203 System.out.println("lst.toDate = " + lst.toDate()); 1204 System.out.println("lst.toTimeOfDay = " + lst.toTimeOfDay()); 1205 System.out.println("HA for RA of " + ra.toStringHms() + 1206 " = " + lst.getHourAngle(ra).toStringHms(0,3)); 1207 System.out.println("HA for RA of " + ra.toStringHms() + 1208 " = " + lst.getHourAngle(ra).toAngle().convertToMinAbsValueNormal().toUnits(ArcUnits.HOUR)); 1209 1210 System.out.println(); 1211 lst = new LocalSiderealTime(); 1212 System.out.print("LST at VLA now = " + lst.toTimeOfDay()); 1213 System.out.print(", DAY # = " + lst.getDayNumber()); 1214 System.out.print(", solar = " + lst.toDate()); 1215 System.out.print(", JD = " + lst.toJulianDate()); 1216 System.out.println(); 1217 } 1218 */ 1219 /* 1220 //Data chosen to match output on page http://zeitladen.de/time.html 1221 public static void main(String... args) throws Exception 1222 { 1223 LocalSiderealTime lst = new LocalSiderealTime(); 1224 lst.setLocationAndTimeZone(new Longitude("0.0"), TimeZone.getTimeZone("GMT")); 1225 1226 java.util.Calendar cal = java.util.Calendar.getInstance(); 1227 cal.setTimeZone(TimeZone.getTimeZone("GMT")); 1228 cal.clear(java.util.Calendar.MILLISECOND); 1229 1230 for (int day=1; day <= 30; day++) 1231 { 1232 cal.set(2008, 5, day, 0, 0, 0); //5 = June 1233 1234 System.out.print(day); 1235 1236 lst.setSolarTime(cal.getTime()); 1237 System.out.print(", " + lst.toTimeOfDay()); 1238 1239 cal.set(2008, 5, day, 18, 0, 0); //5 = June 1240 lst.setSolarTime(cal.getTime()); 1241 System.out.print(", " + lst.toTimeOfDay()); 1242 1243 System.out.println(); 1244 } 1245 } 1246 */ 1247 /* 1248 //Monthly LSTs 1249 public static void main(String... args) throws Exception 1250 { 1251 LocalSiderealTime lst = new LocalSiderealTime(); 1252 1253 java.util.Calendar cal = java.util.Calendar.getInstance(); 1254 cal.clear(java.util.Calendar.MILLISECOND); 1255 1256 for (int month=0; month < 12; month++) 1257 { 1258 cal.set(2007, month, 1, 0, 0, 0); 1259 1260 Date date = cal.getTime(); 1261 1262 System.out.print(date + ", "); 1263 1264 lst.setSolarTime(date); 1265 System.out.print(lst.toTimeOfDay()+", "); 1266 1267 System.out.print(lst.getDayNumber()+", "); 1268 1269 System.out.println(); 1270 } 1271 } 1272 */ 1273 /* 1274 //Daily LSTs 1275 public static void main(String... args) throws Exception 1276 { 1277 LocalSiderealTime lst = new LocalSiderealTime(); 1278 1279 java.util.Calendar cal = java.util.Calendar.getInstance(); 1280 cal.clear(java.util.Calendar.MILLISECOND); 1281 1282 for (int day=1; day <= 31; day++) 1283 { 1284 cal.set(2008, 5, day, 0, 0, 0); 1285 1286 Date date = cal.getTime(); 1287 1288 System.out.print(date + ", "); 1289 1290 lst.setSolarTime(date); 1291 System.out.print(lst.toTimeOfDay()+", "); 1292 1293 System.out.print(lst.getDayNumber()+", "); 1294 1295 System.out.println(); 1296 } 1297 } 1298 */ 1299 /* 1300 //Determines an arbitrary zero-point for "GMST day", which 1301 //is used in this class to get VLA's "LST day number". 1302 public static void main(String... args) throws Exception 1303 { 1304 //Set location to Greenwich 1305 LocalSiderealTime lst = new LocalSiderealTime(); 1306 lst.setLocationAndTimeZone(new Longitude("0.0"), TimeZone.getTimeZone("GMT")); 1307 1308 java.util.Calendar cal = java.util.Calendar.getInstance(); 1309 cal.setTimeZone(TimeZone.getTimeZone("GMT")); 1310 cal.clear(java.util.Calendar.MILLISECOND); 1311 1312 //January 1, 2000 GMT (UTC) 1313 cal.set(2000, 0, 1, 0, 0, 0); 1314 lst.setSolarTime(cal.getTime()); 1315 1316 System.out.println("LST = " + lst.toTimeOfDay().toFractionOfDay()); 1317 System.out.println("JD = " + lst.toJulianDate()); 1318 1319 BigDecimal siderealDayFrac = lst.toTimeOfDay().toFractionOfDay(); 1320 BigDecimal solarDayFrac = siderealDayFrac.divide(MEAN_SIDEREAL_PER_SOLAR, RoundingMode.HALF_UP); 1321 JulianDate timeZero = lst.toJulianDate().subtract(solarDayFrac); 1322 System.out.println("T0 = " + timeZero); 1323 1324 lst.setSolarTime(timeZero); 1325 System.out.println("\nLST[t0] = " + lst.toTimeOfDay()); 1326 } 1327 */ 1328 /* 1329 public static void main(String... args) throws Exception 1330 { 1331 System.out.println(LocalSiderealTime.MEAN_SIDEREAL_PER_SOLAR); 1332 System.out.println(LocalSiderealTime.MEAN_SOLAR_PER_SIDEREAL); 1333 System.out.println(); 1334 1335 TimeDuration solar = new TimeDuration("1000.0", TimeUnits.SECOND); 1336 TimeDuration sidereal = LocalSiderealTime.solarToSidereal(solar); 1337 System.out.println("solar = "+solar.getValue()+"s, sidereal = "+sidereal.getValue()+"s"); 1338 System.out.println("solar = "+solar.toStringHms()+", sidereal = "+sidereal.toStringHms()); 1339 1340 solar = LocalSiderealTime.siderealToSolar(sidereal); 1341 System.out.println("\nback to solar = "+solar.getValue()+"s"); 1342 System.out.println("back to solar = "+solar.toStringHms()); 1343 1344 System.out.println(); 1345 LocalSiderealTime lst = new LocalSiderealTime(); 1346 lst.subtractSolar(new TimeDuration("30", TimeUnits.HOUR)); 1347 JulianDate jd = new JulianDate(); 1348 lst.siderealTimeUntil(jd); 1349 } 1350 */ 1351 /* 1352 public static void main(String... args) throws Exception 1353 { 1354 Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); 1355 cal.set(2008, 10, 10, 3, 51, 44); 1356 cal.set(Calendar.MILLISECOND, 742); 1357 Date javaDate = cal.getTime(); //new Date(); 1358 JulianDate jd = new JulianDate(javaDate); 1359 LocalSiderealTime lst1 = new LocalSiderealTime(javaDate); 1360 LocalSiderealTime lst2 = new LocalSiderealTime(jd); 1361 1362 System.out.println("java date = " + javaDate); 1363 System.out.println("julian date = " + jd); 1364 System.out.println("jd.toDate = " + jd.toDate()); 1365 1366 System.out.println(); 1367 1368 System.out.println("The following are all from lst1, created from javaDate"); 1369 System.out.println("lst = " + lst1); 1370 System.out.println("lst.toDate() = " + lst1.toDate()); 1371 System.out.println("lst.toJulianDate() = " + lst1.toJulianDate()); 1372 System.out.println("lst.toTimeOfDay() = " + lst1.toTimeOfDay()); 1373 System.out.println("lst.toTimeOfDaySolar() = " + lst1.toTimeOfDaySolar()); 1374 System.out.println("lst.toTimeOfDayUtc() = " + lst1.toTimeOfDayUtc()); 1375 1376 System.out.println(); 1377 1378 System.out.println("The following are all from lst2, created from jd"); 1379 System.out.println("lst = " + lst2); 1380 System.out.println("lst.toDate() = " + lst2.toDate()); 1381 System.out.println("lst.toJulianDate() = " + lst2.toJulianDate()); 1382 System.out.println("lst.toTimeOfDay() = " + lst2.toTimeOfDay()); 1383 System.out.println("lst.toTimeOfDaySolar() = " + lst2.toTimeOfDaySolar()); 1384 System.out.println("lst.toTimeOfDayUtc() = " + lst2.toTimeOfDayUtc()); 1385 } 1386 */ 1387 }