Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing a time in UTC with a time in Eastern time using Python

I'm trying to compare two times using the Python datetime module, but I can't seem to create a timezone-aware time object in UTC.

>>> import pytz, datetime
>>> UTC_TZ = pytz.utc
>>> EASTERN_TZ = pytz.timezone('America/New_York')
>>> d1 = datetime.time(10, tzinfo = UTC_TZ)
>>> d1
datetime.time(10, 0, tzinfo=<UTC>)
>>> d2 = datetime.time(10, tzinfo = EASTERN_TZ)
>>> d2
datetime.time(10, 0, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)
>>> d1 < d2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware times

Is this a bug? Is there a special UTC timezone I need to use? What's going on?

like image 780
Chris B. Avatar asked May 09 '12 21:05

Chris B.


People also ask

How does Python handle UTC time?

Getting the UTC timestampdatetime. now() to get the current date and time. Then use tzinfo class to convert our datetime to UTC. Lastly, use the timestamp() to convert the datetime object, in UTC, to get the UTC timestamp.

How does Python handle different time zones?

The parameter pytz. timezone allows us to specify the timezone information as a string. We can pass in any available timezone and will get the current date time of that timezone, and it will also print the offset with respect to the UTC. i.e., the difference between UTC timezone(+00:00) and the specified time zone.


3 Answers

All credit to wberry for puzzling this out, but in the interest of having a concise answer, I'll summarize it here.

According to the datetime docs, when comparing two datetime.time objects: "If both comparands are aware and have different tzinfo attributes, the comparands are first adjusted by subtracting their UTC offsets (obtained from self.utcoffset())"

In the example you gave, the comparison throws the TypeError because EASTERN_TZ.utcoffset() returns None. utcoffset is None because the eastern US observes Daylight Savings Time and so the time offset from UTC depends on the date which isn't available in datetime.time.

You should use datetime.datetime objects for cross-timezone comparisons:

>>> import pytz, datetime
>>> UTC_TZ = pytz.utc
>>> EASTERN_TZ = pytz.timezone('America/New_York')
>>> d1 = datetime.datetime(2012, 1, 1, 10, 0, tzinfo=UTC_TZ)
>>> d2 = datetime.datetime(2012, 1, 1, 10, 0, tzinfo=EASTERN_TZ)
>>> d1 < d2
True
like image 160
Corey Burke Avatar answered Oct 01 '22 22:10

Corey Burke


You receive the error because you are trying to measure the difference between one time object that can be tied to a particular UTC instant and another time object that is "naive" and cannot be tied to a particular UTC instant. The fix is either to make both comparands offset-aware, or both naive.

The below uses datetime objects but it's basically the same idea.

import datetime, time, pytz

EST = pytz.timezone('America/New_York')
UTC = pytz.timezone('Etc/UTC')
dt1 = datetime.datetime.fromtimestamp(time.time(), EST)
# ... time passes
dt2 = datetime.datetime.fromtimestamp(time.time(), UTC)
elapsed = dt2 - dt1
like image 42
wberry Avatar answered Oct 01 '22 23:10

wberry


I'm guessing that the problem is that UTC is considered to be not-any-timezone, or "offset-naive", perhaps? I'd recommend converting everything to UTC before doing any comparisons.

You need to know timezones for inputs and outputs, obviously, but you should try to keep your internal representations all in UTC, and maybe just store the timezone of each user and convert when you need to. It will save a lot of headache in the long run.

Also, you shouldn't do it this way. It's better to use

timezone.localize(dt)

as explained here: http://pytz.sourceforge.net/#localized-times-and-date-arithmetic

like image 30
Aaron Sokoloski Avatar answered Oct 01 '22 23:10

Aaron Sokoloski