23

python's time module seems a little haphazard. For example, here is a list of methods in there, from the docstring:

time() -- return current time in seconds since the Epoch as a float
clock() -- return CPU time since process start as a float
sleep() -- delay for a number of seconds given as a float
gmtime() -- convert seconds since Epoch to UTC tuple
localtime() -- convert seconds since Epoch to local time tuple
asctime() -- convert time tuple to string
ctime() -- convert time in seconds to string
mktime() -- convert local time tuple to seconds since Epoch
strftime() -- convert time tuple to string according to format specification
strptime() -- parse string to time tuple according to format specification
tzset() -- change the local timezone

Looking at localtime() and its inverse mktime(), why is there no inverse for gmtime() ?

Bonus questions: what would you name the method ? How would you implement it ?

Thomas Vander Stichele
  • 36,043
  • 14
  • 56
  • 60

4 Answers4

36

There is actually an inverse function, but for some bizarre reason, it's in the calendar module: calendar.timegm(). I listed the functions in this answer.

Community
  • 1
  • 1
Tom
  • 42,844
  • 35
  • 95
  • 101
  • 3
    calendar.timegm(datetime.datetime.utcnow().utctimetuple()) is the one liner for getting a UTC timestamp. – erikcw Dec 11 '12 at 20:32
  • 2
    Python: batteries included, but sometimes the batteries themselves aren't assembled. – Eddie Parker Jul 17 '13 at 03:13
  • 1
    @erikcw: or just `time.time()` on systems that use Unix epoch (on every system I know). +/- float/int conversion. – jfs Nov 17 '13 at 16:46
4

I always thought the time and datetime modules were a little incoherent. Anyways, here's the inverse of mktime

import time
def mkgmtime(t):
    """Convert UTC tuple to seconds since Epoch"""
    return time.mktime(t)-time.timezone
Mark Roddy
  • 27,122
  • 19
  • 67
  • 71
  • Figuring out whether to use time.timezone or time.altzone is the hard part. :-) – C. K. Young Sep 24 '08 at 22:13
  • 1
    For non-Python people: time.timezone is the non-DST time delta. time.altzone is the DST time delta. To my knowledge, there is no real way to tell whether a timestamp falls on DST, short of calling localtime(). – C. K. Young Sep 26 '08 at 00:54
  • 2
    I second Jester, i general you can't subtract with timezone since DST is not in the timezone, this will only get you localtime (without consideration to DST) – Jonke Oct 26 '08 at 09:24
  • 1. `time.mktime()` expects *local* time unlike `calendar.timegm()` that expects *UTC* time tuple. It may lead to range errors. 2. Some local times are ambiguous or non-existent i.e., either there are two corresponding timestamps or none -- `mktime()` may return a wrong result around DST transitions. 3. `-time.timezone` may be different from [the corresponding utc offset](http://stackoverflow.com/q/3168096/4279) due to DST (`altzone`) or because UTC offset at `t` time was different from the current UTC offset. – jfs Apr 17 '14 at 18:42
1

mktime documentation is a bit misleading here, there is no meaning saying it's calculated as a local time, rather it's calculating the seconds from Epoch according to the supplied tuple - regardless of your computer locality.

If you do want to do a conversion from a utc_tuple to local time you can do the following:

>>> time.ctime(time.time())
'Fri Sep 13 12:40:08 2013'

>>> utc_tuple = time.gmtime()
>>> time.ctime(time.mktime(utc_tuple))
'Fri Sep 13 10:40:11 2013'

>>> time.ctime(time.mktime(utc_tuple) - time.timezone)
'Fri Sep 13 12:40:11 2013'


Perhaps a more accurate question would be how to convert a utc_tuple to a local_tuple. I would call it gm_tuple_to_local_tuple (I prefer long and descriptive names):

>>> time.localtime(time.mktime(utc_tuple) - time.timezone)
time.struct_time(tm_year=2013, tm_mon=9, tm_mday=13, tm_hour=12, tm_min=40, tm_sec=11, tm_wday=4, tm_yday=256, tm_isdst=1)


Validatation:

>>> time.ctime(time.mktime(time.localtime(time.mktime(utc_tuple) - time.timezone)))
'Fri Sep 13 12:40:11 2013'    

Hope this helps, ilia.

Ilialuk
  • 364
  • 3
  • 3
  • 1
    This answer is wrong. Demonstration: `assert time.gmtime(10**9) == (2001,9,9, 1,46,40, 6,252,0)`; `assert time.mktime((2001,9,9, 1,46,40, 6,252,0)) == 10**9 - 4*3600` (the last is true only on some systems, of course, depending on the local time zone). Reason: `mktime` does take into account the local time zone. – atzz Sep 30 '13 at 16:46
0

I'm only a newbie to Python, but here's my approach.

def mkgmtime(fields):
    now = int(time.time())
    gmt = list(time.gmtime(now))
    gmt[8] = time.localtime(now).tm_isdst
    disp = now - time.mktime(tuple(gmt))
    return disp + time.mktime(fields)

There, my proposed name for the function too. :-) It's important to recalculate disp every time, in case the daylight-savings value changes or the like. (The conversion back to tuple is required for Jython. CPython doesn't seem to require it.)

This is super ick, because time.gmtime sets the DST flag to false, always. I hate the code, though. There's got to be a better way to do it. And there are probably some corner cases that I haven't got, yet.

C. K. Young
  • 219,335
  • 46
  • 382
  • 435