[Python-ideas] use gmtime(0) epoch in functions that use mktime()

Akira Li 4kir4.1i at gmail.com
Sat Sep 6 15:53:55 CEST 2014

Python uses "seconds since the epoch" term to describe time.time()
return value. POSIX term is "seconds since the Epoch" (notice the
capitalization) where Epoch is 1970-01-01 00:00:00+00:00. C99 term is
"calendar time" -- the encoding of the calendar time returned by the
time() function is unspecified.

Python documentation defines `epoch` as:

  The :dfn:`epoch` is the point where the time starts.  On January 1st
  of that year, at 0 hours, the "time since the epoch" is zero.  For
  Unix, the epoch is 1970.  To find out what the epoch is, look at

time module documentation specifies calendar.timegm() as the inverse of
time.gmtime() while timegm() uses the fixed 1970 Epoch instead of
gmtime(0) epoch.

datetime.astimezone() (local_timezone()) passes Unix timestamp [1970] to
time.localtime() that may expect timestamp with different epoch

email.util.mktime_tz() uses both mktime() [gmtime(0)] and timegm() [1970].

mailbox.py uses both time.time() [gmtime(0)] and timegm() [1970].

http.cookiejar uses both EPOCH_YEAR=1970 and datetime.utcfromtimestamp()
[gmtime(0) epoch] for "seconds since epoch".

It seems 1970 Epoch is used for file times on Windows (os.stat()) but
os.path.getatime() refers to "seconds since epoch" [gmtime(0) epoch].

date{,time}.{,utc}fromtimestamp(), datetime.timestamp() docs equates
"POSIX timestamp" [1970 Epoch] and time.time()'s returned value
[gmtime(0) epoch].

datetime.timestamp() is inconsistent if gmtime(0) is not 1970. It uses
mktime() for naive datetime objects [gmtime(0) epoch]. But it
uses POSIX Epoch for aware datetime objects.

Correct me if I'm wrong here.

Possible fixes:

Say in the `epoch` definition that stdlib doesn't support
gmtime(0).tm_year != 1970.

OR don't use mktime() if 1970 Epoch is used e.g., create an aware
datetime object in the local timezone instead and use it to compute the
result with 1970 Epoch.

OR add *analog* of TZ=UTC time.mktime() and use it in stdlib where
necessary. Looking at previous attempts (e.g., [1], [2]) to implement
timegm(), the problem seems over-constrained. A different name could be
used, to avoid wrong expectations e.g., datetime could use
`(aware_datetime_object - gmtime0_epoch) // sec`

[1] http://bugs.python.org/issue6280,
[2] http://bugs.python.org/issue1667546

OR set EPOCH_YEAR=gmtime(0).tm_year instead of 1970 in
calendar.timegm(). It may break backward compatibility if there is a
system with non-1970 epoch. Deal on a case-by-case basis with other
places where 1970 Epoch is used.  And drop "POSIX timestamp" [1970
Epoch] and use "seconds since the epoch" [gmtime(0) epoch] in the
datetime documentation. Change internal EPOCH year accordingly.

What is Python-ideas opinion about it?


More information about the Python-ideas mailing list