00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 #ifdef __sun__
00052 #include <stddef.h>
00053 #endif
00054
00055 #include <string.h>
00056 #include <stdlib.h>
00057 #include <stdio.h>
00058 #include <strings.h>
00059 #include <soi_error.h>
00060 #include <timeio.h>
00061
00062 static struct date_time {
00063 double second;
00064 double julday;
00065 double delta;
00066 int year;
00067 int month;
00068 int dofm;
00069 int dofy;
00070 int hour;
00071 int minute;
00072 int civil;
00073 int ut_flag;
00074 char zone[8];
00075 } dattim;
00076
00077 static int molen[] = {31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
00078
00079 static double ut_leap_time[] = {
00080
00081
00082
00083
00084
00085
00086
00087 -536543999.0,
00088 -457747198.0,
00089 -394588797.0,
00090 -363052796.0,
00091 -331516795.0,
00092 -284083194.0,
00093 -252460793.0,
00094 -220924792.0,
00095 -189388791.0,
00096 -157852790.0,
00097 -142127989.0,
00098 -126230388.0,
00099 -94694387.0,
00100 -63158386.0,
00101 -31622385.0,
00102 16.0,
00103 31536017.0,
00104 63072018.0,
00105 94608019.0,
00106 141868820.0,
00107 173404821.0,
00108 204940822.0,
00109 268099223.0,
00110 347068824.0,
00111 410227225.0,
00112 441763226.0,
00113 489024027.0,
00114 520560028.0,
00115 552096029.0,
00116 599529630.0,
00117 646790431.0,
00118 694224032.0,
00119 915148833.0
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 };
00145
00146 static void date_from_epoch_time (TIME t);
00147 static TIME epoch_time_from_date ();
00148 static TIME epoch_time_from_julianday ();
00149 double utc_adjustment (TIME t, char *zone);
00150
00151 static void _clear_date_time () {
00152
00153
00154
00155 dattim.julday = 0.0;
00156 strcpy (dattim.zone, "TAI");
00157 date_from_epoch_time (epoch_time_from_julianday ());
00158 }
00159
00160 static int _parse_error () {
00161 _clear_date_time ();
00162 soi_errno = ILLEGAL_TIME_FORMAT;
00163 return -1;
00164 }
00165
00166 static void _fracday_2_clock (double fdofm) {
00167
00168
00169
00170 dattim.dofm = fdofm;
00171 dattim.second = 86400.0 * (fdofm - dattim.dofm);
00172 dattim.hour = dattim.second / 3600.0;
00173 dattim.second -= 3600.0 * dattim.hour;
00174 dattim.minute = dattim.second / 60.0;
00175 dattim.second -= 60.0 * dattim.minute;
00176 dattim.ut_flag = 0;
00177 }
00178
00179 static int _parse_clock (char *str) {
00180
00181
00182
00183 int status;
00184 char *field0, *field1, *field2;
00185
00186 field0 = strtok (str, ":");
00187 status = sscanf (field0, "%d", &dattim.hour);
00188 if (status != 1) return _parse_error ();
00189 field1 = strtok (NULL, ":");
00190 if (!field1) return _parse_error ();
00191 status = sscanf (field1, "%d", &dattim.minute);
00192 if (status != 1) return _parse_error ();
00193 field2 = strtok (NULL, ":");
00194 if (!field2) {
00195
00196 dattim.second = 0.0;
00197 return (2);
00198 }
00199 status = sscanf (field2, "%lf", &dattim.second);
00200 if (status != 1) return _parse_error ();
00201
00202 dattim.ut_flag = (dattim.second >= 60.0);
00203 return (3);
00204 }
00205
00206 static int _parse_month_name (char *moname) {
00207 int month;
00208
00209 if (!strncmp (moname, "JAN", 3) || !strcmp (moname, "I"))
00210 month = 1;
00211 else if (!strncmp (moname, "FEB", 3) || !strcmp (moname, "II"))
00212 month = 2;
00213 else if (!strncmp (moname, "MAR", 3) || !strcmp (moname, "III"))
00214 month = 3;
00215 else if (!strncmp (moname, "APR", 3) || !strcmp (moname, "IV"))
00216 month = 4;
00217 else if (!strncmp (moname, "MAY", 3) || !strcmp (moname, "V"))
00218 month = 5;
00219 else if (!strncmp (moname, "JUN", 3) || !strcmp (moname, "VI"))
00220 month = 6;
00221 else if (!strncmp (moname, "JUL", 3) || !strcmp (moname, "VII"))
00222 month = 7;
00223 else if (!strncmp (moname, "AUG", 3) || !strcmp (moname, "VIII"))
00224 month = 8;
00225 else if (!strncmp (moname, "SEP", 3) || !strcmp (moname, "IX"))
00226 month = 9;
00227 else if (!strncmp (moname, "OCT", 3) || !strcmp (moname, "X"))
00228 month = 10;
00229 else if (!strncmp (moname, "NOV", 3) || !strcmp (moname, "XI"))
00230 month = 11;
00231 else if (!strncmp (moname, "DEC", 3) || !strcmp (moname, "XII"))
00232 month = 12;
00233 else
00234
00235 month = 0;
00236 return (month);
00237 }
00238
00239 static int _parse_date (char *str) {
00240
00241
00242
00243 double fracday;
00244 int status, dfrac;
00245 char *field0, *field1, *field2, *field3;
00246 char daystr[32];
00247
00248 field0 = strtok (str, ".");
00249 field1 = strtok (NULL, ".");
00250 field2 = strtok (NULL, ".");
00251 field3 = strtok (NULL, ".");
00252 status = sscanf (field0, "%d", &dattim.year);
00253 if (status != 1) return _parse_error ();
00254 if (strlen (field0) == 2) {
00255
00256 if (dattim.year < 10) dattim.year += 100;
00257 dattim.year += 1900;
00258 }
00259 if (!field1) return _parse_error ();
00260 status = sscanf (field1, "%d", &dattim.month);
00261 if (status != 1) {
00262 dattim.month = _parse_month_name (field1);
00263 if (dattim.month == 0) return _parse_error ();
00264 }
00265 if (!field1) return _parse_error ();
00266 status = sscanf (field2, "%d", &dattim.dofm);
00267 if (status != 1) return _parse_error ();
00268 if (field3) {
00269 status = sscanf (field3, "%d", &dfrac);
00270 if (status) {
00271
00272 sprintf (daystr, "%d.%d", dattim.dofm, dfrac);
00273 sscanf (daystr, "%lf", &fracday);
00274 _fracday_2_clock (fracday);
00275 status = 6;
00276 }
00277 }
00278 else status = 3;
00279 return status;
00280 }
00281
00282 static void _raise_case (char *s) {
00283
00284
00285
00286 while (*s) {
00287 if (*s >= 'a' && *s <= 'z')
00288 *s += 'A' - 'a';
00289 s++;
00290 }
00291 }
00292
00293 static int _parse_date_time (char *str) {
00294
00295
00296
00297
00298
00299
00300
00301 double fdofm;
00302 int status;
00303 int length;
00304 char *field0, *field1, *field2;
00305
00306 _raise_case (str);
00307 length = strlen (str);
00308 if (!length) return _parse_error ();
00309 field0 = strtok (str, "_");
00310 if ((strlen (field0)) == length) {
00311
00312
00313 status = sscanf (str, "%d.%d.%lf", &dattim.year, &dattim.month, &fdofm);
00314 if (status != 3) return _parse_error ();
00315 _fracday_2_clock (fdofm);
00316 strcpy (dattim.zone, "UTC");
00317 return 0;
00318 }
00319
00320 field1 = strtok (NULL, "_");
00321 if (!(strcmp (field0, "MJD")) || !(strcmp (field0, "JD"))) {
00322 status = sscanf (field1, "%lf", &dattim.julday);
00323 if (status != 1) return _parse_error ();
00324 field2 = strtok (NULL, "_");
00325 if (field2)
00326 strcpy (dattim.zone, field2);
00327 else
00328
00329 strcpy (dattim.zone, "TDT");
00330 if (field0[0] == 'M')
00331
00332 dattim.julday += 2400000.5;
00333 return 1;
00334 }
00335
00336 dattim.julday = 0.0;
00337 field2 = strtok (NULL, "_");
00338 status = _parse_date (field0);
00339 if (status == 3) {
00340 status = _parse_clock (field1);
00341 if (!status) return _parse_error ();
00342 }
00343 else if (status == 6)
00344 field2 = field1;
00345 if (field2)
00346 strcpy (dattim.zone, field2);
00347 else
00348
00349 strcpy (dattim.zone, "UTC");
00350 return 0;
00351 }
00352
00353 #define JD_EPOCH (2443144.5)
00354 #define EPOCH_2000_01_01 ( 725760000.0)
00355 #define EPOCH_1601_01_01 (-11865398400.0)
00356 #define EPOCH_1600_01_01 (-11897020800.0)
00357 #define EPOCH_1582_10_15 (-12440217600.0)
00358 #define EPOCH_1581_01_01 (-12495686400.0)
00359 #define SEC_DAY (86400.0)
00360 #define SEC_YEAR (31536000.0)
00361 #define SEC_BSYR (31622400.0)
00362 #define SEC_YEAR4 (126144000.0)
00363 #define SEC_4YRS (126230400.0)
00364 #define SEC_GCNT (3155673600.0)
00365 #define SEC_JCNT (3155760000.0)
00366 #define SEC_GR4C (12622780800.0)
00367 #define SEC_JL4C (12623040000.0)
00368
00369 static void date_from_epoch_time (TIME t) {
00370 double century, four_year, one_year;
00371 int year, month, day;
00372
00373 if (t < EPOCH_1582_10_15) {
00374
00375 year = 1585;
00376 t -= EPOCH_1581_01_01 + SEC_4YRS;
00377 while (t < -SEC_JL4C) {
00378 t += SEC_JL4C;
00379 year -= 400;
00380 }
00381 while (t < -SEC_JCNT) {
00382 t += SEC_JCNT;
00383 year -= 100;
00384 }
00385 while (t < -SEC_4YRS) {
00386 t += SEC_4YRS;
00387 year -= 4;
00388 }
00389 one_year = SEC_BSYR;
00390 while (t < 0.0) {
00391 t += one_year;
00392 year -= 1;
00393 one_year = SEC_YEAR;
00394 }
00395 }
00396 else {
00397 year = 1600;
00398 t -= EPOCH_1600_01_01;
00399 while (t < -SEC_4YRS) {
00400 t += SEC_4YRS;
00401 year -= 4;
00402 }
00403 one_year = SEC_YEAR;
00404 while (t < 0.0) {
00405 t += one_year;
00406 year -= 1;
00407 one_year = (year % 4 == 1) ? SEC_BSYR : SEC_YEAR;
00408 }
00409 }
00410
00411 century = SEC_JCNT;
00412 while (t >= century) {
00413 t -= century;
00414 year += 100;
00415 century = (year % 400) ? SEC_GCNT : SEC_JCNT;
00416 }
00417 four_year = (year % 100) ? SEC_4YRS : (year % 400) ? SEC_YEAR4 : SEC_4YRS;
00418 while (t >= four_year) {
00419 t -= four_year;
00420 year += 4;
00421 four_year = SEC_4YRS;
00422 }
00423 one_year = (year % 4) ? SEC_YEAR : (year % 100) ? SEC_BSYR : (year % 400) ?
00424 SEC_YEAR : SEC_BSYR;
00425 while (t >= one_year) {
00426 t -= one_year;
00427 year += 1;
00428 one_year = SEC_YEAR;
00429 }
00430
00431 dattim.year = year;
00432 if (year%4 == 0)
00433 molen[2] = 29;
00434 if ((year%100 == 0) && (year > 1600) && (year%400 != 0))
00435 molen[2] = 28;
00436 month = 1;
00437 day = t / SEC_DAY;
00438 while (day >= molen[month]) {
00439 day -= molen[month];
00440 t -= SEC_DAY * molen[month];
00441 month++;
00442 }
00443 molen[2] = 28;
00444 dattim.month = month;
00445 dattim.dofm = t / SEC_DAY;
00446 t -= SEC_DAY * dattim.dofm;
00447 dattim.dofm++;
00448 dattim.hour = t / 3600.0;
00449 t -= 3600.0 * dattim.hour;
00450 dattim.minute = t / 60.0;
00451 t -= 60.0 * dattim.minute;
00452 dattim.second = t;
00453 }
00454
00455 static TIME epoch_time_from_date () {
00456 TIME t;
00457 int mon, yr1601;
00458
00459 t = dattim.second + 60.0 * (dattim.minute + 60.0 * (dattim.hour));
00460 t += SEC_DAY * (dattim.dofm - 1);
00461 while (dattim.month < 1) {
00462 dattim.year--;
00463 dattim.month += 12;
00464 }
00465 while (dattim.month > 12) {
00466 dattim.year++;
00467 dattim.month -= 12;
00468 }
00469 yr1601 = dattim.year - 1601;
00470 if (yr1601 < 0) {
00471 if (dattim.year%4 ==0)
00472 molen[2] = 29;
00473 while (yr1601 < 1) {
00474 t -= SEC_JL4C;
00475 yr1601 += 400;
00476 }
00477 while (yr1601 > 99) {
00478 t += SEC_JCNT;
00479 yr1601 -= 100;
00480 }
00481 }
00482 else {
00483 if (dattim.year%400 == 0 || (dattim.year%4 == 0 && dattim.year%100 != 0))
00484 molen[2] = 29;
00485 while (yr1601 > 399) {
00486 t += SEC_GR4C;
00487 yr1601 -= 400;
00488 }
00489 while (yr1601 > 99) {
00490 t += SEC_GCNT;
00491 yr1601 -= 100;
00492 }
00493 }
00494 for (mon=1; mon<dattim.month; mon++) {
00495 t += SEC_DAY * molen[mon];
00496 }
00497 molen[2] = 28;
00498 while (yr1601 > 3) {
00499 t += SEC_4YRS;
00500 yr1601 -= 4;
00501 }
00502 while (yr1601 > 0) {
00503 t += SEC_YEAR;
00504 yr1601 -= 1;
00505 }
00506 t += EPOCH_1601_01_01;
00507 if (t < EPOCH_1582_10_15)
00508
00509 t += 10 * SEC_DAY;
00510 return (t);
00511 }
00512
00513 static TIME epoch_time_from_julianday () {
00514 TIME t;
00515
00516 t = SEC_DAY * (dattim.julday - JD_EPOCH);
00517 return (t);
00518 }
00519
00520 TIME sscan_time (char *s) {
00521 TIME t;
00522 int status;
00523 char ls[256];
00524
00525 strcpy (ls, s);
00526 status = _parse_date_time (ls);
00527 if (status)
00528 t = epoch_time_from_julianday ();
00529 else
00530 t = epoch_time_from_date ();
00531 t -= tai_adjustment (t, dattim.zone);
00532 return (t);
00533 }
00534
00535 void sprint_time (char *out, TIME t, char *zone, int precision) {
00536 char format[64];
00537
00538 t += utc_adjustment (t, zone);
00539 date_from_epoch_time (t);
00540 if (dattim.ut_flag) {
00541 dattim.second += 1.0;
00542 }
00543 if (precision > 0) {
00544 sprintf (format, "%s%02d.%df_%%s", "%04d.%02d.%02d_%02d:%02d:%",
00545 precision+3, precision);
00546 sprintf (out, format, dattim.year, dattim.month, dattim.dofm,
00547 dattim.hour, dattim.minute, dattim.second, zone);
00548 } else if (precision == 0)
00549 sprintf (out, "%04d.%02d.%02d_%02d:%02d:%02.0f_%s",
00550 dattim.year, dattim.month, dattim.dofm,
00551 dattim.hour, dattim.minute, dattim.second, zone);
00552 else {
00553 while (dattim.second >= 30.0) {
00554 dattim.minute++;
00555 dattim.second -= 60.0;
00556 if (dattim.minute == 60) {
00557 dattim.minute = 0;
00558 dattim.hour++;
00559 if (dattim.hour == 24) {
00560 dattim.hour = 0;
00561 dattim.dofm++;
00562 if (dattim.dofm > molen[dattim.month]) {
00563 if (dattim.month == 2) {
00564 if ((dattim.year < 1601) && ((dattim.year % 4) == 0)) break;
00565 if (((dattim.year % 4) == 0) && (dattim.year % 100)) break;
00566 if ((dattim.year % 400) == 0) break;
00567 } else {
00568 dattim.dofm = 1;
00569 dattim.month++;
00570 if (dattim.month == 13) {
00571 dattim.month = 1;
00572 dattim.year++;
00573 }
00574 }
00575 }
00576 }
00577 }
00578 }
00579 sprintf (out, "%04d.%02d.%02d_%02d:%02d_%s",
00580 dattim.year, dattim.month, dattim.dofm,
00581 dattim.hour, dattim.minute, zone);
00582 }
00583 }
00584
00585 double tai_adjustment (TIME t, char *zone) {
00586 TIME dt;
00587 int leapsecs, ct;
00588
00589 _raise_case (zone);
00590 if (!strcmp (zone, "TAI")) {
00591 dattim.civil = 0;
00592 return 0.0;
00593 }
00594 if (!strcmp (zone, "TDT") || !strcmp (zone, "TT")) {
00595 dattim.civil = 0;
00596 return 32.184;
00597 }
00598 if (!strcmp (zone, "GPS")) {
00599 dattim.civil = 0;
00600 return -19.0;
00601 }
00602
00603 dattim.civil = 1;
00604 leapsecs = sizeof (ut_leap_time) / sizeof (TIME);
00605 dt = 0.0;
00606 if (t >= ut_leap_time[0]) {
00607 t += 1.0;
00608 for (ct=0; ct<leapsecs && t>=ut_leap_time[ct]; ct++) {
00609 t += 1.0;
00610 dt -= 1.0;
00611 }
00612 if (dattim.ut_flag) dt += 1.0;
00613 }
00614 return (dt + zone_adjustment (zone));
00615 }
00616
00617 double utc_adjustment (TIME t, char *zone) {
00618 TIME dt;
00619 int leapsecs, ct;
00620
00621 dattim.ut_flag = 0;
00622 _raise_case (zone);
00623 if (!strcmp (zone, "TAI")) {
00624 dattim.civil = 0;
00625 return 0.0;
00626 }
00627 if (!strcmp (zone, "TDT") || !strcmp (zone, "TT")) {
00628 dattim.civil = 0;
00629 return 32.184;
00630 }
00631 if (!strcmp (zone, "GPS")) {
00632 dattim.civil = 0;
00633 return -19.0;
00634 }
00635
00636 dattim.civil = 1;
00637 leapsecs = sizeof (ut_leap_time) / sizeof (TIME);
00638 dt = 0.0;
00639 for (ct=0; ct<leapsecs; ct++) {
00640 if (t < (ut_leap_time[ct] - 1.0))
00641 break;
00642 dt -= 1.0;
00643 if (t < ut_leap_time[ct])
00644 dattim.ut_flag = 1;
00645
00646
00647
00648
00649 }
00650 return (dt + zone_adjustment (zone));
00651 }
00652
00653 double zone_adjustment (char *zone) {
00654 TIME dt;
00655 int status, offset, hours, minutes;
00656
00657 dt = 0.0;
00658 hours = minutes = 0;
00659 status = sscanf (zone, "%5d", &offset);
00660 if (status) {
00661 hours = offset / 100;
00662 minutes = offset % 100;
00663 dt += 60.0 * (minutes + 60.0 * hours);
00664 return dt;
00665 }
00666 if (strlen (zone) == 1) {
00667 hours = zone[0] - 'A' + 1;
00668 if (zone[0] > 'I')
00669 hours--;
00670 if (zone[0] > 'M') {
00671 hours = 'M' - zone[0];
00672 if (zone[0] == 'Z')
00673 hours = 0;
00674 }
00675 dt += 3600.0 * hours;
00676 return dt;
00677 }
00678 if (!strcmp (zone, "PST") || !strcmp (zone, "YDT"))
00679 hours = -8;
00680 else if (!strcmp (zone, "MST") || !strcmp (zone, "PDT"))
00681 hours = -7;
00682 else if (!strcmp (zone, "CST") || !strcmp (zone, "MDT"))
00683 hours = -6;
00684 else if (!strcmp (zone, "EST") || !strcmp (zone, "CDT"))
00685 hours = -5;
00686 else if (!strcmp (zone, "AST") || !strcmp (zone, "EDT"))
00687 hours = -4;
00688 else if (!strcmp (zone, "ADT"))
00689 hours = -3;
00690 else if (!strcmp (zone, "GMT") || !strcmp (zone, "WET"))
00691 hours = 0;
00692 else if (!strcmp (zone, "CET") || !strcmp (zone, "BST"))
00693 hours = 1;
00694 else if (!strcmp (zone, "EET"))
00695 hours = 2;
00696 else if (!strcmp (zone, "SST") || !strcmp (zone, "WST"))
00697 hours = 8;
00698 else if (!strcmp (zone, "JST"))
00699 hours = 9;
00700 else if (!strcmp (zone, "JDT"))
00701 hours = 10;
00702 else if (!strcmp (zone, "NZST"))
00703 hours = 12;
00704 else if (!strcmp (zone, "BST"))
00705 hours = -11;
00706 else if (!strcmp (zone, "HST") || !strcmp (zone, "BDT"))
00707 hours = -10;
00708 else if (!strcmp (zone, "YST") || !strcmp (zone, "HDT"))
00709 hours = -9;
00710 else if (!strcmp (zone, "NZDT"))
00711 hours = 13;
00712 dt += 3600.0 * hours;
00713 return dt;
00714 }
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824