localtime_s取决于智利,圣地亚哥时区的当前系统时间

时间:2018-07-16 18:48:42

标签: c windows localtime

我目前正在使用“ localtime_s”功能,语法如下:

errno_t localtime_s (struct tm* _tm, const time_t *time);

我发现了一些奇怪的行为。 如果我们具有智利圣地亚哥时区,则此函数针对不同的当前系统时间(在Windows“控制面板”上设置的时间),返回“ _tm”结构的不同“ tm_isdst”字段(对于相同的“ time”参数)。 >

换句话说,“ localtime_s”为我们提供了不同的系统时间(DST转换日期是“ tm_isdst”字段值为“ False”的日期和前一天)的不同DST转换日期(“时间”中传递的同一年份) “ tm_isdst”的值为“ True”,反之亦然)。

如果通过“ time”参数传递的年份与系统时间中的年份相同,则总是正确的。但是,当系统时间的年份与“时间”参数中的年份不同时,基于“ localtime_s”函数返回的“ tm_isdst”值的DST转换日期将变为错误。

示例: 智利圣地亚哥时区。 2014年(通过“时间”参数传递)。 DST的第一次转换是在4月26/27日之间。 如果当前系统时间年份也是2014,则一切正常-4月26日“ tm_isdst”为“ True”,4月27日为“ False”。 但是,如果系统时间年份为2018,则对于不等于5月10日的日期,“ tm_isdst”将为“ True”,仅从5月11日起,它将变为“ False”。这意味着“ localtime_s”函数将DST转换日期视为5月11日,这是错误的。

另一个示例,如果系统年份为2010,则“ localtime_s”的DST转换日期(2014年使用“ time”参数传递)将为4月6日。 因此,我们在同一年(但Windows中设置的不同年份)获得了不同的DST过渡日期。

我不认为这是默认行为,因为:

  1. 我尝试使用Google的“ localtime_s”函数,但没有找到有关当前系统时间相关性的任何信息,特别是在函数描述中。
  2. 我在其他时区(例如UTC-8太平洋时间(美国和加拿大)和UTC + 2赫尔辛基,基辅,里加,索非亚,塔林,维尔纽斯)测试了“ localtime_s”,并且与它们配合得很好-DST转换日期不依赖于当前系统时间。
  3. 我在Linux上测试了相同的“ localtime_r”功能,并且运行良好-DST转换日期也不取决于当前系统时间(也适用于圣地亚哥时区)。
  4. 如果我们在Windows系统时间为2015年,则“ lolaltime_s”函数认为我们完全没有任何DST转换(“ tm_isdst”在任何时间和任何年份始终为“ True”)。在我看来,这显然是错误的。

系统是Windows Server 2012 R2 Standart,x64。

能否请您说出导致此问题的原因?这是“ localtime_s”功能错误吗?

P.s。以下是一些来自系统年份的DST过渡日期依赖性的示例:

DST transition dates, Santiago, 2014 system time year

DST transition dates, Santiago, 2018 system time year

DST transition dates, Santiago, 2020 system time year

P.p.s。这是一个简单的示例进行测试(抱歉,在包含之前遗漏了“#”,stackoverflow不想使用该符号保存我的帖子):

include <iostream>
include <time.h>

int main()
{
    time_t t_26_Apr = 1398517200;                   // 26-Apr-2014
    time_t t_27_Apr = 1398517200 + 24 * 3600;       // 27-Apr-2014
    time_t t_10_May = 1398517200 + 14 * 24 * 3600;  // 10-May-2014
    time_t t_11_May = 1398517200 + 15 * 24 * 3600;  // 11-May-2014
    tm tm_26_Apr;
    tm tm_27_Apr;
    tm tm_10_May;
    tm tm_11_May;

    localtime_s(&tm_26_Apr, &t_26_Apr);
    localtime_s(&tm_27_Apr, &t_27_Apr);
    localtime_s(&tm_10_May, &t_10_May);
    localtime_s(&tm_11_May, &t_11_May);

    std::cout << "26-Apr-2014 DST status is:\t" << tm_26_Apr.tm_isdst << std::endl;
    std::cout << "27-Apr-2014 DST status is:\t" << tm_27_Apr.tm_isdst << std::endl;
    std::cout << "10-May-2014 DST status is:\t" << tm_10_May.tm_isdst << std::endl;
    std::cout << "11-May-2014 DST status is:\t" << tm_11_May.tm_isdst << std::endl;

    return 0;
}

2014年圣地亚哥实际DST转换日期为4月26/27日午夜。但是如果Windows系统时间年份为2018,过渡日期为5月10/11。我在2个不同的操作系统(Windows 10和Windows Server 2012 R2)和2个不同的计算机上对此进行了测试,并得到了相同的结果。

1 个答案:

答案 0 :(得分:0)

确实看起来很奇怪。在Windows 10上,我检查了圣地亚哥的日期。 2014年和2016年的夏令时日期不同。 2015年完全没有信息(该年可能没有夏令时),这些日期会随着时间的变化而变化。对于美国和加拿大的大部分地区,这种情况在2007年也发生了变化。夏令时的概念一开始就毫无用处,各国政府经常无缘无故地采用这种做法。除了依赖操作系统之外,您无能为力。尽可能使用UTC在内部存储时间,然后转换为本地时间以进行输出。

#include <stdio.h>
#include <Windows.h>

int main()
{
    for(int year = 2014; year < 2020; year++)
    {
        TIME_ZONE_INFORMATION tz;
        GetTimeZoneInformationForYear((USHORT)year, NULL, &tz);

        printf("Year %d, bias: %d\n", year, tz.Bias);
        printf("Standard: %02d/%02d %02d:%02d\n",
            tz.StandardDate.wMonth, tz.StandardDate.wDay,
            tz.StandardDate.wHour, tz.StandardDate.wMinute);

        printf("Daylight: %02d/%02d %02d:%02d\n\n",
            tz.DaylightDate.wMonth, tz.StandardDate.wDay,
            tz.DaylightDate.wHour, tz.DaylightDate.wMinute);
    }

    return 0;
}

输出:

Year 2014, bias: 240
Standard: 04/05 23:59
Daylight: 09/05 23:59

Year 2015, bias: 180
Standard: 00/00 00:00
Daylight: 00/00 00:00

Year 2016, bias: 240
Standard: 05/02 23:59
Daylight: 08/02 23:59

Year 2017, bias: 240
Standard: 05/02 23:59
Daylight: 08/02 23:59

Year 2018, bias: 240
Standard: 05/02 23:59
Daylight: 08/02 23:59

Year 2019, bias: 240
Standard: 05/02 23:59
Daylight: 08/02 23:59