转换不存在的struct tm时的mktime问题(由于日光更改时间)

时间:2012-09-03 16:05:43

标签: windows dst mktime

我有一个mktime问题,如果由于DST更改而不存在小时,则使用MSVS 2010的Windows上的mktime将返回过去的time_t,在我的情况下为23:00,当它应该返回1:00 AM第二天(在Linux上,它应该在凌晨1点返回)。我的问题恰好发生在巴西时区(格林威治标准时间-3),恰好是自动调整夏令时的时间。在他们的情况下,这发生在2012年8月21日凌晨0点(这将是凌晨1点)。

这是代码的一部分:

/* test_date1.cpp : Defines the entry point for the console application.
*
*/
#include "StdAfx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

int _tmain(int argc, _TCHAR* argv[])
{

time_t mytime=1350784881;
struct tm *timeinfo;
char *tz;

/*time ( &mytime ); */
timeinfo = localtime ( &mytime );

printf("%.2d/%.2d/%.4d, %.2d:%.2d isdst?=%d\n", 
timeinfo->tm_mday, timeinfo->tm_mon, timeinfo->tm_year,  timeinfo->tm_hour, timeinfo-> tm_min, timeinfo -> tm_isdst);

timeinfo->tm_mday=21;
timeinfo->tm_mon=9;
timeinfo->tm_year=112;
timeinfo->tm_hour=0;
timeinfo->tm_min=0;
timeinfo->tm_isdst=-1;

printf("The shit: %.2d/%.2d/%.4d, %.2d:%.2d isdst?=%d\n", 
    timeinfo->tm_mday, timeinfo->tm_mon, timeinfo->tm_year,  timeinfo->tm_hour, timeinfo-> tm_min, timeinfo -> tm_isdst);

mytime= mktime(timeinfo);
printf("mytime is=%d\n", mytime);

timeinfo = localtime ( &mytime );

printf("%.2d/%.2d/%.4d, %.2d:%.2d isdst?=%d\n", 
    timeinfo->tm_mday, timeinfo->tm_mon, timeinfo->tm_year,  timeinfo->tm_hour, timeinfo-> tm_min, timeinfo -> tm_isdst);

return 0;
}

Windows上的结果是:

20/09/0112, 23:01 isdst?=0
21/09/0112, 00:00 isdst?=-1
mytime is=1350784800
20/09/0112, 23:00 isdst?=0

在Linux上是:

20/09/0112, 23:01 isdst?=0
21/09/0112, 00:00 isdst?=-1
mytime is=1350788400
21/09/0112, 01:00 isdst?=1

正如你所看到的,mytime diff在time_t从Unix返回C和从Microsoft Visual Studio 2010返回C之间的时间是3600秒。

这个程序应该在不同的平台(UNIX / WINDOWS / etc)和任何时区运行,所以我不应该对时区进行硬编码。

正如您所看到的那样,问题是在Windows上错误地返回时间。在这一刻我不知道如何解决这个问题。有人有这个特殊问题吗?你是怎么解决的?我特别需要瞄准当地日。

非常感谢,

Jokerush

1 个答案:

答案 0 :(得分:0)

我不知道当你传递一个无效的时间时是否定义了mktime的行为,所以这实际上可能不是一个bug。

无论如何,如果没有自己重新实施mktime,你需要解决这个问题。我提出以下算法:

  • 在当天上午9点建立一个struct tm。
  • 转换为time_t。
  • 从time_t减去24小时。

如果没有夏令时变化,那么此时您正在查看前一天上午9点。如果开始夏令时,你会看到早上8点;如果它完成了,你看的是上午10点。

  • 转换回struct tm。
  • 将struct tm中的日期与原始日期进行比较。
  • 如果还不是正确的日期,请在time_t上添加一小时,然后重试。

由于你一次只增加一个小时,一旦你得到你想要的日期,你可以确定你在那个日期有最早的时间。

我做了一些我认为目前安全的假设:夏令时永远不会开始或在一小时内完成,它永远不会在早上8点到早上10点之间开始或结束,并且永远不会超过一小时。

我故意假设夏令时从未开始或在晚上结束(例如,晚上11点变为午夜或反之亦然)或在清晨(例如,凌晨2点变为凌晨3点或副-versa,碰巧就是这里发生的事情)。