所以这是场景:
我的应用程序中有一个交易部分。它记录操作并将时间存储为UNIX时间戳(UTC)。
所以昨天我得到了100.00英镑的报酬,这是用unix时间戳1477762205记录到数据库中的,相当于2016年10月29日星期六17:30:05 UTC / GMT。
(这是我当地时间19:30)
我的应用程序(用PHP编写)使用日期时间对象输出并传入输出时区(欧洲/伦敦)。
昨天它正确输出当地时间为19:30,由于时间时间今天凌晨2点变化,现在是18:30。
这在技术上是正确的,但是如果我记得在事先记录交易时相对于事件,这现在看起来不正确,因为我记得它是当地时间19:30。
我的问题是,相对于事件,从UTC输出时间的最佳方法是什么?我是否需要使用UTC日志存储时区以确定日志发生时的时区?
代码:
存储日志时:
(这是我正在创建的记录器类的一部分)
if($dateTime == null) {
$dateTime = time();
}
$query = "INSERT INTO `".$this->databaseName."`.`log`(`datetime`,`action`) VALUES(?, ?);";
if(!$stmt = $this->database->prepare($query)) {
return $this->database->error;
}
$stmt->bind_param('ss',$dateTime,$action);
$stmt->execute();
输出时:
$dateTime = new DateTime(null, new DateTimeZone('UTC'));
$dateTime->setTimestamp($log->timeStamp);
$dateTime->setTimezone(new DateTimeZone('Europe/London'));
echo $dateTime->format('d/m/Y H:i');
技术上正确的输出:29/10/2016 18:30
但我希望它显示相对于实际时间戳的DST感知,而不是相对于现在的DST。
所以我希望能输出:29/10/2016 19:30
答案 0 :(得分:1)
首先,让我们总结一下1477762205
Unix时间戳的预期本地值:
只要你使用基于城市的时区标识符,东西似乎按预期工作:
foreach (['UTC', 'Europe/London', 'Europe/Madrid'] as $time_zone_id) {
$dt = new DateTime('@1477762205');
$tz = new DateTimeZone($time_zone_id);
$dt->setTimezone($tz);
echo $time_zone_id . ': ' . $dt->format('H:i:s [e=T, O]') . PHP_EOL;
}
UTC: 17:30:05 [UTC=UTC, +0000]
Europe/London: 18:30:05 [Europe/London=BST, +0100]
Europe/Madrid: 19:30:05 [Europe/Madrid=CEST, +0200]
一旦我们使用命名区域首字母缩略词,就会发生奇怪的事情:
foreach (['UTC', 'BST', 'GMT', 'CEST', 'CET'] as $time_zone_id) {
$dt = new DateTime('@1477762205');
$tz = new DateTimeZone($time_zone_id);
$dt->setTimezone($tz);
echo $time_zone_id . ': ' . $dt->format('H:i:s [e=T, O]') . PHP_EOL;
}
UTC: 17:30:05 [UTC=UTC, +0000]
BST: 17:30:05 [BST=BST, +0000]
GMT: 17:30:05 [GMT=GMT, +0000]
CEST: 18:30:05 [CEST=CEST, +0100]
CET: 18:30:05 [CET=CET, +0100]
可能与基础数据库中可用的时区转换信息(或缺少信息)存在某种关系:
$dt = new DateTime('@1477762205');
foreach (['UTC', 'BST', 'Europe/London', 'CEST', 'Europe/Madrid'] as $time_zone_id) {
$tz = new DateTimeZone($time_zone_id);
$dt->setTimezone($tz);
echo $time_zone_id . PHP_EOL;
echo '- Time zone offset: ' . $tz->getOffset($dt) . ' seconds' . PHP_EOL;
$transitions = $tz->getTransitions(mktime(0, 0, 0, 1, 1, 2016), mktime(0, 0, 0, 12, 31, 2016));
if ($transitions===false) {
echo '- Error fetching transitions' . PHP_EOL;
} else {
echo '- ' . count($transitions) . ' transitions found' . PHP_EOL;
}
}
UTC
- Time zone offset: 0 seconds
- 1 transitions found
BST
- Time zone offset: 0 seconds
- Error fetching transitions
Europe/London
- Time zone offset: 3600 seconds
- 3 transitions found
CEST
- Time zone offset: 3600 seconds
- Error fetching transitions
Europe/Madrid
- Time zone offset: 7200 seconds
- 3 transitions found
很难说这有多少是一个普通的错误,多少是反直觉但有记录的; PHP bug数据库里挤满了而不是bug 条目,这确实是一个误解,但我个人发现了涉及DST边界的日期计算中的奇怪但实际的错误。