首先,请认识到,在现代术语中,您应该说 UTC 而不是 GMT。它们大多是等效的,只是 UTC 的定义更精确。保留术语“GMT”来指代英国冬季有效的时区部分,偏移量为 UTC+0。
现在回答你的问题。 UTC 不一定是存储所有日期和时间值的最佳方式。它特别适用于past事件,或未来absolute事件,但对未来来说效果不太好local事件——尤其是未来再次发生的 events.
我写过这个在另一个答案上 https://stackoverflow.com/a/19170823/634824最近,这是本地时间比 UTC 更有意义的少数例外情况之一。主要争论点是“闹钟问题”。如果您按照 UTC 设置闹钟,您将在 DST 转换当天提前或晚起一小时。这就是为什么大多数人按当地时间设置闹钟的原因。
当然,你不能just如果您正在处理来自世界各地的数据,请存储当地时间。你应该存储一些不同的东西:
- 重复事件的当地时间,例如“08:00”
- 当地时间表示的时区,例如“America/New_York”
- 重复模式,采用对您的应用程序有意义的任何格式,例如每天、每两周或每月的第三个星期四等。
- 下一个即时UTC 日期和时间相当于您可以预测的最佳时间。
- 也许(但并非总是)未来事件 UTC 日期和时间的列表,预测了未来的某个预定义时期(可能是一周,可能是 6 个月,可能是一两年,具体取决于您的需要)。
对于后两个,请了解,如果负责该时区的政府决定更改任何内容,则任何本地日期/时间的 UTC 等效值都可能会更改。由于每年都会有多个时区数据库更新,因此您需要制定一个计划订阅更新公告 https://mm.icann.org/mailman/listinfo/tz-announce and 更新您的时区数据库 http://pecl.php.net/package/timezonedb经常。每当您更新时区数据时,您都需要重新计算所有未来事件的 UTC 等效时间。
如果您计划显示跨越多个时区的任何类型的事件列表,那么拥有 UTC 等效值非常重要。这些是您将查询以构建该列表的值。
需要考虑的另一点是,如果事件安排在 DST 回退过渡期间发生的当地时间,您将必须决定该事件是发生在第一个实例(通常)还是第二个实例(有时),或两者(很少),并在您的应用程序中构建一种机制,以确保事件不会触发两次,除非您愿意。
如果您正在寻找一个简单的答案 - 抱歉,但没有。跨时区安排未来的活动是一项复杂的任务。
替代方法
有几个人向我展示了一种技术,他们可以do使用 UTC 时间进行调度,即选择本地时间的开始日期,将其转换为 UTC 进行存储,并存储时区 ID。然后在运行时,他们应用时区将原始 UTC 时间转换回本地时间,然后使用该本地时间来计算其他重复时间,就好像它是最初存储的时间一样。
虽然这项技术将work,其缺点是:
如果在第一个实例运行之前发生时区更新更改了本地时间,则会打乱整个计划。这可以通过为“第一个”实例选择过去的时间来缓解,这样第二个实例实际上是第一个实例。
如果时间确实是一个应该跟随用户的“浮动时间”(例如手机上的闹钟),您仍然必须存储它最初创建的区域的时区信息 - 即使那不是你想要跑步的区域。
它增加了额外的复杂性,但没有任何好处。我会保留这种技术,用于您可能拥有仅 UTC 调度程序并试图改进时区支持的情况。