3

在我的应用程序中,我需要使用文件中描述的模式来计算班次。最近,在我的一位客户那里,由于以下原因,该应用程序被挂起:

如果您在冬季(非 DST)结束时的确切时刻填写“struct tm”,_mktime 似乎会返回不正确的结果。

代码如下所示:

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);

假设在 4 月 5 日 2:00 从冬季时间切换到夏季时间。在实践中,这意味着我们有以下时刻:

5 April, 1:58
5 April, 1:59
5 April, 3:00

由于我在应用程序中不知道 DST 何时开始或结束(我真的想知道这个吗?)我使用上面显示的代码将日期“4 月 5 日,2:00”传递给 _mktime64。

我希望 _mktime64 给我对应于 4 月 5 日 3:00 的 time_t 值(与 4 月 5 日 2:00 完全相同的时刻)。

然而,这不是正在发生的事情。_mktime64 将 tm_start 更改为 4 月 5 日 1:00 并返回相应的 time_t 值。这意味着我得到了一个完全不同的时刻。(实际上:2:00 到 3:00 之间的每一刻都会导致 _mktime64 返回 1:00 到 2:00 之间的一个时刻)

我认为这是 Visual Studio 2005 中的错误,但显然 Visual Studio 2010 (Release Candidate) 具有相同的行为。

该问题出现在 XP 和 Windows7 上(未检查 Vista)。

这是一个已知的错误?或者还有其他解决这个问题的技巧吗?

4

3 回答 3

3

这是使用当地时间而不是 UTC 的必然结果。DST 的结束也很糟糕,在转换过程中时间戳是矛盾的,因为本地时间匹配两次。

这很容易通过使用 UTC 来解决,这也是操作系统所做的。检查您的 CRT 实现,例如 _gmtime64() 或本机 GetFileTime()。

于 2010-03-04T14:30:07.280 回答
2

我想它根本不知道如何正确处理您传入的无效时间。而且对于您的时区肯定是无效的-您将其视为“冬天 1:59 后 1 分钟”,这意味着您希望它在 DST 恢复运行时返回“3:00”,这听起来很合理。但是,它同样可以将其视为“夏季 3:00 前一小时”,这意味着它必须来自冬季,因此返回“1:00”。因此,我不认为这是一个错误——它更有可能是关于如何处理不存在的时间的未定义行为。

我希望解决此问题的最安全方法是始终使用 UTC,因为这样就不会有歧义了。显然,这可能无法清晰地映射到您的应用程序域,但这就是时间来回推进的阴暗世界!

于 2010-03-04T15:19:16.810 回答
1

尝试将 5 April, 2:30 转换为 atime_t类似于尝试将 29 February 2011 转换为 a time_t。在这两种情况下,您都不期望得到有效结果,因为输入不是有效日期。4 月 5 日,甚至 2:00 都不存在。1:59.59 之后直接是 3:00:00

于 2010-03-04T11:58:24.373 回答