首先,请注意,在现代术语中,您应该说UTC而不是GMT。它们大多是等效的,除了UTC的定义更精确。保留术语 GMT,以指在冬季生效的英国时区中偏移量为 UTC+0 的部分。
现在回答你的问题。UTC 不一定是存储所有日期和时间值的最佳方式。它对于过去的事件或未来的绝对事件特别有效,但对于未来的本地事件(尤其是未来的重复事件)却不是那么有效。
我最近在另一个答案上写了关于这个问题的文章,这是本地时间比UTC更有意义的少数例外情况之一。主要论点是“闹钟问题”。如果按 UTC 设置闹钟,则会在 DST 转换当天提前或延迟一小时起床。这就是为什么大多数人按当地时间设置闹钟的原因。
当然,如果您使用的是来自世界各地的数据,则不能只存储本地时间。您应该存储一些不同的东西:
- 定期事件的本地时间,如“08:00”
- 表示本地时间的时区,例如“美国/New_York”
- 重复执行模式,采用对应用程序有意义的任何格式,例如每天、每两周或每月的第三个星期四等。
- 下一个即时 UTC 日期和时间等效,以达到您可以预测的最佳效果。
- 也许,但并非总是,未来事件UTC日期和时间的列表,将一些预定义的时间段投影到未来(也许是一周,也许是6个月,也许是一两年,具体取决于您的需求)。
对于最后两个,请了解,如果负责该时区的政府决定更改任何内容,则相当于任何本地日期/时间的UTC可能会更改。由于每年都有多个时区数据库更新,因此您需要有一个计划来订阅更新公告并定期更新时区数据库。每当您更新时区数据时,都需要重新计算所有未来事件的UTC等效时间。
如果您计划显示跨越多个时区的任何类型的事件列表,则具有 UTC 等效项非常重要。这些是您将查询以构建该列表的值。
要考虑的另一点是,如果将事件安排在 DST 回退转换期间发生的本地时间,则必须确定该事件是发生在第一个实例上(通常),还是在第二个实例上(有时),或者同时发生在两者上(很少),并在应用程序中构建一种机制,以确保事件不会触发两次,除非您希望它触发。
如果您正在寻找一个简单的答案 - 对不起,但没有答案。跨时区安排未来事件是一项复杂的任务。
替代方法
我有一些人向我展示了一种技术,他们确实使用UTC时间进行调度,即他们选择本地时间的开始日期,将其转换为要存储的UTC,并存储时区ID。然后在运行时,他们应用时区将原始 UTC 时间转换回本地时间,然后使用该本地时间计算其他重复周期,就好像它是最初存储的重复时间一样。
虽然这种技术可以工作,但缺点是:
如果时区更新在第一个实例运行之前更改了本地时间,则会丢弃整个计划。这可以通过为“第一个”实例选择过去的时间来缓解,这样第二个实例实际上是第一个实例。
如果时间确实是一个应该跟随用户的“浮动时间”(例如在手机上的闹钟中),您仍然必须存储最初创建它的区域的时区信息 - 即使这不是您想要运行的区域。
它增加了额外的复杂性,没有任何好处。我会保留此技术,用于您可能有一个仅限 UTC 的调度程序,您正在尝试将时区支持改装到其中的情况。