eigenjohnson
eigenjohnson

Reputation: 208

The Trouble with Timezones - all timezones are local timezones?

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?

Upvotes: 3

Views: 1366

Answers (1)

Harry Tsai
Harry Tsai

Reputation: 378

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.

Upvotes: 3

Related Questions