001 /* 002 * $Id: Time.java,v 1.3 2012/02/19 17:35:39 davep Exp $ 003 * 004 * This file is part of McIDAS-V 005 * 006 * Copyright 2007-2012 007 * Space Science and Engineering Center (SSEC) 008 * University of Wisconsin - Madison 009 * 1225 W. Dayton Street, Madison, WI 53706, USA 010 * https://www.ssec.wisc.edu/mcidas 011 * 012 * All Rights Reserved 013 * 014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 015 * some McIDAS-V source code is based on IDV and VisAD source code. 016 * 017 * McIDAS-V is free software; you can redistribute it and/or modify 018 * it under the terms of the GNU Lesser Public License as published by 019 * the Free Software Foundation; either version 3 of the License, or 020 * (at your option) any later version. 021 * 022 * McIDAS-V is distributed in the hope that it will be useful, 023 * but WITHOUT ANY WARRANTY; without even the implied warranty of 024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 025 * GNU Lesser Public License for more details. 026 * 027 * You should have received a copy of the GNU Lesser Public License 028 * along with this program. If not, see http://www.gnu.org/licenses. 029 */ 030 031 package edu.wisc.ssec.mcidasv.data.adde.sgp4; 032 033 import java.text.DateFormat; 034 import java.text.DecimalFormat; 035 import java.text.SimpleDateFormat; 036 import java.util.Calendar; 037 import java.util.GregorianCalendar; 038 import java.util.TimeZone; 039 040 /** 041 * Used to keep track of a time and convert to multiple formats. 042 * @author Shawn E. Gano 043 */ 044 public class Time implements java.io.Serializable 045 { 046 // time units 047 /** 048 * year type 049 */ 050 public final static int YEAR=Calendar.YEAR; 051 /** 052 * month type 053 */ 054 public final static int MONTH=Calendar.MONTH; 055 /** 056 * date type 057 */ 058 public final static int DATE=Calendar.DATE; 059 /** 060 * hour type 061 */ 062 public final static int HOUR=Calendar.HOUR; 063 /** 064 * Hour type 065 */ 066 public final static int HOUR_OF_DAY=Calendar.HOUR_OF_DAY; 067 /** 068 * Minute type 069 */ 070 public final static int MINUTE=Calendar.MINUTE; 071 /** 072 * Second type 073 */ 074 public final static int SECOND=Calendar.SECOND; 075 /** 076 * Millisecond type 077 */ 078 public final static int MILLISECOND=Calendar.MILLISECOND; 079 080 // main calendar 081 private GregorianCalendar currentTime; 082 // other date formats 083 private double mjd; // Modified Julian date 084 private double mjde; // Modified Julian Day Ephemeris time 085 086 // decimal formats 087 private final static DecimalFormat fmt4Dig = new DecimalFormat("0000"); 088 private final static DecimalFormat fmt2Dig = new DecimalFormat("00"); 089 090 // output format 091 private DateFormat dateFormat=null; 092 093 // time zone 094 private final static TimeZone tz=TimeZone.getTimeZone("UTC"); // default internal timezone 095 private TimeZone tzStringFormat = TimeZone.getTimeZone("UTC"); // SEG removed static April 16 2009 096 097 098 public static void main(String args[]) 099 { 100 Time t = new Time(2007,9,1,11,59,0.0); 101 System.out.println("Jul Date:" + t.getJulianDate() + ", string:" + t.getDateTimeStr()); 102 // System.out.println("MJD :" + t.getMJD()); 103 // System.out.println("MJDE :" + t.getMJDE()); 104 // System.out.println("DT: " + t.deltaT( t.getMJD() )*60*60*24 ); 105 // 2454344.5 106 t.addSeconds(120.0); // add 60 sec 107 System.out.println("Jul Date + 120 sec:" + t.getJulianDate()+ ", string:" + t.getDateTimeStr()); 108 109 t.add(Time.HOUR,12); 110 System.out.println("Jul Date + 12 hour:" + t.getJulianDate()+ ", string:" + t.getDateTimeStr()); 111 112 } 113 114 115 /** 116 * Default Constructor 117 */ 118 public Time() 119 { 120 // create new calendar with default timezone 121 currentTime = new GregorianCalendar(tz); 122 123 // update other time formates 124 updateTimeMeasures(); 125 } 126 127 128 /** 129 * Constructor with given calendar date (UT) 130 * 131 * @param year year 132 * @param month month (1-12) 133 * @param day day of month 134 * @param hour hour 0-24 135 * @param min minute 136 * @param sec second and fraction of second (accurate up to 1 millisecond) 137 */ 138 public Time(int year, int month, int day, int hour, int min, double sec) 139 { 140 int secInt = new Double( Math.floor(sec) ).intValue(); 141 int millisec = new Double( Math.round((sec - Math.floor(sec))*1000.0) ).intValue(); 142 143 currentTime = new GregorianCalendar(tz); // set default timezone 144 145 currentTime.set(Calendar.YEAR,year); 146 currentTime.set(Calendar.MONTH,month-1); 147 currentTime.set(Calendar.DATE,day); 148 currentTime.set(Calendar.HOUR_OF_DAY,hour); 149 currentTime.set(Calendar.MINUTE,min); 150 currentTime.set(Calendar.SECOND,secInt); 151 currentTime.set(Calendar.MILLISECOND,millisec); 152 153 // update other time formats 154 updateTimeMeasures(); 155 } 156 157 158 /** 159 * Updates the time to current system time 160 */ 161 public void update2CurrentTime() 162 { 163 // update to current time (which is faster?) 164 //currentTime =new GregorianCalendar(tz); 165 currentTime.setTimeInMillis( System.currentTimeMillis() ); 166 //currentTime.setTime( new Date() ); 167 168 // update other time formats 169 updateTimeMeasures(); 170 } // update2CurrentTime 171 172 /** 173 * Set the current time (UT) to the number of milliseconds 174 * @param milliseconds number of millisconds as in from the function Calendar.getTimeInMillis() 175 */ 176 public void set(long milliseconds) 177 { 178 currentTime.setTimeInMillis(milliseconds); 179 180 // update other time formats 181 updateTimeMeasures(); 182 } // set 183 184 /** 185 * Add specified value in specified time unit to current time 186 * 187 * @param unit int Time unit 188 * @param val int Time increment 189 */ 190 public void add(int unit, int val) 191 { 192 currentTime.add(unit, val); 193 194 // update other time formats 195 updateTimeMeasures(); 196 } 197 198 /** 199 * Add specified seconds to current time 200 * 201 * @param seconds number of seconds to add to current time (can be fractional) 202 */ 203 public void addSeconds(double seconds) 204 { 205 // multiply input by 1000 then round off and add this number of milliseconds to date 206 int millis2Add = new Double(Math.round( seconds*1000 )).intValue(); 207 208 currentTime.add(Calendar.MILLISECOND, millis2Add); 209 210 // update other time formats 211 updateTimeMeasures(); 212 } 213 214 /** 215 * Updates the Julian and Julian Epehermis Dates using Current GregorianCalendar 216 */ 217 private void updateTimeMeasures() 218 { 219 mjd = calcMjd(currentTime); 220 mjde = mjd + deltaT(mjd); 221 } 222 223 /** 224 * Gets the Julian Date (UT) 225 * @return Returns the Julian Date 226 */ 227 public double getJulianDate() 228 { 229 return mjd + 2400000.5; 230 } 231 232 /** 233 * Gets the Modified Julian Date (Julian date minus 2400000.5) (UT) 234 * @return Returns the Modified Julian Date 235 */ 236 public double getMJD() 237 { 238 return mjd ; 239 } 240 241 /** 242 * Gets the Modified Julian Ephemeris Date (Julian date minus 2400000.5) (TT) 243 * @return Returns the Modified Julian Ephemeris Date 244 */ 245 public double getMJDE() 246 { 247 return mjde; 248 } 249 250 /** 251 * Sets timezone for the output string to use via the function getDateTimeStr() 252 * @param aTzStringFormat time zone to format output strings with 253 */ 254 public void setTzStringFormat(TimeZone aTzStringFormat) 255 { 256 tzStringFormat = aTzStringFormat; 257 } 258 259 260 /** 261 * Set SimpleDateFormat for displaying date/time string 262 * @param dateFormat SimpleDateFormat 263 */ 264 public void setDateFormat(SimpleDateFormat dateFormat) 265 { 266 this.dateFormat=dateFormat; 267 } 268 269 /** 270 * Set SimpleDateFormat string 271 * ISSUE - only valid after Jan 1, 1970 272 *@param formatStr String format for simple date format to use for creating strings of the date 273 */ 274 public void setDateFormat(java.lang.String formatStr) 275 { 276 if ((formatStr!=null)&&(formatStr.length()>0)) 277 { 278 dateFormat=new SimpleDateFormat(formatStr); 279 } 280 } 281 282 /** 283 * Gets the date format 284 * @return date format 285 */ 286 public DateFormat getDateFormat() 287 { 288 return dateFormat; 289 } 290 291 /** 292 * Returns the specified field 293 * @param field int The specified field 294 * @return int The field value 295 */ 296 public final int get(int field) 297 { 298 return currentTime.get(field); 299 } 300 301 /* 302 * Get the UTC date/time string in the format of yyyy-mm-dd hh:mm:ss 303 * If the dateFormat is not set or if the date is before Jan 1, 1970 304 * otherwise the empty string "" will be returned.) 305 * @return java.lang.String 306 */ 307 public String getDateTimeStr() 308 { 309 String retStr=""; 310 311 if ((dateFormat!=null) &&( getJulianDate() >= 2440587.5)) 312 { 313 dateFormat.setTimeZone(tzStringFormat); 314 retStr=dateFormat.format( currentTime.getTime() ); 315 } 316 else 317 { 318 StringBuffer strBuf = new StringBuffer(fmt4Dig.format(get(Time.YEAR))); 319 strBuf.append("-"); 320 strBuf.append(fmt2Dig.format(get(Time.MONTH)+1)); 321 strBuf.append("-"); 322 strBuf.append(fmt2Dig.format(get(Time.DATE))); 323 strBuf.append(" "); 324 strBuf.append(fmt2Dig.format(get(Time.HOUR_OF_DAY))); 325 strBuf.append(":"); 326 strBuf.append(fmt2Dig.format(get(Time.MINUTE))); 327 strBuf.append(":"); 328 strBuf.append(fmt2Dig.format(get(Time.SECOND))); 329 strBuf.append(" "); 330 strBuf.append( tz.getID() ); 331 retStr=strBuf.toString(); 332 } 333 return retStr; 334 } 335 336 // ============================== STATIC Functions ==================================== 337 338 /** 339 * Calculate Modified Julian Date from calendar object 340 * 341 * @param cal Calendar object 342 * @return Modified Julian Date (UT) 343 */ 344 public static double calcMjd(Calendar cal) 345 { 346 double sec = cal.get(Calendar.SECOND) + cal.get(Calendar.MILLISECOND)/1000.0; 347 return calcMjd(cal.get(Calendar.YEAR),cal.get(Calendar.MONTH)+1,cal.get(Calendar.DATE),cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), sec); 348 } 349 350 /** 351 * Calculate Modified Julian Date from calendar date and time elements 352 * 353 * @param year calendar year 354 * @param month calendar month 355 * @param day calendar day 356 * @param hour calendar hour (0-24) 357 * @param min calendar min 358 * @param sec calendar sec 359 * @return Modified Julian Date (UT) 360 */ 361 public static double calcMjd(int year, int month, int day, int hour, int min, double sec) 362 { 363 // Variables 364 long MjdMidnight; 365 double FracOfDay; 366 int b; 367 368 if (month<=2) 369 { month+=12; --year;} 370 371 if ( (10000L*year+100L*month+day) <= 15821004L ) 372 { 373 b = -2 + ((year+4716)/4) - 1179; // Julian calendar 374 } 375 else 376 { 377 b = (year/400)-(year/100)+(year/4); // Gregorian calendar 378 } 379 380 MjdMidnight = 365L*year - 679004L + b + (int) (30.6001*(month+1)) + day; 381 FracOfDay = (hour+min/60.0+sec/3600.0) / 24.0; 382 383 return MjdMidnight + FracOfDay; 384 } //calcMjd 385 386 387 /** 388 * Return TT minus UT. 389 * 390 * <p>Up to 1983 Ephemeris Time (ET) was used in place of TT, between 391 * 1984 and 2000 Temps Dynamique Terrestrial (TDT) was used in place of TT. 392 * The three time scales, while defined differently, form a continuous time 393 * scale for most purposes. TT has a fixed offset from TAI (Temps Atomique 394 * International). 395 * 396 * <p>This method returns the difference TT - UT in days. Usually this 397 * would be looked up in a table published after the fact. Here we use 398 * polynomial fits for the distant past, for the future and also for the 399 * time where the table exists. Except for 1987 to 2015, the expressions 400 * are taken from 401 * Jean Meeus, 1991, <I>Astronomical Algorithms</I>, Willmann-Bell, Richmond VA, p.73f. 402 * For the present (1987 to 2015 we use our own graphical linear fit to the 403 * data 1987 to 2001 from 404 * USNO/RAL, 2001, <I>Astronomical Almanach 2003</I>, U.S. Government Printing Office, Washington DC, Her Majesty's Stationery Office, London, p.K9: 405 * 406 * <p>t = Ep - 2002 407 * <p>DeltaT/s = 9.2 * t / 15 + 65 408 * 409 * <p>Close to the present (1900 to 1987) we use Schmadl and Zech: 410 * 411 * <p>t = (Ep - 1900) / 100 412 * <p>DeltaT/d = -0.000020 + 0.000297 * t 413 * + 0.025184 * t<sup>2</sup> - 0.181133 * t<sup>3</sup><BR> 414 * + 0.553040 * t<sup>4</sup> - 0.861938 * t<sup>5</sup> 415 * + 0.677066 * t<sup>6</sup> - 0.212591 * t<sup>7</sup> 416 * 417 * <p>This work dates from 1988 and the equation is supposed to be valid only 418 * to 1987, but we extend its use into the near future. For the 19th 419 * century we use Schmadl and Zech: 420 * 421 * <p>t = (Ep - 1900) / 100 422 * <p>DeltaT/d = -0.000009 + 0.003844 * t 423 * + 0.083563 * t<sup>2</sup> + 0.865736 * t<sup>3</sup><BR> 424 * + 4.867575 * t<sup>4</sup> + 15.845535 * t<sup>5</sup> 425 * + 31.332267 * t<sup>6</sup> + 38.291999 * t<sup>7</sup><BR> 426 * + 28.316289 * t<sup>8</sup> + 11.636204 * t<sup>9</sup> 427 * + 2.043794 * t<sup>10</sup> 428 * 429 * <p>Stephenson and Houlden are credited with the equations for times before 430 * 1600. First for the period 948 to 1600: 431 * 432 * <p>t = (Ep - 1850) / 100 433 * <p>DeltaT/s = 22.5 * t<sup>2</sup> 434 * 435 * <p>and before 948: 436 * 437 * <p>t = (Ep - 948) / 100 438 * <p>DeltaT/s = 1830 - 405 * t + 46.5 * t<sup>2</sup> 439 * 440 * <p>This leaves no equation for times between 1600 and 1800 and beyond 441 * 2015. For such times we use the equation of Morrison and Stephenson: 442 * 443 * <p>t = Ep - 1810 444 * <p>DeltaT/s = -15 + 0.00325 * t<sup>2</sup> 445 * 446 * @param givenMJD Modified Julian Date (UT) 447 * @return TT minus UT in days 448 */ 449 450 public static double deltaT(double givenMJD) 451 { 452 double theEpoch; /* Julian Epoch */ 453 double t; /* Time parameter used in the equations. */ 454 double D; /* The return value. */ 455 456 givenMJD -= 50000; 457 458 theEpoch = 2000. + (givenMJD - 1545.) / 365.25; 459 460 /* For 1987 to 2015 we use a graphical linear fit to the annual tabulation 461 * from USNO/RAL, 2001, Astronomical Almanach 2003, p.K9. We use this up 462 * to 2015 about as far into the future as it is based on data in the past. 463 * The result is slightly higher than the predictions from that source. */ 464 465 if (1987 <= theEpoch && 2015 >= theEpoch) 466 { 467 t = (theEpoch - 2002.); 468 D = 9.2 * t / 15. + 65.; 469 D /= 86400.; 470 } 471 472 /* For 1900 to 1987 we use the equation from Schmadl and Zech as quoted in 473 * Meeus, 1991, Astronomical Algorithms, p.74. This is precise within 474 * 1.0 second. */ 475 476 else if (1900 <= theEpoch && 1987 > theEpoch) 477 { 478 t = (theEpoch - 1900.) / 100.; 479 D = -0.212591 * t * t * t * t * t * t * t 480 + 0.677066 * t * t * t * t * t * t 481 - 0.861938 * t * t * t * t * t 482 + 0.553040 * t * t * t * t 483 - 0.181133 * t * t * t 484 + 0.025184 * t * t 485 + 0.000297 * t 486 - 0.000020; 487 } 488 489 /* For 1800 to 1900 we use the equation from Schmadl and Zech as quoted in 490 * Meeus, 1991, Astronomical Algorithms, p.74. This is precise within 1.0 491 * second. */ 492 493 else if (1800 <= theEpoch && 1900 > theEpoch) 494 { 495 t = (theEpoch - 1900.) / 100.; 496 D = 2.043794 * t * t * t * t * t * t * t * t * t * t 497 + 11.636204 * t * t * t * t * t * t * t * t * t 498 + 28.316289 * t * t * t * t * t * t * t * t 499 + 38.291999 * t * t * t * t * t * t * t 500 + 31.332267 * t * t * t * t * t * t 501 + 15.845535 * t * t * t * t * t 502 + 4.867575 * t * t * t * t 503 + 0.865736 * t * t * t 504 + 0.083563 * t * t 505 + 0.003844 * t 506 - 0.000009; 507 } 508 509 /* For 948 to 1600 we use the equation from Stephenson and Houlden as 510 * quoted in Meeus, 1991, Astronomical Algorithms, p.73. */ 511 512 else if (948 <= theEpoch && 1600 >= theEpoch) 513 { 514 t = (theEpoch - 1850.) / 100.; 515 D = 22.5 * t * t; 516 D /= 86400.; 517 } 518 519 /* Before 948 we use the equation from Stephenson and Houlden as quoted 520 * in Meeus, 1991, Astronomical Algorithms, p.73. */ 521 522 else if (948 > theEpoch) 523 { 524 t = (theEpoch - 948.) / 100.; 525 D = 46.5 * t * t - 405. * t + 1830.; 526 D /= 86400.; 527 } 528 529 /* Else (between 1600 and 1800 and after 2010) we use the equation from 530 * Morrison and Stephenson, quoted as eqation 9.1 in Meeus, 1991, 531 * Astronomical Algorithms, p.73. */ 532 533 else 534 { 535 t = theEpoch - 1810.; 536 D = 0.00325 * t * t - 15.; 537 D /= 86400.; 538 } 539 540 return D; // in days 541 } // deltaT 542 543 public GregorianCalendar getCurrentGregorianCalendar() 544 { 545 return currentTime; 546 } 547 548 // function to take a given Julian date and parse it to a Gerorian Calendar 549 public static GregorianCalendar convertJD2Calendar(double jd) 550 { 551 /** 552 * Calculate calendar date for Julian date field this.jd 553 */ 554 Double jd2 = new Double(jd + 0.5); 555 long I = jd2.longValue(); 556 double F = jd2.doubleValue() - (double) I; 557 long A = 0; 558 long B = 0; 559 560 if (I > 2299160) 561 { 562 Double a1 = new Double(((double) I - 1867216.25) / 36524.25); 563 A = a1.longValue(); 564 Double a3 = new Double((double) A / 4.0); 565 B = I + 1 + A - a3.longValue(); 566 } 567 else 568 { 569 B = I; 570 } 571 572 double C = (double) B + 1524; 573 Double d1 = new Double((C - 122.1) / 365.25); 574 long D = d1.longValue(); 575 Double e1 = new Double(365.25 * (double) D); 576 long E = e1.longValue(); 577 Double g1 = new Double((double) (C - E) / 30.6001); 578 long G = g1.longValue(); 579 Double h = new Double((double) G * 30.6001); 580 long da = (long) C - E - h.longValue(); 581 582 Integer date = new Integer((int) da); // DATE 583 584 Integer month; 585 Integer year; 586 587 if (G < 14L) 588 { 589 month = new Integer((int) (G - 2L)); 590 } 591 else 592 { 593 month = new Integer((int) (G - 14L)); 594 } 595 596 if (month.intValue() > 1) 597 { 598 year = new Integer((int) (D - 4716L)); 599 } 600 else 601 { 602 year = new Integer((int) (D - 4715L)); 603 } 604 605 // Calculate fractional part as hours, minutes, and seconds 606 Double dhr = new Double(24.0 * F); 607 Integer hour = new Integer(dhr.intValue()); 608 Double dmin = new Double((dhr.doubleValue() - (double) dhr.longValue()) * 60.0); 609 Integer minute = new Integer(dmin.intValue()); 610 611 Double dsec = new Double((dmin.doubleValue() - (double) dmin.longValue()) * 60.0); 612 Integer second=new Integer(dsec.intValue()); 613 614 //int ms = (int)((dsec.doubleValue() - (double) second.longValue()) * 1000.0); 615 // rounding fix - e-mailed to SEG by Hani A. Altwaijry 28 May 2009 616 int ms = (int) Math.round((dsec.doubleValue() - (double) second.longValue()) * 1000.0); 617 618 // create Calendar object 619 GregorianCalendar newTime = new GregorianCalendar(tz); // set default timezone 620 621 newTime.set(Calendar.YEAR,year); 622 newTime.set(Calendar.MONTH,month); 623 newTime.set(Calendar.DATE,date); 624 newTime.set(Calendar.HOUR_OF_DAY,hour); 625 newTime.set(Calendar.MINUTE,minute); 626 newTime.set(Calendar.SECOND,second); 627 newTime.set(Calendar.MILLISECOND,ms); 628 629 return newTime; 630 631 } // convertJD2Calendar 632 633 // function used to take a given Julian Date and parse it as a string using the current settings 634 public String convertJD2String(double jd) 635 { 636 // convert to calendar 637 GregorianCalendar newTime = convertJD2Calendar(jd); 638 639 // format as String -- ASSUMES dateFromat is not NULL!! 640 dateFormat.setTimeZone(tzStringFormat); 641 String retStr=dateFormat.format( newTime.getTime() ); 642 643 return retStr; 644 645 646 } // convertJD2String 647 648 649 650 651 }