确定夏令时是否适用于特定日期

问题描述 投票:2回答:1

我正在尝试将文件的创建日期修改为发布日期。我首先将诸如“ 2005年4月2日”之类的字符串转换为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转换为FILETIME,并使用它来应用更改。

将文件时间设置为正确的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_INFORMATIONGetTimeZoneInformation,但我只得到了TIME_ZONE_ID_STANDARD

c++ windows datetime dst
1个回答
0
投票

几件事:

  • SYSTEMTIME只是一个简单的结构。它具有年,月,星期几,日(月),小时,分钟,秒和毫秒的单独字段。它既不是UTC时间也不是当地时间,也不是其他时间。除非将其传递给函数,否则不会考虑这一点。

  • FILETIME是另一个普通结构。它表示自1601-01-01午夜以来的100纳秒间隔数。许多文档会让您以为它始终使用UTC,但是有些函数FileTimeToLocalFileTime却证明了这一点。因此,像SYSTEMTIME一样,由每个函数决定如何解释它。

  • SystemTimeToFileTime函数接受指向被解释为UTC的SYSTEMTIME的指针,并返回也代表UTC的FILETIME的指针。不涉及本地时区。

  • 请勿尝试自己调整本地时间(代码中的st.wHour = 6)。小时将根据时区和夏令时而有所不同。

  • 除了GetTimeZoneInformation,您没有看到来自TIME_ZONE_STANDARD的任何响应,因为它告诉您当前正在执行的操作-与您可能正在使用的日期断开了连接。

  • 您不应该试图自己弄清楚如何调整DST。 DST并非普遍适用,并且并非总是偏移一小时。相反,请使用将您关心的时区转换为UTC的函数。

最终,听起来您正在询问如何将文件时间设置为特定日期的本地时区的午夜。因此,我建议您执行以下步骤:

  • 用您关心的日期构造一个SYSTEMTIME,并将时间分量设置为零(默认值)。

  • 使用GetDynamicTimeZoneInformation功能获取当地时区。您希望使用“动态”版本,以便考虑Windows知道的标准时间和DST规则中的任何历史差异,而不仅仅是当前的规则集。

  • 将这两个值传递给GetDynamicTimeZoneInformation函数。它将输入时间解释为处于输入时区(这是系统的本地时区)中。结果是以UTC表示的TzSpecificLocalTimeToSystemTimeEx

  • 将该值传递给TzSpecificLocalTimeToSystemTimeEx,后者期望输入的单位是UTC。

此外,请记住FILETIME

  • NTFS存储实际的UTC时间,因此即使计算机具有不同的时区设置,您也可以在计算机之间移动文件,并且时间戳记表示通用时间中的同一点。

  • FAT及其变体存储本地时间。因此,当您调用SetFileTime时,Windows会将UTC转换为本地时区并写入结果。如果随后在具有不同时区的系统上打开文件,则日期将在that时区中解释,从而导致不同的UTC时间。 (将文件从相机移动到计算机时,通常在USB记忆棒,存储卡等上看到这种情况。)

最后,您说:

...最好在日期可以追溯到60年代的日期,也可以在现在使用。

[遗憾的是,Windows时区无法跟踪到目前为止的历史日期。 not all file systems track file times in the same way将跟踪2010年的时区和DST规则,并转发地球上所有人口稠密的地方。虽然,一些时区跟踪2010年以前的历史变化,因为该政策正式制定之前的工件。 (它们在给定区域内是准确的,只是开始年份在所有区域内均不一致)。如果历史日期对您的应用程序很重要,则您将需要一种非常不同的方法-一种不使用Windows时区数据,而是使用SetFileTime的方法。 (有关这些内容的更多信息,请参见Microsoft's time zone policy。)以下是您可以探索的一些想法:

  • IANA time zone database具有时区支持和the timezone tag wiki。对于这个目的,它有点繁重,但是如果您将其用于应用程序的其他本地化方面,那就很好了。

  • Howard Hinnant(对上述问题发表评论的人)在支持IANA时区方面表现出色[ICU project
  • 可能可以从C implementation UWP类中获得所需的东西。我尚未测试过是否会使用IANA数据中的历史规则,或者是否会使用Windows数据。 (如果有机会检查,我会回来并更新此答案。)
  • 请记住,IANA数据库仅保证从1970年开始。您说过您需要从1960年开始,尽管有一些区域提供了该数据(并且还有一些更旧的数据),但不能保证该时期的正确性。

© www.soinside.com 2019 - 2024. All rights reserved.