这个答案已经更新,以适应赏金。未经编辑的原始答案在线下。
在时区的背景下,赏金所有者添加的几乎所有问题点都与MySQL和PHP日期时间应该如何交互有关。
>将MySQL连接时区设置为UTC,如上面的链接中所述。这将导致MySQL处理的所有日期时间(包括NOW())得到妥善处理。
> Always use DATETIME, never use TIMESTAMP除非您非常明确地要求TIMESTAMP中的特殊行为。这比过去痛苦少。
>如果必须,可以将Unix纪元时间存储为整数,例如用于传统目的。时代是UTC。
> MySQL的首选日期时间格式是使用PHP日期格式字符串Y-m-d H:i:s创建的
>将所有PHP日期时间转换为UTC,将其存储在MySQL中,这是一个简单的事情,如下所述
>从MySQL返回的日期时间可以安全地传递给PHP DateTime构造函数。一定要传入UTC时区!
>在回声时将PHP DateTime转换为用户的本地时区。值得庆幸的是DateTime比较和数字与其他DateTimes将考虑每个DateTimes的时区。
>您仍然可以使用PHP提供的DST数据库。让您的PHP和OS补丁保持最新!让MySQL处于幸福的UTC状态,以消除一个潜在的DST烦恼。
这解决了大多数问题。
最后一件事是doozy:
What should someone do if they have previously inserted data (e.g. using NOW()) without worrying about the time zone to make sure everything stays consistent?
这是一个真正的烦恼。其中一个答案指出MySQL的CONVERT_TZ,虽然我个人已经通过在选择和更新期间在服务器本地和UTC时区之间跳跃来做到这一点,因为我是那样的硬核。
the app should also be able to SET/Choose the DST accordingly itself for each user.
在现代,你不需要也不应该这样做。
现代版本的PHP具有DateTimeZone类,其中包括list named timezones的功能。命名时区允许用户选择其实际位置,并让系统根据该位置自动确定其DST规则。
您可以将DateTimeZone与DateTime结合使用,以实现一些简单但功能强大的功能。您可以在UTC by default中简单地存储和使用所有时间戳,并将它们转换为显示的用户时区。
// UTC default
date_default_timezone_set('UTC');
// Note the lack of time zone specified with this timestamp.
$nowish = new DateTime('2011-04-23 21:44:00');
echo $nowish->format('Y-m-d H:i:s'); // 2011-04-23 21:44:00
// Let's pretend we're on the US west coast.
// This will be PDT right now, UTC-7
$la = new DateTimeZone('America/Los_Angeles');
// Update the DateTime's timezone...
$nowish->setTimeZone($la);
// and show the result
echo $nowish->format('Y-m-d H:i:s'); // 2011-04-23 14:44:00
通过使用此技术,系统将自动为用户选择正确的DST设置,而无需询问用户他们当前是否在DST中。
您可以使用类似的方法渲染选择菜单。您可以不断为单个DateTime对象重新分配时区。例如,此代码将列出区域及其当前时间,此时:
$dt = new DateTime('now', new DateTimeZone('UTC'));
foreach(DateTimeZone::listIdentifiers() as $tz) {
$dt->setTimeZone(new DateTimeZone($tz));
echo $tz, ': ', $dt->format('Y-m-d H:i:s'), "\n";
}
您可以通过使用一些客户端魔术来大大简化选择过程。 Javascript有一个spotty but functional Date类,标准方法为get the UTC offset in minutes.你可以使用它来帮助缩小可能的时区列表,盲目假设用户的时钟是正确的。
让我们自己比较一下这种方法。除了向用户推断他们不会真正关心的选择之外,您每次操作日期时都需要实际执行日期数学运算。这不仅仅是次优的,它是蝙蝠 – 鸟粪疯狂。强制用户表示他们何时需要DST支持,这就是要求麻烦和困惑。
此外,如果您想使用现代PHP DateTime和DateTimeZone框架,则需要使用use deprecated Etc/GMT... timezone strings而不是命名时区。这些区域名称可能会从未来的PHP版本中删除,因此这样做是不明智的。我从经验中说出这一切。
tl; dr:使用现代工具集,免除日期数学的恐怖。向用户显示指定时区列表。以UTC格式存储您的日期,这不会受到DST的任何影响。将日期时间转换为显示的用户所选的指定时区,而不是更早。
根据要求,这里是可用时区的循环,以分钟为单位显示其GMT偏移。我在这里选择了几分钟来证明一个不幸的事实:并非所有的补偿都在整个小时内!有些人实际上在DST期间提前半小时而不是整整一小时。以分钟为单位的结果偏移量应与Javascript的Date.getTimezoneOffset匹配。
$utc = new DateTimeZone('UTC');
$dt = new DateTime('now', $utc);
foreach(DateTimeZone::listIdentifiers() as $tz) {
$local = new DateTimeZone($tz);
$dt->setTimeZone($local);
$offset = $local->getOffset($dt); // Yeah, really.
echo $tz, ': ',
$dt->format('Y-m-d H:i:s'),
', offset = ',
($offset / 60),
" minutes\n";
}