【问题标题】:DateTime object not bound by its timestamp?DateTime 对象不受其时间戳的约束?
【发布时间】:2017-08-30 16:30:18
【问题描述】:

DateTime 对象是否不受其时间戳的约束? 或者 getTimestamp() 在 DST 更改时使用时是否有某种副作用

详情
在设置DST 上的DateTime 对象的时间戳时(意味着格式化时间在更改时钟之前/之后都存在),返回的时间戳与设置的时间戳不同。

$ php --version
PHP 7.1.3 (cli) (built: Mar 17 2017 16:59:59) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies

复制
考虑以下php 脚本:

date_default_timezone_set('Europe/Berlin');

$date = new DateTime();
$set_timestamp = 1319932800;
$date->setTimestamp($set_timestamp);
$get_timestamp = $date->getTimestamp();

fwrite(STDERR, $set_timestamp . "\n");  // 1319932800
fwrite(STDERR, $get_timestamp . "\n");  // 1319936400 **(WHY IS THIS DIFFERENT?)**

为什么打印的值不相等?

【问题讨论】:

  • @elbarto ofc 你也一样。我的问题明确依赖于 PHP 对 DateTime 的 DST 处理以及对于给定时间戳的 DST 更改,您需要 Europe/Berlin 或类似的。如果你给我们你的默认时区,我可以很容易地为你生成一个时间戳(同样会失败)
  • 请检查是否已经存在bugs.php.net/….
  • 我认为这是因为时区不适用于静态值 $set_timestamp 但是时区确实适用 $get_timestamp 因为它的值是生成的,这就是我的想法,但无论哪种方式它都会给它带来乐趣以后试试我自己

标签: php datetime dst


【解决方案1】:

首先,unix 时间戳始终是 UTC,所以它没有时区和 DST。

另一方面,DateTime 对象仅存储本地时间(“本地”表示DateTime 实例中设置的时区)。 p>

因此,您应该在设置时间戳之前将时区设置为 +00:00UTC,以避免不必要的时间转换和 DST 猜测。

你有两个选择:

1。通过DateTime的构造函数设置时间戳

构造函数将覆盖默认时区,并在第一个参数中获得时间戳(以@开头)时显式设置为+00:00

$set_timestamp = 1319932800;
$date = new DateTime('@' . $set_timestamp);

print($set_timestamp . "\n");
print($date->getTimestamp() . "\n");

信息:在这种情况下,构造函数的时区参数总是会被覆盖。

2。在调用setTimestamp()之前设置时区

在调用setTimestamp() 之前,使用DateTimeZone('+00:00')DateTimeZone('UTC') 时区调用setTimezone()

$set_timestamp = 1319932800;
$date = new DateTime();
$date->setTimezone(new DateTimeZone('UTC'));
$date->setTimestamp($set_timestamp);

print($set_timestamp . "\n");
print($date->getTimestamp() . "\n");

注意事项

当然,这两种情况的输出都是:

1319932800
1319932800

date_default_timezone_set() 在这些情况下是不必要的,因为您不想对当地时间做任何事情。

但是,当您想以人类可读的格式打印$date(因此当您将 unix 时间戳转换为本地时间时)时区将再次变得有趣。

【讨论】:

  • 值得一提的是类DateTime在构造函数中接受DateTimeZone的对象作为第二个参数
  • 如果时区在getTimestamp() repl.it/GwOF/0 之前更改回Europe/Berlin 则不起作用 =( 假设@p1100i 需要本地时区来进行其他日期时间计算。
【解决方案2】:

\DateTime 对象不保留时间戳,而是保留本地时间,并在 timestamp gettertimestamp setter 中进行转换。

每年关闭 DST 时会产生一次副作用,因为时间戳范围 1319932800..1319936400 和 1319936400..1319940000 解析为相同的本地时间:
https://www.epochconverter.com/timezones?q=1319936399&tz=Europe%2FBerlin https://www.epochconverter.com/timezones?q=1319939999&tz=Europe%2FBerlin

【讨论】:

  • 我明白了,所以基本上,getter/setter 有副作用?
  • 而且 datetime 对象不受其时间戳的约束,而是受本地时间 + 时间戳的约束(以一种奇怪的 php-kind-of-way 方式)?
  • 不,它只是本地时间+时区,这会导致每年两次类似问题的 SO 高峰。
猜你喜欢
  • 1970-01-01
  • 2018-03-27
  • 2012-10-07
  • 2020-11-21
  • 2011-09-04
  • 2021-10-21
  • 1970-01-01
  • 1970-01-01
  • 2020-04-12
相关资源
最近更新 更多