尝试使用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"
}
经过测试
如果我们关注时区,就会出现问题。这是一个错误吗?或者我做错了什么?提前谢谢!
答案 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会依赖它。