【问题标题】:DateTime formatting and timezone日期时间格式和时区
【发布时间】:2012-01-24 13:40:49
【问题描述】:

当尝试使用DateTime::createFromFormat 解析日期时,PHP 将无法识别时区。

例子:

$t = new \DateTime(); 
echo $t->format('Y-m-dTH:i:s');

会输出

2012-01-24MSK16:53:52

现在,当我尝试从相同格式解析该字符串时

var_dump(\DateTime::createFromFormat('Y-m-dTH:i:s', '2012-01-24MSK16:53:52'));

我明白了

bool(false)

当我不将时区放入字符串时,它可以工作

$t = new \DateTime(); 
echo $t->format('Y-m-dH:i:s');

会给

2012-01-2417:17:24

并解析

var_dump(\DateTime::createFromFormat('Y-m-dH:i:s', "2012-01-2417:17:24"));

会给

object(DateTime)#3 (3) {
  ["date"]=>
  string(19) "2012-01-24 17:17:24"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(13) "Europe/Moscow"
}

经过测试

  • 带有 Suhosin-Patch (cli) 的 PHP 5.3.6-13ubuntu3.3(构建时间:2011 年 12 月 13 日 18:18:37)和
  • PHP 5.3.9 (cli)(构建时间:2012 年 1 月 18 日 20:02:33)

只要我们注意时区,就会出现问题。这是一个错误吗?还是我做错了什么?提前谢谢!

【问题讨论】:

  • 我应该看到:php > $t = new \DateTime(); echo $t->format('Y-m-dH:i:s'); 2012-01-2417:17:24 php > var_dump(\DateTime::createFromFormat('Y-m-dH:i:s', "2012-01-2417:17:24")); object(DateTime)#3 (3) { ["date"]=> string(19) "2012-01-24 17:17:24" ["timezone_type"]=> int(3) ["timezone"]= > string(13) "欧洲/莫斯科" }
  • 我知道答案,但是:哎呀!无法提交您的答案,因为:声誉低于 100 的用户在提问后 8 小时内无法回答自己的问题。您可以在 7 小时内自行回答。在此之前,请使用 cmets,或编辑您的问题。
  • 戈登,非常感谢您的编辑!!!刚刚在推特上关注了你 =)
  • Y-m-dTH:i:s到底是什么格式;你是不是想要Y-m-d\TH:i:s

标签: php datetime timezone format


【解决方案1】:

这看起来像是 PHP 的一个错误(或至少是一个未记录的限制)...如果我们尝试 4 种可能的空白排列:

var_dump(\DateTime::createFromFormat('Y-m-dTH:i:s', '2012-01-24MSK16:53:52'));
var_dump(\DateTime::createFromFormat('Y-m-d T H:i:s', '2012-01-24 MSK 16:53:52'));
var_dump(\DateTime::createFromFormat('Y-m-d TH:i:s', '2012-01-24 MSK16:53:52'));
var_dump(\DateTime::createFromFormat('Y-m-dT H:i:s', '2012-01-24MSK 16:53:52'));

我们得到(测试 PHP 5.3、5.4rc6 和 Trunk):

bool(false)
object(DateTime)#2 (3) {
  ["date"]=>
  string(19) "2012-01-24 16:53:52"
  ["timezone_type"]=>
  int(2)
  ["timezone"]=>
  string(3) "MSK"
}
bool(false)
object(DateTime)#3 (3) {
  ["date"]=>
  string(19) "2012-01-24 16:53:52"
  ["timezone_type"]=>
  int(2)
  ["timezone"]=>
  string(3) "MSK"
}

所以这似乎表明时区标识符和/或小时对空格很敏感......进一步测试:

var_dump(\DateTime::createFromFormat('Y-m-d H:i:s', '2012-01-24 16:53:52'));
var_dump(\DateTime::createFromFormat('Y-m-dH:i:s', '2012-01-2416:53:52'));

产生正确的结果。并且:

var_dump(\DateTime::createFromFormat('TY-m-d', 'MSK2012-01-24'));
var_dump(\DateTime::createFromFormat('T Y-m-d', 'MSK 2012-01-24'));

产量:

bool(false)
object(DateTime)#4 (3) {
  ["date"]=>
  string(19) "2012-01-24 01:49:26"
  ["timezone_type"]=>
  int(2)
  ["timezone"]=>
  string(3) "MSK"
}

所以是的,时区说明符似乎对尾随空格很敏感......

编辑:它对空格敏感

如果我们查看parse_date.c timelib_parse_from_format() on line 25075,我们可以看到所有 4 种时区格式都以相同的方式解析!这意味着解析的格式标识符之间完全没有区别,因此解析它们是可以互换的。

仅此一项似乎足以继续存在错误(或缺少功能)。但是,让我们看看timelib_get_zone() 会发生什么,当您使用时区标识符时会调用它。好吧,看看,我们可以看到当它不是 GMT 或时间偏移时,我们调用了timelib_lookup_zone()

我们在那里发现了错误。在timelib_lookup_zone 的第768 行,我们可以看到它将消耗整个输入字符串,直到\0 (null)、) 或空格之一:

while (**ptr != '\0' && **ptr != ')' && **ptr != ' ') {
    ++*ptr;
}

关于修复它,这有点棘手。要解决这个问题,需要为每个时区重新实现格式解析器。对于T 解析器,这很容易,因为它总是一个3 个字母的字符串。但对于其他人来说,这更有趣,因为有可变字母,因此空格敏感性可能是一个问题。

简而言之,我建议在您的时区标识符中添加一个尾随空格并完成它...

【讨论】:

  • FWIW,T 并不总是三个字母的字符串。例如,它也可以是CEST
【解决方案2】:

您可以检查您的 php.ini 是否有默认的 date.timezone,如果没有,请使用 date_default_timezone_set,因为 DateTime 依赖它。

【讨论】:

  • 从第二个示例的输出来看,他已经设置了默认时区。而且我怀疑这与它有什么关系
  • 正确答案是:要从带时区的格式创建 \DateTime 对象,您需要用空格分隔时间和时区。 php > var_dump(\DateTime::createFromFormat('Y-m-dH:i:s T', "2012-01-2417:15:59 MSK")); object(DateTime)#16 (3) { ["date"]=> string(19) "2012-01-24 17:15:59" ["timezone_type"]=> int(2) ["timezone"]= > string(3) "MSK" } OR php > var_dump(\DateTime::createFromFormat('Y-m-d T H:i:s', "2012-01-24 MSK 17:15:59")); object(DateTime)#21 (3) { ["date"]=> string(19) "2012-01-24 17:15:59" ["timezone_type"]=> int(2) ["timezone"]= > 字符串(3)“MSK”}
  • 但我无法将其作为答案,因为:但是:糟糕!无法提交您的答案,因为:声誉低于 100 的用户在提问后 8 小时内无法回答自己的问题。您可以在 7 小时内自行回答。在此之前,请使用 cmets,或改为编辑您的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-25
  • 2017-03-28
  • 1970-01-01
  • 1970-01-01
  • 2014-11-10
相关资源
最近更新 更多