Release: libc-2.2.5 Environment: Linux kernel 2.4.18 of Suse Linux 8.0 Host type: i486-suse-linux-gnu System: Linux gateway 2.4.18-4GB #1 Wed Mar 27 13:57:05 UTC 2002 i686 unknown Architecture: i686 Description: In a struct tm, if you set tm_mday=d to a value greater than 31, and you also set tm_hours=10, what sould that mean? In my opinion 10 o'clock local time, d-1 calendar days after the time that would have been specified if you had set tm_mday=1. So, after calling mktime, you should end up with a normalized time of tm_hour=10. But in fact, tm_hour may be changed by mktime if dayligt saving is in effect. Code: #include <ctime> #include <iostream> using namespace std; int main() { struct tm date; date.tm_sec=0; date.tm_min=0; date.tm_hour=10; // Here I want to set 10.00 on the date.tm_mday=150; // 150th day date.tm_mon=0; // of the year date.tm_year=2003-1900; // 2003. date.tm_wday=0; date.tm_yday=0; date.tm_isdst=0; time_t t=mktime(&date); // Normalize date and time. cout << "t=" << t << endl; cout << "mday=" << date.tm_mday << endl; cout << "mon=" << date.tm_mon << endl; cout << "yday=" << date.tm_yday << endl; cout << "isdst=" << date.tm_isdst << endl; cout << "gmtoff=" << date.tm_gmtoff << endl; cout << "zone=" << date.tm_zone << endl; cout << "hour=" << date.tm_hour << endl; // date.tm_hour should be always 10 (unchanged from the value preset // above) but in fact it is influenced by the daylight saving offset // in the TZ environment variable. E.g. if // TZ="TEST-1TESTDS-3,100,200", then date.tm_hour=12, which is not // what was intended. } Compilation: g++ mktime.cpp Result: mf@gateway:~/projects/bugreports/glibc_mktime> TZ="TEST-1TESTDS-2,100,200" ./a.out t=1054285200 mday=30 mon=4 yday=149 isdst=1 gmtoff=7200 zone=TESTDS hour=11 mf@gateway:~/projects/bugreports/glibc_mktime> TZ="TEST-1TESTDS-3,100,200" ./a.out t=1054285200 mday=30 mon=4 yday=149 isdst=1 gmtoff=10800 zone=TESTDS hour=12 I get hour=11 or hour=12 where I would expect hour=10. Obviously, glibc takes daylight saving into account somehow. The manual says in the mktime section: The `mktime' function ignores the specified contents of the `tm_wday' and `tm_yday' members of the broken-down time structure. It uses the values of the other components to determine the calendar time; it's permissible for these components to have unnormalized values outside their normal ranges. The last thing that `mktime' does is adjust the components of the BROKENTIME structure (including the `tm_wday' and `tm_yday'). But it does not describe exactly what an unnormalized value of tm_mday means. I would expect that tm_mday += 10 always means "The same local time, as specified in tm_hour, ten calendar days later". But in fact it means something like "The same local time, as specified in tm_hour, ten calendar days later, or, if tm_mday becomes greater than 31, exactly 10*24 hours later." So, if during these 10 days daylight saving changes, glibc changes tm_hour accordingly, which is wrong. Either this is a bug in glibc or the manual entry regarding the mktime function is unclear. I would vote for a bug because if you meant "exactly 10*24 hours later" you would have set tm_hour += 10*24. Thank you, Moritz
And now we try this again without C++. This is the C library. Everything related to C++ is ignored.
In C, the behavior of the program is the same. Code: #include <time.h> int main() { struct tm date; date.tm_sec=0; date.tm_min=0; date.tm_hour=10; // Here I want to set 10.00 on the date.tm_mday=150; // 150th day date.tm_mon=0; // of the year date.tm_year=2003-1900; // 2003. date.tm_wday=0; date.tm_yday=0; date.tm_isdst=0; time_t t=mktime(&date); // Normalize date and time. printf("t=%d\n",t); printf("mday=%d\n",date.tm_mday); printf("mon=%d\n",date.tm_mon); printf("yday=%d\n",date.tm_yday); printf("isdst=%d\n",date.tm_isdst); printf("gmtoff=%d\n",date.tm_gmtoff); printf("zone=%d\n",date.tm_zone); printf("hour=%d\n",date.tm_hour); // date.tm_hour should be always 10 (unchanged from the value preset // above) but in fact it is influenced by the daylight saving offset // in the TZ environment variable. E.g. if // TZ="TEST-1TESTDS-3,100,200", then date.tm_hour=12, which is not // what was intended. } Compiling: gcc mktime.c Result: jfranosc@koma:~/projects/bugreports/glibc_mktime> TZ="TEST-1TESTDS-2,100,200" ./a.out t=1054285200 mday=30 mon=4 yday=149 isdst=1 gmtoff=7200 zone=134520904 hour=11 jfranosc@koma:~/projects/bugreports/glibc_mktime> TZ="TEST-1TESTDS-3,100,200" ./a.out t=1054285200 mday=30 mon=4 yday=149 isdst=1 gmtoff=10800 zone=134520904 hour=12 Thank you for your fast response. Moritz
I think you also know that tm_mday is recommended to be specified in the range [1,31] (ex: SuSv3). And looking at SuSv3 mktime (line 25160): Local timezone information shall be set as though mktime( ) called tzset( ). The relationship between the tm structure (defined in the <time.h> header) and the time in seconds since the Epoch is that the result shall be as specified in the expression given in the definition of seconds since the Epoch (see the Base Definitions volume of IEEE Std 1003.1-200x, Section 4.14, Seconds Since the Epoch) corrected for timezone and any seasonal time adjustments, where the names in the structure and in the expression correspond. Upon successful completion, the values of the tm_wday and tm_yday components of the structure shall be 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 shall not be set until tm_mon and tm_year are determined. So I think adjusting with seasonal time (daylight saving time) is acceptable. BTW, I checked it on some OSes: FreeBSD 4.3: > TZ="TEST-1TESTDS-2,100,200" ./a.out t=1054285200 mday=30 mon=4 yday=149 isdst=1 gmtoff=7200 zone=672058865 hour=11 Solaris 7: > TZ="TEST-1TESTDS-2,100,200" ./a.out t=1054285200 mday=30 mon=4 yday=149 isdst=1 hour=11 They also seem "Epoch + seconds" based behavior.
"Upon successful completion, the values of the tm_wday and tm_yday components of the structure shall be 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 point is: What is the "specified time"? Or, what do users of mktime mean by 2004-01-32, 10:00? Is it 10:00 on 2004-02-01 or exactly 24 hours after 10:00 on 2004-01-31? I thought it should be 10:00 on 2004-01-02. Else, the behavior would be inconsistent: mday+=1 would sometimes mean "the same local time the next day" and sometimes "exactly 24 hours later". Moreover, if I specify 10:00 2004-02-31, e.g. in a video recording program, and am not aware that February has 30 only days, I mean 10:00 local time the next day and not 24 hours later. But as other OSs behave the same, the documentation should say cleary that you should not specify an mday out of range, although normalization takes place. This would be somewhat inconvenient, because you can not compute 10:00 on the 100th day of the year (you can not specify yday because it will be overwritten, and an out of range mday leads to +/- daylight saving hours). Moritz
The results are exactly right. The adjustment must be made because the isdst information and the date do not match. Just set isdst correctly and the 10 isn't changed.
Hello. Excuse me for posting a spam comment. But you have a very good site. And I really need this link. https://www.history-of-great-discoveries.com/