我目前正在使用“localtime_s”函数,语法如下:
errno_t localtime_s (struct tm* _tm, const time_t *time);
我发现了一些奇怪的行为。 如果我们有智利、圣地亚哥时区,则对于不同的当前系统时间(在 Windows 控制面板上设置的时间),此函数返回“_tm”结构的不同“tm_isdst”字段(对于相同的“time”参数)。
换句话说,“localtime_s”为不同的系统时间提供了不同的 DST 转换日期(对于在“time”中传递的同一年)(DST 转换日期是“tm_isdst”字段值为“False”的日期和前一天) “tm_isdst”值为“True”,反之亦然)。
如果使用“time”参数传递的年份与系统时间中的年份相同,则总是正确的。但是,当系统时间的年份与“time”参数中的年份不同时,基于“localtime_s”函数返回的“tm_isdst”值的夏令时转换日期就会出错。
示例: 圣地亚哥,智利时区。 2014 年(通过“时间”参数)。第一次 DST 转换发生在 4 月 26 日至 27 日之间。 如果当前系统时间年份也是 2014 年,则一切正常 - “tm_isdst”对于 4 月 26 日为“True”,对于 4 月 27 日为“False”。 但如果系统时间年份是 2018 年,则对于小于 5 月 10 日的日期,“tm_isdst”将为“True”,并且仅从 5 月 11 日开始,它才变为“False”。这意味着“localtime_s”函数将 DST 转换日期视为 5 月 11 日,这是错误的。
另一个例子,如果系统年份是 2010 年,则来自“localtime_s”的 DST 转换日期(对于通过“time”参数传递的 2014 年)将为 4 月 6 日。 因此,我们在同一年获得了不同的 DST 过渡日期(但在 Windows 中设置了不同的年份)。
我不认为这是默认行为,因为:
- 我尝试在 google 上搜索“localtime_s”函数,但没有找到任何有关当前系统时间依赖性的信息,特别是在函数描述中。
- 我测试了其他时区的“localtime_s”(例如 UTC-8 太平洋时间(美国和加拿大)和 UTC+2 赫尔辛基、基辅、里加、索非亚、塔林、维尔纽斯),它与它们配合良好 - DST 过渡日期不依赖于当前系统时间。
- 我在 Linux 上测试了相同的“localtime_r”函数,它运行良好 - DST 转换日期也不依赖于当前系统时间(也适用于圣地亚哥时区)。
- 如果 Windows 系统时间为 2015 年,“lolaltime_s”函数会认为我们根本没有任何年份的 DST 转换(“tm_isdst”对于任何时间和任何年份始终为“True”)。从我的角度来看,这显然是错误的。
系统是 Windows Server 2012 R2 Standard,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 日。我在 2 个不同的操作系统(Windows 10 和 Windows Server 2012 R2)和 2 台不同的计算机上对此进行了测试,并得到了相同的结果。
最佳答案
看起来确实很奇怪。在 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
关于c - localtime_s取决于智利圣地亚哥时区的当前系统时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51368350/