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 #ifdef __sun__
00048 #include <stddef.h>
00049 #endif
00050
00051 #include <ctype.h>
00052 #include <math.h>
00053 #include <string.h>
00054 #include <stdlib.h>
00055 #include <stdio.h>
00056 #include <strings.h>
00057 #include "timeio.h"
00058 #include "util.h"
00059
00060 static struct date_time {
00061 double second;
00062 double julday;
00063 double delta;
00064 int year;
00065 int month;
00066 int dofm;
00067 int dofy;
00068 int hour;
00069 int minute;
00070 int civil;
00071 int ut_flag;
00072 char zone[8];
00073 int isISO;
00074 } dattim;
00075
00076 const int kTIMEIO_MaxTimeEpochStr = 64;
00077
00078 static int molen[] = {31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
00079
00080 static double ut_leap_time[] = {
00081
00082
00083
00084
00085
00086
00087
00088 -536543999.0,
00089 -457747198.0,
00090 -394588797.0,
00091 -363052796.0,
00092 -331516795.0,
00093 -284083194.0,
00094 -252460793.0,
00095 -220924792.0,
00096 -189388791.0,
00097 -157852790.0,
00098 -142127989.0,
00099 -126230388.0,
00100 -94694387.0,
00101 -63158386.0,
00102 -31622385.0,
00103 16.0,
00104 31536017.0,
00105 63072018.0,
00106 94608019.0,
00107 141868820.0,
00108 173404821.0,
00109 204940822.0,
00110 268099223.0,
00111 347068824.0,
00112 410227225.0,
00113 441763226.0,
00114 489024027.0,
00115 520560028.0,
00116 552096029.0,
00117 599529630.0,
00118 646790431.0,
00119 694224032.0,
00120 915148833.0,
00121 1009843234.0,
00122 1120176035.0,
00123 1214784036.0,
00124 1262304037.0
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141 };
00142
00143 static void date_from_epoch_time (TIME t);
00144 static TIME epoch_time_from_julianday ();
00145 static double zone_adjustment_inner (char *zone, int *valid);
00146
00147 static void _clear_date_time () {
00148
00149
00150
00151 dattim.julday = 0.0;
00152 strcpy (dattim.zone, "TDT");
00153 date_from_epoch_time (epoch_time_from_julianday ());
00154 dattim.hour = 11;
00155 dattim.minute = 59;
00156 dattim.second = 27.816;
00157 }
00158
00159 static int _parse_error () {
00160 _clear_date_time ();
00161 return -1;
00162 }
00163
00164 static void _fracday_2_clock (double fdofm) {
00165
00166
00167
00168 dattim.dofm = (int)fdofm;
00169 dattim.second = 86400.0 * (fdofm - dattim.dofm);
00170 dattim.hour = (int)(dattim.second / 3600.0);
00171 dattim.second -= 3600.0 * dattim.hour;
00172 dattim.minute = (int)(dattim.second / 60.0);
00173 dattim.second -= 60.0 * dattim.minute;
00174 dattim.ut_flag = 0;
00175 }
00176
00177 static int _parse_clock_int (char *str, int *hour, int *minute, double *second, int *ut_flag, int *consumed)
00178 {
00179
00180
00181
00182 char *ptr, *endptr;
00183 int retval;
00184
00185 if (!str || strlen(str)==0)
00186 return 0;
00187 ptr = str;
00188 *hour = (int)strtol(str, &endptr, 10);
00189 if (ptr == endptr)
00190 return 0;
00191 else
00192 {
00193 if (*endptr == 'h' || *endptr == 'H')
00194 endptr++;
00195 if (!*endptr || *endptr != ':')
00196 {
00197 *minute = 0.0;
00198 *second = 0.0;
00199 retval = 1;
00200 }
00201 else
00202 {
00203 ptr = endptr+1;
00204 *minute = (int)strtol(ptr, &endptr, 10);
00205 if (ptr == endptr)
00206 return 0;
00207 else
00208 {
00209 if (*endptr == 'm' || *endptr == 'M')
00210 endptr++;
00211 if (!*endptr || *endptr != ':')
00212 {
00213 *second = 0.0;
00214 retval = 2;
00215 }
00216 else
00217 {
00218 ptr = endptr+1;
00219 *second = strtod(ptr, &endptr);
00220 if (ptr == endptr)
00221 return 0;
00222 else
00223 {
00224 if (*endptr == 's' || *endptr == 'S')
00225 endptr++;
00226 retval = 3;
00227 }
00228 }
00229 }
00230 }
00231 }
00232 if (consumed)
00233 *consumed = endptr - str;
00234
00235 *ut_flag = (*second >= 60.0);
00236 return (retval);
00237 }
00238
00239 static int _parse_clock (char *str, int *consumed)
00240 {
00241 return _parse_clock_int (str, &dattim.hour, &dattim.minute, &dattim.second, &dattim.ut_flag, consumed);
00242 }
00243
00244
00245 static int clock_isvalid(char *str)
00246 {
00247 int status;
00248 int hr;
00249 int min;
00250 double sec;
00251 int consumed;
00252 int ut_flag;
00253 status = _parse_clock_int (str, &hr, &min, &sec, &ut_flag, &consumed);
00254 if (status)
00255 status = 1;
00256 return status;
00257 }
00258
00259 static int _parse_month_name (char *moname) {
00260 char *p, monthname[10];
00261 int month;
00262 p = monthname;
00263 while (*moname && isalpha(*moname) && p-monthname < 9)
00264 *p++ = *moname++;
00265 *p = '\0';
00266
00267 if (!strncasecmp (monthname, "JAN", 3) || !strcasecmp (monthname, "I"))
00268 month = 1;
00269 else if (!strncasecmp (monthname, "FEB", 3) || !strcasecmp (monthname, "II"))
00270 month = 2;
00271 else if (!strncasecmp (monthname, "MAR", 3) || !strcasecmp (monthname, "III"))
00272 month = 3;
00273 else if (!strncasecmp (monthname, "APR", 3) || !strcasecmp (monthname, "IV"))
00274 month = 4;
00275 else if (!strncasecmp (monthname, "MAY", 3) || !strcasecmp (monthname, "V"))
00276 month = 5;
00277 else if (!strncasecmp (monthname, "JUN", 3) || !strcasecmp (monthname, "VI"))
00278 month = 6;
00279 else if (!strncasecmp (monthname, "JUL", 3) || !strcasecmp (monthname, "VII"))
00280 month = 7;
00281 else if (!strncasecmp (monthname, "AUG", 3) || !strcasecmp (monthname, "VIII"))
00282 month = 8;
00283 else if (!strncasecmp (monthname, "SEP", 3) || !strcasecmp (monthname, "IX"))
00284 month = 9;
00285 else if (!strncasecmp (monthname, "OCT", 3) || !strcasecmp (monthname, "X"))
00286 month = 10;
00287 else if (!strncasecmp (monthname, "NOV", 3) || !strcasecmp (monthname, "XI"))
00288 month = 11;
00289 else if (!strncasecmp (monthname, "DEC", 3) || !strcasecmp (monthname, "XII"))
00290 month = 12;
00291 else
00292
00293 month = 0;
00294 return (month);
00295 }
00296
00297 static int _parse_doy (int year, int doy)
00298 {
00299 int month;
00300 if (year%4 == 0)
00301 molen[2] = 29;
00302 if ((year%100 == 0) && (year > 1600) && (year%400 != 0))
00303 molen[2] = 28;
00304 for (month = 1; month <= 12 && doy > molen[month]; month += 1)
00305 doy -= molen[month];
00306 dattim.month = month;
00307 dattim.dofm = doy;
00308 return (month < 13);
00309 }
00310
00311 static int _parse_date (char *strin, int *consumed)
00312 {
00313
00314
00315
00316
00317
00318 double fracday;
00319 int status, dfrac;
00320 char *ptr, *endptr;
00321 int len;
00322 char daystr[32];
00323
00324 status = 3;
00325 dattim.isISO = 0;
00326 ptr = strin;
00327 dattim.year = strtol (ptr, &endptr, 10);
00328 len = endptr - ptr;
00329 if (len == 0)
00330 {
00331 return _parse_error ();
00332 }
00333
00334 if (len == 8)
00335 {
00336 if (*endptr == '.' || *endptr == '-')
00337 return _parse_error ();
00338 sscanf(ptr, "%4d%2d%2d", &dattim.year, &dattim.month, &dattim.dofm);
00339 dattim.isISO = 1;
00340 status = 8;
00341 }
00342 else if (len == 7)
00343 {
00344 int doy;
00345 sscanf(ptr, "%4d%3d", &dattim.year, &doy);
00346 if (_parse_doy (dattim.year, doy) ==0)
00347 return _parse_error ();
00348 dattim.isISO = 1;
00349 status = 8;
00350 }
00351 else if (len > 5)
00352 return _parse_error ();
00353 if (status != 8)
00354 {
00355 if (*endptr == '.' || *endptr == '-')
00356 {
00357 if (*endptr == '-')
00358 dattim.isISO = 1;
00359 ptr = endptr +1;
00360 dattim.month = strtol (ptr, &endptr, 10);
00361 len = endptr - ptr;
00362 if (len == 0)
00363 {
00364 dattim.month = _parse_month_name (ptr);
00365 if (dattim.month == 0)
00366 return _parse_error ();
00367
00368 while (*endptr && isalpha(*endptr))
00369 endptr++;
00370 }
00371 else if (len == 3)
00372 {
00373 int doy = dattim.month;
00374 if (_parse_doy (dattim.year, doy) ==0)
00375 return _parse_error ();
00376 status = 8;
00377 }
00378 else if (dattim.month > 12)
00379 return _parse_error ();
00380
00381 if (status != 8)
00382 {
00383 if (*endptr == '.' || (dattim.isISO && *endptr == '-'))
00384 {
00385
00386 ptr = endptr +1;
00387 dattim.dofm = strtol (ptr, &endptr, 10);
00388 len = endptr - ptr;
00389 if (len == 0)
00390 return _parse_error ();
00391 if (dattim.dofm > 366 && dattim.month > 1)
00392 return _parse_error ();
00393 }
00394 else
00395 {
00396 dattim.dofm = 1;
00397 }
00398 }
00399 }
00400 else
00401 {
00402 dattim.month = 1;
00403 dattim.dofm = 1;
00404 }
00405 }
00406
00407 if (*endptr == '.')
00408 {
00409 ptr = endptr +1;
00410 dfrac = (int)strtol(ptr, &endptr, 10);
00411 len = endptr - ptr;
00412 if (len > 0)
00413 {
00414 sprintf (daystr, "%d.%d", dattim.dofm, dfrac);
00415 sscanf (daystr, "%lf", &fracday);
00416 _fracday_2_clock (fracday);
00417 status = 6;
00418 }
00419 else
00420 return _parse_error ();
00421 }
00422 if (status == 8)
00423 status = 3;
00424 if (consumed)
00425 *consumed = endptr - strin;
00426 return status;
00427 }
00428
00429 static int _parse_date_time_inner (char *str,
00430 char **first,
00431 char **second,
00432 char **third,
00433 int *jdout,
00434 int *consumed) {
00435
00436
00437
00438
00439
00440
00441
00442 int status;
00443 int length;
00444 char *field0, *field1, *field2;
00445 char *tmpstr = NULL;
00446 int earlytz = 0;
00447 char *endptr = NULL;
00448 char realzone[64];
00449 int field1consumed = 0;
00450 int field0consumed = 0;
00451 char field0cpy[64] = {'\0'};
00452
00453 if (first) {
00454 *first = NULL;
00455 }
00456
00457 if (second) {
00458 *second = NULL;
00459 }
00460
00461 if (third) {
00462 *third = NULL;
00463 }
00464
00465 if (jdout) {
00466 *jdout = 0;
00467 }
00468
00469 if (consumed) {
00470 *consumed = 0;
00471 }
00472
00473 length = strlen (str);
00474 if (!length)
00475 return _parse_error ();
00476 field0 = str;
00477 dattim.isISO = 0;
00478
00479
00480 strncpy(field0cpy, field0, sizeof(field0cpy)-1);
00481 strtoupper(field0cpy);
00482 char *pc = field0cpy;
00483 while (*pc == ' ') pc++;
00484
00485 if (strncmp(pc , "MJD", 3) == 0 || strncmp(pc, "JD", 2) == 0)
00486 {
00487 if (*pc == 'M') pc++;
00488
00489 pc += 2;
00490 if (*pc++ != '_')
00491 return _parse_error();
00492 field0consumed = pc - field0cpy;
00493
00494
00495
00496
00497 field1 = field0 + field0consumed;
00498
00499 if (first && field1 && strlen(field1) > 0)
00500 *first = strdup(field1);
00501
00502 dattim.julday = strtod(field1, &endptr);
00503 if (endptr == field1)
00504 return _parse_error ();
00505
00506 if (consumed)
00507 *consumed = endptr - field0;
00508
00509 if (*endptr == '_')
00510 {
00511 field2 = endptr + 1;
00512 if (consumed)
00513 *consumed += 1;
00514 }
00515 else
00516 field2 = NULL;
00517
00518 if (field2)
00519 {
00520 if (parse_zone(field2, realzone, sizeof(realzone)))
00521 {
00522 return _parse_error ();
00523 }
00524
00525 snprintf(dattim.zone, sizeof(dattim.zone), "%s", realzone);
00526
00527 if (consumed)
00528 *consumed += strlen(realzone) ;
00529
00530 if (third && strlen(realzone) > 0)
00531 {
00532 *third = strdup(realzone);
00533 }
00534 }
00535 else
00536 strcpy (dattim.zone, "TDT");
00537
00538 if (field0cpy[0] == 'M')
00539
00540 dattim.julday += 2400000.5;
00541
00542 if (jdout)
00543 *jdout = 1;
00544 return 1;
00545 }
00546
00547
00548 dattim.julday = 0.0;
00549
00550 if (first && field0 && strlen(field0) > 0)
00551 *first = strdup(field0);
00552
00553 status = _parse_date (field0, &field0consumed);
00554
00555 if (status == -1)
00556 return status;
00557
00558 if (consumed)
00559 *consumed = field0consumed;
00560
00561
00562 field1 = field0 + field0consumed;
00563 if (*field1 == '_' || (dattim.isISO && (*field1 == 'T' || *field1 == ' ')))
00564 {
00565 field1 += 1;
00566 field2 = NULL;
00567 if (consumed)
00568 *consumed += 1;
00569 }
00570 else
00571 {
00572 field2 = field1 = NULL;
00573 field1consumed = 0;
00574 earlytz = status == 3;
00575 }
00576
00577 if (field1)
00578 {
00579 if (status == 3)
00580 {
00581
00582 status = _parse_clock (field1, &field1consumed);
00583 if (!status)
00584 {
00585
00586
00587
00588
00589 field1consumed = 0;
00590 field2 = field1;
00591 field1 = NULL;
00592 earlytz = 1;
00593 }
00594 else
00595 {
00596 char nextchar = *(field1 + field1consumed);
00597 if (second && field1 && strlen(field1) > 0)
00598 *second = strdup(field1);
00599 if (field1 && (nextchar == '+' || nextchar == '-'))
00600 {
00601
00602
00603 field2 = field1 + field1consumed;
00604 }
00605 else if (field1 && nextchar == '_')
00606 {
00607 if (consumed)
00608 *consumed += 1;
00609 field2 = field1 + field1consumed + 1;
00610 }
00611 else if (field1 && (nextchar <= 'I' && nextchar >= 'A' || nextchar <= 'Z' && nextchar >= 'K'))
00612 {
00613
00614 field2 = field1 + field1consumed;
00615 }
00616 else
00617 {
00618 field2 = NULL;
00619 }
00620 }
00621 }
00622 else
00623 {
00624
00625 if (!clock_isvalid(field1))
00626 {
00627
00628 field1consumed = 0;
00629 field2 = field1;
00630
00631 }
00632 }
00633 }
00634
00635 if (consumed)
00636 *consumed += field1consumed;
00637
00638
00639
00640 if (earlytz) {
00641
00642
00643
00644 dattim.hour = 0;
00645 dattim.minute = 0;
00646 dattim.second = 0.0;
00647 if (second)
00648 *second = NULL;
00649 }
00650
00651 if (field2)
00652 {
00653 if (third && field2 && strlen(field2) > 0)
00654 *third = strdup(field2);
00655
00656 if (parse_zone(field2, realzone, sizeof(realzone)))
00657 {
00658 return _parse_error ();
00659 }
00660 snprintf(dattim.zone, sizeof(dattim.zone), "%s", realzone);
00661 if (consumed)
00662 *consumed += strlen(realzone);
00663 }
00664 else
00665 strcpy (dattim.zone, "UTC");
00666
00667 if (tmpstr)
00668 free(tmpstr);
00669 return 0;
00670 }
00671
00672 static int _parse_date_time (char *str)
00673 {
00674 return _parse_date_time_inner (str, NULL, NULL, NULL, NULL, NULL);
00675 }
00676
00677 #define JD_EPOCH (2443144.5)
00678 #define EPOCH_2000_01_01 ( 725760000.0)
00679 #define EPOCH_1601_01_01 (-11865398400.0)
00680 #define EPOCH_1600_01_01 (-11897020800.0)
00681 #define EPOCH_1582_10_15 (-12440217600.0)
00682 #define EPOCH_1581_01_01 (-12495686400.0)
00683 #define SEC_DAY (86400.0)
00684 #define SEC_YEAR (31536000.0)
00685 #define SEC_BSYR (31622400.0)
00686 #define SEC_YEAR4 (126144000.0)
00687 #define SEC_4YRS (126230400.0)
00688 #define SEC_GCNT (3155673600.0)
00689 #define SEC_JCNT (3155760000.0)
00690 #define SEC_GR4C (12622780800.0)
00691 #define SEC_JL4C (12623040000.0)
00692
00693 static void date_from_epoch_time (TIME t) {
00694 double century, four_year, one_year;
00695 int year, month, day;
00696
00697 if (t < EPOCH_1582_10_15) {
00698
00699 year = 1585;
00700 t -= EPOCH_1581_01_01 + SEC_4YRS;
00701 while (t < -SEC_JL4C) {
00702 t += SEC_JL4C;
00703 year -= 400;
00704 }
00705 while (t < -SEC_JCNT) {
00706 t += SEC_JCNT;
00707 year -= 100;
00708 }
00709 while (t < -SEC_4YRS) {
00710 t += SEC_4YRS;
00711 year -= 4;
00712 }
00713 one_year = SEC_BSYR;
00714 while (t < 0.0) {
00715 t += one_year;
00716 year -= 1;
00717 one_year = SEC_YEAR;
00718 }
00719 } else {
00720 year = 1600;
00721 t -= EPOCH_1600_01_01;
00722 while (t < -SEC_4YRS) {
00723 t += SEC_4YRS;
00724 year -= 4;
00725 }
00726 one_year = SEC_YEAR;
00727 while (t < 0.0) {
00728 t += one_year;
00729 year -= 1;
00730 one_year = (year % 4 == 1) ? SEC_BSYR : SEC_YEAR;
00731 }
00732 }
00733
00734 century = SEC_JCNT;
00735 while (t >= century) {
00736 t -= century;
00737 year += 100;
00738 century = (year % 400) ? SEC_GCNT : SEC_JCNT;
00739 }
00740 four_year = (year % 100) ? SEC_4YRS : (year % 400) ? SEC_YEAR4 : SEC_4YRS;
00741 while (t >= four_year) {
00742 t -= four_year;
00743 year += 4;
00744 four_year = SEC_4YRS;
00745 }
00746 one_year = (year % 4) ? SEC_YEAR : (year % 100) ? SEC_BSYR : (year % 400) ?
00747 SEC_YEAR : SEC_BSYR;
00748 while (t >= one_year) {
00749 t -= one_year;
00750 year += 1;
00751 one_year = SEC_YEAR;
00752 }
00753
00754 dattim.year = year;
00755 if (year%4 == 0)
00756 molen[2] = 29;
00757 if ((year%100 == 0) && (year > 1600) && (year%400 != 0))
00758 molen[2] = 28;
00759 month = 1;
00760 day = (int)(t / SEC_DAY);
00761 while (day >= molen[month]) {
00762 day -= molen[month];
00763 t -= SEC_DAY * molen[month];
00764 month++;
00765 }
00766 molen[2] = 28;
00767 dattim.month = month;
00768 dattim.dofm = (int)(t / SEC_DAY);
00769 t -= SEC_DAY * dattim.dofm;
00770 dattim.dofm++;
00771 dattim.hour = (int)(t / 3600.0);
00772 t -= 3600.0 * dattim.hour;
00773 dattim.minute = (int)(t / 60.0);
00774 t -= 60.0 * dattim.minute;
00775 dattim.second = t;
00776 }
00777
00778 static TIME epoch_time_from_date () {
00779 TIME t;
00780 int mon, yr1601;
00781
00782 t = dattim.second + 60.0 * (dattim.minute + 60.0 * dattim.hour);
00783 t += SEC_DAY * (dattim.dofm - 1);
00784 while (dattim.month < 1) {
00785 dattim.year--;
00786 dattim.month += 12;
00787 }
00788 while (dattim.month > 12) {
00789 dattim.year++;
00790 dattim.month -= 12;
00791 }
00792 yr1601 = dattim.year - 1601;
00793 if (yr1601 < 0) {
00794 if (dattim.year%4 ==0)
00795 molen[2] = 29;
00796 while (yr1601 < 1) {
00797 t -= SEC_JL4C;
00798 yr1601 += 400;
00799 }
00800 while (yr1601 > 99) {
00801 t += SEC_JCNT;
00802 yr1601 -= 100;
00803 }
00804 }
00805 else {
00806 if (dattim.year%400 == 0 || (dattim.year%4 == 0 && dattim.year%100 != 0))
00807 molen[2] = 29;
00808 while (yr1601 > 399) {
00809 t += SEC_GR4C;
00810 yr1601 -= 400;
00811 }
00812 while (yr1601 > 99) {
00813 t += SEC_GCNT;
00814 yr1601 -= 100;
00815 }
00816 }
00817 for (mon=1; mon<dattim.month; mon++) {
00818 t += SEC_DAY * molen[mon];
00819 }
00820 molen[2] = 28;
00821 while (yr1601 > 3) {
00822 t += SEC_4YRS;
00823 yr1601 -= 4;
00824 }
00825 while (yr1601 > 0) {
00826 t += SEC_YEAR;
00827 yr1601 -= 1;
00828 }
00829 t += EPOCH_1601_01_01;
00830 if (t < EPOCH_1582_10_15)
00831
00832 t += 10 * SEC_DAY;
00833 return (t);
00834 }
00835
00836 static void julianday_from_epoch_time (TIME t) {
00837 dattim.julday = t / SEC_DAY + JD_EPOCH;
00838 }
00839
00840 static TIME epoch_time_from_julianday () {
00841 TIME t;
00842
00843 t = SEC_DAY * (dattim.julday - JD_EPOCH);
00844 return (t);
00845 }
00846
00847 static double utc_adjustment (TIME t, char *zone) {
00848 TIME tt = t;
00849 double dt;
00850 int leapsecs, ct;
00851
00852 dattim.civil = 0;
00853 if (!strcasecmp (zone, "TAI")) return 0.0;
00854 if (!strcasecmp (zone, "TDT") || !strcasecmp (zone, "TT")) return 32.184;
00855 if (!strcasecmp (zone, "GPS")) return -19.0;
00856
00857 dattim.civil = 1;
00858 leapsecs = sizeof (ut_leap_time) / sizeof (TIME);
00859 dt = 0.0;
00860 if (tt >= ut_leap_time[0]) {
00861 tt += 1.0;
00862 for (ct = 0; ct < leapsecs && tt >= ut_leap_time[ct]; ct++) {
00863 tt += 1.0;
00864 dt -= 1.0;
00865 }
00866 if (dattim.ut_flag) dt += 1.0;
00867 }
00868 return (dt + zone_adjustment (zone));
00869 }
00870
00871 TIME sscan_time (char *s) {
00872 TIME t, tt;
00873 double dt;
00874 int status;
00875 char ls[256];
00876
00877 strncpy (ls, s, 255);
00878 ls[255] = '\0';
00879 status = _parse_date_time (ls);
00880 if (status) t = epoch_time_from_julianday ();
00881 else t = epoch_time_from_date ();
00882 dt = utc_adjustment (t, dattim.zone);
00883 tt = t - dt;
00884 return (tt);
00885 }
00886
00887 int sscan_time_ext(char *s, TIME *out)
00888 {
00889 TIME t, tt;
00890 double dt;
00891 int status;
00892 char ls[256];
00893 int consumed = -1;
00894
00895 strncpy (ls, s, 255);
00896 ls[255] = '\0';
00897 status = _parse_date_time_inner (ls, NULL, NULL, NULL, NULL, &consumed);
00898 if (status) t = epoch_time_from_julianday ();
00899 else t = epoch_time_from_date ();
00900 dt = utc_adjustment (t, dattim.zone);
00901 tt = t - dt;
00902
00903 if (out)
00904 {
00905 *out = tt;
00906 }
00907
00908 return consumed;
00909 }
00910
00911 static void _raise_case (char *s) {
00912
00913
00914
00915 while (*s) {
00916 if (*s >= 'a' && *s <= 'z')
00917 *s += 'A' - 'a';
00918 s++;
00919 }
00920 }
00921
00922 void sprint_time (char *out, TIME t, char *zone, int precision) {
00923 int nozone = 0, concat_zone = 0;
00924 char format[64], pzone[6];
00925
00926 if (!out) return;
00927 if (!zone) {
00928 nozone = 1;
00929 zone = "Z";
00930 }
00931 if (strlen (zone) < 1) {
00932 nozone = 1;
00933 zone = "Z";
00934 } else {
00935 if (strlen (zone) == 1) concat_zone = 1;
00936 else if (zone[0] == '+' || zone[0] == '-') concat_zone = 1;
00937 strncpy (pzone, zone, 5);
00938 _raise_case (pzone);
00939 }
00940 if (isnan (t) || isinf (t)) t = JULIAN_DAY_ZERO;
00941 if (fabs (t) > 6.776e+16) zone = "JD";
00942
00943 if (!strcasecmp (zone, "JD") || !strcasecmp (zone, "MJD")) {
00944 t += tai_adjustment (t, "TDT");
00945 julianday_from_epoch_time (t);
00946 if (strcasecmp (zone, "JD")) {
00947 dattim.julday -= 2400000.5;
00948 zone = "MJD";
00949 } else zone = "JD";
00950 if (precision >= 0) sprintf (format, "%%s_%%.%df", precision);
00951 else sprintf (format, "%%s_%%.0f");
00952 sprintf (out, format, zone, dattim.julday);
00953 return;
00954 }
00955 if (!strcasecmp (zone, "ISO")) {
00956 t += tai_adjustment (t, "UTC");
00957 date_from_epoch_time (t);
00958 if (dattim.year < 1583 || dattim.year > 9999) {
00959 sprintf (pzone, "Z");
00960 concat_zone = 1;
00961 } else {
00962 if (dattim.ut_flag) dattim.second += 1.0;
00963 if (precision > 0) {
00964 sprintf (format, "%s%02d.%dfZ", "%04d-%02d-%02dT%02d:%02d:%",
00965 precision+3, precision);
00966 sprintf (out, format, dattim.year, dattim.month, dattim.dofm,
00967 dattim.hour, dattim.minute, dattim.second);
00968 } else if (precision == 0) {
00969 sprintf (out, "%04d-%02d-%02dT%02d:%02d:%02.0fZ",
00970 dattim.year, dattim.month, dattim.dofm,
00971 dattim.hour, dattim.minute, dattim.second);
00972 } else switch (precision) {
00973 case (-1) :
00974 sprintf (out, "%04d-%02d-%02dT%02d:%02dZ",
00975 dattim.year, dattim.month, dattim.dofm, dattim.hour,
00976 dattim.minute);
00977 break;
00978 case (-2) :
00979 sprintf (out, "%04d-%02d-%02dT%02dZ",
00980 dattim.year, dattim.month, dattim.dofm, dattim.hour);
00981 break;
00982 case (-3) :
00983 sprintf (out, "%04d-%02d-%02d",
00984 dattim.year, dattim.month, dattim.dofm);
00985 break;
00986 case (-4) :
00987 sprintf (out, "%04d-%02d", dattim.year, dattim.month);
00988 break;
00989 default :
00990 sprintf (out, "%04d", dattim.year);
00991 }
00992 return;
00993 }
00994 }
00995
00996 t += tai_adjustment (t, zone);
00997 date_from_epoch_time (t);
00998 if (dattim.ut_flag) dattim.second += 1.0;
00999 if (precision > 0) {
01000 if (nozone) {
01001 sprintf (format, "%s%02d.%df", "%04d.%02d.%02d_%02d:%02d:%",
01002 precision+3, precision);
01003 sprintf (out, format, dattim.year, dattim.month, dattim.dofm,
01004 dattim.hour, dattim.minute, dattim.second);
01005 } else if (concat_zone) {
01006 sprintf (format, "%s%02d.%df%%s",
01007 "%04d.%02d.%02d_%02d:%02d:%", precision+3, precision);
01008 sprintf (out, format, dattim.year, dattim.month, dattim.dofm,
01009 dattim.hour, dattim.minute, dattim.second, pzone);
01010 } else {
01011 sprintf (format, "%s%02d.%df_%%s", "%04d.%02d.%02d_%02d:%02d:%",
01012 precision+3, precision);
01013 sprintf (out, format, dattim.year, dattim.month, dattim.dofm,
01014 dattim.hour, dattim.minute, dattim.second, pzone);
01015 }
01016 } else if (precision == 0)
01017 if (nozone) sprintf (out, "%04d.%02d.%02d_%02d:%02d:%02.0f",
01018 dattim.year, dattim.month, dattim.dofm,
01019 dattim.hour, dattim.minute, dattim.second);
01020 else if (concat_zone) sprintf (out, "%04d.%02d.%02d_%02d:%02d:%02.0f%s",
01021 dattim.year, dattim.month, dattim.dofm,
01022 dattim.hour, dattim.minute, dattim.second, pzone);
01023 else sprintf (out, "%04d.%02d.%02d_%02d:%02d:%02.0f_%s",
01024 dattim.year, dattim.month, dattim.dofm,
01025 dattim.hour, dattim.minute, dattim.second, pzone);
01026 else {
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055 switch (precision) {
01056 case (-1) :
01057 if (nozone) sprintf (out, "%04d.%02d.%02d_%02d:%02d",
01058 dattim.year, dattim.month, dattim.dofm, dattim.hour, dattim.minute);
01059 else if (concat_zone) sprintf (out, "%04d.%02d.%02d_%02d:%02d%s",
01060 dattim.year, dattim.month, dattim.dofm,
01061 dattim.hour, dattim.minute, pzone);
01062 else sprintf (out, "%04d.%02d.%02d_%02d:%02d_%s",
01063 dattim.year, dattim.month, dattim.dofm,
01064 dattim.hour, dattim.minute, pzone);
01065 break;
01066 case (-2) :
01067 if (nozone) sprintf (out, "%04d.%02d.%02d_%02d",
01068 dattim.year, dattim.month, dattim.dofm, dattim.hour);
01069 else if (concat_zone) sprintf (out, "%04d.%02d.%02d_%02d%s",
01070 dattim.year, dattim.month, dattim.dofm, dattim.hour, pzone);
01071 else sprintf (out, "%04d.%02d.%02d_%02d_%s",
01072 dattim.year, dattim.month, dattim.dofm, dattim.hour, pzone);
01073 break;
01074 case (-3) :
01075 if (concat_zone) sprintf (out, "%04d.%02d.%02d",
01076 dattim.year, dattim.month, dattim.dofm);
01077 else sprintf (out, "%04d.%02d.%02d_%s",
01078 dattim.year, dattim.month, dattim.dofm, pzone);
01079 break;
01080 case (-4) :
01081 if (concat_zone) sprintf (out, "%04d.%02d", dattim.year, dattim.month);
01082 else sprintf (out, "%04d.%02d_%s", dattim.year, dattim.month, pzone);
01083 break;
01084 default :
01085 if (concat_zone) sprintf (out, "%04d", dattim.year);
01086 else sprintf (out, "%04d_%s", dattim.year, pzone);
01087 }
01088 }
01089 }
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100 double tai_adjustment (TIME t, char *zone) {
01101 TIME dt;
01102 int leapsecs, ct;
01103
01104 dattim.ut_flag = 0;
01105 dattim.civil = 0;
01106 if (!strcasecmp (zone, "TAI")) return 0.0;
01107 if (!strcasecmp (zone, "TDT") || !strcasecmp (zone, "TT")) return 32.184;
01108 if (!strcasecmp (zone, "GPS")) return -19.0;
01109
01110 dattim.civil = 1;
01111 leapsecs = sizeof (ut_leap_time) / sizeof (TIME);
01112 dt = 0.0;
01113 for (ct=0; ct<leapsecs; ct++) {
01114 if (t < (ut_leap_time[ct] - 1.0)) break;
01115 dt -= 1.0;
01116 if (t < ut_leap_time[ct]) dattim.ut_flag = 1;
01117 }
01118 return (dt + zone_adjustment (zone));
01119 }
01120
01121 double zone_adjustment_inner (char *zone, int *valid) {
01122 TIME dt;
01123 int status, offset, hours, minutes;
01124
01125 if (valid)
01126 *valid = 1;
01127
01128 dt = 0.0;
01129 hours = minutes = 0;
01130 status = sscanf (zone, "%5d", &offset);
01131 if (status) {
01132 hours = offset / 100;
01133 minutes = offset % 100;
01134 dt += 60.0 * (minutes + 60.0 * hours);
01135 return dt;
01136 }
01137 if (strlen (zone) == 1) {
01138 hours = zone[0] - 'A' + 1;
01139 if (zone[0] > 'I')
01140 hours--;
01141 if (zone[0] > 'M') {
01142 hours = 'M' - zone[0];
01143 if (zone[0] == 'Z')
01144 {
01145 hours = 0;
01146 }
01147 }
01148 dt += 3600.0 * hours;
01149 return dt;
01150 }
01151
01152
01153 if (!strcmp (zone, "PST") || !strcmp (zone, "YDT"))
01154 hours = -8;
01155 else if (!strcmp (zone, "MST") || !strcmp (zone, "PDT"))
01156 hours = -7;
01157 else if (!strcmp (zone, "CST") || !strcmp (zone, "MDT"))
01158 hours = -6;
01159 else if (!strcmp (zone, "EST") || !strcmp (zone, "CDT"))
01160 hours = -5;
01161 else if (!strcmp (zone, "AST") || !strcmp (zone, "EDT"))
01162 hours = -4;
01163 else if (!strcmp (zone, "ADT"))
01164 hours = -3;
01165 else if (!strcmp (zone, "GMT") || !strcmp (zone, "WET"))
01166 hours = 0;
01167 else if (!strcmp (zone, "CET") || !strcmp (zone, "BST"))
01168 hours = 1;
01169 else if (!strcmp (zone, "EET"))
01170 hours = 2;
01171 else if (!strcmp (zone, "SST") || !strcmp (zone, "WST"))
01172 hours = 8;
01173 else if (!strcmp (zone, "JST"))
01174 hours = 9;
01175 else if (!strcmp (zone, "JDT"))
01176 hours = 10;
01177 else if (!strcmp (zone, "NZST"))
01178 hours = 12;
01179 else if (!strcmp (zone, "BST"))
01180 hours = -11;
01181 else if (!strcmp (zone, "HST") || !strcmp (zone, "BDT"))
01182 hours = -10;
01183 else if (!strcmp (zone, "YST") || !strcmp (zone, "HDT"))
01184 hours = -9;
01185 else if (!strcmp (zone, "NZDT"))
01186 hours = 13;
01187 else {
01188
01189
01190
01191
01192 if (strcasecmp(zone, "TDT") &&
01193 strcasecmp(zone, "TAI") &&
01194 strcasecmp(zone, "TT") &&
01195 strcasecmp(zone, "GPS") &&
01196 strcasecmp(zone, "UT") &&
01197 strcasecmp(zone, "UTC") &&
01198 strcasecmp(zone, "ISO") &&
01199 strcasecmp(zone, "JD") &&
01200 strcasecmp(zone, "MJD")) {
01201
01202 if (valid)
01203 *valid = 0;
01204 }
01205 }
01206
01207 dt += 3600.0 * hours;
01208 return dt;
01209 }
01210
01211
01212 double zone_adjustment (char *zone) {
01213 return zone_adjustment_inner(zone, NULL);
01214 }
01215
01216 int zone_isvalid (char *zone) {
01217 int valid = 0;
01218 zone_adjustment_inner(zone, &valid);
01219 return valid;
01220 }
01221
01222
01223 int parse_zone(const char *zonestr, char *out, int size)
01224 {
01225 int err = 0;
01226 char *zone = strdup(zonestr);
01227 strtoupper(zone);
01228
01229 if (zone[0] == '+' || zone[0] == '-')
01230 {
01231
01232 char *endptr = NULL;
01233 int tzlen = 0;
01234
01235 strtol(zone, &endptr, 10);
01236 tzlen = endptr - zone;
01237
01238 if (size < tzlen + 1)
01239 {
01240 fprintf(stderr, "parse_zone() buff size too small.\n");
01241 err = 1;
01242 }
01243 else
01244 {
01245 snprintf(out, tzlen + 1, "%s", zone);
01246 }
01247 }
01248 else
01249 {
01250 char *pc = zone;
01251 char *pout = out;
01252 int state;
01253
01254
01255
01256
01257
01258 state = 0;
01259
01260 while (state != 'Z' && state != 'X' && size >= 8)
01261 {
01262 if (state == 0)
01263 {
01264 char abb = zone[0];
01265 state = 'X';
01266
01267 if (abb == 'D' || abb == 'F' || abb == 'I' || abb == 'K' || abb == 'L' ||
01268 abb == 'O' || abb == 'Q' || abb == 'R' || abb == 'V' || abb == 'X' ||
01269 abb == 'Z')
01270 {
01271
01272
01273 state = 'Z';
01274 *pout++ = *pc++;
01275 }
01276 else if (*pc == 'A' || *pc == 'B' || *pc == 'C' || *pc == 'E' || *pc == 'G' ||
01277 *pc == 'H' || *pc == 'J' || *pc == 'M' || *pc == 'N' || *pc == 'P' ||
01278 *pc == 'S' || *pc == 'T' || *pc == 'U' || *pc == 'Y' || *pc == 'W')
01279 {
01280 state = *pc;
01281 *pout++ = *pc++;
01282 }
01283 }
01284 else if (state == 'T')
01285 {
01286 state = 'Z';
01287
01288 if (*pc)
01289 {
01290 if (*pc == 'A' && *(pc+1) == 'I')
01291 {
01292
01293 *pout++ = *pc++;
01294 *pout++ = *pc++;
01295 }
01296 else if (*pc == 'D' && *(pc+1) == 'T')
01297 {
01298
01299 *pout++ = *pc++;
01300 *pout++ = *pc++;
01301 }
01302 else if (*pc == 'T')
01303 {
01304
01305 *pout++ = *pc++;
01306 }
01307 }
01308 }
01309 else if (state == 'U')
01310 {
01311 state = 'Z';
01312
01313 if (*pc && *pc == 'T')
01314 {
01315 *pout++ = *pc++;
01316
01317 if (*pc && *pc == 'C')
01318 {
01319
01320 *pout++ = *pc++;
01321 }
01322 else
01323 {
01324
01325 }
01326 }
01327 }
01328 else if (state == 'A')
01329 {
01330 state = 'Z';
01331
01332 if (*pc && (*pc == 'S' || *pc == 'D') && *(pc+1) == 'T')
01333 {
01334
01335 *pout++ = *pc++;
01336 *pout++ = *pc++;
01337 }
01338 }
01339 else if (state == 'B')
01340 {
01341 state = 'Z';
01342
01343 if (*pc && (*pc == 'S' || *pc == 'D') && *(pc+1) == 'T')
01344 {
01345
01346 *pout++ = *pc++;
01347 *pout++ = *pc++;
01348 }
01349 }
01350 else if (state == 'C')
01351 {
01352 state = 'Z';
01353
01354 if (*pc && (*pc == 'D' || *pc == 'E' || *pc == 'S') && *(pc+1) == 'T')
01355 {
01356
01357 *pout++ = *pc++;
01358 *pout++ = *pc++;
01359 }
01360 }
01361 else if (state == 'E')
01362 {
01363 state = 'Z';
01364
01365 if (*pc && (*pc == 'D' || *pc == 'E' || *pc == 'S') && *(pc+1) == 'T')
01366 {
01367
01368 *pout++ = *pc++;
01369 *pout++ = *pc++;
01370 }
01371 }
01372 else if (state == 'G')
01373 {
01374 state = 'Z';
01375
01376 if (*pc && (*pc == 'M' && *(pc+1) == 'T' || *pc == 'P' && *(pc+1) == 'S'))
01377 {
01378
01379 *pout++ = *pc++;
01380 *pout++ = *pc++;
01381 }
01382 }
01383 else if (state == 'H')
01384 {
01385 state = 'Z';
01386
01387 if (*pc && (*pc == 'D' || *pc == 'S') && *(pc+1) == 'T')
01388 {
01389
01390 *pout++ = *pc++;
01391 *pout++ = *pc++;
01392 }
01393 }
01394 else if (state == 'J')
01395 {
01396 state = 'X';
01397
01398 if (*pc && (*pc == 'D' || *pc == 'S') && *(pc+1) == 'T')
01399 {
01400
01401 state = 'Z';
01402 *pout++ = *pc++;
01403 *pout++ = *pc++;
01404 }
01405 }
01406 else if (state == 'M')
01407 {
01408 state = 'Z';
01409
01410 if (*pc && (*pc == 'D' || *pc == 'S') && *(pc+1) == 'T')
01411 {
01412
01413 *pout++ = *pc++;
01414 *pout++ = *pc++;
01415 }
01416 }
01417 else if (state == 'N')
01418 {
01419 state = 'Z';
01420
01421 if (*pc && *pc == 'Z' && (*(pc+1) == 'D' || *(pc+1) == 'S') && *(pc+1) == 'T')
01422 {
01423
01424 *pout++ = *pc++;
01425 *pout++ = *pc++;
01426 *pout++ = *pc++;
01427 }
01428 }
01429 else if (state == 'P')
01430 {
01431 state = 'Z';
01432
01433 if (*pc && (*pc == 'D' || *pc == 'S') && *(pc+1) == 'T')
01434 {
01435
01436 *pout++ = *pc++;
01437 *pout++ = *pc++;
01438 }
01439 }
01440 else if (state == 'S')
01441 {
01442 state = 'Z';
01443
01444 if (*pc && *pc == 'S' && *(pc+1) == 'T')
01445 {
01446
01447 *pout++ = *pc++;
01448 *pout++ = *pc++;
01449 }
01450 }
01451 else if (state == 'Y')
01452 {
01453 state = 'Z';
01454
01455 if (*pc && (*pc == 'D' || *pc == 'S') && *(pc+1) == 'T')
01456 {
01457
01458 *pout++ = *pc++;
01459 *pout++ = *pc++;
01460 }
01461 }
01462 else if (state == 'W')
01463 {
01464 state = 'Z';
01465
01466 if (*pc && (*pc == 'E' || *pc == 'S') && *(pc+1) == 'T')
01467 {
01468
01469 *pout++ = *pc++;
01470 *pout++ = *pc++;
01471 }
01472 }
01473 }
01474
01475 if (size < 8)
01476 {
01477 fprintf(stderr, "parse_zone() buff size too small.\n");
01478 err = 1;
01479 }
01480 else if (state == 'Z')
01481 {
01482 *pout = '\0';
01483 }
01484 else if (state == 'X')
01485 {
01486 err = 1;
01487 }
01488 }
01489
01490 if (zone)
01491 {
01492 free(zone);
01493 }
01494
01495 return err;
01496 }
01497
01498 int time_is_invalid (TIME t) {
01499 return (isnan (t) || (t < JULIAN_DAY_ZERO + 10.0e-5 && t > JULIAN_DAY_ZERO - 10.0e-5));
01500 }
01501
01502
01503
01504
01505
01506
01507
01508
01509 int parsetimestr (const char *timestr,
01510 int **year,
01511 int **month,
01512 int **dofm,
01513 int **dofy,
01514 int **hour,
01515 int **minute,
01516 double **second,
01517 char **zone,
01518 double **juliday,
01519 int *consumedout) {
01520 int ret = 0;
01521 int status;
01522 char ls[256];
01523
01524
01525
01526
01527
01528 char *f1 = NULL;
01529 char *f2 = NULL;
01530 char *f3 = NULL;
01531 int isjd = 0;
01532 int consumed = 0;
01533
01534 strncpy (ls, timestr, 255);
01535 ls[255] = '\0';
01536 status = _parse_date_time_inner (ls, &f1, &f2, &f3, &isjd, &consumed);
01537 if (status != -1) {
01538 if (consumedout)
01539 {
01540 *consumedout = consumed;
01541 }
01542
01543 if (!isjd)
01544 {
01545
01546 if (year)
01547 {
01548 *year = malloc(sizeof(int));
01549 **year = dattim.year;
01550 }
01551
01552 if (month)
01553 {
01554 *month = malloc(sizeof(int));
01555 **month = dattim.month;
01556 }
01557
01558 if (dofm)
01559 {
01560 *dofm = malloc(sizeof(int));
01561 **dofm = dattim.dofm;
01562 }
01563
01564 if (juliday)
01565 {
01566 *juliday = NULL;
01567 }
01568 }
01569 else
01570 {
01571 if (year)
01572 {
01573 *year = NULL;
01574 }
01575
01576 if (month)
01577 {
01578 *month = NULL;
01579 }
01580
01581 if (dofm)
01582 {
01583 *dofm = NULL;
01584 }
01585
01586 if (juliday)
01587 {
01588 *juliday = malloc(sizeof(double));
01589 **juliday = dattim.julday;
01590 }
01591 }
01592
01593 if (f2)
01594 {
01595 if (hour)
01596 {
01597 *hour = malloc(sizeof(int));
01598 **hour = dattim.hour;
01599 }
01600 if (minute)
01601 {
01602 *minute = malloc(sizeof(int));
01603 **minute = dattim.minute;
01604 }
01605 if (second)
01606 {
01607 *second = malloc(sizeof(double));
01608 **second = dattim.second;
01609 }
01610 }
01611 else
01612 {
01613 if (hour) *hour = NULL;
01614 if (minute) *minute = NULL;
01615 if (second) *second = NULL;
01616 }
01617
01618
01619
01620
01621
01622 if (zone)
01623 {
01624 if (f3)
01625 {
01626 *zone = strdup(f3);
01627 }
01628 else
01629 {
01630 *zone = NULL;
01631 }
01632 }
01633
01634 if (dofy)
01635 {
01636
01637 *dofy = NULL;
01638 }
01639
01640 ret = 1;
01641 }
01642
01643 if (f1)
01644 {
01645 free(f1);
01646 }
01647
01648 if (f2)
01649 {
01650 free(f2);
01651 }
01652
01653 if (f3)
01654 {
01655 free(f3);
01656 }
01657
01658 return ret;
01659 }
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693