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 #include <ctype.h>
00042 #include <math.h>
00043 #include "qsastimeP.h"
00044 #include "tai-utc.h"
00045
00046
00047
00048 #define MJD_0000J -678943
00049
00050
00051
00052
00053 #define MJD_0000G -678941
00054
00055
00056 #define MJD_0001J -678577
00057 #define MJD_0001G -678575
00058
00059 #define MJD_1970 40587
00060
00061 static const double SecInDay = 86400;
00062 static const int MonthStartDOY[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
00063 static const int MonthStartDOY_L[] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
00064
00065
00066 static int geMJDtime_TAI( const MJDtime *number1, const TAI_UTC *number2 );
00067 static int geMJDtime_UTC( const MJDtime *number1, const TAI_UTC *number2 );
00068 static double leap_second_TAI( const MJDtime *MJD_TAI, int *inleap, int *index );
00069
00070
00071 int setFromUT( int year, int month, int day, int hour, int min, double sec, MJDtime *MJD, int forceJulian )
00072 {
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083 int leaps, year4, year100, year400;
00084 double dbase_day, non_leaps = 365.;
00085
00086 double time_sec, dextraDays;
00087 int extraDays;
00088
00089 if ( month < 0 || month > 11 )
00090 {
00091 fprintf( stderr, "setfromUT: invalid month value\n" );
00092 exit( EXIT_FAILURE );
00093 }
00094
00095
00096
00097
00098
00099
00100 if ( year <= 0 )
00101 {
00102 year4 = year - 4;
00103 year100 = year - 100;
00104 year400 = year - 400;
00105 }
00106 else
00107 {
00108 year4 = year - 1;
00109 year100 = year - 1;
00110 year400 = year - 1;
00111 }
00112
00113 if ( forceJulian )
00114 {
00115
00116 leaps = year4 / 4;
00117 if ( year % 4 == 0 )
00118 dbase_day = year * non_leaps + leaps + MonthStartDOY_L[month] + day + MJD_0000J;
00119 else
00120 dbase_day = year * non_leaps + leaps + MonthStartDOY[month] + day + MJD_0000J;
00121 }
00122 else
00123 {
00124
00125
00126
00127
00128
00129 leaps = year4 / 4 - year100 / 100 + year400 / 400;
00130
00131
00132
00133
00134
00135
00136
00137
00138 if ( ( year % 4 == 0 && year % 100 != 0 ) || ( year % 4 == 0 && year % 400 == 0 ) )
00139 dbase_day = year * non_leaps + leaps + MonthStartDOY_L[month] + day + MJD_0000G;
00140 else
00141 dbase_day = year * non_leaps + leaps + MonthStartDOY[month] + day + MJD_0000G;
00142 }
00143
00144 time_sec = sec + ( (double) min + (double) hour * 60. ) * 60.;
00145
00146 if ( time_sec >= SecInDay )
00147 {
00148 dextraDays = ( time_sec / SecInDay );
00149
00150 if ( fabs( dextraDays ) > 2.e9 )
00151 {
00152 return 3;
00153 }
00154 extraDays = (int) ( dextraDays );
00155 dbase_day += extraDays;
00156 time_sec -= extraDays * SecInDay;
00157 }
00158
00159 if ( fabs( dbase_day ) > 2.e9 )
00160 {
00161 return 4;
00162 }
00163 else
00164 {
00165
00166
00167
00168
00169 MJD->base_day = (int) dbase_day;
00170 MJD->time_sec = time_sec;
00171 return 0;
00172 }
00173 }
00174
00175 void getYAD( int *year, int *ifleapyear, int *doy, const MJDtime *MJD, int forceJulian )
00176 {
00177
00178
00179 int j, ifcorrect, year4, year100, year400;
00180
00181 j = MJD->base_day;
00182
00183 if ( forceJulian )
00184 {
00185
00186 j -= MJD_0000J;
00187
00188
00189
00190
00191
00192 if ( j >= 366 )
00193 {
00194 *year = (int) ( (double) ( j ) / 365.25 );
00195 year4 = *year - 1;
00196 }
00197 else
00198 {
00199 *year = (int) ( (double) ( j - 365 ) / 365.25 );
00200 year4 = *year - 4;
00201 }
00202
00203 *doy = j - *year * 365 - year4 / 4;
00204
00205 *ifleapyear = *year % 4 == 0;
00206 }
00207 else
00208 {
00209
00210 j -= MJD_0000G;
00211
00212
00213
00214
00215
00216 if ( j >= 366 )
00217 {
00218 *year = (int) ( (double) ( j ) / 365.2425 );
00219 year4 = *year - 1;
00220 year100 = *year - 1;
00221 year400 = *year - 1;
00222 }
00223 else
00224 {
00225 *year = (int) ( (double) ( j - 365 ) / 365.2425 );
00226 year4 = *year - 4;
00227 year100 = *year - 100;
00228 year400 = *year - 400;
00229 }
00230
00231 *doy = j - *year * 365 - year4 / 4 + year100 / 100 - year400 / 400;
00232 *ifleapyear = ( *year % 4 == 0 && *year % 100 != 0 ) || ( *year % 4 == 0 && *year % 400 == 0 );
00233
00234
00235 if ( *doy < 1 )
00236 {
00237 ( *year )--;
00238 ifcorrect = 1;
00239 }
00240 else if ( *doy > 365 && ( !*ifleapyear || *doy > 366 ) )
00241 {
00242 ( *year )++;
00243 ifcorrect = 1;
00244 }
00245 else
00246 {
00247 ifcorrect = 0;
00248 }
00249 if ( ifcorrect )
00250 {
00251 if ( j >= 366 )
00252 {
00253 year4 = *year - 1;
00254 year100 = *year - 1;
00255 year400 = *year - 1;
00256 }
00257 else
00258 {
00259 year4 = *year - 4;
00260 year100 = *year - 100;
00261 year400 = *year - 400;
00262 }
00263
00264 *doy = j - *year * 365 - year4 / 4 + year100 / 100 - year400 / 400;
00265 *ifleapyear = ( *year % 4 == 0 && *year % 100 != 0 ) || ( *year % 4 == 0 && *year % 400 == 0 );
00266 }
00267 }
00268 }
00269
00270 void normalize_MJD( MJDtime *MJD )
00271 {
00272 int extra_days;
00273
00274
00275 if ( MJD->time_sec >= 0 )
00276 {
00277 extra_days = (int) ( MJD->time_sec / SecInDay );
00278 }
00279 else
00280 {
00281
00282 extra_days = (int) ( MJD->time_sec / SecInDay ) - 1;
00283 }
00284
00285 MJD->base_day += extra_days;
00286 MJD->time_sec -= extra_days * SecInDay;
00287 }
00288
00289 void breakDownMJD( int *year, int *month, int *day, int *hour, int *min, double *sec, const MJDtime *MJD, int forceJulian )
00290 {
00291
00292
00293
00294 int doy, ifleapyear;
00295 MJDtime nMJD_value, *nMJD = &nMJD_value;
00296
00297 *nMJD = *MJD;
00298 normalize_MJD( nMJD );
00299
00300
00301 *sec = nMJD->time_sec;
00302 *hour = (int) ( *sec / 3600. );
00303 *sec -= (double) *hour * 3600.;
00304 *min = (int) ( *sec / 60. );
00305 *sec -= (double) *min * 60.;
00306
00307 getYAD( year, &ifleapyear, &doy, nMJD, forceJulian );
00308
00309
00310
00311 *month = -1;
00312 if ( ifleapyear )
00313 {
00314 while ( doy > MonthStartDOY_L[*month + 1] )
00315 {
00316 ( *month )++;
00317 if ( *month == 11 )
00318 break;
00319 }
00320 *day = doy - MonthStartDOY_L[*month];
00321 }
00322 else
00323 {
00324 while ( doy > MonthStartDOY[*month + 1] )
00325 {
00326 ( *month )++;
00327 if ( *month == 11 )
00328 break;
00329 }
00330 *day = doy - MonthStartDOY[*month];
00331 }
00332 }
00333
00334 const char * getDayOfWeek( const MJDtime *MJD )
00335 {
00336 static char *dow = { "Wed\0Thu\0Fri\0Sat\0Sun\0Mon\0Tue" };
00337 int d = MJD->base_day % 7;
00338 if ( d < 0 )
00339 d += 7;
00340 return &( dow[d * 4] );
00341 }
00342
00343 const char * getLongDayOfWeek( const MJDtime *MJD )
00344 {
00345 static char *dow = { "Wednesday\0Thursday\0\0Friday\0\0\0\0Saturday\0\0Sunday\0\0\0\0Monday\0\0\0\0Tuesday" };
00346 int d = MJD->base_day % 7;
00347 if ( d < 0 )
00348 d += 7;
00349 return &( dow[d * 10] );
00350 }
00351
00352 const char * getMonth( int m )
00353 {
00354 static char *months = { "Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec" };
00355 return &( months[( m ) * 4] );
00356 }
00357
00358 const char * getLongMonth( int m )
00359 {
00360 static char *months = { "January\0\0\0February\0\0March\0\0\0\0\0April\0\0\0\0\0May\0\0\0\0\0\0\0June\0\0\0\0\0\0July\0\0\0\0\0\0August\0\0\0\0September\0October\0\0\0November\0\0December" };
00361 return &( months[( m ) * 10] );
00362 }
00363
00364
00365 size_t strfMJD( char * buf, size_t len, const char *format, const MJDtime *MJD, int forceJulian, int inleap )
00366 {
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377 int year, month, day, hour, min, ysign, second, d, y;
00378 int y1, ifleapyear;
00379 int i, secsSince1970;
00380 int nplaces, fmtlen, slen;
00381 int resolution;
00382 double shiftPlaces;
00383 char * ptr;
00384 double sec, sec_fraction;
00385 int w, doy, days_in_wk1;
00386 const char *dayText;
00387 const char *monthText;
00388 char DateTime[80];
00389 size_t posn = 0;
00390 size_t last = len - 1;
00391 MJDtime nMJD_value, *nMJD = &nMJD_value;
00392 char dynamic_format[10];
00393
00394
00395 resolution = 0;
00396 fmtlen = strlen( format );
00397 i = 0;
00398 while ( i < fmtlen )
00399 {
00400 char next = format[i];
00401 if ( next == '%' )
00402 {
00403
00404 i++;
00405 next = format[i];
00406 if ( isdigit( next ) != 0 )
00407 {
00408 nplaces = strtol( &( format[i] ), NULL, 10 );
00409 if ( nplaces > resolution )
00410 resolution = nplaces;
00411 }
00412 else if ( next == '.' )
00413 {
00414 resolution = 9;
00415 }
00416 }
00417 i++;
00418 }
00419
00420
00421 shiftPlaces = pow( 10, (double) resolution );
00422 *nMJD = *MJD;
00423 nMJD->time_sec += 0.5 / shiftPlaces;
00424
00425 buf[last] = '\0';
00426 buf[0] = '\0';
00427
00428 if ( inleap )
00429 nMJD->time_sec -= 1.;
00430
00431 breakDownMJD( &year, &month, &day, &hour, &min, &sec, nMJD, forceJulian );
00432 if ( inleap )
00433 sec += 1.;
00434
00435 if ( year < 0 )
00436 {
00437 ysign = 1;
00438 year = -year;
00439 }
00440 else
00441 ysign = 0;
00442
00443
00444 sec = floor( sec * shiftPlaces ) / shiftPlaces;
00445 second = (int) sec;
00446
00447
00448 i = 0;
00449 while ( i < fmtlen )
00450 {
00451 char next = format[i];
00452 if ( next == '%' )
00453 {
00454
00455 i++;
00456 next = format[i];
00457 if ( next == '%' )
00458 {
00459
00460 buf[posn] = next;
00461 posn++;
00462 if ( posn >= last )
00463 return posn;
00464 }
00465 else if ( next == 'a' )
00466 {
00467
00468 dayText = getDayOfWeek( nMJD );
00469 strncat( &( buf[posn] ), dayText, last - posn );
00470 posn = strlen( buf );
00471 if ( posn >= last )
00472 return posn;
00473 }
00474 else if ( next == 'A' )
00475 {
00476
00477 dayText = getLongDayOfWeek( nMJD );
00478 strncat( &( buf[posn] ), dayText, last - posn );
00479 posn = strlen( buf );
00480 if ( posn >= last )
00481 return posn;
00482 }
00483 else if ( next == 'b' || next == 'h' )
00484 {
00485
00486 monthText = getMonth( month );
00487 strncat( &( buf[posn] ), monthText, last - posn );
00488 posn = strlen( buf );
00489 if ( posn >= last )
00490 return posn;
00491 }
00492 else if ( next == 'B' )
00493 {
00494
00495 monthText = getLongMonth( month );
00496 strncat( &( buf[posn] ), monthText, last - posn );
00497 posn = strlen( buf );
00498 if ( posn >= last )
00499 return posn;
00500 }
00501 else if ( next == 'c' )
00502 {
00503
00504 dayText = getDayOfWeek( nMJD );
00505 monthText = getMonth( month );
00506 if ( ysign == 0 )
00507 sprintf( DateTime, "%s %s %02d %02d:%02d:%02d %04d", dayText, monthText, day, hour, min, second, year );
00508 else
00509 sprintf( DateTime, "%s %s %02d %02d:%02d:%02d -%04d", dayText, monthText, day, hour, min, second, year );
00510
00511 strncat( &( buf[posn] ), DateTime, last - posn );
00512 posn = strlen( buf );
00513 if ( posn >= last )
00514 return posn;
00515 }
00516 else if ( next == 'C' )
00517 {
00518
00519 int century = year / 100;
00520 if ( ysign == 0 )
00521 sprintf( DateTime, "%02d", century );
00522 else
00523 sprintf( DateTime, "-%02d", century + 1 );
00524
00525 strncat( &( buf[posn] ), DateTime, last - posn );
00526 posn = strlen( buf );
00527 if ( posn >= last )
00528 return posn;
00529 }
00530 else if ( next == 'd' )
00531 {
00532
00533 sprintf( DateTime, "%02d", day );
00534
00535 strncat( &( buf[posn] ), DateTime, last - posn );
00536 posn = strlen( buf );
00537 if ( posn >= last )
00538 return posn;
00539 }
00540 else if ( next == 'D' )
00541 {
00542
00543 int y = year % 100;
00544 if ( ysign == 0 )
00545 sprintf( DateTime, "%02d/%02d/%02d", month + 1, day, y );
00546 else
00547 sprintf( DateTime, "%02d/%02d/-%02d", month + 1, day, y );
00548
00549 strncat( &( buf[posn] ), DateTime, last - posn );
00550 posn = strlen( buf );
00551 if ( posn >= last )
00552 return posn;
00553 }
00554 else if ( next == 'e' )
00555 {
00556
00557 if ( day < 10 )
00558 sprintf( DateTime, " %01d", day );
00559 else
00560 sprintf( DateTime, "%02d", day );
00561
00562 strncat( &( buf[posn] ), DateTime, last - posn );
00563 posn = strlen( buf );
00564 if ( posn >= last )
00565 return posn;
00566 }
00567 else if ( next == 'F' )
00568 {
00569
00570 if ( ysign == 0 )
00571 sprintf( DateTime, "%04d-%02d-%02d", year, month + 1, day );
00572 else
00573 sprintf( DateTime, "-%04d-%02d-%02d", year, month + 1, day );
00574
00575 strncat( &( buf[posn] ), DateTime, last - posn );
00576 posn = strlen( buf );
00577 if ( posn >= last )
00578 return posn;
00579 }
00580 else if ( next == 'H' )
00581 {
00582
00583 sprintf( DateTime, "%02d", hour );
00584
00585 strncat( &( buf[posn] ), DateTime, last - posn );
00586 posn = strlen( buf );
00587 if ( posn >= last )
00588 return posn;
00589 }
00590 else if ( next == 'I' )
00591 {
00592
00593 if ( hour == 0 )
00594 sprintf( DateTime, "%02d", hour + 12 );
00595 else if ( hour > 12 )
00596 sprintf( DateTime, "%02d", hour - 12 );
00597 else
00598 sprintf( DateTime, "%02d", hour );
00599
00600 strncat( &( buf[posn] ), DateTime, last - posn );
00601 posn = strlen( buf );
00602 if ( posn >= last )
00603 return posn;
00604 }
00605 else if ( next == 'j' )
00606 {
00607
00608 getYAD( &y1, &ifleapyear, &doy, nMJD, forceJulian );
00609 sprintf( DateTime, "%03d", doy );
00610
00611 strncat( &( buf[posn] ), DateTime, last - posn );
00612 posn = strlen( buf );
00613 if ( posn >= last )
00614 return posn;
00615 }
00616 else if ( next == 'k' )
00617 {
00618
00619 if ( hour < 10 )
00620 sprintf( DateTime, " %01d", hour );
00621 else
00622 sprintf( DateTime, "%02d", hour );
00623
00624 strncat( &( buf[posn] ), DateTime, last - posn );
00625 posn = strlen( buf );
00626 if ( posn >= last )
00627 return posn;
00628 }
00629 else if ( next == 'l' )
00630 {
00631
00632 if ( hour == 0 )
00633 sprintf( DateTime, "%02d", hour + 12 );
00634 else if ( hour < 10 )
00635 sprintf( DateTime, " %01d", hour );
00636 else if ( hour <= 12 )
00637 sprintf( DateTime, "%02d", hour );
00638 else if ( hour < 22 )
00639 sprintf( DateTime, " %01d", hour - 12 );
00640 else
00641 sprintf( DateTime, "%02d", hour - 12 );
00642
00643 strncat( &( buf[posn] ), DateTime, last - posn );
00644 posn = strlen( buf );
00645 if ( posn >= last )
00646 return posn;
00647 }
00648 else if ( next == 'm' )
00649 {
00650
00651 sprintf( DateTime, "%02d", month + 1 );
00652
00653 strncat( &( buf[posn] ), DateTime, last - posn );
00654 posn = strlen( buf );
00655 if ( posn >= last )
00656 return posn;
00657 }
00658 else if ( next == 'M' )
00659 {
00660
00661 sprintf( DateTime, "%02d", min );
00662
00663 strncat( &( buf[posn] ), DateTime, last - posn );
00664 posn = strlen( buf );
00665 if ( posn >= last )
00666 return posn;
00667 }
00668 else if ( next == 'n' )
00669 {
00670
00671 buf[posn] = '\n';
00672 posn++;
00673 if ( posn >= last )
00674 return posn;
00675 }
00676 else if ( next == 'p' )
00677 {
00678
00679 if ( hour < 0 )
00680 sprintf( DateTime, "AM" );
00681 else
00682 sprintf( DateTime, "PM" );
00683
00684 strncat( &( buf[posn] ), DateTime, last - posn );
00685 posn = strlen( buf );
00686 if ( posn >= last )
00687 return posn;
00688 }
00689 else if ( next == 'r' )
00690 {
00691
00692 if ( hour == 0 )
00693 sprintf( DateTime, "%02d:%02d:%02d AM", hour + 12, min, second );
00694 else if ( hour > 12 )
00695 sprintf( DateTime, "%02d:%02d:%02d PM", hour - 12, min, second );
00696 else if ( hour == 12 )
00697 sprintf( DateTime, "%02d:%02d:%02d PM", hour, min, second );
00698 else
00699 sprintf( DateTime, "%02d:%02d:%02d AM", hour, min, second );
00700
00701 strncat( &( buf[posn] ), DateTime, last - posn );
00702 posn = strlen( buf );
00703 if ( posn >= last )
00704 return posn;
00705 }
00706 else if ( next == 'R' )
00707 {
00708
00709 sprintf( DateTime, "%02d:%02d", hour, min );
00710
00711 strncat( &( buf[posn] ), DateTime, last - posn );
00712 posn = strlen( buf );
00713 if ( posn >= last )
00714 return posn;
00715 }
00716 else if ( next == 'S' )
00717 {
00718
00719 if ( i + 2 < fmtlen && format[i + 1] == '%' && ( format[i + 2] == '.' || isdigit( format[i + 2] ) != 0 ) )
00720 {
00721
00722 if ( format[i + 2] == '.' )
00723
00724 nplaces = 9;
00725 else
00726 nplaces = strtol( &( format[i + 2] ), NULL, 10 );
00727 i += 2;
00728 }
00729 else
00730 {
00731 nplaces = 0;
00732 }
00733
00734 if ( nplaces == 0 )
00735 {
00736 sprintf( DateTime, "%02d", (int) ( sec + 0.5 ) );
00737 }
00738 else
00739 {
00740 sprintf( dynamic_format, "%%0%d.%df", nplaces + 3, nplaces );
00741 sprintf( DateTime, dynamic_format, sec );
00742 if ( format[i] == '.' )
00743 {
00744 slen = strlen( DateTime ) - 1;
00745 while ( DateTime[slen] == '0' && DateTime[slen - 1] != '.' )
00746 {
00747 DateTime[slen] = '\0';
00748 slen--;
00749 }
00750 }
00751 }
00752
00753 strncat( &( buf[posn] ), DateTime, last - posn );
00754 posn = strlen( buf );
00755 if ( posn >= last )
00756 return posn;
00757 }
00758 else if ( next == 's' )
00759 {
00760
00761 secsSince1970 = (int) ( nMJD->time_sec + ( nMJD->base_day - MJD_1970 ) * SecInDay );
00762 sprintf( DateTime, "%d", secsSince1970 );
00763
00764 strncat( &( buf[posn] ), DateTime, last - posn );
00765 posn = strlen( buf );
00766 if ( posn >= last )
00767 return posn;
00768 }
00769 else if ( next == 't' )
00770 {
00771
00772 buf[posn] = '\t';
00773 posn++;
00774 if ( posn >= last )
00775 return posn;
00776 }
00777 else if ( next == 'T' )
00778 {
00779
00780 sprintf( DateTime, "%02d:%02d:%02d", hour, min, second );
00781
00782 strncat( &( buf[posn] ), DateTime, last - posn );
00783 posn = strlen( buf );
00784 if ( posn >= last )
00785 return posn;
00786 }
00787 else if ( next == 'U' )
00788 {
00789
00790 getYAD( &y1, &ifleapyear, &doy, nMJD, forceJulian );
00791 days_in_wk1 = ( nMJD->base_day - doy - 4 ) % 7;
00792
00793 w = ( doy + 6 - days_in_wk1 ) / 7;
00794
00795 sprintf( DateTime, "%02d", w );
00796
00797 strncat( &( buf[posn] ), DateTime, last - posn );
00798 posn = strlen( buf );
00799 if ( posn >= last )
00800 return posn;
00801 }
00802 else if ( next == 'u' )
00803 {
00804
00805 d = 1 + ( nMJD->base_day - 5 ) % 7;
00806
00807 sprintf( DateTime, "%01d", d );
00808
00809 strncat( &( buf[posn] ), DateTime, last - posn );
00810 posn = strlen( buf );
00811 if ( posn >= last )
00812 return posn;
00813 }
00814 else if ( next == 'v' )
00815 {
00816
00817
00818 monthText = getMonth( month );
00819
00820 if ( ysign == 0 )
00821 {
00822 if ( day < 10 )
00823 sprintf( DateTime, " %01d-%s-%04d", day, monthText, year );
00824 else
00825 sprintf( DateTime, "%02d-%s-%04d", day, monthText, year );
00826 }
00827 else
00828 {
00829 if ( day < 10 )
00830 sprintf( DateTime, " %01d-%s-(-)%04d", day, monthText, year );
00831 else
00832 sprintf( DateTime, "%02d-%s-(-)%04d", day, monthText, year );
00833 }
00834
00835 strncat( &( buf[posn] ), DateTime, last - posn );
00836 posn = strlen( buf );
00837 if ( posn >= last )
00838 return posn;
00839 }
00840 else if ( next == 'V' )
00841 {
00842 int days_in_wk1;
00843
00844 getYAD( &y1, &ifleapyear, &doy, nMJD, forceJulian );
00845 days_in_wk1 = ( nMJD->base_day - doy - 3 ) % 7;
00846
00847 if ( days_in_wk1 <= 3 )
00848 w = ( doy + 6 - days_in_wk1 ) / 7;
00849 else
00850 w = 1 + ( doy + 6 - days_in_wk1 ) / 7;
00851
00852 if ( w == 0 )
00853 w = 53;
00854 sprintf( DateTime, "%02d", w );
00855
00856 strncat( &( buf[posn] ), DateTime, last - posn );
00857 posn = strlen( buf );
00858 if ( posn >= last )
00859 return posn;
00860 }
00861 else if ( next == 'w' )
00862 {
00863
00864 d = ( nMJD->base_day - 4 ) % 7;
00865
00866 sprintf( DateTime, "%01d", d );
00867
00868 strncat( &( buf[posn] ), DateTime, last - posn );
00869 posn = strlen( buf );
00870 if ( posn >= last )
00871 return posn;
00872 }
00873 else if ( next == 'W' )
00874 {
00875
00876 getYAD( &y1, &ifleapyear, &doy, nMJD, forceJulian );
00877 days_in_wk1 = ( nMJD->base_day - doy - 3 ) % 7;
00878
00879 w = ( doy + 6 - days_in_wk1 ) / 7;
00880
00881 sprintf( DateTime, "%02d", w );
00882
00883 strncat( &( buf[posn] ), DateTime, last - posn );
00884 posn = strlen( buf );
00885 if ( posn >= last )
00886 return posn;
00887 }
00888 else if ( next == 'x' )
00889 {
00890
00891 dayText = getDayOfWeek( nMJD );
00892 monthText = getMonth( month );
00893 if ( ysign == 0 )
00894 sprintf( DateTime, "%s %s %02d, %04d", dayText, monthText, day, year );
00895 else
00896 sprintf( DateTime, "%s %s %02d, -%04d", dayText, monthText, day, year );
00897
00898 strncat( &( buf[posn] ), DateTime, last - posn );
00899 posn = strlen( buf );
00900 if ( posn >= last )
00901 return posn;
00902 }
00903 else if ( next == 'X' )
00904 {
00905
00906 sprintf( DateTime, "%02d:%02d:%02d", hour, min, second );
00907
00908 strncat( &( buf[posn] ), DateTime, last - posn );
00909 posn = strlen( buf );
00910 if ( posn >= last )
00911 return posn;
00912 }
00913 else if ( next == 'y' )
00914 {
00915
00916 y = year % 100;
00917
00918 if ( ysign == 0 )
00919 sprintf( DateTime, "%02d", y );
00920 else
00921 sprintf( DateTime, "-%02d", y );
00922
00923 strncat( &( buf[posn] ), DateTime, last - posn );
00924 posn = strlen( buf );
00925 if ( posn >= last )
00926 return posn;
00927 }
00928 else if ( next == 'Y' )
00929 {
00930
00931 if ( ysign == 0 )
00932 sprintf( DateTime, "%04d", year );
00933 else
00934 sprintf( DateTime, "-%04d", year );
00935
00936 strncat( &( buf[posn] ), DateTime, last - posn );
00937 posn = strlen( buf );
00938 if ( posn >= last )
00939 return posn;
00940 }
00941 else if ( next == 'Z' )
00942 {
00943
00944 if ( forceJulian )
00945 strncat( &( buf[posn] ), "UTC Julian", last - posn );
00946 else
00947 strncat( &( buf[posn] ), "UTC Gregorian", last - posn );
00948
00949 posn = strlen( buf );
00950 if ( posn >= last )
00951 return posn;
00952 }
00953 else if ( next == 'z' )
00954 {
00955
00956 strncat( &( buf[posn] ), "+0000", last - posn );
00957 posn = strlen( buf );
00958 if ( posn >= last )
00959 return posn;
00960 }
00961 else if ( next == '+' )
00962 {
00963
00964 dayText = getDayOfWeek( nMJD );
00965 monthText = getMonth( month );
00966 if ( ysign == 0 )
00967 sprintf( DateTime, "%s %s %02d %02d:%02d:%02d UTC %04d", dayText, monthText, day, hour, min, second, year );
00968 else
00969 sprintf( DateTime, "%s %s %02d %02d:%02d:%02d UTC -%04d", dayText, monthText, day, hour, min, second, year );
00970
00971 strncat( &( buf[posn] ), DateTime, last - posn );
00972 posn = strlen( buf );
00973 if ( posn >= last )
00974 return posn;
00975 }
00976 else if ( next == '.' || isdigit( next ) != 0 )
00977 {
00978
00979 if ( next == '.' )
00980
00981 nplaces = 9;
00982 else
00983 nplaces = strtol( &( format[i] ), NULL, 10 );
00984
00985
00986 sec_fraction = sec - (int) sec;
00987 sprintf( dynamic_format, "%%-%d.%df", nplaces + 2, nplaces );
00988
00989 sprintf( DateTime, dynamic_format, sec_fraction );
00990 while ( ( ptr = strrchr( &( DateTime[0] ), ' ' ) ) != NULL )
00991 ptr[0] = '\0';
00992
00993 if ( next == '.' )
00994 {
00995 slen = strlen( DateTime ) - 1;
00996 while ( DateTime[slen] == '0' && DateTime[slen - 1] != '.' )
00997 {
00998 DateTime[slen] = '\0';
00999 slen--;
01000 }
01001 }
01002
01003 ptr = strchr( DateTime, '.' );
01004
01005
01006 if ( ptr != NULL )
01007 strncat( &( buf[posn] ), ptr, last - posn );
01008 posn = strlen( buf );
01009 if ( posn >= last )
01010 return posn;
01011 }
01012 }
01013 else
01014 {
01015
01016 buf[posn] = next;
01017 posn++;
01018 if ( posn >= last )
01019 return posn;
01020 }
01021 buf[posn] = '\0';
01022 i++;
01023 }
01024 return posn;
01025 }
01026
01027 int geMJDtime_TAI( const MJDtime *number1, const TAI_UTC *number2 )
01028 {
01029
01030
01031 if ( number1->base_day > number2->base_day )
01032 {
01033 return 1;
01034 }
01035 else if ( number1->base_day < number2->base_day )
01036 {
01037 return 0;
01038 }
01039 else
01040 {
01041 return ( number1->time_sec >= number2->time_sec_tai );
01042 }
01043 }
01044
01045 int geMJDtime_UTC( const MJDtime *number1, const TAI_UTC *number2 )
01046 {
01047
01048
01049 if ( number1->base_day > number2->base_day )
01050 {
01051 return 1;
01052 }
01053 else if ( number1->base_day < number2->base_day )
01054 {
01055 return 0;
01056 }
01057 else
01058 {
01059 return ( number1->time_sec >= number2->time_sec_utc );
01060 }
01061 }
01062
01063 double leap_second_TAI( const MJDtime *MJD_TAI, int *inleap, int *index )
01064 {
01065
01066
01067
01068
01069 MJDtime MJD_value, *MJD = &MJD_value;
01070 double leap;
01071 int debug = 0;
01072
01073 *MJD = *MJD_TAI;
01074 normalize_MJD( MJD );
01075
01076 bhunt_search( MJD, TAI_UTC_lookup_table, number_of_entries_in_tai_utc_table, sizeof ( TAI_UTC ), index, ( int ( * )( const void *, const void * ) )geMJDtime_TAI );
01077 if ( debug == 2 )
01078 fprintf( stderr, "*index = %d\n", *index );
01079 if ( *index == -1 )
01080 {
01081
01082
01083 if ( debug && geMJDtime_TAI( MJD, &TAI_UTC_lookup_table[*index + 1] ) )
01084 {
01085 fprintf( stderr, "libqsastime (leap_second_TAI) logic ERROR: bad condition for *index = %d\n", *index );
01086 exit( EXIT_FAILURE );
01087 }
01088
01089
01090 *inleap = 0;
01091
01092
01093
01094
01095 return -TAI_UTC_lookup_table[*index + 1].offset1;
01096 }
01097 else if ( *index == number_of_entries_in_tai_utc_table - 1 )
01098 {
01099
01100
01101 if ( debug && !geMJDtime_TAI( MJD, &TAI_UTC_lookup_table[*index] ) )
01102 {
01103 fprintf( stderr, "libqsastime (leap_second_TAI) logic ERROR: bad condition for *index = %d\n", *index );
01104 exit( EXIT_FAILURE );
01105 }
01106
01107 *inleap = 0;
01108
01109
01110
01111 return -TAI_UTC_lookup_table[*index].offset1;
01112 }
01113 else if ( *index >= 0 && *index < number_of_entries_in_tai_utc_table )
01114 {
01115
01116
01117 if ( debug && !( geMJDtime_TAI( MJD, &TAI_UTC_lookup_table[*index] ) && !geMJDtime_TAI( MJD, &TAI_UTC_lookup_table[*index + 1] ) ) )
01118 {
01119 fprintf( stderr, "MJD = {%d, %f}\n", MJD->base_day, MJD->time_sec );
01120 fprintf( stderr, "libqsastime (leap_second_TAI) logic ERROR: bad condition for *index = %d\n", *index );
01121 exit( EXIT_FAILURE );
01122 }
01123 leap = -( TAI_UTC_lookup_table[*index].offset1 + ( ( MJD->base_day - TAI_UTC_lookup_table[*index].offset2 ) + MJD->time_sec / SecInDay ) * TAI_UTC_lookup_table[*index].slope ) / ( 1. + TAI_UTC_lookup_table[*index].slope / SecInDay );
01124
01125 MJD->time_sec += leap;
01126 normalize_MJD( MJD );
01127
01128
01129
01130
01131
01132
01133 *inleap = geMJDtime_UTC( MJD, &TAI_UTC_lookup_table[*index + 1] );
01134 return leap;
01135 }
01136 else
01137 {
01138 fprintf( stderr, "libqsastime (leap_second_TAI) logic ERROR: bad *index = %d\n", *index );
01139 exit( EXIT_FAILURE );
01140 }
01141 }
01142
01143 void configqsas( double scale, double offset1, double offset2, int ccontrol, int ifbtime_offset, int year, int month, int day, int hour, int min, double sec, QSASConfig **qsasconfig )
01144 {
01145
01146
01147 int forceJulian, ret;
01148 MJDtime MJD_value, *MJD = &MJD_value;
01149
01150
01151
01152 if ( *qsasconfig == NULL )
01153 {
01154 *qsasconfig = (QSASConfig *) malloc( (size_t) sizeof ( QSASConfig ) );
01155 if ( *qsasconfig == NULL )
01156 {
01157 fprintf( stderr, "configqsas: out of memory\n" );
01158 exit( EXIT_FAILURE );
01159 }
01160 }
01161
01162
01163
01164 ( *qsasconfig )->index = -40;
01165
01166 if ( scale != 0. )
01167 {
01168 if ( ifbtime_offset )
01169 {
01170 if ( ccontrol & 0x1 )
01171 forceJulian = 1;
01172 else
01173 forceJulian = 0;
01174 ret = setFromUT( year, month, day, hour, min, sec, MJD, forceJulian );
01175 if ( ret )
01176 {
01177 fprintf( stderr, "configqsas: some problem with broken-down arguments\n" );
01178 exit( EXIT_FAILURE );
01179 }
01180 offset1 = (double) MJD->base_day;
01181 offset2 = MJD->time_sec / (double) SecInDay;
01182 }
01183 ( *qsasconfig )->scale = scale;
01184 ( *qsasconfig )->offset1 = offset1;
01185 ( *qsasconfig )->offset2 = offset2;
01186 ( *qsasconfig )->ccontrol = ccontrol;
01187 }
01188 else
01189 {
01190
01191
01192
01193
01194 ( *qsasconfig )->scale = 1. / (double) SecInDay;
01195 ( *qsasconfig )->offset1 = (double) MJD_1970;
01196 ( *qsasconfig )->offset2 = 0.;
01197 ( *qsasconfig )->ccontrol = 0x0;
01198 }
01199 }
01200
01201 void closeqsas( QSASConfig **qsasconfig )
01202 {
01203
01204 if ( *qsasconfig != NULL )
01205 {
01206 free( (void *) *qsasconfig );
01207 *qsasconfig = NULL;
01208 }
01209 }
01210
01211 int ctimeqsas( int year, int month, int day, int hour, int min, double sec, double * ctime, QSASConfig *qsasconfig )
01212 {
01213 MJDtime MJD_value, *MJD = &MJD_value;
01214 int forceJulian, ret;
01215
01216 if ( qsasconfig == NULL )
01217 {
01218 fprintf( stderr, "libqsastime (ctimeqsas) ERROR: configqsas must be called first.\n" );
01219 exit( EXIT_FAILURE );
01220 }
01221
01222 if ( qsasconfig->ccontrol & 0x1 )
01223 forceJulian = 1;
01224 else
01225 forceJulian = 0;
01226
01227 ret = setFromUT( year, month, day, hour, min, sec, MJD, forceJulian );
01228 if ( ret )
01229 return ret;
01230 *ctime = ( ( (double) ( MJD->base_day ) - qsasconfig->offset1 ) - qsasconfig->offset2 + MJD->time_sec / (double) SecInDay ) / qsasconfig->scale;
01231 return 0;
01232 }
01233
01234 void btimeqsas( int *year, int *month, int *day, int *hour, int *min, double *sec, double ctime, QSASConfig *qsasconfig )
01235 {
01236 MJDtime MJD_value, *MJD = &MJD_value;
01237 int forceJulian;
01238 double integral_offset1, integral_offset2, integral_scaled_ctime;
01239 int inleap;
01240
01241 if ( qsasconfig == NULL )
01242 {
01243 fprintf( stderr, "libqsastime (btimeqsas) ERROR: configqsas must be called first.\n" );
01244 exit( EXIT_FAILURE );
01245 }
01246
01247 MJD->time_sec = SecInDay * ( modf( qsasconfig->offset1, &integral_offset1 ) + modf( qsasconfig->offset2, &integral_offset2 ) + modf( ctime * qsasconfig->scale, &integral_scaled_ctime ) );
01248 MJD->base_day = (int) ( integral_offset1 + integral_offset2 + integral_scaled_ctime );
01249
01250 if ( qsasconfig->ccontrol & 0x1 )
01251 forceJulian = 1;
01252 else
01253 forceJulian = 0;
01254
01255 if ( qsasconfig->ccontrol & 0x2 )
01256 MJD->time_sec += leap_second_TAI( MJD, &inleap, &( qsasconfig->index ) );
01257 else
01258 inleap = 0;
01259
01260
01261
01262
01263
01264 if ( inleap )
01265 MJD->time_sec -= 1.;
01266
01267 breakDownMJD( year, month, day, hour, min, sec, MJD, forceJulian );
01268 if ( inleap )
01269 *sec += 1.;
01270 }
01271
01272 size_t strfqsas( char * buf, size_t len, const char *format, double ctime, QSASConfig *qsasconfig )
01273 {
01274 MJDtime MJD_value, *MJD = &MJD_value;
01275 int forceJulian;
01276 double integral_offset1, integral_offset2, integral_scaled_ctime;
01277 int inleap;
01278
01279 if ( qsasconfig == NULL )
01280 {
01281 fprintf( stderr, "libqsastime (strfqsas) ERROR: configqsas must be called first.\n" );
01282 exit( EXIT_FAILURE );
01283 }
01284 MJD->time_sec = SecInDay * ( modf( qsasconfig->offset1, &integral_offset1 ) + modf( qsasconfig->offset2, &integral_offset2 ) + modf( ctime * qsasconfig->scale, &integral_scaled_ctime ) );
01285 MJD->base_day = (int) ( integral_offset1 + integral_offset2 + integral_scaled_ctime );
01286
01287 if ( qsasconfig->ccontrol & 0x1 )
01288 forceJulian = 1;
01289 else
01290 forceJulian = 0;
01291
01292 if ( qsasconfig->ccontrol & 0x2 )
01293 MJD->time_sec += leap_second_TAI( MJD, &inleap, &( qsasconfig->index ) );
01294 else
01295 inleap = 0;
01296
01297 return strfMJD( buf, len, format, MJD, forceJulian, inleap );
01298 }
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313 void bhunt_search( const void *key, const void *base, int n, size_t size, int *low, int ( *ge )( const void *keyval, const void *datum ) )
01314 {
01315 const void *indexbase;
01316 int mid, high, hunt_inc = 1;
01317
01318
01319 if ( *low == -1 )
01320 *low = 0;
01321
01322
01323 if ( *low < 0 || *low >= n )
01324 {
01325 *low = -1;
01326 high = n;
01327 }
01328 else
01329 {
01330
01331 indexbase = (void *) ( ( (const char *) base ) + ( size * ( *low ) ) );
01332 if ( ( *ge )( key, indexbase ) )
01333 {
01334 high = ( *low ) + hunt_inc;
01335 indexbase = (void *) ( ( (const char *) base ) + ( size * high ) );
01336
01337 while ( ( high < n ) && ( ( *ge )( key, indexbase ) ) )
01338 {
01339 *low = high;
01340 hunt_inc += hunt_inc;
01341 high = high + hunt_inc;
01342 indexbase = (void *) ( ( (const char *) base ) + ( size * high ) );
01343 }
01344 if ( high >= n )
01345 high = n;
01346
01347
01348 }
01349 else
01350 {
01351 high = *low;
01352 *low = high - hunt_inc;
01353 indexbase = (void *) ( ( (const char *) base ) + ( size * ( *low ) ) );
01354
01355 while ( ( ( *low ) >= 0 ) && !( ( *ge )( key, indexbase ) ) )
01356 {
01357 high = *low;
01358 hunt_inc += hunt_inc;
01359 *low = ( *low ) - hunt_inc;
01360 indexbase = (void *) ( ( (const char *) base ) + ( size * ( *low ) ) );
01361 }
01362 if ( ( *low ) < 0 )
01363 *low = -1;
01364
01365
01366 }
01367 }
01368
01369
01370
01371 while ( high - *low > 1 )
01372 {
01373 mid = *low + ( high - *low ) / 2;
01374 indexbase = (void *) ( ( (const char *) base ) + ( size * mid ) );
01375 if ( ( *ge )( key, indexbase ) )
01376 *low = mid;
01377 else
01378 high = mid;
01379 }
01380 }