c++ - 确定夏令时是否适用于某个日期
问题描述
我正在尝试将文件的创建日期修改为发布日期。我首先将诸如“2 April 2005”之类的字符串转换为std::tm
. 然后我创建一个SYSTEMTIME
如下:
std::tm dt = from_string("2 April 2005");
SYSTEMTIME st { 0 };
st.wYear = dt.tm_year + 1900; // dt is years from 1900
st.wMonth = dt.tm_mon + 1; // dt is month index 0
st.wDay = dt.tm_mday;
st.wHour = 6; // FILETIME is based on UTC, which is 6 hours ahead
之后,我将其转换SYSTEMTIME
为 aFILETIME
并使用它来应用更改。
这将设置正确的文件时间2 April 2005 12:00:00 AM
。然而,4 月 2 日之后的视频被设置为1:00:00 AM
,果然,夏令时发生在 2005 年 4 月 3 日。
如何确定某个日期是在夏令时之前还是之后,以便进行st.wHour
相应调整?目标是将所有时间设置为12:00:00 AM
。最好这适用于可追溯到 60 年代和当前的日期。
我尝试使用TIME_ZONE_INFORMATION
,GetTimeZoneInformation
但我只回来了TIME_ZONE_ID_STANDARD
。
解决方案
一些东西:
SYSTEMTIME
只是一个简单的结构。它具有年、月、周几、日(月)、小时、分钟、秒和毫秒的单独字段。它既不是 UTC 也不是本地时间,也不是其他任何东西。在将其传递给函数之前,不会考虑到这一点。FILETIME
是另一种简单的结构。它表示自 1601-01-01 午夜以来的 100 纳秒间隔数。许多文档会让您认为它始终使用 UTC,但有类似的功能FileTimeToLocalFileTime
反驳了这一点。因此,就像 一样SYSTEMTIME
,由每个单独的函数来决定如何解释它。该
SystemTimeToFileTime
函数接受指向SYSTEMTIME
被解释为 UTC 的 a 的指针,并返回指向FILETIME
同样以 UTC 表示的 a 的指针。不涉及本地时区。不要尝试自己调整当地时间(
st.wHour = 6
在您的代码中)。小时需要根据时区和 DST 有所不同。GetTimeZoneInformation
除了 之外,您没有看到任何回复TIME_ZONE_STANDARD
,因为这会告诉您当前有效的内容 - 这与您可能正在使用的日期无关。您不应该试图弄清楚如何自己调整 DST。DST 并非普遍适用,而且并不总是一小时偏移。相反,请使用将您关心的时区转换为 UTC 的函数。
最终听起来你在问如何将文件时间设置为特定日期本地时区的午夜。因此,我建议您执行以下步骤:
SYSTEMTIME
使用您关心的日期和时间组件设置为零(默认值)构造 a 。GetDynamicTimeZoneInformation
使用该函数获取本地时区。您需要“动态”版本,以便考虑 Windows 知道的标准时间和 DST 规则的任何历史差异,而不仅仅是当前的规则集。将这两个值传递给
TzSpecificLocalTimeToSystemTimeEx
函数。它将输入时间解释为输入时区(这是系统的本地时区)。结果是以FILETIME
UTC 表示的。将该值传递给
SetFileTime
,它需要 UTC 格式的输入。
另外,请记住,并非所有文件系统都以相同的方式跟踪文件时间:
NTFS 存储实际的 UTC 时间,因此您可以在计算机之间移动文件,即使计算机具有不同的时区设置,时间戳也表示世界时的同一点。
FAT 及其变体存储本地时间。因此,当您调用 时
SetFileTime
,Windows 会从 UTC 转换为本地时区并写入结果。如果您随后在具有不同时区的系统上打开文件,则日期将在该时区中解释,从而导致不同的 UTC 时间。(在将文件从相机移动到计算机时,这种情况经常出现在 U 盘、存储卡等上。)
最后,你说:
...最好这适用于可追溯到 60 年代和当前的日期。
不幸的是,Windows 时区并没有跟踪那么远的历史日期。 Microsoft 的时区政策是跟踪 2010 年和地球上所有人口稠密地区的时区和 DST 规则。虽然,有几个时区会跟踪2010 年之前的一些历史变化,因为这是该政策正式制定之前的产物。(它们在给定区域内是准确的,只是在所有区域的起始年份不统一)。
如果历史日期对您的应用程序很重要,您将需要一种非常不同的方法 - 一种不使用 Windows 时区数据,而是使用IANA 时区数据库的方法。(有关时区标签 wiki 的更多信息。)以下是您可以探索的一些想法:
Howard Hinnant(他对上述问题发表了评论)有一个出色的Date 库,支持 IANA 时区。
或许可以从
Windows.Globalization.Calendar
UWP 类中获得您需要的东西。我还没有测试它是否会使用来自 IANA 数据的历史规则,或者它是否使用 Windows 数据。(如果我有机会检查,我会回来更新这个答案。)
请记住,IANA 数据库只保证从 1970 年开始。你说你需要从 1960 年开始,虽然有一些区域有数据(还有一些更早),但不能保证那个时期的正确性。
推荐阅读
- java - 没有互联网显示对话框
- php - 隐藏 URL 查询字符串 WordPress
- excel - 根据特定条件删除大量行(例如 ~500k 行)
- javascript - jQuery 下载适用于 Chrome 而不是资源管理器
- winforms - 如何防止状态栏覆盖我的 RichTextBox?
- github - 无法从 AWS EMR Jupyterhub 笔记本设置 Github 访问
- python - 如何将 Panda DataFrame 或 QTableWidget 转换为 Pdf?
- web - 我可以在没有互联网的情况下在本地托管网站吗
- javascript - 更简洁地编写 Google Apps 脚本声明
- java - Java 将 ET 时间转换为 UTC 时间 Oracle DB Timestamp