日期时间格式和时区

时间:2012-01-24 13:40:50

标签: php datetime timezone format

尝试使用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"
}

经过测试

  • PHP 5.3.6-13ubuntu3.3与Suhosin-Patch(cli)(内置:2011年12月13日18:18:37)和
  • PHP 5.3.9(cli)(建于:2012年1月18日20:02:33)

如果我们关注时区,就会出现问题。这是一个错误吗?或者我做错了什么?提前谢谢!

2 个答案:

答案 0 :(得分:14)

使用PHP看起来像一个bug(或者至少是无证件的限制)...如果我们尝试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个字母的字符串。但对于其他人来说,它更有趣,因为有可变字母,因此空白敏感性可能是一个问题。

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

答案 1 :(得分:0)

您可以检查您的php.ini是否有默认的date.timezone,如果不使用date_default_timezone_set,则DateTime会依赖它。