5

I wanted to do some DateTime calculations with Leap Seconds, but it stopped pretty early because I could not tell DateTime what I meant:

### June 30, 2012 at 23:59:60 UTC ###

$leap = new DateTime('2012-06-30T23:59:60UTC');
var_export($leap);

Output:

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

I'm unable to create a DateTime for that UTC leap second of last year (also not other leap seconds I tried). I wondered if DateTime supports leap seconds at all, I thought it has support for UTC, but probably not for leap seconds, so just support for GMT?

hakre
  • 193,403
  • 52
  • 435
  • 836
  • 1
    I think the answer to this question might help: http://stackoverflow.com/questions/7780464/is-time-guaranteed-to-be-leap-second-aware – cheesemacfly Jan 08 '13 at 02:48
  • @cheesemacfly: The `DateTime` object is not the `time()` function, so I wonder what the system has to do with this. It's not `NOW` I instantiated the object with. Also `time()` starts 1970, the `DateTime` object goes much more back, so it is not unix-timestamp (which is oriented on GMT, not UTC) based. – hakre Jan 08 '13 at 02:50
  • Just when I thought I heard about all the date and time quirks, you introduce me to leap seconds. – zneak Jan 08 '13 at 02:58
  • Internally, it handles leap seconds for you. As far as resolving the second a leap second resolves to, I have no idea... http://lxr.php.net/xref/PHP_5_5/ext/date/lib/parse_tz.c#70 – ircmaxell Jan 08 '13 at 03:16
  • Just out of curiosity... is there a practical application that prompted this? I'm trying hard to imagine one... – squarecandy Jan 08 '13 at 03:28
  • @squarecandy: Count the number of seconds passed in UTC between two given dates for example. – hakre Jan 08 '13 at 10:42
  • sure, but in what real world example where PHP is an appropriate programming language would being a few *seconds* off be a major issue. I'm not trying to be snarky - I'm honestly interested if someone is working on a project where these few seconds make an impact that normal users would notice. – squarecandy Jan 08 '13 at 21:25
  • Yes, this question is specific, I see that. Normally GMT time is all we need. I'm also a bit curious. Perhaps answer is just that this is not a supported feature for the moment. – hakre Jan 08 '13 at 21:59

2 Answers2

3

UNIX time is ignorant of leap seconds. As far as it is concerned, every day consists of exactly 86,400 seconds, and time just happens to either skip or repeat a second once in a while. (This is, in large part, necessary because leap seconds are not fully scheduled in advance. If leap seconds were counted in UNIX time, the "mapping" between UNIX times and human-readable dates/times would change unpredictably as leap seconds were announced.)

Since its date/time primitives are all based on UNIX time, PHP cannot easily represent leap seconds either. They are effectively invisible.

  • 1
    Yes, GMT time does not have leap seconds either, that is why UTC has introduced them, so to keep the time aligned with GMT. However, the `DateTime` class is not in UNIX time and it is aware of differences in seconds from a timezone to UTC, see this [answer that which has such an example](http://stackoverflow.com/a/10450710/367456): Fri, 10 Mar 1911 23:51:38 +0009 PMT (Europe/Paris) 561 secs offset from UTC – hakre Jan 08 '13 at 10:38
1

This is not quite an answer, but at least it's something.

There are two possible problems here:

  1. As mentioned by ircmaxell, PHP may be eating the leap second somewhere inside the timezone manipulation bits, but more research is needed.
  2. However I personally expect that PHP is "fixing" the "overflow" of seconds into minutes. The DateTime constructor passes the given argument through the same code that handles strtotime, which is well-known to take totally bogus dates (Feb 31, for example) and transform them into something that kind of maybe makes sense.

The only reference to leap seconds in the documentation is in strptime:

"tm_sec" includes any leap seconds (currently upto 2 a year).

For example, abbreviated from the PHP interactive prompt:

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)

Unfortunately it also takes things that are "leap seconds" that aren't on December 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) ""
}

or aren't at midnight:

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) ""
}

Further, it's entirely a presentational function that isn't attached to DateTime in any way. You can't do math on it, and getting real leap seconds out of it is impossible in real life, given the well-defined nature of the things. It's useless here.

Conclusion: PHP doesn't think about leap seconds. Make sure your server is sync'd with an upstream NTP server that does care about it, and you'll eventually be fine. If you need to care about second-level accuracy with regard to leap seconds, PHP is probably the wrong language for you anyway.

Charles
  • 50,943
  • 13
  • 104
  • 142
  • Yes, since 1975 something there were introduce 25 seconds, so normally nobody would probably notice. The roll-over / "overflow" is known to me, was not aware `strptime` does handle these. Unless a `DateTime` system is using a database of past leap seconds (and allowing to define new ones), it's not possible anyway to say *when* those leap seconds were (and are). – hakre Jan 08 '13 at 10:48