给定日期/时间作为字符串,知道当时是不是是 DST 的最佳方法是啥?
Posted
技术标签:
【中文标题】给定日期/时间作为字符串,知道当时是不是是 DST 的最佳方法是啥?【英文标题】:Given a Date/Time as a string, what is the best way to know if it was DST at that time?给定日期/时间作为字符串,知道当时是否是 DST 的最佳方法是什么? 【发布时间】:2012-03-13 06:23:04 【问题描述】:假设给了我这样一个字符串:"2009-4-9"
,表示 2009 年 4 月 9 日。假设首先,我只关心本地时间(我也关心其他时区,但我'将首先解决简单的事情)。了解夏令时是否在当时有效的最佳方式是什么?
您可以假设系统具有正确更新的时区文件,例如/etc/localtime
,并且我对便携式解决方案感兴趣。 c 或 c++ 都可以接受。
你也可以假设我只关心过去或现在的日期,而不关心未来。
目前我有一个看起来像这样的“hack”(我知道 localtime_r 是一个库扩展,但它与我可以使其便携的相同功能足够接近)
struct tm tm;
// convert the time string to a broken down structure in localtime
if(strptime("2009-4-9", "%Y-%m-%d", &tm))
// convert the broken down structure into seconds since epoch
const time_t t = mktime(&tm);
// convert it back to a broken down structure, this seems pointless at first...
// but libc will fill out fields such as tm_isdst
localtime_r(&t, &tm);
printf("DST : %d\n", tm.tm_isdst);
虽然这行得通(而且似乎是一种非常有效的方法),但我觉得来回转换很愚蠢。有没有更好的办法?
【问题讨论】:
您关心一天中的什么时间?它可能是一天开始时的一个偏移量和一天结束时的另一个偏移量...... @JonSkeet:好问题,您可以假设一天中的任何时间。我敢肯定这会使问题进一步复杂化......实际上,标准工作时间左右的时间是常见的用例。 【参考方案1】:您根本不需要致电localtime_r()
。 mktime()
规范化您传递的 struct tm
,包括将 tm_isdst
设置为非负值,如果它被传递到 -1
。所以你只需要:
struct tm tm = 0 ;
// convert the time string to a broken down structure in localtime
if(strptime("2009-4-9", "%Y-%m-%d", &tm))
tm.tm_isdst = -1;
// normalise the broken down structure - this calculates tm_isdst
mktime(&tm);
printf("DST : %d\n", tm.tm_isdst);
mktime()
的这种行为是 C 标准所要求的;例如,C99 说:
mktime
函数转换故障时间,表示为 当地时间,在timeptr
指向的结构中放入日历 与返回的值具有相同编码的时间值time
函数。tm_wday
的原始值和tm_yday
结构的组件被忽略了,原来的 其他组件的值不限于范围 如上所述。276 成功完成后, 设置了结构的tm_wday
和tm_yday
组件 适当地,并且其他组件被设置为代表 指定的日历时间,但其值强制为范围 如上所示;tm_mday
的最终值直到tm_mon
和tm_year
已确定。
脚注 276 明确指出 tm_isdst
成员:
276) 因此,
tm_isdst
的正值或零值会导致mktime
函数分别假设夏令时, 在指定时间内是否有效。负值导致 它试图确定夏令时是否有效 指定时间。
【讨论】:
这是记录和/或标准行为吗?还是只是副作用?如果这是标准行为,请分享您的来源。 @EvanTeran:C标准要求;我已更新答案以包含相关部分。【参考方案2】:从 UTC 到本地时间的转换不是可逆函数。例如,在秋季,当时钟跳回一小时时,当地时间 02:00 和 03:00 之间会出现两次。给定此时间间隔内的时间,无法确定本地时间是在本地 daylight 时间的特定 UTC 时间,还是在本地 的一小时后发生标准时间。
【讨论】:
这个问题似乎只涉及日期,我认为这将是该日期的午夜。我认为 DST 过渡特别避开了午夜。 这是一个我没有想到的好点。出于我的需要,这可能被认为是可接受的情况,因为所讨论的时间通常在工作时间左右。 @MarkRansom:再想一想。例如,巴西的过渡时间是在午夜。你不应该假设午夜总是存在 - 或者它只发生一次。 @MarkRansom:不幸的是,我也担心时间问题。 :-/ @MarkRansom:我刚刚通过 Noda Time 运行了那个“查询”,有一些例子,是的。朱巴和喀土穆都在 2000 年 1 月 15 日下午 1 点进行了过渡。那是最接近中午的时间,但还有很多其他的例子,人们会醒着。例如,复活节岛的过渡时间看起来像是当地时间晚上 10 点->11 点和晚上 10 点->9 点。【参考方案3】:我之前在 C 语言中进行过多次转换,我认为您几乎可以按照我的方式进行转换。据我所知,localtime_r 及其亲属可能是您唯一的选择(除非有一些第三方日期库。)当然,Greg Hewgill 对于时间切换之间的“灰色时间”是正确的。
【讨论】:
以上是关于给定日期/时间作为字符串,知道当时是不是是 DST 的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
如何确定给定时区中的给定时间是不是在postgresql中是DST?