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