2

It seems that checking if it's xx:00:00 UTC/GMT is as simple as checking if timestamp % 3600 == 0, with timestamp = number of seconds elapsed since epoch (1970-01-01 00:00:00). We can see it here:

import datetime 
print datetime.datetime.fromtimestamp(3600*24*17000)
# 2016-07-18 02:00:00

But isn't this in contradiction with leap seconds? Indeed, the number of seconds elapsed between 1970-01-01 00:00:00 and 2016-07-18 02:00:00 is not a multiple of 3600, but a multiple of 3600 + 26 leap seconds (there have been 26 leap seconds between 1972 and now).


To be more precise: the number of elapsed seconds between 1970-01-01 00:00:00 and 2016-07-18 02:00:00 is 3600*24*17000 + 26 and not 3600*24*17000.

Basj
  • 41,386
  • 99
  • 383
  • 673
  • Many (most?) computer systems track [Unix Time](https://en.wikipedia.org/wiki/Unix_time). – Howard Hinnant Jan 18 '18 at 18:56
  • 1
    Why do you need this? If it's to run some code at midnight (or another time of day), there are better ways. – Thomas Jan 18 '18 at 19:03
  • @Thomas I do know `cron` and similar scheduling tools for Python but I don't need it for this, I just wanted to know how UNIX timestamp works. – Basj Jan 18 '18 at 19:16

2 Answers2

0

Python's datetime.datetime objects can not handle leap seconds since the seconds attribute is limited to the range 0..59:

In [19]: DT.datetime(2012, 6, 30, 23, 59, 60)
ValueError: second must be in 0..59

(There was a leap second just before midnight, 2012-06-30).

So Python's datetime system does not quite represent all times as they exist in the real world. It models a simplified world where no leap seconds exist.

See also: this python issue which was closed with status "won't fix".

The linked page shows mxDatetime as an alternative to datetime.datetime which can (sort of) handle leap seconds.

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • Yes, but this means that either 1) Python's datetime/timestamp is different than other UNIX timestamps implementations in other languages (that would be bad, and I think it's not the case) or 2) All UNIX timestamps implementations don't care about leap seconds in general. Then is there a slow "drift" between real time and time extracted from a UNIX timestamp? – Basj Jan 18 '18 at 19:00
  • Per [Howard Hinnant's comment](https://stackoverflow.com/questions/48328382/how-to-check-if-its-xx0000-with-a-timestamp/48328495#comment83642427_48328382) all UNIX timestamps ignore leap seconds. – unutbu Jan 18 '18 at 19:03
  • [It seems](https://stackoverflow.com/a/48328717/1422096) that it dosn't ignore them @unutbu, it does process them by jumping back the timestamp of 1 second when it appears. – Basj Jan 18 '18 at 19:13
  • @Basj: Perhaps I mispoke by saying UNIX timestamps ignore leap seconds. The UNIX timestamp is rolled back to account for the leap second. The problem is now you have two real moments in time represented by the same UNIX timestamp. Python uses your system's `localtime` to convert the timestamp to a date which may or may not recognize leap seconds. [This code](https://github.com/python/cpython/blob/3.6/Lib/datetime.py#L1440) shows Python squashing seconds >= 60 down to 59 seconds, thus ignoring leap seconds. – unutbu Jan 18 '18 at 19:49
0

I finally found it here:

When a leap second is inserted, which happens about every year and a half on average, the Unix time number increases continuously during the leap second, during which time it is more than 86,400 seconds since the start of the current day, and then jumps back by 1 at the end of the leap second, which is the start of the next day

1998-12-31T23:59:59.75  915 148 799.75
1998-12-31T23:59:60.00  915 148 800.00  # leap second here
1998-12-31T23:59:60.25  915 148 800.25
1998-12-31T23:59:60.50  915 148 800.50
1998-12-31T23:59:60.75  915 148 800.75
1999-01-01T00:00:00.00  915 148 800.00  # timestamp jumps back!
1999-01-01T00:00:00.25  915 148 800.25

So probably there's some code somewhere in datetime.py that does this leap second detection + jumping back. There's a reference to "leap second" here but I can't see how it could detect if it's one or not.

import datetime 
print datetime.datetime.fromtimestamp(915148799) #1999-01-01 00:59:59
print datetime.datetime.fromtimestamp(915148800) #1999-01-01 01:00:00
Basj
  • 41,386
  • 99
  • 383
  • 673
  • 1
    Jumping back is one way that it can be done, but also look at the many implementations that implement a "leap smear" rather than a leap second. Google is only one example https://developers.google.com/time/smear of how smears are done. The Go language has chosen a different strategy https://github.com/golang/proposal/blob/master/design/12914-monotonic.md The underlying problem is that different agencies have chosen different goals for what is important about how time should work http://www.ucolick.org/~sla/leapsecs/picktwo.html – Steve Allen Jan 18 '18 at 21:27