00001
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <stdio.h>
00028 #include <math.h>
00029 #include <time.h>
00030 #include <ctype.h>
00031 #include "platform.h"
00032 #include "timestamp.h"
00033 #include "exception.h"
00034 #include "find.h"
00035 #include "output.h"
00036 #include "globals.h"
00037
00038 #ifndef WIN32
00039 #define _tzname tzname
00040 #define _timezone timezone
00041 #endif
00042
00043 #define TZFILE "tzinfo.txt"
00044
00045 #define DAY (86400*TS_SECOND)
00046 #define HOUR (3600*TS_SECOND)
00047 #define MINUTE (60*TS_SECOND)
00048 #define SECOND (TS_SECOND)
00049 #define MICROSECOND (TS_SECOND/1000000)
00051 typedef struct{
00052 int month, nth, day, hour, minute;
00053 } SPEC;
00055 static daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
00056 static char *dow[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
00057
00058 #define YEAR0 (1970)
00059 #define YEAR0_ISLY (0)
00060 #define DOW0 (4)
00061
00062 static int tzvalid=0;
00063 static TIMESTAMP tszero[1000] = {-1};
00064 static TIMESTAMP dststart[1000], dstend[1000];
00065 static TIMESTAMP tzoffset;
00066 static char current_tzname[64], tzstd[32], tzdst[32];
00067
00068 #define LOCALTIME(T) ((T)-tzoffset+(isdst((T))?3600:0))
00069 #define GMTIME(T) ((T)+tzoffset-(isdst((T)+tzoffset)?3600:0))
00070
00074 char *timestamp_current_timezone(void){
00075 return current_tzname;
00076 }
00077
00081 int timestamp_year(TIMESTAMP ts, TIMESTAMP *remainder){
00082 static int year = 0;
00083 int tsyear = 0;
00084
00085 if (tszero[0] == -1){
00086 TIMESTAMP ts = 0;
00087 int year = YEAR0;
00088 int n = (365 + YEAR0_ISLY) * DAY;
00089 while (ts < TS_MAX && year < 2969){
00090 tszero[year-YEAR0] = ts;
00091 ts += n;
00092 year++;
00093 n = (ISLEAPYEAR(year) ? 366 : 365) * DAY;
00094 }
00095 }
00096
00097 while(year > 0 && ts < tszero[year]){
00098 year--;
00099 }
00100
00101 while(year < MAXYEAR-YEAR0-1 && ts > tszero[year+1]){
00102 year++;
00103 }
00104
00105 if(remainder){
00106 *remainder = ts - tszero[year];
00107 }
00108
00109 if((year + YEAR0) < 0){
00110 output_error("timestamp_year: the year has rolled over or become negative!");
00111
00112
00113
00114
00115 }
00116
00117 return year + YEAR0;
00118 }
00119
00122 int isdst(TIMESTAMP t)
00123 {
00124 int year = timestamp_year(t + tzoffset, NULL) - YEAR0;
00125
00126 return dststart>=0 && dststart[year] <= t && t < dstend[year];
00127 }
00128
00131 int local_tzoffset(TIMESTAMP t)
00132 {
00133 static old_t = 0;
00134 static old_tzoffset = 0;
00135 if (old_t==0 || old_t!=t)
00136 old_tzoffset = tzoffset + isdst(t)?3600:0;
00137 return old_tzoffset;
00138 }
00139
00143 int local_datetime(TIMESTAMP ts, DATETIME *dt)
00144 {
00145
00146 int n;
00147 TIMESTAMP rem = 0;
00148 TIMESTAMP local;
00149 int tsyear;
00150
00151
00152 static TIMESTAMP old_ts =0;
00153 static DATETIME old_dt;
00154
00155 if(dt == NULL){
00156 return 0;
00157 }
00158
00159
00160 if (old_ts == ts && old_ts!=0)
00161 memcpy(dt,&old_dt,sizeof(DATETIME));
00162 else
00163 old_ts = 0;
00164
00165 local = LOCALTIME(ts);
00166 tsyear = timestamp_year(local, &rem);
00167
00168 if (rem < 0){
00169
00170
00171
00172 throw_exception("local_datetime(...): unable to determine localtime; did you forget to initialize the clock?");
00173
00174
00175
00176
00177 }
00178
00179
00180 if(ts < TS_ZERO && ts > TS_MAX)
00181 return 0;
00182
00183 if(ts == TS_NEVER)
00184 return 0;
00185
00186
00187 dt->timestamp = ts;
00188
00189
00190 dt->is_dst = (tzvalid && isdst(ts));
00191
00192
00193 dt->year = tsyear;
00194
00195
00196 dt->yearday = (unsigned short)(rem / DAY);
00197 dt->weekday = (unsigned short)((local / DAY + DOW0 + 7) % 7);
00198
00199
00200 dt->month = 0;
00201 n = daysinmonth[0] * DAY;
00202 while(rem >= n){
00203 rem -= n;
00204 dt->month++;
00205 n = (daysinmonth[dt->month] + ((dt->month == 1 && ISLEAPYEAR(dt->year)) ? 1:0)) * 86400 * TS_SECOND;
00206 if(n < 86400 * 28){
00207 output_fatal("Breaking an infinite loop in local_datetime! (ts = %"FMT_INT64"ds", ts);
00208
00209
00210
00211
00212
00213
00214
00215 return 0;
00216 }
00217 }
00218 dt->month++;
00219
00220
00221 dt->day = (unsigned short)(rem / DAY + 1);
00222 rem %= DAY;
00223
00224
00225 dt->hour = (unsigned short)(rem / HOUR);
00226 rem %= HOUR;
00227
00228
00229 dt->minute = (unsigned short)(rem / MINUTE);
00230 rem %= MINUTE;
00231
00232
00233 dt->second = (unsigned short)rem / TS_SECOND;
00234 rem %= SECOND;
00235
00236
00237 dt->microsecond = (unsigned int)rem;
00238
00239
00240 strncpy(dt->tz, tzvalid ? (dt->is_dst ? tzdst : tzstd) : "GMT", sizeof(dt->tz));
00241
00242
00243 old_ts = ts;
00244 memcpy(&old_dt,dt,sizeof(old_dt));
00245 return 1;
00246 }
00247
00250 TIMESTAMP mkdatetime(DATETIME *dt)
00251 {
00252 TIMESTAMP ts;
00253 int n;
00254
00255 if(dt == NULL){
00256 return TS_INVALID;
00257 }
00258
00259
00260 timestamp_year(0,NULL);
00261 if(dt->year < YEAR0 || dt->year >= YEAR0 + sizeof(tszero) / sizeof(tszero[0]) ){
00262 return TS_INVALID;
00263 }
00264 ts = tszero[dt->year-YEAR0];
00265
00266 if(dt->month > 12 || dt->month < 1)
00267 {
00268 output_fatal("Invalid month provided in datetime");
00269 return ts;
00270 }
00271 else if(dt->day > daysinmonth[dt->month-1] || dt->day < 1)
00272 {
00273 output_fatal("Invalid day provided in datetime");
00274 return ts;
00275 }
00276 else
00277 {
00278
00279 for (n=1; n<dt->month; n++){
00280 ts += (daysinmonth[n - 1] + (n == 2 && ISLEAPYEAR(dt->year) ? 1 : 0)) * DAY;
00281 }
00282
00283 if(dt->hour < 0 || dt->hour > 23 || dt->minute < 0 || dt->minute > 60 || dt->second < 0 || dt->second > 62){
00284 output_fatal("Invalid time of day provided in datetime");
00285 return ts;
00286 }
00287
00288 ts += (dt->day - 1) * DAY + dt->hour * HOUR + dt->minute * MINUTE + dt->second * SECOND + dt->microsecond * MICROSECOND;
00289
00290 if(dt->tz[0] == 0){
00291 strcpy(dt->tz, (isdst(ts) ? tzdst : tzstd));
00292 }
00293
00294 if (strcmp(dt->tz, "GMT") == 0){
00295 return ts;
00296 } else if(strcmp(dt->tz, tzstd) == 0 || (strcmp(dt->tz, "")==0 && ts < dststart[dt->year - YEAR0] || ts >= dstend[dt->year - YEAR0])){
00297
00298 return ts + tzoffset;
00299 } else if(strcmp(dt->tz, tzdst) == 0 || (strcmp(dt->tz, "")==0 && ts >= dststart[dt->year - YEAR0] && ts < dstend[dt->year - YEAR0])){
00300
00301 return ts + tzoffset - HOUR;
00302 }
00303 }
00304
00305 return TS_INVALID;
00306 }
00307
00310 int strdatetime(DATETIME *t, char *buffer, int size){
00311 int len;
00312 char tbuffer[1024];
00313
00314 if(t == NULL){
00315 output_error("strdatetime: null DATETIME pointer passed in");
00316 return 0;
00317 }
00318
00319 if(buffer == NULL){
00320 output_error("strdatetime: null string buffer passed in");
00321 return 0;
00322 }
00323
00324
00325 if(global_dateformat == DF_ISO){
00326 if(t->microsecond != 0){
00327 len = sprintf(tbuffer, "%04d-%02d-%02d %02d:%02d:%02d.%06d %s",
00328 t->year, t->month, t->day, t->hour, t->minute, t->second, t->microsecond, t->tz);
00329 } else {
00330 len = sprintf(tbuffer, "%04d-%02d-%02d %02d:%02d:%02d %s",
00331 t->year, t->month, t->day, t->hour, t->minute, t->second, t->tz);
00332 }
00333 } else if(global_dateformat == DF_US){
00334 len = sprintf(tbuffer, "%02d-%02d-%04d %02d:%02d:%02d",
00335 t->month, t->day, t->year, t->hour, t->minute, t->second);
00336 } else if(global_dateformat == DF_EURO){
00337 len = sprintf(tbuffer,"%02d-%02d-%04d %02d:%02d:%02d",
00338 t->day, t->month, t->year, t->hour, t->minute, t->second);
00339 } else {
00340 throw_exception("global_dateformat=%d is not valid", global_dateformat);
00341
00342
00343
00344
00345
00346 }
00347
00348 if(len < size){
00349 strncpy(buffer, tbuffer, len+1);
00350 return len;
00351 } else {
00352 output_error("strdatetime: timestamp larger than provided buffer");
00353
00354
00355
00356
00357
00358 return 0;
00359 }
00360 }
00361
00365 TIMESTAMP compute_dstevent(int year, SPEC *spec, time_t offset){
00366 TIMESTAMP t = TS_INVALID;
00367 int y, m, d, ndays = 0, day1;
00368
00369 if(spec == NULL){
00370 output_error("compute_dstevent: null SPEC* pointer passed in");
00371 return -1;
00372 }
00373
00374
00375 if (spec->day<0 || spec->day>7
00376 || spec->hour<0 || spec->hour>23
00377 || spec->minute<0 || spec->minute>59
00378 || spec->month<0 || spec->month>11
00379 || spec->nth<0 || spec->nth>5){
00380 output_error("compute_dstevent: date/time values are not valid");
00381 return -1;
00382 }
00383
00384
00385 for (y = YEAR0; y < year; y++){
00386 ndays += 365 + (ISLEAPYEAR(y) ? 1 : 0);
00387 }
00388
00389 for (m = 0; m < spec->month - 1; m++){
00390 ndays += daysinmonth[m] + ((m==1&&ISLEAPYEAR(y))?1:0);
00391 }
00392
00393 day1 = (ndays + DOW0+7)%7;
00394 d = ((8 - day1) + (spec->nth - 1) * 7);
00395
00396 while(d > daysinmonth[m] + ((m == 1 && ISLEAPYEAR(y)) ? 1 : 0)){
00397 d -= 7;
00398 }
00399
00400 ndays += d-1;
00401 t = (ndays * 86400 + spec->hour * 3600 + spec->minute * 60);
00402
00403 return t * TS_SECOND + tzoffset;
00404 }
00405
00408 int tz_info(char *tzspec, char *tzname, char *std, char *dst, time_t *offset){
00409 int hours = 0, minutes = 0;
00410 char buf1[32], buf2[32];
00411
00412 if ((strchr(tzspec, ':') != NULL && sscanf(tzspec, "%[A-Z]%d:%d%[A-Z]", buf1, &hours, &minutes, buf2) < 3)
00413 || sscanf(tzspec, "%[A-Z]%d%[A-Z]", buf1, &hours, buf2) < 2){
00414 output_error("tz_info: \'%s\' not a timezone-format string", tzspec);
00415 return 0;
00416 }
00417
00418 if (hours < -12 || hours > 12){
00419 output_error("timezone %s (%s) has out-of-bounds hour offset of %i", tzname, std, hours);
00420 return 0;
00421 }
00422
00423 if (minutes < 0 || minutes > 59){
00424 output_error("timezone %s (%s) has out-of-bounds minutes offset of %i", tzname, std, minutes);
00425 return 0;
00426 }
00427
00428 if(std){
00429 strcpy(std, buf1);
00430 }
00431
00432 if(dst){
00433 strcpy(dst, buf2);
00434 }
00435
00436 if(minutes == 0) {
00437 if(tzname){
00438 sprintf(tzname, "%s%d%s", buf1, hours, buf2);
00439 }
00440
00441 if(offset){
00442 *offset = hours * 3600;
00443 }
00444
00445 return 1;
00446 } else {
00447 if(tzname){
00448 sprintf(tzname, "%s%d:%02d%s", buf1, hours, minutes, buf2);
00449 }
00450
00451 if(offset){
00452 *offset = hours * 3600 + minutes * 60;
00453 }
00454
00455 return 2;
00456 }
00457 }
00458
00462 char *tz_name(char *tzspec){
00463 static char name[32] = "GMT";
00464
00465 if(tz_info(tzspec, name, NULL, NULL, NULL)){
00466 return name;
00467 } else {
00468
00469
00470
00471
00472 return NULL;
00473 }
00474
00475 }
00476
00479 time_t tz_offset(char *tzspec){
00480 time_t offset;
00481
00482 if(tz_info(tzspec, NULL, NULL, NULL, &offset)){
00483 return offset;
00484 } else {
00485 return -1;
00486 }
00487
00488 }
00489
00492 char *tz_std(char *tzspec){
00493 static char std[32] = "GMT";
00494
00495 if(tz_info(tzspec, NULL, std, NULL, NULL)){
00496 return std;
00497 } else {
00498 return "GMT";
00499 }
00500
00501 }
00502
00505 char *tz_dst(char *tzspec){
00506 static char dst[32]="GMT";
00507
00508 if(tz_info(tzspec,NULL,NULL,dst,NULL)){
00509 return dst;
00510 } else {
00511 return "GMT";
00512 }
00513
00514 }
00515
00518 void set_tzspec(int year, char *tzname, SPEC *pStart, SPEC *pEnd){
00519 int y;
00520
00521
00522 for (y = year - YEAR0; y < sizeof(tszero) / sizeof(tszero[0]); y++)
00523 {
00524 if (pStart!=NULL && pEnd!=NULL)
00525 {
00526 dststart[y] = compute_dstevent(y + YEAR0, pStart, tzoffset);
00527 dstend[y] = compute_dstevent(y + YEAR0, pEnd, tzoffset);
00528 }
00529 else
00530 dststart[y] = dstend[y] = -1;
00531 }
00532 }
00533
00536 void load_tzspecs(char *tz){
00537 char *filepath = find_file(TZFILE, NULL, FF_READ);
00538 char *pTzname = 0;
00539 FILE *fp = NULL;
00540 char buffer[1024];
00541 int linenum = 0;
00542 int year = YEAR0;
00543
00544 tzvalid = 0;
00545 pTzname = tz_name(tz);
00546
00547 if(pTzname == 0){
00548 throw_exception("timezone '%s' was not understood by tz_name.", tz);
00549
00550
00551
00552
00553 }
00554
00555 strncpy(current_tzname, pTzname, sizeof(current_tzname));
00556 tzoffset = tz_offset(current_tzname);
00557 strncpy(tzstd, tz_std(current_tzname), sizeof(tzstd));
00558 strncpy(tzdst, tz_dst(current_tzname), sizeof(tzdst));
00559
00560 if(filepath == NULL){
00561 throw_exception("timezone specification file %s not found in GLPATH=%s: %s", TZFILE, getenv("GLPATH"), strerror(errno));
00562
00563
00564
00565
00566 }
00567
00568 fp = fopen(filepath,"r");
00569
00570 if(fp == NULL){
00571 throw_exception("%s: access denied: %s", filepath, strerror(errno));
00572
00573
00574
00575 }
00576
00577 while(fgets(buffer,sizeof(buffer),fp)){
00578 char *p = NULL;
00579 char tzname[32];
00580 SPEC start, end;
00581 int form = -1;
00582
00583 linenum++;
00584
00585
00586 p = strchr(buffer,';');
00587
00588 if(p != NULL){
00589 *p = '\0';
00590 }
00591
00592
00593 p = buffer + strlen(buffer) - 1;
00594
00595 while (iswspace(*p) && p > buffer){
00596 *p-- = '\0';
00597 }
00598
00599
00600 if (buffer[0] == '\0' || iswspace(buffer[0])){
00601 continue;
00602 }
00603
00604
00605 if(sscanf(buffer, "[%d]", &year) == 1){
00606 continue;
00607 }
00608
00609
00610 form = sscanf(buffer, "%[^,],M%d.%d.%d/%d:%d,M%d.%d.%d/%d:%d", tzname,
00611 &start.month, &start.nth, &start.day, &start.hour, &start.minute,
00612 &end.month, &end.nth, &end.day, &end.hour, &end.minute);
00613
00614
00615 pTzname = tz_name(tzname);
00616
00617 if (tz != NULL && pTzname != NULL && strcmp(pTzname,current_tzname) != 0){
00618 continue;
00619 }
00620
00621 if(form == 1){
00622 set_tzspec(year, current_tzname, NULL, NULL);
00623 } else if(form == 11) {
00624 set_tzspec(year, current_tzname, &start, &end);
00625 } else {
00626 throw_exception("%s(%d): %s is not a valid timezone spec", filepath, linenum, buffer);
00627
00628
00629
00630
00631 }
00632 }
00633
00634 if(ferror(fp)){
00635 output_error("%s(%d): %s", filepath, linenum, strerror(errno));
00636 } else {
00637 output_verbose("%s loaded ok", filepath);
00638 }
00639
00640 fclose(fp);
00641 tzvalid = 1;
00642 }
00643
00647 char *timestamp_set_tz(char *tz_name){
00648 static char guess[64];
00649
00650 if (tz_name == NULL){
00651 tz_name=getenv("TZ");
00652 }
00653
00654 if(tz_name == NULL){
00655 if (strcmp(_tzname[0], "") == 0){
00656 throw_exception("timezone not identified");
00657
00658
00659
00660
00661
00662
00663 }
00664
00665 if (_timezone % 60 == 0){
00666 sprintf(guess, "%s%d%s", _tzname[0], _timezone / 3600, _tzname[1]);
00667 } else {
00668 sprintf(guess, "%s%d:%d%s", _tzname[0], _timezone / 3600, _timezone / 60, _tzname[1]);
00669 }
00670 tz_name = guess;
00671 }
00672
00673 load_tzspecs(tz_name);
00674
00675 return current_tzname;
00676 }
00677
00680 int convert_from_timestamp(TIMESTAMP ts, char *buffer, int size)
00681 {
00682 char temp[64]="INVALID";
00683 int len=(int)strlen(temp);
00684 if (ts>=365*DAY)
00685 { DATETIME t;
00686 if (ts>=0)
00687 {
00688 if (ts<TS_NEVER)
00689 {
00690 if (local_datetime(ts,&t))
00691 len = strdatetime(&t,temp,sizeof(temp));
00692 else
00693 throw_exception("%"FMT_INT64"d is an invalid timestamp", ts);
00694
00695
00696
00697
00698 }
00699 else
00700 len=sprintf(temp,"%s","NEVER");
00701 }
00702 }
00703 else if (ts>=DAY)
00704 len=sprintf(temp,"%lfd",(double)ts/DAY);
00705 else if (ts>=HOUR)
00706 len=sprintf(temp,"%lfh",(double)ts/HOUR);
00707 else if (ts>=MINUTE)
00708 len=sprintf(temp,"%lfm",(double)ts/MINUTE);
00709 else if (ts>=SECOND)
00710 len=sprintf(temp,"%lfs",(double)ts/SECOND);
00711 else if (ts==0)
00712 len=sprintf(temp,"%s","INIT");
00713 else
00714 len=sprintf(temp,"%"FMT_INT64"d",ts);
00715 if (len<size)
00716 {
00717 if(ts == TS_NEVER){
00718 strcpy(buffer, "NEVER");
00719 return (int)strlen("NEVER");
00720 }
00721 strcpy(buffer,temp);
00722 return len;
00723 }
00724 else
00725 return 0;
00726 }
00727
00730 TIMESTAMP convert_to_timestamp(char *value)
00731 {
00732
00733 int Y=0,m=0,d=0,H=0,M=0,S=0;
00734 char tz[5]="";
00735 if (*value=='\'' || *value=='"') value++;
00736
00737 if (sscanf(value,"%d-%d-%d %d:%d:%d %[-+:A-Za-z0-9]",&Y,&m,&d,&H,&M,&S,tz)>=3)
00738 {
00739 int isdst = (strcmp(tz,tzdst)==0) ? 1 : 0;
00740 DATETIME dt = {Y,m,d,H,M,S,0,isdst};
00741 strncpy(dt.tz,tz,sizeof(dt.tz));
00742 return mkdatetime(&dt);
00743 }
00744
00745 else if (global_dateformat==DF_ISO && sscanf(value,"%d/%d/%d %d:%d:%d %[-+:A-Za-z0-9]",&Y,&m,&d,&H,&M,&S,tz)>=3)
00746 {
00747 int isdst = (strcmp(tz,tzdst)==0) ? 1 : 0;
00748 DATETIME dt = {Y,m,d,H,M,S,0,isdst};
00749 strncpy(dt.tz,tz,sizeof(dt.tz));
00750 return mkdatetime(&dt);
00751 }
00752
00753 else if (global_dateformat==DF_US && sscanf(value,"%d/%d/%d %d:%d:%d %[-+:A-Za-z0-9]",&m,&d,&Y,&H,&M,&S,tz)>=3)
00754 {
00755 int isdst = (strcmp(tz,tzdst)==0) ? 1 : 0;
00756 DATETIME dt = {Y,m,d,H,M,S,0,isdst};
00757 strncpy(dt.tz,tz,sizeof(dt.tz));
00758 return mkdatetime(&dt);
00759 }
00760
00761 else if (global_dateformat==DF_EURO && sscanf(value,"%d/%d/%d %d:%d:%d %[-+:A-Za-z0-9]",&d,&m,&Y,&H,&M,&S,tz)>=3)
00762 {
00763 int isdst = (strcmp(tz,tzdst)==0) ? 1 : 0;
00764 DATETIME dt = {Y,m,d,H,M,S,0,isdst};
00765 strncpy(dt.tz,tz,sizeof(dt.tz));
00766 return mkdatetime(&dt);
00767 }
00768
00769 else if (strcmp(value,"INIT")==0)
00770 return 0;
00771 else if (strcmp(value, "NEVER")==0)
00772 return TS_NEVER;
00773 else if (strcmp(value, "NOW") == 0)
00774 return global_clock;
00775 else if (isdigit(value[0]))
00776 {
00777 double t = atof(value);
00778 char *p=value;
00779 while (isdigit(*p) || *p=='.') p++;
00780 switch (*p) {
00781 case 's':
00782 case 'S':
00783 t *= SECOND;
00784 break;
00785 case 'm':
00786 case 'M':
00787 t *= MINUTE;
00788 break;
00789 case 'h':
00790 case 'H':
00791 t *= HOUR;
00792 break;
00793 case 'd':
00794 case 'D':
00795 t *= DAY;
00796 break;
00797 default:
00798 return TS_NEVER;
00799 break;
00800 }
00801 return (TIMESTAMP)(t+0.5);
00802 }
00803 else
00804 return TS_NEVER;
00805 }
00806
00807 double timestamp_to_days(TIMESTAMP t)
00808 {
00809 return (double)t/DAY;
00810 }
00811
00812 double timestamp_to_hours(TIMESTAMP t)
00813 {
00814 return (double)t/HOUR;
00815 }
00816
00817 double timestamp_to_minutes(TIMESTAMP t)
00818 {
00819 return (double)t/MINUTE;
00820 }
00821
00822 double timestamp_to_seconds(TIMESTAMP t)
00823 {
00824 return (double)t/SECOND;
00825 }
00826
00830 int timestamp_test(void)
00831 {
00832 #define NYEARS 50
00833 int year;
00834 static DATETIME last_t;
00835 TIMESTAMP step = SECOND;
00836 TIMESTAMP ts;
00837 char buf1[64], buf2[64];
00838 char steptxt[32];
00839 TIMESTAMP *event[]={dststart,dstend};
00840 int failed=0, succeeded=0;
00841
00842 output_test("BEGIN: daylight saving time event test for TZ=%s...", current_tzname);
00843 convert_from_timestamp(step,steptxt,sizeof(steptxt));
00844 for (year=0; year<NYEARS; year++)
00845 {
00846 int test;
00847 for (test=0; test<2; test++)
00848 {
00849 for (ts=(event[test])[year]-2*step; ts<(event[test])[year]+2*step;ts+=step)
00850 {
00851 DATETIME t;
00852 if (local_datetime(ts,&t))
00853 {
00854 if (last_t.is_dst!=t.is_dst)
00855 output_test("%s + %s = %s", strdatetime(&last_t,buf1,sizeof(buf1))?buf1:"(invalid)", steptxt, strdatetime(&t,buf2,sizeof(buf2))?buf2:"(invalid)");
00856 last_t = t;
00857 succeeded++;
00858 }
00859 else
00860 {
00861 output_test("FAILED: unable to convert ts=%"FMT_INT64"d to local time", ts);
00862 failed++;
00863 }
00864 }
00865 }
00866 }
00867 output_test("END: daylight saving time event test");
00868
00869 step=HOUR;
00870 convert_from_timestamp(step,steptxt,sizeof(steptxt));
00871 output_test("BEGIN: round robin test at %s timesteps",steptxt);
00872 for (ts=DAY+tzoffset; ts<DAY*365*NYEARS; ts+=step)
00873 {
00874 DATETIME t;
00875 if (local_datetime(ts,&t))
00876 {
00877 TIMESTAMP tt = mkdatetime(&t);
00878 convert_from_timestamp(ts,buf1,sizeof(buf1));
00879 convert_from_timestamp(tt,buf2,sizeof(buf2));
00880 if (tt==TS_INVALID)
00881 {
00882 output_test("FAILED: unable to extract %04d-%02d-%02d %02d:%02d:%02d %s (dow=%s, doy=%d)", t.year,t.month,t.day,t.hour,t.minute,t.second,t.tz,dow[t.weekday],t.yearday);
00883 failed++;
00884 }
00885 else if (tt!=ts)
00886 {
00887 output_test("FAILED: unable to match %04d-%02d-%02d %02d:%02d:%02d %s (dow=%s, doy=%d)\n from=%s, to=%s", t.year,t.month,t.day,t.hour,t.minute,t.second,t.tz,dow[t.weekday],t.yearday,buf1,buf2);
00888 failed++;
00889 }
00890 else if (convert_to_timestamp(buf1)!=ts)
00891 {
00892 output_test("FAILED: unable to convert %04d-%02d-%02d %02d:%02d:%02d %s (dow=%s, doy=%d) back to a timestamp\n from=%s, to=%s", t.year,t.month,t.day,t.hour,t.minute,t.second,t.tz,dow[t.weekday],t.yearday,buf1,buf2);
00893 output_test(" expected %" FMT_INT64 "d but got %" FMT_INT64 "d", ts, convert_to_timestamp(buf1));
00894 failed++;
00895 }
00896 else
00897 succeeded++;
00898 }
00899 else
00900 {
00901 output_test("FAILED: timestamp_test: unable to convert ts=%"FMT_INT64"d to local time", ts);
00902 failed++;
00903 }
00904 }
00905 output_test("END: round robin test",steptxt);
00906 output_test("END: daylight saving time tests for %d to %d", YEAR0, YEAR0+NYEARS);
00907 output_verbose("daylight saving time tests: %d succeeded, %d failed (see '%s' for details)", succeeded, failed, global_testoutputfile);
00908 return failed;
00909 }
00910