Linux-x64 glibc: Why does Feb 1 come before Jan 31?
When you call mktime(), Feb 1 seems to come before Jan 31. Why is this? Am I doing something wrong or is this a bug in glibc?
Here's the code:
struct tm tm;
time_t tt;
memset(&tm, 0, sizeof(tm));
tm.tm_year = 2011;
tm.tm_mon = 1;
tm.tm_mday = 31;
tm.tm_hour = 11;
tm.tm_min = 41;
tm.tm_sec = 28;
tm.tm_isdst = 0;
tt = mkti开发者_如何转开发me(&tm);
printf("Time now %d-%d-%d %d:%d:%d (%s) = %lu\n",
tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone, tt);
memset(&tm, 0, sizeof(tm));
tm.tm_year = 2011;
tm.tm_mon = 2;
tm.tm_mday = 1;
tm.tm_hour = 1;
tm.tm_min = 1;
tm.tm_sec = 1;
tm.tm_isdst = 0;
tt = mktime(&tm);
printf("Time now %d-%d-%d %d:%d:%d (%s) = %lu\n",
tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone, tt);
And here's the output:
Time now 2011-2-3 11:41:28 (PST) = 61257325288
Time now 2011-2-1 1:1:1 (PST) = 61257114061
Note that the original intention was to compare two time_t's. This issue causes the first date/time to appear to be later than the second, which is obviously a bit of a problem.
This is just compiled with "gcc test.c" and run with "./a.out" on Ubuntu 9.10, gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu8), libc-2.10.1-0ubuntu15
On a 32-bit system the results are as expected - i.e. completely different to the 64 bit result!
Would anyone care to confirm/refute this result and/or give some insight into what I may be doing wrong?
tm_mon is zero-based, so you attempted to set February 31st, which got normalized. Here's a link to the definition of mktime().
Why does Feb 1 come before Jan 31?
Incorrect assignments to struct tm
members.
.tm_mon
is zero based
.tm_mon
is zero based@Jim Garrison.
// tm.tm_mon = 1;
tm.tm_mon = 1 - 1; // For January
.tm.tm_year
is 1900 based
// tm.tm_year = 2011;
tm.tm_year = 2011 - 1900;
time_t
print specifier
"%ld"
is not certainly the matching specifier for time_t
, thus incurring undefined behavior (UB). time_t
might not not even be an integer type. Recommend a cast to a wide signed type or this. Note that tt = mktime(&tm)
returns a -1 value on error, so useful to see -1 and not an unsigned value.
// printf("%lu\n", tt);
printf("%lld\n", (long long) tt);
.tm_isdst
mktime()
operates on local time. tm.tm_isdst = 0;
asserts the time stamp is standard time (reasonable for PST about January). Had this code been run in a timezone with daylight time in January (e.g. Wellington), the reported tm.tm_hour
may differ from expectations. Usually best to let mktime()
deduce .tm_isdst
. Otherwise finding the difference between timestamps (OP's higher goal) may shift an hour unexpectedly when spanning a DST change.
// tm.tm_isdst = 0;
tm.tm_isdst = -1; // DST information is not available, mktime will adjust.
tt = mktime(&tm)
精彩评论