This is not quite an answer, but at least it's something.
There are two possible problems here:
- As mentioned by ircmaxell, PHP may be eating the leap second somewhere inside the timezone manipulation bits, but more research is needed.
- 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.