In my application I need to calculate shifts using a pattern described in a file. Recently, at one of my customers the application was hanging because of the following reason:
If you fill in a 'struct tm' with the exact moment at the end of the wintertime (non-DST) _mktime seems to 开发者_StackOverflow中文版return an incorrect result.
The code looks like this:
struct tm tm_start;
tm_start.tm_mday = startday;
tm_start.tm_mon = startmonth-1;
tm_start.tm_year = startyear-1900;
tm_start.tm_hour = starthour;
tm_start.tm_min = startmin;
tm_start.tm_sec = startsec;
tm_start.tm_isdst = -1; // Don't know if DST is active at this moment
_int64 contTime = _mktime64(&tm_start);
Suppose that there is a switch from winter- to summer-time on the 5th of April at 2:00. In practice, this means we have the following time-moments:
5 April, 1:58
5 April, 1:59
5 April, 3:00
Since I don't know in the application when DST starts or ends (do I really want to know this?) I pass the date "5 april, 2:00" to _mktime64 using the code shown above.
I would expect _mktime64 to give me the time_t value that corresponds to 5 April, 3:00 (which is exactly the same moment as 5 April, 2:00).
However, this isn't what's happening. _mktime64 changes tm_start to 5 April, 1:00 and returns the corresponding time_t value. Which means that I get a totally different moment. (in fact: every moment between 2:00 and 3:00 causes _mktime64 to return a moment between 1:00 and 2:00)
I thought this was a bug in Visual Studio 2005, but apparently Visual Studio 2010 (Release Candidate) has the same behavior.
The problem appears on both XP and Windows7 (didn't check Vista).
Is this a known bug? Or are there other tips to tackle this problem?
This is an inevitable consequence of working with local time instead of UTC. The end of DST is a doozy too, timestamps are ambivalent during the change-over since local time matches two times.
This is easily solved by working with UTC instead, that's what the operating system does as well. Check your CRT implementation, something like _gmtime64() or the native GetFileTime().
I guess it simply doesn't know how to correctly handle the invalid time you pass in. And it is certainly invalid for your time zone - you're thinking of it as '1 minute after 1:59 in the winter' implying that you wanted it to return '3:00' with DST back in operation, which sounds reasonable. However it could equally well treat it as 'an hour before 3:00 in the summer' meaning it must have been from the winter period and thus returns '1:00'. Thus I don't think it's a bug - it's more likely to be undefined behaviour about how to handle a non-existent time.
I expect the safest way to approach this is to use UTC throughout as then there are no ambiguities. Obviously this may not map cleanly to your application domain, but such is the murky world of pushing time backwards and forwards!
Trying to convert 5 April, 2:30 to a time_t
is similar to trying to convert 29 February 2011 to a time_t
. In neither case do you expect a valid result, because the input is not a valid date. On April 5th, even 2:00 doesn't exist. 1:59.59 is followed directly by 3:00:00
精彩评论