记住夏令时如何存储重复date

我在我的数据库中存储事件。 我有“开始”和“结束”的date时间,“tickets_start”和“tickets_end”(当售票实际开始/结束 – 而不是实际事件的开始/结束时)。

到目前为止,我已经构build了一些方法来完成所有有趣的function,例如在保存之前将date/时间转换为GMT,然后返回到各自的时区进行显示。

我将时区存储在类似“America / New_York”的值的varchar字段中。

但是 – 现在我需要开始处理,如果用户想要允许重复事件。 我之前做过,这不是什么大不了的事情,但从来没有跨越多个时区。

起初,我认为没什么大不了的,但后来才意识到,如果最初的开始date是七月份(例如),并且每月重复一年,在某个时间点,夏令时会使它所以从格林尼治标准时间的转换会有所不同。 一个月,当转换12:00,它会改变到-5,下一个,它会改变到-4,因为DST。

我目前的想法是,我将存储一个'dst'tinyint(1)是否在DST期间input了开始/结束date,然后制定方法在必要时将时间改变一个小时。

但是 – 我想在这里问,希望也许这是一个“正常的”或这是一个容易的东西,我没有想到。

(cakephp 2.4.x)

首先,请认识到,在现代术语中,你应该说UTC而不是GMT。 除了UTC更精确的定义以外,它们大部分是等效的。 保留“GMT”这一术语,指的是在冬季月份有UTC + 0偏移的英国时区部分。

现在你的问题。 UTC不一定是存储所有date和时间值的最佳方式。 这对于过去的事件或未来的绝对事件来说效果特别好,但对未来的地方事件 – 特别是未来的事件再次发生并不是那么有效。

我最近在另一个答案上写了这个,是当地时间比UTC更有意义的less数例外情况之一。 主要的观点是“闹钟问题”。 如果按UTC设置闹钟,则在DST转换当天早上或晚上醒来一小时。 这就是为什么大多数人在当地时间设置闹钟。

当然,如果您正在处理来自世界各地的数据,您不能只保存当地时间。 你应该存储一些不同的东西:

  • 经常性事件的当地时间,例如“08:00”
  • 当地时间表示的时区,如“America / New_York”
  • 重复模式以任何forms适用于您的应用程序,例如每天,每两周或本月的第三个星期四等。
  • 下一个即时 UTCdate和时间相当于最好的,你可以投影它。
  • 或许(但不总是)未来事件UTCdate和时间的列表,预计在未来的某个预定义的时间段内(也许是一个星期,也许是6个月,也许是一年或两年,这取决于你的需要)。

对于最后两个,理解如果负责该时区的政府决定改变任何事情,那么任何当地date/时间的UTC等值都可以改变。 由于每年都有多个时区数据库更新,因此您需要制定计划来订阅更新通知并定期更新您的时区数据库 。 每当您更新时区数据时,您都需要重新计算所有未来事件的UTC等效时间。

如果您计划显示跨越多个时区的任何types的事件列表,则具有UTC等效性非常重要。 这些是你将要查询build立该列表的值。

还有一点需要考虑的是,如果事件计划在DST回退转换期间发生的本地时间,则必须决定事件是发生在第一个实例(通常)还是第二个实例(有时)上,或两者(很less),并build立到您的应用程序的机制,以确保该事件不会触发两次,除非你想要它。

如果你正在寻找一个简单的答案 – 抱歉,但没有一个。 跨时区安排未来事件是一项复杂的任务。

替代方法

我有几个人向我展示了一种技术,他们使用UTC时间进行调度,即他们select当地时间的开始date,将其转换为UTC以存储,并存储时区ID。 然后,在运行时,他们应用时区将原始UTC时间转换回当地时间,然后使用该当地时间计算其他重现,就好像它是原始存储的一样。

虽然这种技术将起作用 ,但缺点是:

  • 如果有一个时区更新在第一个实例运行之前更改本地时间,则它将closures整个时间表。 这可以通过为“第一”实例select过去的时间来减轻,使得第二实例是第一实例。

  • 如果时间确实是应该跟随用户的“浮动时间”(例如手机闹钟),那么您仍然必须存储最初创build的区域的时区信息 – 即使那不是你想要跑的区域。

  • 它增加了额外的复杂性没有任何好处 我会保留这种技术的情况下,你可能有一个UTC的调度程序,你正在尝试改造时区支持。