classification
Title: time.time() documentation should mention UTC timezone
Type: Stage: resolved
Components: Documentation Versions: Python 3.7, Python 3.6, Python 3.5
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: docs@python Nosy List: Eric Appelt, Mariatta, belopolsky, docs@python, haypo, lemburg, ncoghlan
Priority: normal Keywords: patch

Created on 2016-12-20 14:24 by haypo, last changed 2017-03-14 21:47 by haypo. This issue is now closed.

Files
File name Uploaded Description Edit
29026_unixtime_v1.patch Eric Appelt, 2016-12-23 04:58 review
Pull Requests
URL Status Linked Edit
PR 34 merged Eric Appelt, 2017-02-16 10:00
PR 417 merged Mariatta, 2017-03-03 05:42
PR 418 merged Mariatta, 2017-03-03 05:42
Messages (11)
msg283690 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2016-12-20 14:24
The documentation of the time.time() mentions "epoch" which it doesn't define epoch. If I recall correctly, it's January 1st, 1970 on most OS and most implementations of Python, except of IronPython which uses a different epoch.

https://docs.python.org/dev/library/time.html#time.time

Moreover, the timezone is not defined. In practice, it's UTC, so it would be nice to document it.

I opened this issue because I wasn't sure if time.time() is impacted by DST or not. The answer is no. Maybe the behaviour of time.time() on DST should also be documentation. Hint: it is not impacted by DST since it uses UTC timezone.

Related question on StackOverflow:
http://stackoverflow.com/questions/32469318/python-time-time-and-daylight-saving-time
msg283697 - (view) Author: Marc-Andre Lemburg (lemburg) * (Python committer) Date: 2016-12-20 14:59
time.time() is not quite UTC on Unix: it usually (*) doesn't include leap seconds, which UTC does.

The Wikipedia page has a good definition and explanation:

https://en.wikipedia.org/wiki/Unix_time

(*) "usually" because POSIX defines time() to not include leap seconds, but on some older or not quite POSIX compliant Unix systems, leap seconds are included.
msg283698 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2016-12-20 15:07
> time.time() is not quite UTC on Unix

Handling time is a complex task, so we should enhance the doc to help users.

If there are multiple cases, we can list them: "time.time() uses UTC timezone with or without leap seconds". Maybe with a link to https://en.wikipedia.org/wiki/Unix_time ?
msg283845 - (view) Author: Eric Appelt (Eric Appelt) * Date: 2016-12-22 14:54
I would be happy to work on a documentation patch for this - I'll try to have something up by tomorrow evening if no one beats me to it.
msg283871 - (view) Author: Eric Appelt (Eric Appelt) * Date: 2016-12-23 04:58
I looked at the documentation and implementation and made a patch to hopefully clarify the issue. I also have some comments:

- The term "epoch" is actually defined at the top of the page with instructions for how to determine it, i.e. run "gmtime(0)".

- I added a definition for the term "seconds since the epoch" since this typically means the number of seconds that have elapsed since the epoch excluding leap seconds, although it may vary by platform.

- I'm a bit uncomfortable with potential confusion regarding Windows, since the Windows epoch begins on 1601, although we adjust it to 1970: https://github.com/python/cpython/blob/d739274e7b69f63263054cc24684e7e637264350/Python/pytime.c#L536-L539 I didn't add a note in the patch as I am not a windows developer, but I wonder if there could be some confusion.

- Even though its redundant with the top of the page, I added specific clarification to time.time() as it appears that most readers are going to navigate to that anchor specifically and not read the discussion of what we mean by "epoch" above.

- I need to test my assertion that Windows does not count leap seconds. I'm pretty sure but not 100% confident that I am correct from what I read, but I need to find someone with a windows machine tomorrow and actually check it. The windows documentation for the FILETIME structure suggests that leap seconds might be counted - https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284(v=vs.85).aspx - but I think this is just an oversight in the documentation.

