00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "qsastime.h"
00022 #include "qsastimeP.h"
00023 #include <time.h>
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <math.h>
00027 #include <errno.h>
00028
00029 #define TEST01 0x1
00030 #define TEST02 0x2
00031 #define TEST03 0x4
00032 #define TEST04 0x8
00033 #define TEST05 0x10
00034 #define TEST06 0x20
00035 #define TEST07 0x40
00036 #define TEST08 0x80
00037 #define TEST09 0x100
00038 #define TEST10 0x200
00039 #define TEST11 0x400
00040 #define TEST12 0x800
00041 #define TEST13 0x1000
00042 #define TEST14 0x2000
00043 #define TEST15 0x4000
00044 #define TEST16 0x8000
00045
00046 #define MJD_1970 40587
00047
00048
00049 time_t my_timegm( struct tm *tm )
00050 {
00051 time_t ret;
00052 char *tz;
00053
00054 tz = getenv( "TZ" );
00055 setenv( "TZ", "", 1 );
00056 tzset();
00057 ret = mktime( tm );
00058 if ( tz )
00059 setenv( "TZ", tz, 1 );
00060 else
00061 unsetenv( "TZ" );
00062 tzset();
00063 return ret;
00064 }
00065
00066 int testlib_broken_down_time( int year, int month, int day, int hour, int min, double sec, int forceJulian, int inner_test_choice, int verbose )
00067 {
00068 char buf[360];
00069 int year1, month1, day1, hour1, min1;
00070 double sec1;
00071 struct tm tm;
00072 struct tm *ptm = &tm;
00073 struct tm tm1;
00074 struct tm *ptm1 = &tm1;
00075 time_t secs_past_epoch, secs_past_epoch1, delta_secs;
00076
00077 MJDtime MJD1, *pMJD1 = &MJD1;
00078 double jd;
00079 int ifleapyear, ifleapday, iffeb29, ifsamedate, ifsametime;
00080 ptm->tm_year = year - 1900;
00081 ptm->tm_mon = month;
00082 ptm->tm_mday = day;
00083 ptm->tm_hour = hour;
00084 ptm->tm_min = min;
00085 ptm->tm_sec = (int) sec;
00086 if ( verbose )
00087 {
00088 if ( forceJulian )
00089 {
00090 printf( "Start of Julian proleptic inner test\n" );
00091 printf( "input and output (strfMJD) date/time\n" );
00092 }
00093 else
00094 {
00095 printf( "Start of Gregorian proleptic inner test\n" );
00096 printf( "input and output (strftime), and output (strfMJD) date/time\n" );
00097 }
00098 printf( "%.4d-%02d-%02dT%02d:%02d:%018.15fZ\n", year, month + 1, day, hour, min, sec );
00099 }
00100
00101 setFromUT( year, month, day, hour, min, sec, pMJD1, forceJulian );
00102
00103
00104 if ( !forceJulian && ( inner_test_choice & TEST01 ) )
00105 {
00106 secs_past_epoch1 = (time_t) ( 86400. * ( (double) pMJD1->base_day - (double) MJD_1970 ) + (int) pMJD1->time_sec );
00107 secs_past_epoch = my_timegm( ptm );
00108 delta_secs = abs( secs_past_epoch1 - secs_past_epoch );
00109 if ( delta_secs != 0 )
00110 {
00111 printf( "setFromUT secs_past_epoch = %lld seconds\n", (long long) secs_past_epoch1 );
00112 printf( "my_timegm secs_past_epoch = %lld seconds\n", (long long) secs_past_epoch );
00113 printf( "delta secs_past_epoch = %lld seconds\n", (long long) ( secs_past_epoch1 - secs_past_epoch ) );
00114 printf( "test failed with inconsistency between setFromUT and my_timegm\n" );
00115 return 1;
00116 }
00117 }
00118
00119
00120
00121 if ( inner_test_choice & TEST02 )
00122 {
00123 if ( !forceJulian )
00124 {
00125 strftime( &( buf[0] ), 360, "%Y-%m-%dT%H:%M:%SZ\n", ptm );
00126 if ( verbose )
00127 printf( "%s", buf );
00128 }
00129 strfMJD( &( buf[0] ), 360, "%Y-%m-%dT%H:%M:%S%.Z\n", pMJD1, forceJulian, 0 );
00130 if ( verbose )
00131 printf( "%s", buf );
00132 }
00133
00134 if ( verbose )
00135 {
00136 jd = 2400000.5 + pMJD1->base_day + pMJD1->time_sec / 86400.;
00137 printf( "setFromUT JD = %25.16f days\n", jd );
00138 }
00139
00140 if ( forceJulian )
00141 ifleapyear = ( year % 4 == 0 );
00142 else
00143 ifleapyear = ( ( year % 4 == 0 && year % 100 != 0 ) || year % 400 == 0 );
00144 iffeb29 = month == 1 && day == 29;
00145 ifleapday = ( ifleapyear && iffeb29 );
00146
00147
00148 if ( inner_test_choice & TEST03 )
00149 {
00150 breakDownMJD( &year1, &month1, &day1, &hour1, &min1, &sec1, pMJD1, forceJulian );
00151 ifsamedate = ( year1 - year == 0 && ( ( ( !iffeb29 || ifleapday ) && ( month1 - month == 0 && day1 - day == 0 ) ) || ( ( iffeb29 && !ifleapday ) && ( month1 == 2 && day1 == 1 ) ) ) );
00152 ifsametime = ( hour1 - hour == 0 && min1 - min == 0 && fabs( sec1 - sec ) < 1.e-10 );
00153
00154 if ( !( ifsamedate && ifsametime ) )
00155 {
00156 printf( "output date calculated with breakDownMJD = %d-%02d-%02dT%02d:%02d:%018.15fZ\n", year1, month1 + 1, day1, hour1, min1, sec1 );
00157 printf( "test failed with inconsistency between setFromUT and breakDownMJD\n" );
00158 return 1;
00159 }
00160 }
00161
00162
00163 if ( !forceJulian && ( inner_test_choice & TEST04 ) )
00164 {
00165 ptm1 = gmtime( &secs_past_epoch );
00166 ifsamedate = ( ptm1->tm_year == ptm->tm_year && ( ( ( !iffeb29 || ifleapday ) && ( ptm1->tm_mon == ptm->tm_mon && ptm1->tm_mday == ptm->tm_mday ) ) || ( ( iffeb29 && !ifleapday ) && ( ptm1->tm_mon == 2 && ptm1->tm_mday == 1 ) ) ) );
00167 ifsametime = ( ptm1->tm_hour == ptm->tm_hour && ptm1->tm_min == ptm->tm_min && ptm1->tm_sec == ptm->tm_sec );
00168
00169 if ( !( ifsamedate && ifsametime ) )
00170 {
00171 printf( "test failed with inconsistency between my_timegm and its C library inverse gmtime" );
00172 return 1;
00173 }
00174 }
00175 return 0;
00176 }
00177
00178 int testlib_MJD( const MJDtime *MJD, int forceJulian, int inner_test_choice, int verbose )
00179 {
00180 int year, month, day, hour, min;
00181 double sec;
00182 char buf[360];
00183 int year1, month1, day1, hour1, min1;
00184 double sec1;
00185 struct tm tm;
00186 struct tm *ptm = &tm;
00187 struct tm tm1;
00188 struct tm *ptm1 = &tm1;
00189 time_t secs_past_epoch, secs_past_epoch1;
00190
00191 MJDtime MJD1_value, *MJD1 = &MJD1_value;
00192 MJDtime MJD2_value, *MJD2 = &MJD2_value;
00193 double jd;
00194 int ifleapyear, ifleapday, iffeb29, ifsamedate, ifsametime;
00195
00196 *MJD1 = *MJD;
00197 normalize_MJD( MJD1 );
00198 secs_past_epoch = (time_t) ( 86400. * ( (double) MJD1->base_day - (double) MJD_1970 ) + MJD1->time_sec );
00199 breakDownMJD( &year, &month, &day, &hour, &min, &sec, MJD1, forceJulian );
00200
00201 ptm->tm_year = year - 1900;
00202 ptm->tm_mon = month;
00203 ptm->tm_mday = day;
00204 ptm->tm_hour = hour;
00205 ptm->tm_min = min;
00206 ptm->tm_sec = (int) sec;
00207 if ( verbose )
00208 {
00209 if ( forceJulian )
00210 {
00211 printf( "Start of Julian proleptic inner test\n" );
00212 printf( "input and output (strfMJD) date/time\n" );
00213 }
00214 else
00215 {
00216 printf( "Start of Gregorian proleptic inner test\n" );
00217 printf( "input and output (strftime), and output (strfMJD) date/time\n" );
00218 }
00219 printf( "%.4d-%02d-%02dT%02d:%02d:%018.15fZ\n", year, month + 1, day, hour, min, sec );
00220 }
00221
00222
00223 if ( !forceJulian && ( inner_test_choice & TEST01 ) )
00224 {
00225 ptm1 = gmtime( &secs_past_epoch );
00226 if ( !( ( ptm1->tm_year + 1900 ) == year && ptm1->tm_mon == month && ptm1->tm_mday == day && ptm1->tm_hour == hour && ptm1->tm_min == min && ptm1->tm_sec == (int) sec ) )
00227 {
00228 printf( "date calculated with breakDownMJD = %d-%02d-%02dT%02d:%02d:%018.15fZ\n", year, month + 1, day, hour, min, sec );
00229 printf( "date calculated with gmtime = %d-%02d-%02dT%02d:%02d:%02dZ\n", ptm1->tm_year + 1900, ptm1->tm_mon + 1, ptm1->tm_mday, ptm1->tm_hour, ptm1->tm_min, ptm1->tm_sec );
00230 printf( "test failed with inconsistency between breakDownMJD and gmtime\n" );
00231 return 1;
00232 }
00233 }
00234
00235
00236
00237 if ( inner_test_choice & TEST02 )
00238 {
00239 if ( !forceJulian )
00240 {
00241 strftime( &( buf[0] ), 360, "%Y-%m-%dT%H:%M:%SZ\n", ptm );
00242 if ( verbose )
00243 printf( "%s", buf );
00244 }
00245 strfMJD( &( buf[0] ), 360, "%Y-%m-%dT%H:%M:%S%.Z\n", MJD1, forceJulian, 0 );
00246 if ( verbose )
00247 printf( "%s", buf );
00248 }
00249
00250 if ( verbose )
00251 {
00252 jd = 2400000.5 + MJD1->base_day + MJD1->time_sec / 86400.;
00253 printf( "JD = %25.16f days\n", jd );
00254 }
00255
00256 if ( forceJulian )
00257 ifleapyear = ( year % 4 == 0 );
00258 else
00259 ifleapyear = ( ( year % 4 == 0 && year % 100 != 0 ) || year % 400 == 0 );
00260 iffeb29 = month == 1 && day == 29;
00261 ifleapday = ( ifleapyear && iffeb29 );
00262
00263
00264 if ( inner_test_choice & TEST03 )
00265 {
00266 setFromUT( year, month, day, hour, min, sec, MJD2, forceJulian );
00267 if ( !( MJD2->time_sec == MJD1->time_sec && MJD2->base_day == MJD1->base_day ) )
00268 {
00269 printf( "(normalized) input MJD components are = %d, %f\n", MJD1->base_day, MJD1->time_sec );
00270 printf( "(output MJD2 components generated by setFromUT are = %d, %f\n", MJD2->base_day, MJD2->time_sec );
00271 printf( "test failed with inconsistency between breakDownMJD and setFromUT\n" );
00272 return 1;
00273 }
00274 }
00275
00276
00277 if ( !forceJulian && ( inner_test_choice & TEST04 ) )
00278 {
00279 secs_past_epoch1 = my_timegm( ptm );
00280 if ( !( secs_past_epoch == secs_past_epoch1 ) )
00281 {
00282 printf( "secs_past_epoch calculated from input = %lld\n", (long long) secs_past_epoch );
00283 printf( "secs_past_epoch calculated from my_timegm = %lld\n", (long long) secs_past_epoch1 );
00284 printf( "delta secs_past_epoch = %lld seconds\n", (long long) ( secs_past_epoch1 - secs_past_epoch ) );
00285 printf( "test failed with inconsistency between breakDownMJD and its C library based inverse, my_timegm\n" );
00286 return 1;
00287 }
00288 }
00289 return 0;
00290 }
00291
00292
00293
00294
00295
00296 int main()
00297 {
00298 char buf[360];
00299 char buf1[360];
00300 int year, month, day, hour, min;
00301 double sec;
00302 int year1, month1, day1, hour1, min1;
00303 double sec1;
00304 struct tm tm;
00305 struct tm *ptm = &tm;
00306 struct tm tm1;
00307 struct tm *ptm1 = &tm1;
00308 int seconds;
00309
00310 MJDtime MJD1_value, *MJD1 = &MJD1_value;
00311 double jd;
00312 int test_choice, date_choice, ret;
00313
00314
00315
00316 scanf( "%i", &test_choice );
00317
00318 printf( "sizeof(time_t) = %d\n", (int) sizeof ( time_t ) );
00319 if ( sizeof ( time_t ) < 8 )
00320 {
00321 printf( "tests abandoned because time_t is too small on this platform to represent the extremely large date range used for many of these tests. Note, the limitation is in the C library routines (gmtime and mktime) used for these test comparisons and not libqsastime itself.\n" );
00322 return 1;
00323 }
00324
00325 printf( "sizeof(int) = %d\n", (int) sizeof ( int ) );
00326 if ( sizeof ( int ) != 4 )
00327 {
00328 printf( "tests abandoned because int must be 32-bits to test this library properly for how well it will potentially perform on 32-bit platforms\n" );
00329 return 2;
00330 }
00331
00332 setenv( "TZ", "", 1 );
00333 tzset();
00334
00335 if ( test_choice & TEST01 )
00336 {
00337 printf( "Test 01 of calendar dates in the vicinity of the JD epoch \n" );
00338
00339 for ( date_choice = 0; date_choice < 5; date_choice++ )
00340 {
00341 if ( date_choice == 0 )
00342 {
00343 month = 0;
00344 day = 1;
00345 }
00346 else if ( date_choice == 1 )
00347 {
00348 month = 1;
00349 day = 28;
00350 }
00351 else if ( date_choice == 2 )
00352 {
00353 month = 1;
00354 day = 29;
00355 }
00356 else if ( date_choice == 3 )
00357 {
00358 month = 2;
00359 day = 1;
00360 }
00361 else if ( date_choice == 4 )
00362 {
00363 month = 11;
00364 day = 31;
00365 }
00366 hour = 12;
00367 min = 0;
00368 sec = 0.;
00369
00370 for ( year = -4717; year <= -4707; year++ )
00371 {
00372 printf( "\n" );
00373 ret = testlib_broken_down_time( year, month, day, hour, min, sec, 1, 0xffff, 1 );
00374 if ( ret )
00375 return ret;
00376 ret = testlib_broken_down_time( year, month, day, hour, min, sec, 0, 0xffff, 1 );
00377 if ( ret )
00378 return ret;
00379 }
00380 }
00381 }
00382
00383 if ( test_choice & TEST02 )
00384 {
00385 printf( "Test 02 of calendar dates in the vicinity of the year epoch. \n" );
00386
00387 for ( date_choice = 0; date_choice < 5; date_choice++ )
00388 {
00389 if ( date_choice == 0 )
00390 {
00391 month = 0;
00392 day = 1;
00393 }
00394 else if ( date_choice == 1 )
00395 {
00396 month = 1;
00397 day = 28;
00398 }
00399 else if ( date_choice == 2 )
00400 {
00401 month = 1;
00402 day = 29;
00403 }
00404 else if ( date_choice == 3 )
00405 {
00406 month = 2;
00407 day = 1;
00408 }
00409 else if ( date_choice == 4 )
00410 {
00411 month = 11;
00412 day = 31;
00413 }
00414 hour = 0;
00415 min = 0;
00416 sec = 0.;
00417
00418 for ( year = -5; year <= 5; year++ )
00419 {
00420 printf( "\n" );
00421 ret = testlib_broken_down_time( year, month, day, hour, min, sec, 1, 0xffff, 1 );
00422 if ( ret )
00423 return ret;
00424 ret = testlib_broken_down_time( year, month, day, hour, min, sec, 0, 0xffff, 1 );
00425 if ( ret )
00426 return ret;
00427 }
00428 }
00429 }
00430
00431 if ( test_choice & TEST03 )
00432 {
00433 printf( "Test 03 of calendar dates in the vicinity of the MJD epoch. \n" );
00434
00435 for ( date_choice = 0; date_choice < 6; date_choice++ )
00436 {
00437 if ( date_choice == 0 )
00438 {
00439 month = 0;
00440 day = 1;
00441 }
00442 else if ( date_choice == 1 )
00443 {
00444 month = 1;
00445 day = 28;
00446 }
00447 else if ( date_choice == 2 )
00448 {
00449 month = 1;
00450 day = 29;
00451 }
00452 else if ( date_choice == 3 )
00453 {
00454 month = 2;
00455 day = 1;
00456 }
00457 else if ( date_choice == 4 )
00458 {
00459 month = 10;
00460 day = 17;
00461 }
00462 else if ( date_choice == 5 )
00463 {
00464 month = 11;
00465 day = 31;
00466 }
00467 hour = 0;
00468 min = 0;
00469 sec = 0.;
00470
00471 for ( year = 1853; year <= 1863; year++ )
00472 {
00473 printf( "\n" );
00474 ret = testlib_broken_down_time( year, month, day, hour, min, sec, 1, 0xffff, 1 );
00475 if ( ret )
00476 return ret;
00477 ret = testlib_broken_down_time( year, month, day, hour, min, sec, 0, 0xffff, 1 );
00478 if ( ret )
00479 return ret;
00480 }
00481 }
00482 }
00483
00484 if ( test_choice & TEST04 )
00485 {
00486 printf( "Test 04 of small second range near Year 0 (Julian)\n" );
00487
00488 ret = setFromUT( 0, 0, 1, 0, 0, 0., MJD1, 1 );
00489 if ( ret )
00490 {
00491 printf( "Test 04 cannot even start for Year 0 (Julian)" );
00492 return ret;
00493 }
00494
00495 for ( seconds = -5; seconds < 5; seconds++ )
00496 {
00497 printf( "\n" );
00498 ret = testlib_MJD( MJD1, 1, 0xffff, 1 );
00499 if ( ret )
00500 return ret;
00501 MJD1->time_sec++;
00502 }
00503
00504 printf( "Test 04 of small second range near Year 0 (Gregorian)\n" );
00505
00506
00507 ret = setFromUT( 0, 0, 1, 0, 0, 0., MJD1, 0 );
00508 if ( ret )
00509 {
00510 printf( "Test 04 cannot even start for Year 0 (Gregorian)" );
00511 return ret;
00512 }
00513
00514 for ( seconds = -5; seconds < 5; seconds++ )
00515 {
00516 printf( "\n" );
00517 ret = testlib_MJD( MJD1, 0, 0xffff, 1 );
00518 if ( ret )
00519 return ret;
00520 MJD1->time_sec++;
00521 }
00522
00523 printf( "Test 04 of small second range near 2009-01-01 (Gregorian) when a leap second was inserted\n" );
00524
00525
00526 ret = setFromUT( 2009, 0, 1, 0, 0, 0.1234567890123456 - 5., MJD1, 0 );
00527 if ( ret )
00528 {
00529 printf( "Test 04 cannot even start for Year 0 (Gregorian)" );
00530 return ret;
00531 }
00532
00533 for ( seconds = -5; seconds < 5; seconds++ )
00534 {
00535 printf( "\n" );
00536 ret = testlib_MJD( MJD1, 0, 0xffff, 1 );
00537 if ( ret )
00538 return ret;
00539 MJD1->time_sec++;
00540 }
00541 }
00542
00543 if ( test_choice & TEST05 )
00544 {
00545 printf( "Test 05 of normalization of breakDownMJD result and strfMJD results near the hour.\n" );
00546 MJD1->base_day = 51910;
00547 MJD1->time_sec = 3600.;
00548 int iepsilon;
00549 for ( iepsilon = -1; iepsilon < 2; iepsilon++ )
00550 {
00551 MJD1->time_sec = 3600. + 1.e-8 * (double) iepsilon;
00552 breakDownMJD( &year, &month, &day, &hour, &min, &sec, MJD1, 0 );
00553 printf( "MJD = {%d,%20.15f}\n", MJD1->base_day, MJD1->time_sec );
00554 printf( "breakDownMJD result is year, month, day, hour, min, sec = %d, %d, %d, %d, %d, %20.15f\n", year, month, day, hour, min, sec );
00555 strfMJD( &( buf[0] ), 360, "%Y-%m-%dT%H:%M:%S%9Z\n", MJD1, 0, 0 );
00556 printf( "strfMJD %%S%%9 result is %s", buf );
00557 strfMJD( &( buf[0] ), 360, "%Y-%m-%dT%H:%M:%S%.Z\n", MJD1, 0, 0 );
00558 printf( "strfMJD %%S%%. result is %s", buf );
00559 strfMJD( &( buf[0] ), 360, "%H:%M:%S, %H:%M:%S%0, %H:%M:%S%1, %H:%M:%S%2, %H:%M:%S%3, %H:%M:%S%4\n %H:%M:%S %0,%H:%M:%S %1,%H:%M:%S %2,%H:%M:%S %3,%H:%M:%S %4\n", MJD1, 0, 0 );
00560 printf( "strfMJD more heavily rounded results (the latter ones with a blank before the\ndecimal point to prove separated formatting works) for H:M:S are the following:\n%s", buf );
00561 }
00562 }
00563
00564 if ( test_choice & TEST06 )
00565 {
00566 printf( "Test 06 (non-verbose) of calendar dates for every year from -5000000 to 5000000\n" );
00567
00568 for ( date_choice = 0; date_choice < 5; date_choice++ )
00569 {
00570 if ( date_choice == 0 )
00571 {
00572 month = 0;
00573 day = 1;
00574 }
00575 else if ( date_choice == 1 )
00576 {
00577 month = 1;
00578 day = 28;
00579 }
00580 else if ( date_choice == 2 )
00581 {
00582 month = 1;
00583 day = 29;
00584 }
00585 else if ( date_choice == 3 )
00586 {
00587 month = 2;
00588 day = 1;
00589 }
00590 else if ( date_choice == 4 )
00591 {
00592 month = 11;
00593 day = 31;
00594 }
00595 hour = 0;
00596 min = 0;
00597 sec = 0.123456;
00598
00599
00600
00601 for ( year = -5000000; year <= 5000000; year += 1 )
00602 {
00603 ret = testlib_broken_down_time( year, month, day, hour, min, sec, 1, 0xffff, 0 );
00604 if ( ret )
00605 return ret;
00606 ret = testlib_broken_down_time( year, month, day, hour, min, sec, 0, 0xffff, 0 );
00607 if ( ret )
00608 return ret;
00609 }
00610 }
00611 }
00612
00613 if ( test_choice & TEST07 )
00614 {
00615 printf( "Test 07 (non-verbose) of all seconds from late 2007 to early 2009\n" );
00616 ret = setFromUT( 2007, 11, 30, 0, 0, 0., MJD1, 0 );
00617 if ( ret )
00618 {
00619 printf( "Test 06 cannot even start" );
00620 return ret;
00621 }
00622
00623
00624 for ( seconds = 0; seconds < 430 * 86400; seconds++ )
00625 {
00626 MJD1->time_sec = (double) seconds;
00627 ret = testlib_MJD( MJD1, 1, 0xffff, 0 );
00628 if ( ret )
00629 return ret;
00630
00631 ret = testlib_MJD( MJD1, 0, 0xffff, 0 );
00632 if ( ret )
00633 return ret;
00634 }
00635 }
00636
00637
00638 return 0;
00639 }