PHP 日期时间转换问题
PHP DateTime converting issue
我在将 DateTime 从莫斯科时区转换为纽约时区时遇到问题。这是我的测试脚本:
$year = 2015;
$month = 3;
$tzMoscow = new DateTimeZone('Europe/Moscow');
$tzNewYork = new DateTimeZone('America/New_York');
$startDate = DateTime::createFromFormat('Y-n-d', "$year-$month-01", $tzMoscow);
echo $startDate->format('Y-m-d H:i:s')."\n"; // 2015-03-01 16:16:05
$startDate = DateTime::createFromFormat('Y-n-d', "$year-$month-01", $tzNewYork);
echo $startDate->format('Y-m-d H:i:s') . "\n"; // 2015-03-01 09:16:05
$startDate->setTimezone($tzMoscow);
echo $startDate->format('Y-m-d H:i:s') . "\n"; // 2015-03-01 17:16:05
第三次输出不正确,时间应该是16:16:05。我做错了什么或者这是 php 中的错误?
您可以使用此功能,在时区之间切换
function changeTimezone($time, $currentTimezone, $timezoneRequired, $FormtsTime = 'Y-m-d h:i:s')
{
$dayLightFlag = false;
$dayLgtSecCurrent = $dayLgtSecReq = 0;
$system_timezone = date_default_timezone_get();
$local_timezone = $currentTimezone;
date_default_timezone_set($local_timezone);
$local = date($FormtsTime);
date_default_timezone_set("GMT");
$gmt = date($FormtsTime);
$require_timezone = $timezoneRequired;
date_default_timezone_set($require_timezone);
$required = date($FormtsTime);
date_default_timezone_set($system_timezone);
$diff1 = (strtotime($gmt) - strtotime($local));
$diff2 = (strtotime($required) - strtotime($gmt));
$date = new DateTime($time);
$date->modify("+$diff1 seconds");
$date->modify("+$diff2 seconds");
if ($dayLightFlag) {
$final_diff = $dayLgtSecCurrent + $dayLgtSecReq;
$date->modify("$final_diff seconds");
}
$timestamp = $date->format($FormtsTime);
return $timestamp;
}
我想我明白了。问题是你没有指定一天中的时间,所以 createFromFormat
使用 "the current system time":
If format does not contain the character ! then portions of the generated time which are not specified in format will be set to the current system time.
现在,当纽约时区在指定日期(3 月 1 日)和当前日期(3 月14)? 3 月 1 日是 UTC-5,由于夏令时,现在是 UTC-4。
我相信 PHP 正在获取指定时区的当前时间(您 运行 该代码时的 9:16),然后将其用作指定的日期。所以我们最终得到 2015 年 3 月 1 日,09:16 纽约时间 - 或 3 月 1 日,14:16 UTC,这确实是 3 月 1 日 17:16 莫斯科时间。
这与您 运行 代码 16:16.
时莫斯科的当前时间不同
基本上,您应该尽量不要这样做 - 或者预料到会发生这样的问题。想一想您 真正 试图表示一天中的什么时间,请记住在特定时区内,偏移量会随时间而变化。我真的无法就您的代码 应该 向您提供建议,因为我们不知道您要实现的目标 - 但使用当前时间 换一个日期肯定会导致这个问题。
我也认为这是 DST 的问题,3 月 8 日在纽约时区发生变化。我将您的日期格式扩展为 Y-m-d H:i:s U I
以包括 unix 时间戳和 DST 值。
现在的输出如下:
2015-03-01 19:07:17 1425222437 0
2015-03-01 11:07:17 1425226037 0
2015-03-01 20:07:17 1425226037 0
如您所见,创建的两个 DateTime
对象的 unix 时间戳已经不同。
现在当我将具体时间指定为
$startDate = DateTime::createFromFormat('Y-n-d H:i', "$year-$month-01 00:00", $tzMoscow);
以及
$startDate = DateTime::createFromFormat('Y-n-d H:i', "$year-$month-01 00:00", $tzNewYork);
输出更改为:
2015-03-01 00:00:00 1425153600 0
2015-03-01 00:00:00 1425186000 0
2015-03-01 09:00:00 1425186000 0
另一方面,如果我将 $month
更改为 4
(纽约使用 DST),我会得到以下输出:
2015-04-01 19:08:35 1427900915 0
2015-04-01 11:08:35 1427900915 1
2015-04-01 19:08:35 1427900915 0
这些结果是什么意思?
纽约和莫斯科时区之间的转换在所有情况下都是正确的,您可以从相同的 unix 时间戳判断。此外,“2015-03-01 00:00”对于莫斯科和纽约来说显然是不同的时间戳,因为它们取决于具体的时区。
所以我认为你的代码是正确的并且 php 中没有错误。但是,由于 3 月 1 日和今天(3 月 14 日)之间的 DST 切换,纽约和莫斯科的 "current" 时间有所不同。
因此,虽然 Jon 的回答已经解释了这个理论(我不想要所有的功劳,他是第一个),也许有人仍然会发现一些有用的具体例子。
我在将 DateTime 从莫斯科时区转换为纽约时区时遇到问题。这是我的测试脚本:
$year = 2015;
$month = 3;
$tzMoscow = new DateTimeZone('Europe/Moscow');
$tzNewYork = new DateTimeZone('America/New_York');
$startDate = DateTime::createFromFormat('Y-n-d', "$year-$month-01", $tzMoscow);
echo $startDate->format('Y-m-d H:i:s')."\n"; // 2015-03-01 16:16:05
$startDate = DateTime::createFromFormat('Y-n-d', "$year-$month-01", $tzNewYork);
echo $startDate->format('Y-m-d H:i:s') . "\n"; // 2015-03-01 09:16:05
$startDate->setTimezone($tzMoscow);
echo $startDate->format('Y-m-d H:i:s') . "\n"; // 2015-03-01 17:16:05
第三次输出不正确,时间应该是16:16:05。我做错了什么或者这是 php 中的错误?
您可以使用此功能,在时区之间切换
function changeTimezone($time, $currentTimezone, $timezoneRequired, $FormtsTime = 'Y-m-d h:i:s')
{
$dayLightFlag = false;
$dayLgtSecCurrent = $dayLgtSecReq = 0;
$system_timezone = date_default_timezone_get();
$local_timezone = $currentTimezone;
date_default_timezone_set($local_timezone);
$local = date($FormtsTime);
date_default_timezone_set("GMT");
$gmt = date($FormtsTime);
$require_timezone = $timezoneRequired;
date_default_timezone_set($require_timezone);
$required = date($FormtsTime);
date_default_timezone_set($system_timezone);
$diff1 = (strtotime($gmt) - strtotime($local));
$diff2 = (strtotime($required) - strtotime($gmt));
$date = new DateTime($time);
$date->modify("+$diff1 seconds");
$date->modify("+$diff2 seconds");
if ($dayLightFlag) {
$final_diff = $dayLgtSecCurrent + $dayLgtSecReq;
$date->modify("$final_diff seconds");
}
$timestamp = $date->format($FormtsTime);
return $timestamp;
}
我想我明白了。问题是你没有指定一天中的时间,所以 createFromFormat
使用 "the current system time":
If format does not contain the character ! then portions of the generated time which are not specified in format will be set to the current system time.
现在,当纽约时区在指定日期(3 月 1 日)和当前日期(3 月14)? 3 月 1 日是 UTC-5,由于夏令时,现在是 UTC-4。
我相信 PHP 正在获取指定时区的当前时间(您 运行 该代码时的 9:16),然后将其用作指定的日期。所以我们最终得到 2015 年 3 月 1 日,09:16 纽约时间 - 或 3 月 1 日,14:16 UTC,这确实是 3 月 1 日 17:16 莫斯科时间。
这与您 运行 代码 16:16.
时莫斯科的当前时间不同基本上,您应该尽量不要这样做 - 或者预料到会发生这样的问题。想一想您 真正 试图表示一天中的什么时间,请记住在特定时区内,偏移量会随时间而变化。我真的无法就您的代码 应该 向您提供建议,因为我们不知道您要实现的目标 - 但使用当前时间 换一个日期肯定会导致这个问题。
我也认为这是 DST 的问题,3 月 8 日在纽约时区发生变化。我将您的日期格式扩展为 Y-m-d H:i:s U I
以包括 unix 时间戳和 DST 值。
现在的输出如下:
2015-03-01 19:07:17 1425222437 0
2015-03-01 11:07:17 1425226037 0
2015-03-01 20:07:17 1425226037 0
如您所见,创建的两个 DateTime
对象的 unix 时间戳已经不同。
现在当我将具体时间指定为
$startDate = DateTime::createFromFormat('Y-n-d H:i', "$year-$month-01 00:00", $tzMoscow);
以及
$startDate = DateTime::createFromFormat('Y-n-d H:i', "$year-$month-01 00:00", $tzNewYork);
输出更改为:
2015-03-01 00:00:00 1425153600 0
2015-03-01 00:00:00 1425186000 0
2015-03-01 09:00:00 1425186000 0
另一方面,如果我将 $month
更改为 4
(纽约使用 DST),我会得到以下输出:
2015-04-01 19:08:35 1427900915 0
2015-04-01 11:08:35 1427900915 1
2015-04-01 19:08:35 1427900915 0
这些结果是什么意思?
纽约和莫斯科时区之间的转换在所有情况下都是正确的,您可以从相同的 unix 时间戳判断。此外,“2015-03-01 00:00”对于莫斯科和纽约来说显然是不同的时间戳,因为它们取决于具体的时区。
所以我认为你的代码是正确的并且 php 中没有错误。但是,由于 3 月 1 日和今天(3 月 14 日)之间的 DST 切换,纽约和莫斯科的 "current" 时间有所不同。
因此,虽然 Jon 的回答已经解释了这个理论(我不想要所有的功劳,他是第一个),也许有人仍然会发现一些有用的具体例子。