- Just out of personal curiousity does anyone have an example of a legacy UNIX system that counts leap seconds in the epoch? This seems tricky to do as I would presume that the OS would need some table that would be updated whenever the astronomers declare a new leap second.
msg283885 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2016-12-23 15:59
Another suggestion: mention localtime() and gmtime() in time() documentation to explain how to convert such timestamp to a more common date format.
msg283887 - (view) Author: Eric Appelt (Eric Appelt) * Date: 2016-12-23 17:22
I had some checks performed on a Windows platform using the following snippet:

# valid for 2016
import time
def check():
    t = time.gmtime()
    print(46*86400*365 + 11*86400 + (t.tm_yday-1)*86400 + t.tm_hour*3600 + t.tm_min*60 + t.tm_sec)
    print(time.time())
    print(time.gmtime(0))
check()

This ensures that the time since the epoch is counted excluding leap seconds if the first two lines of output are approximately the same (to nearest second), and finally that the epoch is the Unix epoch.

On Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 07:18:10) [MSC v.1900 32 bit (Intel)] on win32 I see:

1482502941
1482502941.9609053
time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)

Unless there is major variation among windows versions on how FILETIMEs are calculated and the results of basic system calls, I feel fairly confident now that the calculation of time since the epoch in CPython is the same on Windows as it is in POSIX-compliant platforms.
msg287630 - (view) Author: Eric Appelt (Eric Appelt) * Date: 2017-02-12 02:46
As we have moved to GitHub and mandatory reviews with Pull Requests, I have created a new patch in PR#34 which incorporates Victor's suggestions.
msg287926 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2017-02-16 10:00
New changeset 23557d59b819f57800ddef0b1373acef8e024670 by Victor Stinner in branch 'master':
bpo-29026: Clarify documentation of time.time (#34)
https://github.com/python/cpython/commit/23557d59b819f57800ddef0b1373acef8e024670
msg288904 - (view) Author: Mariatta Wijaya (Mariatta) * (Python committer) Date: 2017-03-03 17:26
Hi, does this need backport to 2.7?
I'm getting a lot of conflicts while trying to do that... Not sure how to proceed.
msg289623 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2017-03-14 21:47
Mariatta: "Hi, does this need backport to 2.7? I'm getting a lot of conflicts while trying to do that... Not sure how to proceed."

I think it's ok to leave Python 2.7 doc unchanged. It's only a minor doc enhancement, the 2.7 doc is still correct. I close the issue.
History
Date User Action Args
2017-03-14 21:47:16hayposetstatus: open -> closed
versions: - Python 2.7
messages: + msg289623

resolution: fixed
stage: resolved
2017-03-03 17:26:38Mariattasetnosy: + Mariatta
messages: + msg288904
2017-03-03 05:42:50Mariattasetpull_requests: + pull_request349
2017-03-03 05:42:00Mariattasetpull_requests: + pull_request348
2017-02-18 05:26:46ezio.melottisetmessages: - msg288063
2017-02-18 05:13:19ncoghlansetnosy: + ncoghlan
messages: + msg288063
2017-02-16 10:00:47hayposetmessages: + msg287926
2017-02-16 10:00:47Eric Appeltsetpull_requests: + pull_request91
2017-02-12 02:46:09Eric Appeltsetmessages: + msg287630
2016-12-23 17:22:30Eric Appeltsetmessages: + msg283887
2016-12-23 15:59:48hayposetmessages: + msg283885
2016-12-23 04:58:55Eric Appeltsetfiles: + 29026_unixtime_v1.patch
keywords: + patch
messages: + msg283871
2016-12-22 14:54:53Eric Appeltsetnosy: + Eric Appelt
messages: + msg283845
2016-12-20 15:07:03hayposetmessages: + msg283698
2016-12-20 14:59:11lemburgsetnosy: + lemburg
messages: + msg283697
2016-12-20 14:24:49haypocreate