3

I am having trouble with time zones in python and have a curious example... I am using Python 2.7.2

import time
import datetime
import pytz
utc = pytz.utc
est = pytz.timezone('US/Eastern')
mst = pytz.timezone('US/Mountain')
print 'UTC time',time.mktime(datetime.datetime(1970, 01, 01, 0, 0, 0, tzinfo=utc).timetuple())/3600
print 'EST time',time.mktime(datetime.datetime(1970, 01, 01, 0, 0, 0, tzinfo=est).timetuple())/3600
print 'MST time',time.mktime(datetime.datetime(1970, 01, 01, 0, 0, 0, tzinfo=mst).timetuple())/3600

I thought that I should get 0.0, 5.0, and 7.0 for the three examples (UTC,EST,MST) - however I get 5.0 for all three cases (My computer is operating in EST).

additionally

time.mktime(time.gmtime(0))

returns 18000.0 (5 hours) - so - explicitly requesting gmtime for a tuple and then converting to epoch returns 5 hours. My python distribution has time.time() and time.gmtime(), but not time.timegm()

So, if I receive data from a customer in MST - and want to generate an epoch in UTC - must I just pretend that the time stamps are in EST and then add five hours?

is this a result of strptime throwing away time zone info?

alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
eigenjohnson
  • 208
  • 1
  • 9

1 Answers1

3

timetuple() (and all other struct-tm-based functions) throw away the timezone information; i.e., the time tuple data structure simply doesn't have a timezone field. It is intended for breaking down a datetime into its component display fields, so it was never really designed for computation on time values. Keep your value in datetime format as much as possible.

>>> datetime.datetime(1970, 01, 01, 0, 0, 0, tzinfo=utc)
datetime.datetime(1970, 1, 1, 0, 0, tzinfo=<UTC>)
>>> datetime.datetime(1970, 01, 01, 0, 0, 0, tzinfo=utc).timetuple()
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)

Also, you shouldn't just plug a tzinfo directly into the datetime constructor -- it doesn't always give the right result, according to this answer: dateutil and pytz give different results. Use localize() instead, to give pytz a chance to massage the data according to any applicable timezone rules.

The following code will convert from MST to EST:

>>> now = mst.localize(datetime.datetime(1970, 01, 01, 0, 0, 0))
>>> now
datetime.datetime(1970, 1, 1, 0, 0, tzinfo=<DstTzInfo 'US/Mountain' MST-1 day, 17:00:00 STD>)
>>> now.astimezone(est)
datetime.datetime(1970, 1, 1, 2, 0, tzinfo=<DstTzInfo 'US/Eastern' EST-1 day, 19:00:00 STD>)

I don't know if this handles all the corner cases. For example, you often see weird stuff happening around the daylight savings transition. If you run into problems, start searching for third-party time libraries.

Community
  • 1
  • 1
Harry Tsai
  • 379
  • 2
  • 11
  • I see - so then I could import calendar and use calendar.timegm(now.astimezone(utc).timetuple()) to get the utc epoch from an mst date – eigenjohnson Aug 11 '14 at 16:44
  • 1
    Yes, timegm works once you get your datetime into UTC. You can also use timedelta arithmetic to compute seconds since the epoch, as suggested in http://stackoverflow.com/questions/8777753/converting-datetime-date-to-utc-timestamp-in-python#answer-8778548. epoch=utc.localize(datetime.datetime(1970, 01, 01, 0, 0, 0)); timestamp=now-epoch – Harry Tsai Aug 11 '14 at 18:25
  • 1
    @eigenjohnson: `(now - datetime(1970, 1, 1, tzinfo=utc)).total_seconds()` works for a timezone-aware datetime object (`now`). `utc` is a special timezone that you may pass to `tzinfo` parameter directly. Local time (given as `naive_dt`) may be ambiguous or non-existent, you could use `aware_dt = tz.localize(naive_dt, is_dst=None)` to raise an exception in such cases instead of silently returning a wrong answer (note: `is_dst=None` parameter). – jfs Aug 31 '14 at 14:49