我正在数据库中存储事件.我有"开始"和"结束"日期时间、"门票开始"和"门票结束"(用于门票销售实际开始/结束的时间,而不是实际活动的开始/结束时间).

到目前为止,我已经建立了一些方法,可以完成所有有趣的事情,比如在保存之前将日期/时间转换为GMT,然后返回各自的时区进行显示.

我将时区存储在一个varchar字段中,其值为"America/New_York".

但是-现在我需要开始处理用户是否希望允许重复事件.我以前做过,没什么大不了的,但从来没有跨越多个时区.

起初,我以为这没什么大不了的,但后来意识到——如果最初的开始日期是在7月(例如),并且在一年中每个月重复一次,在某个时候,夏令时将使其成为可能,因此从GMT的转换将改变一个不同的时间.一个月,当转换为12:00时,它会将其更改为-5,下一个月,由于DST,它会将其更改为-4.

我目前的 idea 是,我将存储一个"dst"tinyint(1),以确定开始/结束日期是否在dst期间输入,然后在必要时制作一种方法,将时间更改一小时.

但是——我想我会在这里问,希望这可能是一个"正常的"或一个简单的东西,我没有想到.

(cakephp 2.4.x)

推荐答案

首先,请认识到,在现代术语中,你应该说UTC而不是GMT.它们基本上是等价的,只是UTC的定义更精确.保留GMT一词,以指英国在冬季月份生效的时区中UTC+0偏移部分.

现在来回答你的问题.UTC不一定是存储所有日期和时间值的最佳方式.它对past项赛事或future absolute项赛事特别有效,但对future local项赛事——尤其是future recurring项赛事——效果不太好.

我最近写了关于这on another answer的文章,这是当地时间比UTC更有意义的少数例外情况之一.主要论点是"闹钟问题".如果您将闹钟设置为UTC,则在DST转换当天,您将早起或晚起一小时.这就是为什么大多数人按当地时间设置闹钟.

当然,如果你使用的是来自世界各地的数据,你就无法存储一个本地时间.你应该储存一些不同的东西:

  • 重复事件的本地时间,例如"08:00"
  • 表示当地时间的时区,如"美国/纽约"
  • 重复模式,以任何对应用程序有意义的格式,例如每天、每两周或每月的第三个星期四等.
  • 下一个immediate UTC的日期和时间,尽你所能预测.
  • 也许,但并非总是,future 事件UTC日期和时间的列表,将某个预定义的时间段投射到future (可能是一周,可能是6个月,可能是一年或两年,取决于您的需要).

对于后两种情况,请理解,如果负责该时区的政府决定更改任何内容,则与任何本地日期/时间相当的UTC时间可能会更改.因为每年都有多个时区数据库更新,所以你需要有一个定期更新subscribe to announcements of updatesupdate your timezone database的计划.无论何时更新时区数据,都需要重新计算所有future 事件的UTC等效时间.

如果您计划显示跨越多个时区的任何类型的事件列表,使用UTC等效值非常重要.这些是您将查询以构建该列表的值.

另一点需要考虑的是,如果一个事件被安排在DST回落过渡期间发生的本地时间,则必须决定事件是否发生在第一个实例(通常)、或第二个实例(有时),或者两者都(很少).并在应用程序中构建一种机制,以确保事件不会触发两次,除非您愿意.

如果你在寻找一个简单的答案——对不起,没有.跨时区安排future 事件是一项复杂的任务.

Alternative Approach

我让一些人向我展示了一种技术,他们do使用UTC时间进行日程安排,即他们 Select 当地时间的开始日期,将其转换为UTC进行存储,并存储时区ID.然后在运行时,他们应用时区将原始UTC时间转换回本地时间,然后使用该本地时间计算其他重复出现的时间,就好像它是最初按上述方式存储的时间一样.

虽然这项技术可以达到work%,但缺点是:

  • 如果在第一个实例运行之前有一个时区更新更改了本地时间,那么它将取消整个时间表.这可以通过为"第一"实例 Select 过go 的时间来缓解,这样第二个实例实际上就是第一个实例.

  • 如果时间真的是一个"浮动时间",应该跟随用户四处移动(比如在手机上的闹钟中),那么你仍然需要存储最初创建它的区域的时区信息——即使那不是你想要运行的区域.

  • 它增加了额外的复杂性,但没有任何好处.我将保留这项技术,以便在您可能有一个仅适用于UTC的调度器的情况下,try 将时区支持 retrofit 为该调度器.

Mysql相关问答推荐

SQL MaxSum查询为列 Select 了不正确的值

约会时的意外行为

子查询是否可以按主查询中的列进行分组?

将上传文件的存储路径放在一张表中的缺点是什么?

GoRM中行最大值查询返回"0"

MySQL - 事务绑定多个存储过程调用和回滚的简单方法?

如果存在N个特殊行,如何 Select 它们,其余的必须填充常规行,总行数不能超过MySQL中的X行?

在 MySQL 中使用非空条件 LAG() 函数

使用 DISTINCT 时无法从数据库中查询所有数据

MySQL - 考虑到所有前几天,每天计算唯一用户

非常规字符的不正确字符串值错误

如果在表中多次发现 a 列中的相同值,则排除所有行

避免重复进入mysql数据库的最佳方法

MySQL INSERT IF(自定义 if 语句)

用于国际和多语言目的的数据库建模

MySQL计算特定值的列

MySQL - 表'my_table'没有被锁定表锁定

由于在 MySQL 中使用保留字作为表名或列名导致的语法错误

在 MySQL 中找不到 outfile 创建的文件

在 Postgresql 中模拟 MySQL 的 ORDER BY FIELD()