需要帮助TimeZone调试

时间:2016-09-24 18:15:33

标签: php mysql symfony datetime ubuntu

我有一个Ubuntu / Apache2 / PHP(Symfony2)/ MySQL日期问题。我认为这是一个系统问题,因为我没有在dev env中,只有rec和prod envs。当我发布一个包含日期时间的表单时,我输入的数据库比DB少2小时。当我阅读它时,屏幕上的日期时间与我在DB中的日期时间相同。 2小时的差异符合我的时区(欧洲/巴黎)。

开发环境:

  • 本地机器
  • Ubuntu 16.04 LTS桌面
  • Apache / 2.4.18(Ubuntu)
  • 在局域网上的Debian 8虚拟主机上的Mysql 5.5.43-0 + deb8u1
  • PHP 7.0.8-0ubuntu0.16.04.2,Symfony 2.8.7

rec / prod环境:

  • 两者都在同一台专用服务器上
  • Ubuntu 15.10服务器
  • 的Apache / 2.4.12
  • MySQL 5.6.28-0ubuntu0.15.10.1
  • PHP 5.6.11-1ubuntu3.1

当我在两台机器上运行date -R时,我有一个匹配项:Sat, 24 Sep 2016 19:39:53 +0200,还有几秒钟的时间。更少,是我输入命令的时间。

/etc/timezone在两台机器上都包含“Europe / Paris”。

在两台机器上,PHP的(CGI端)date.timezone也是“Europe / Paris”。

在两台计算机上,SQL查询SELECT @@global.time_zone, @@session.time_zone;返回“SYSTEM”& “SYSTEM”

我使用bootstrap日期时间选择器,基于moment.js,输入此日期&时间。但我通过检查浏览器控制台中的POSTed数据并确认日期没有被更改,从嫌疑人中删除了它。

两台机器上的应用程序代码完全相同(相同的颠覆修订版)。

你看到别人要测试的东西吗?

2 个答案:

答案 0 :(得分:1)

可能是因为this PR最近才合并。

尝试更改此

-            $dateTime = new \DateTime(sprintf('@%s', $timestamp), new \DateTimeZone($this->outputTimezone));
+            $dateTime = new \DateTime(sprintf('@%s', $timestamp));
+            // set timezone separately, as it would be ignored if set via the constructor,
+            // see http://php.net/manual/en/datetime.construct.php
+            $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));

DateTimeToLocalizedStringTransformerTest.php

请参阅this

答案 1 :(得分:0)

PHP不使用系统时区。它有自己的内部时区设置date.timezone可由PHP配置。它还有自己的internal timezone database依赖,而不是您的系统/etc/timezone

您可以在php.ini中全局配置时区,或在代码中本地配置时区(即使用date_default_timezone_set(),使用PHP timezone identifiers之一。而不在{{{{}}中指定时区例如,构造函数,或者在传递给DateTime等函数的参数中没有GMT偏移量时,PHP使用默认配置的strtotime设置来选择时区。如果没有配置,它会回退到date.timezone

来自UTC上的PHP手册:

  

按优先顺序,此函数返回默认时区:

     
      
  • 使用date_default_timezone_set()函数(如果有)读取时区集

  •   
  • 仅限PHP 5.4.0之前:阅读date_default_timezone_set()环境变量(如果非空)

  •   
  • 读取TZ ini选项的值(如果已设置)

  •   
  • 仅限PHP 5.4.0之前:查询主机操作系统(如果支持且操作系统允许>)。这使用了一种必须猜测时区的算法。对于任何情况,这都无法正常工作。到达此阶段时会显示警告。不要依赖它正确猜测,而是将date.timezone设置为正确的时区。

  •   
     

如果以上都不成功,date_default_timezone_get()将返回UTC的默认时区。

因为你不使用PHP< 5.4.0,PHP将始终只查看date.timezone设置,如果未设置,则回退到date.timezone

以时区无关的方式在客户端和服务器之间传输时间的最佳方法是在传输期间使用Unix时间戳(即UTC) ,并且仅在远程端进行转换。例如,将UTC之类的内容发送到浏览器,并让您的Javascript使用time() * 1000将其转换为格式日期/时间,这意味着最终用户会根据以下内容查看正确的日期/时间他们在本地的时区信息,但无论时区如何,您的服务器仍然会得到正确的时间。

因此,作为一般惯例,它是一个好主意:

  • 以UTC格式存储数据库中的所有内容
  • 仅以UTC格式在PHP和数据库之间传输时间戳
  • 以UTC(Datestrtotime()等方式从服务器传输到客户端...)
  • 以UTC(DateTime::getTimestamp()
  • 从客户端传输到服务器

这样做可以确保时间格式和时区之间的转换与存储正确的时间分开,因为将时区转换应用于格式化日期然后不小心忘记或存储/传输错误时区。这就是为什么始终以时区不可知的方式进行传输可以防止破坏数据并且仅在该传输的终止端应用转换(如果需要)。然后PHP或Javascript可以使用Unix时间戳,但是当他们需要再次相互交谈时,他们可以转换回UTC / Unix时间戳并发送它。