事件相对时间

时间:2016-10-30 15:25:22

标签: php mysql datetime

所以这是场景:

我的应用程序中有一个交易部分。它记录操作并将时间存储为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

1 个答案:

答案 0 :(得分:1)

首先,让我们总结一下1477762205 Unix时间戳的预期本地值:

  • UTC: 17:30:05 (UTC,+ 0000)
  • 伦敦: 18:30:05 (BST,+ 0100又名3600,DST = 1)
  • 马德里: 19:30:05 (CEST,+ 0200又名7200,DST = 1)

只要你使用基于城市的时区标识符,东西似乎按预期工作:

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边界的日期计算中的奇怪但实际的错误。