如何在 PHP 的日期时间中启用对闰秒的完整 UTC 支持


How to enable full UTC support for Leap Seconds in PHP's DateTime?

我想用闰秒做一些DateTime计算,但它很早就停止了,因为我无法DateTime我的意思:

### June 30, 2012 at 23:59:60 UTC ###
$leap = new DateTime('2012-06-30T23:59:60UTC');
var_export($leap);

输出:

DateTime::__set_state(array(
   'date' => '2012-07-01 00:00:00',
   'timezone_type' => 3,
   'timezone' => 'UTC',
))

我无法为去年的 UTC 闰秒创建DateTime(也不是我尝试过的其他闰秒(。我想知道DateTime是否支持闰秒,我认为它支持 UTC,但可能不支持闰秒,所以只支持 GMT?

UNIX时间不知道闰秒。就它而言,每天正好由 86,400 秒组成,时间恰好偶尔跳过或重复一秒钟。(这在很大程度上是必要的,因为闰秒没有完全提前安排。如果以 UNIX 时间计算闰秒,则随着闰秒的宣布,UNIX 时间和人类可读的日期/时间之间的"映射"将不可预测地发生变化。

由于它的日期/时间原语都是基于UNIX时间的,PHP也不能轻易地表示闰秒。它们实际上是不可见的。

这不是一个答案,但至少它是一些东西。

这里有两个可能的问题:

  1. 正如 ircmaxell 所提到的,PHP 可能在时区操作位的某个地方吃闰秒,但还需要更多的研究。
  2. 然而,我个人希望PHP将秒的"溢出"修复"为几分钟。 DateTime构造函数通过处理strtotime的相同代码传递给定的参数,众所周知,该代码采用完全伪造的日期(例如 2 月 31 日(并将它们转换为可能有意义的东西。

文档中唯一对闰秒的引用是 strptime

"tm_sec">包括任何闰秒(目前每年最多 2 个(。

例如,缩写自 PHP 交互式提示:

php > $eviler_format = '%Y-%m-%d %H:%M:%S %z';
php > $evil = '2012-12-31 23:59:59 +0000';
php > var_dump(strptime($evil, $eviler_format));
array(9) {
  'tm_sec' =>
  int(59) // ...
}
php > $evil = '2012-12-31 23:59:60 +0000';
php > var_dump(strptime($evil, $eviler_format));
array(9) {
  'tm_sec' =>
  int(60) // ...
}
php > $evil = '2012-12-31 23:59:61 +0000';
php > var_dump(strptime($evil, $eviler_format));
array(9) {
  'tm_sec' =>
  int(61) // ...
}
php > $evil = '2012-12-31 23:59:62 +0000';
php > var_dump(strptime($evil, $eviler_format));
bool(false)

不幸的是,它也需要一些不在 12 月 31 日的"闰秒":

php > $evil = '2012-01-07 23:59:61 +0000';
php > var_dump(strptime($evil, $eviler_format));
array(9) {
  'tm_sec' =>
  int(61)
  'tm_min' =>
  int(59)
  'tm_hour' =>
  int(23)
  'tm_mday' =>
  int(7)
  'tm_mon' =>
  int(0)
  'tm_year' =>
  int(112)
  'tm_wday' =>
  int(6)
  'tm_yday' =>
  int(6)
  'unparsed' =>
  string(0) ""
}

或不在午夜:

php > $evil = '2012-01-07 08:59:61 +0000';
php > var_dump(strptime($evil, $eviler_format));
array(9) {
  'tm_sec' =>
  int(61)
  'tm_min' =>
  int(59)
  'tm_hour' =>
  int(8)
  'tm_mday' =>
  int(7)
  'tm_mon' =>
  int(0)
  'tm_year' =>
  int(112)
  'tm_wday' =>
  int(6)
  'tm_yday' =>
  int(6)
  'unparsed' =>
  string(0) ""
}

此外,它完全是一个表示功能,不会以任何方式附加到DateTime。 你不能对它做数学,在现实生活中不可能从中获得真正的闰秒,因为事物的定义很明确。 这里没用。

结论:PHP 不考虑闰秒。 确保您的服务器与关心它的上游 NTP 服务器同步,您最终会没事的。 如果你需要关心闰秒的秒级精度,PHP 可能不适合你。