PHP、MySQL和时区

PHP、MySQL和时区,php,mysql,datetime,timezone,Php,Mysql,Datetime,Timezone,我正在尝试在我的应用程序中集成一个时区系统,到目前为止,我一直在努力避免制作具有时区意识的应用程序,但这是一项强制性要求,所以我别无选择。时区,它就在我头上。我在PHP.net和其他网站上读过几个主题,包括但不限于此。但我永远也弄不懂它的窍门 所以我想知道是否有人能帮我:(我想做的是在我的应用程序中提供一个偏好选项,允许用户从选择菜单中选择自己的时区,但应用程序也应该能够为每个用户设置/选择相应的DST 请相信这会帮助那些仍在努力抓住时区的人,所以请尽可能提供详细的解释,即使你认为我是一个完整的

我正在尝试在我的应用程序中集成一个时区系统,到目前为止,我一直在努力避免制作具有时区意识的应用程序,但这是一项强制性要求,所以我别无选择。时区,它就在我头上。我在PHP.net和其他网站上读过几个主题,包括但不限于此。但我永远也弄不懂它的窍门

所以我想知道是否有人能帮我:(我想做的是在我的应用程序中提供一个偏好选项,允许用户从选择菜单中选择自己的时区,但应用程序也应该能够为每个用户设置/选择相应的DST

请相信这会帮助那些仍在努力抓住时区的人,所以请尽可能提供详细的解释,即使你认为我是一个完整的傻瓜/ NOOB。


编辑悬赏:

我给这个问题添加了一个悬赏,因为我真的觉得在编写PHP/MySQL应用程序时,我们需要一个关于时区的好的规范问题(因此我也添加了MySQL标记).我从很多地方都找到了一些东西,但是把它们放在一起会很好。查尔斯的答案很好,但我仍然觉得有些欠缺。以下是我想到的一些事情:

  • 如何从PHP
    DateTime
    对象将时间存储在数据库中
  • 它们应该存储在
    日期时间
    时间戳
    中吗?它们各自的优点或注意事项是什么
  • 使用MySQL
    DATE
    ,我们是否需要担心时区问题
  • 如何使用
    NOW()
    插入值。这些值需要在插入之前或之后进行转换吗
  • 是否有必要设置MySQL使用的时区?如果有,如何设置?应该持续设置还是在每次HTTP请求时设置?是否必须将其设置为UTC或其他任何设置?或者服务器的时间是否足够
  • 如何从MySQL中检索值并将其转换为
    DateTime
    对象。将其直接放入
    DateTime::\u construct()
    就足够了,还是需要使用
    DateTime::createFromFormat()
  • 何时转换为本地时间以及原因。在将其回显给用户(例如,与另一个DateTime对象或静态值进行比较)之前,我们是否希望转换该时间
  • 有没有时间我们需要担心夏令时(DST)?为什么
  • 如果某人以前插入过数据(例如,使用
    NOW()
    ),而不用担心时区以确保所有内容保持一致,该怎么办
  • 还有什么你认为应该有人注意的吗

如果可能,尝试将其分成逻辑部分,以便未来用户更容易找到信息。确保在必要时提供代码示例。

此答案已更新,以适应悬赏。未经编辑的原始答案在该行下方

赏金所有者添加的几乎所有问题都与MySQL和PHP datetimes在时区上下文中应该如何交互有关

,这意味着智能必须是PHP端

  • 如上面链接中所述,将MySQL连接时区设置为UTC。这将导致MySQL处理的所有日期时间,包括
    NOW()
    ,都被正常处理
  • 除非您非常明确地要求在
    时间戳中执行特殊行为,否则这将比过去更少痛苦。
    • 如果有必要,可以将Unix历元时间存储为整数,例如用于传统用途。历元是UTC
    • MySQL首选的日期时间格式是使用PHP日期格式字符串
      Y-m-dh:i:s
  • 在MySQL中存储所有PHP日期时间时,将其转换为UTC,这是一件小事,如下所述
  • 从MySQL返回的Datetimes可以安全地传递给PHP DateTime构造函数。请确保同时传递UTC时区
  • 尽快将PHP日期时间转换为echo上用户的本地时区。谢天谢地,与其他日期时间的日期时间比较和数学将考虑每个日期时间所在的时区
  • 您仍然可以随心所欲地使用PHP提供的DST数据库。保持您的PHP和操作系统补丁最新!保持MySQL处于UTC的幸福状态,以消除DST的一个潜在烦恼
这解决了大部分问题

最后一件事是一件蠢事:

  • 如果某人以前插入过数据(例如,使用
    NOW()
    ),而不用担心时区以确保所有内容保持一致,该怎么办
这是一个真正的烦恼。另一个答案指出了MySQL,尽管我个人会在选择和更新期间在服务器本地时区和UTC时区之间跳跃,因为我是这样的铁杆


应用程序还应该能够为每个用户设置/选择相应的DST

在现代,你不需要也不应该这样做

现代版本的PHP有一个类,它包括命名时区的功能,允许用户选择他们的实际位置,并让系统根据该位置自动确定他们的DST规则

您可以将DateTimeZone与结合使用,以实现一些简单但功能强大的功能。您只需将所有时间戳存储并使用UTC,然后将其转换为显示的用户时区

// 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";
}
您可以大大简化sele
$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";
}
[ deletia ] [ deletia ]