用于确定日期是否在DST中的高效算法

时间:2009-12-16 04:31:27

标签: algorithm datetime timezone dst

我正在寻找比O(n)算法更好的方法来确定未来的日期是否会应用夏令时(以及多少)。给定年,月,日,小时,分钟和时区(以及Olsen时区数据库的副本)如何有效地确定该日期是否在DST中?我正在寻找算法,而不是要调用的库函数。

谢谢。

进一步说明:当您创建具有未来日期和时区的对象时,我正在使用的日期库非常慢。事实证明,它进行了线性计算,以计算日期是否为夏令时。不仅如此,它还在对象创建时执行此操作。显然它可以等到被问到,但它也应该更有效率。

当然,DST规则发生变化,日期库无法预测未来,但另一种方法是对本地化日期设置任意上限。

4 个答案:

答案 0 :(得分:1)

每个人都已经对持续改变DST的问题发表了评论。但我可以接受这样的前提:我们只是假装当前已知的规则将永远适用。

要获取您的DST信息,首先要做的是计算您未来日期的年/月/日(如果它不是那种形式)。然后,您查找时区并根据UTC,DST开/关规则和偏移量拉出变化。可能有几个不同的规则取决于哪一年,你想确保为你的“目标”年抓住正确的规则。由于下面解释的原因,也可以方便地了解前一年的规则。

开/关规则将有一个有趣的规格,如“Oct lastSun”:这意味着切换发生在十月的最后一个星期天的夜晚。

您需要做的是收集所有这些简洁格式的“规则”,并为每个规则开发一些代码,以确定该规则指示的最后日期。现在是十二月,所以考虑到我的时区的“Mar lastSun”和“Oct lastSun”等几条规则,这些日期将是2009年3月29日和2009年10月25日。哪些日期更近?十月。 10月与“关闭”相关联,因此我们目前必须没有DST。

无论目标日期是在这些日期之前还是之后,您都可以计算当前(即目标)年份的夏令时开/关日期;如果开/关日期是您目标日期的未来,则只需再次对上一年进行规则计算。请注意,规则可能在间隔期间发生了变化,因此请确保在您正在查看的年份中应用正确的规则。

此计算的最坏情况是,您必须重复上一年的两个规则计算。但是没有其他搜索,所以它严格来说是O(1)。

我在这里找到了一个Local / DST / Tz计算器:http://home-4.tiscali.nl/~t876506/WhatDay.html因为它是一个JavaScript小程序,你应该能够简单地编写代码。但它并不处理所有规则,因此您需要为剩余的规则添加一些代码。


更新:我刚刚注意到你的时间也只有一小时一分钟。这使问题变得复杂一点。如果您的日期不在“切换”日期,那么我上面给出的说明对您没问题。否则,你需要考虑时间。我想最干净的事情就是把时间包括在你决定“最近”的时候。即如果您的目标时间是00:30 UTC并且给定区域的切换时间是01:00,那么目标年份的切换时间仍然是未来,您必须使用上一年的切换时间。出于实际目的,这将意味着“其他”切换时间是最新的,并且其开/关状态适用。

答案 1 :(得分:0)

您的头号问题是由当地政府设定的夏令时规则。后者几乎可以在任何时候通过任何法律,因此以您无法预测的方式改变规则。

答案 2 :(得分:0)

据我所知,每年固定日开始和结束的DST变化(4月的第一个周末,10月的最后一个周末,类似的东西)。因此,您可以使用Doomsday Algorithm查找给定年份的星期几,并从中计算转换日期。然后,您可以确定DST是否在源和/或目标语言环境中有效。收敛本身只是添加和/或减去一小时以补偿DST然后考虑时区差异的问题。

答案 3 :(得分:0)

嗯,正如我所看到的那样,问题在于确定某一天的工作日,远在将来。

为此,我建议这样的事情:

  • 每400年后,整个系统就会转过来,所以首先将年数除以400,作为整体部分。 400年来,有99个闰年和301个简单的闰年。如果任意一天是星期一,那么400年后的同一天将是301 + 2x99 = 499(mod 7)--->星期一+ 2 --->星期三。所以你必须说出类似的话:
  

wday = (ref_day + 2 * (int)((target_year - ref_year) / 400)) mod 7

  • 然后你可以做进一步的优化,但我想你可以逐年进行,这样做。你最多可以进行399次简单操作,if(leap_year)然后++ else + = 2,mod 7。

当你在当年1月1日的工作日之后,你可以像Carl Smotricz所写的那样计算DST转换日期。