bug in mktime() normalization?
Hi all, I've been looking over the time zone package and testing various scenerios. In mktime(), or rather time2(), I noticed that a change was made a while back which removed the following seconds normalization: ! if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0) ! normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN); Instead, these seconds are now saved aside into saved_seconds and only added back in after an appropriate match is found using the remaining normalized data. The question I have is whether this could lead to erroneous rejection of certain tm structs. For example: If the values (other than tm_sec) of an incoming tm struct result in no match from time2()'s binary search, such as a time between a dst change, the struct is rejected and the function returns WRONG. However, the value of tm_sec may have been large enough to push the rest of my tm struct into an acceptible range where a match could have occurred. As with other tm struct members, the value of tm_sec before normalization is not restricted to the range specified in <time.h>. Here's what UNIX98 has to say regarding this:
The mktime() function converts the broken-down time, expressed as local time, in the structure pointed to by timeptr, into a time since the Epoch value with the same encoding as that of the values returned by time(). The original values of the tm_wday and tm_yday components of the structure are ignored, and the original values of the other components are not restricted to the ranges described in the <time.h> entry.
...
Upon successful completion, the values of the tm_wday and tm_yday components of the structure are set appropriately, and the other components are set to represent the specified time since the Epoch, but with their values forced to the ranges indicated in the <time.h> entry; the final value of tm_mday is not set until tm_mon and tm_year are determined.
Here's an example program: #include <stdio.h> #include <time.h> #include <stdlib.h> void display_tm(void); void run_test(); struct tm tm; time_t mktime_returned; #define TZ_value "ABC0DEF,J81,J300" #define TM_year 1988 #define TM_mon 3 #define TM_mday 22 #define TM_hour1 2 #define TM_hour2 4 #define TM_min 0 #define TM_sec1 7200 #define TM_sec2 0 #define TM_wday -1 #define TM_yday -1 #define TM_isdst -1 main() { putenv("TZ=ABC0DEF,J81,J300"); printf("TZ = %s\n\n", getenv("TZ")); /* same time as below, but tm_hour and tm_sec have not yet been * normalized */ tm.tm_year = TM_year - 1900; tm.tm_mon = TM_mon - 1; tm.tm_mday = TM_mday; tm.tm_hour = TM_hour1; /* un-normalized hour */ tm.tm_min = TM_min; tm.tm_sec = TM_sec1; /* un-normalized seconds */ tm.tm_wday = TM_wday; tm.tm_yday = TM_yday; tm.tm_isdst = TM_isdst; run_test(); printf("\n"); /* same time as above, but tm_hour and tm_sec have already been * normalized */ tm.tm_year = TM_year - 1900; tm.tm_mon = TM_mon - 1; tm.tm_mday = TM_mday; tm.tm_hour = TM_hour2; /* pre-normalized hour */ tm.tm_min = TM_min; tm.tm_sec = TM_sec2; /* pre-normalized seconds */ tm.tm_wday = TM_wday; tm.tm_yday = TM_yday; tm.tm_isdst = TM_isdst; run_test(); } void run_test(void) { printf("tm struct set to:\n"); display_tm(); if ((mktime_returned = mktime(&tm)) == (time_t)-1) { (void)puts("mktime returned -1 (-unknown-)"); } else { printf("mktime returned value = %d\n", (int) mktime_returned); } printf("mktime() final tm struct reset to:\n"); display_tm(); } void display_tm(void) { printf("tm_year = %d, tm_mon = %d, tm_mday = %d, tm_hour = %d, \ tm_min = %d, sec = %d,\nwday = %d, yday = %d, isdst = %d\n", tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday, tm.tm_yday, tm.tm_isdst); } output ====== $ a.out TZ = ABC0DEF,J81,J300 tm struct set to: tm_year = 88, tm_mon = 2, tm_mday = 22, tm_hour = 2, tm_min = 0, sec = 7200, wday = -1, yday = -1, isdst = -1 mktime returned -1 (-unknown-) mktime() final tm struct reset to: tm_year = 88, tm_mon = 2, tm_mday = 22, tm_hour = 2, tm_min = 0, sec = 7200, wday = -1, yday = -1, isdst = -1 tm struct set to: tm_year = 88, tm_mon = 2, tm_mday = 22, tm_hour = 4, tm_min = 0, sec = 0, wday = -1, yday = -1, isdst = -1 mktime returned value = 575002800 mktime() final tm struct reset to: tm_year = 88, tm_mon = 2, tm_mday = 22, tm_hour = 4, tm_min = 0, sec = 0, wday = 2, yday = 81, isdst = 1 $ I would very much appreciate any thoughts concerning this matter and any possible solutions. thanks, - Tom ===================================================================== Tom Peterson | DIGITAL UNIX Development Environment Digital Equipment Corporation | Phone:(603)884-7550 110 Spit Brook Road ZKO3-2/W17 | FAX:(603)881-2257 Nashua, NH 03062-2698 | Email: mailto:tomp@zk3.dec.com
participants (1)
-
Tom Peterson