How to get daylight saving status of another time zone
假设我的Windows服务器应用程序在东部时区(NY)运行。
我将每个日期时间事件(发生的时刻)转换并存储为UTC格式,这样任何连接到服务器的客户机应用程序都可以读取事件的UTC时间,并将其转换并显示在客户机自己的TZ中。
但这里有一个棘手的部分,一些事件在另一个州的时间报告它们的时间戳,并且没有明确指定夏令时信息(例如,xx:xx:xx am pt,意思是太平洋时间,但我不知道它当前是否在夏令时)。
服务器可以检查它是否在夏令时,但这将是服务器自己的TZ(东部时间)。我能想到的最好办法是读取服务器的本地日光节约信息,并将其用于PT,但我知道这不是100%准确。尤其是当ET刚刚开始(或停止)使用日光节约时,PT还有几个小时可以这样做时,通过短窗口。
现在我的问题是,有没有一种方法(在Windows API中)可以准确地了解另一个时区的夏令时状态,无论服务器应用程序位于哪个时区?
编辑:好的,我如何将它从东部时间运行的Windows计算机转换为UTC"Sun,Mar 13,2016,1:15 am pt"?(注意,当正在运行的机器(在ET中)在此时处于DST中,并且要转换的日期/时间不只是在DST中时,特别选择的日期/时间。我已经介绍了UTC转换,但无法确定给定的日期/时间是否为DST。
- 前面的问题有帮助吗?
- 如何在应用程序中标识时区?如果你只有像PT这样的缩写,你可能会发现这非常困难或不可能。这些输入是否仅限于某些固定值集?或者它们真的是什么?
- @MattJohnson通常是HTTP标准日期/时间字符串(实际上包含DST信息,例如,如果DST处于活动状态,则为xx:xx:xx AM PST或PDT),但有些服务器不太慷慨地提供DST信息,只说是pt(pasific time),让您了解pt是否在给定的日期/时间处于DST中。系统(Windows)应该知道这一点,因为它在3月和11月的第2、1个星期日调整系统时钟,并且可以向用户提供API。
- 更糟糕的是,夏令时的开始和结束日期/时间因国家而异(见鬼,即使美国的一些州也有不同的看法,夏威夷和亚利桑那州没有夏令时)。因此,对于应用程序来说,确定给定的日期/时间是否采用DST将是一项非常艰巨的工作,但是底层操作系统很容易向应用程序提供这些信息,因为它们已经为每个国家和时区提供了内置的数据库。
- 是的,我对时区了如指掌。检查我的个人资料。;我要问的是,对于你的应用程序,是否有一致的输入形式?您是否专门使用RFC822/2822样式的输入字符串以及它所允许的有限时区缩写?或者这是任意的随机输入?注意,PST和PDT是该规范的一部分(在HTTP头中使用),但PT不是。请准确点。谢谢。
- 问另一种方式,你只是在寻找关于可用的API的信息来在时区之间转换时间吗?如果是这样的话,它还可以帮助您了解您是在寻找Windows解决方案还是Linux/Mac解决方案,还是跨平台解决方案,等等,而且,您是否已经搜索过了?你发现了什么?什么不起作用?关于这个主题已经有很多文章了。
- Matt,我的输入字符串以前是符合RFC的,直到最近。例如,Amazon.com不久前就开始使用pt而不是pst/pdt。我只需要Windows的解决方案。我搜索了几小时(不是几天),发现在Windows上这样做是不可能的,不必编写自己的代码,它有自己的时区数据库(如果不是州到州,需要定期从一个国家更新到另一个国家)
- 看起来这是WindowsAPI所缺少的(而Linux/Mac有一个解决方案),尽管它记录了每个国家和每个州的时区开始和结束日期。如果当地法律决定更改时区规则,也会定期通过Windows Update进行更新。顺便说一句,马特,这是一个很酷的形象;-)
Windows的时区数据实际存储在注册表中:
1 2 3 4 5 6
| HKLM
SOFTWARE
Microsoft
Windows NT
CurrentVersion
Time Zones |
"时区"实际上是两个词。
每个时区都有自己的子键,每个子键都有一个TZI值,它是一个二进制REG_TZI_FORMAT结构:
1 2 3 4 5 6 7 8
| typedef struct _REG_TZI_FORMAT
{
LONG Bias;
LONG StandardBias;
LONG DaylightBias;
SYSTEMTIME StandardDate;
SYSTEMTIME DaylightDate;
} REG_TZI_FORMAT; |
两个相关的结构成员是StandardDate和DaylightDate。
有关详细信息,请参阅msdn:时区信息
- @雷米:我添加了这个链接以避免复制微软的代码,这两个代码都有可能是版权保护的,并且没有清晰地标明"合理使用"准则。
- 这与我的问题无关。注册表只是Windows向用户显示时区信息以便他们设置计算机时区的地方。我需要的是找出另一个州(或国家)目前是否在DST。
- 它提供了你需要的信息来解决这个问题。DaylightDate的SYSTEMTIME的成员拥有你所需要的。
- 这是我的Windows'Tzi在Pasific Time LONG Bias = 480 (minutes, which is correct) LONG StandardBias = 0 LONG DaylightBias = -60 SYSTEMTIME StandardDate = { WORD wYear = 0 WORD wMonth = 11 WORD wDayOfWeek = 0 WORD wDay = 1 WORD wHour = 2 WORD wMinute = 0 WORD wSecond = 0 WORD wMilliseconds = 0 } SYSTEMTIME DaylightDate = { WORD wYear = 0 WORD wMonth = 3 WORD wDayOfWeek = 0 WORD wDay = 2 WORD wHour = 2 WORD wMinute = 0 WORD wSecond = 0 WORD wMilliseconds = 0 }中的应用。
- 如您所见,StandardDate和DaylightDate结构成员没有反映正确的DST开始和结束日期。
- @布莱恩霍克:做更多的研究。
我不确定Windows API,但一般来说,您要做的是调用mktime,远程时间的Tz值有效。在UNIX下,您可以直接调用setenv("TZ", whatever)来完成此操作。对窗户不太确定,但我想你也可以在那里做同样的事情。
如果除了mktime和timegm之外,还有一个变量允许您明确指定要使用的区域(而不是将tz环境变量视为全局变量),但这种变量不是标准的,那当然会很好。
在转换不知道DST是否有效的本地时间时,请记住将tm_isdst设置为-1,以便库可以为您解决问题。
下面是一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main ()
{
struct tm tm = {0};
time_t t ;
tm. tm_hour = 12; tm. tm_min = 30, tm. tm_sec = 15; /* 12:30:15 */
tm. tm_year = 2005-1900; tm. tm_mon = 4-1; tm. tm_mday = 12; /* 2005-04-12 */
tm. tm_isdst = -1;
setenv ("TZ","America/Los_Angeles", 1);
t = mktime(&tm );
setenv ("TZ","America/New_York", 1);
printf("%ld = %.24s
", t , ctime(&t ));
} |
这告诉您,洛杉矶时间12:30:15对应于Unix(UTC)时间1113334215和纽约时间15:30:15。
附录:这对Windows也没有帮助,但是如果您不喜欢每次需要在不同时区处理时间时从程序内部设置一个环境变量,请查看是否可以使用BSD函数tzalloc、localtime_rz和mktime_z。
- 小贴士:最好在调用mktime()之前完全填满struct tm,比如struct tm tm = {0};。该函数使用除tm_wday, tm_yday和struct tm以外的所有字段,这些字段可能比通常的9个字段多。
- @祝你一路顺风,一路顺风。
- 你真的在Windows上运行过这个代码吗?根据我的经验,Windows不关注TZ环境变量。这是一种姿势。有关此主题的先前处理,请参阅Windows程序如何临时更改其时区?
- @RobKennedy不,我在MacOS上测试过。我有一个想法,这个或类似的东西在窗户上是可能的,但我可能是错的。
- @SteveSummit感谢您的工作和回答,但不幸的是,它不适用于Windows。(同样,在系统中设置全局env变量是否也会影响其他程序?,或者该更改只是当前程序的本地更改?)
- 环境变量是进程的局部变量,至少在UNIX/Linux中是如此。