What I need to do
I have a timezone-unaware datetime object, to which I need to add a time zone in order to be able to compare it with other timezone-aware datetime objects. I do not want to convert my entire application to timezone unaware for this one legacy case.
What I've Tried
First, to demonstrate the problem:
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49) [GCC 4.2.1 (Apple Inc. build 5646)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import datetime >>> import pytz >>> unaware = datetime.datetime(2011,8,15,8,15,12,0) >>> unaware datetime.datetime(2011, 8, 15, 8, 15, 12) >>> aware = datetime.datetime(2011,8,15,8,15,12,0,pytz.UTC) >>> aware datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>) >>> aware == unaware Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't compare offset-naive and offset-aware datetimes
First, I tried astimezone:
>>> unaware.astimezone(pytz.UTC) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: astimezone() cannot be applied to a naive datetime >>>
It's not terribly surprising this failed, since it's actually trying to do a conversion. Replace seemed like a better choice (as per Python: How to get a value of datetime.today() that is "timezone aware"?):
>>> unaware.replace(tzinfo=pytz.UTC) datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>) >>> unaware == aware Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't compare offset-naive and offset-aware datetimes >>>
But as you can see, replace seems to set the tzinfo, but not make the object aware. I'm getting ready to fall back to doctoring the input string to have a timezone before parsing it (I'm using dateutil for parsing, if that matters), but that seems incredibly kludgy.
Also, I've tried this in both python 2.6 and python 2.7, with the same results.
I am writing a parser for some data files. There is an old format I need to support where the date string does not have a timezone indicator. I've already fixed the data source, but I still need to support the legacy data format. A one time conversion of the legacy data is not an option for various business BS reasons. While in general, I do not like the idea of hard-coding a default timezone, in this case it seems like the best option. I know with reasonable confidence that all the legacy data in question is in UTC, so I'm prepared to accept the risk of defaulting to that in this case.
In general, to make a naive datetime timezone-aware, use the localize method:
import datetime import pytz unaware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0) aware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0, pytz.UTC) now_aware = pytz.utc.localize(unaware) assert aware == now_aware
For the UTC timezone, it is not really necessary to use
localize since there is no daylight savings time calculation to handle:
now_aware = unaware.replace(tzinfo=pytz.UTC)
.replace returns a new datetime; it does not modify
All of these examples use an external module, but you can achieve the same result using just the datetime module, as also presented in this SO answer:
from datetime import datetime from datetime import timezone dt = datetime.now() dt.replace(tzinfo=timezone.utc) print(dt.replace(tzinfo=timezone.utc).isoformat()) '2017-01-12T22:11:31+00:00'
Fewer dependencies and no pytz issues.
NOTE: If you wish to use this with python3 and python2, you can use this as well for the timezone import (hardcoded for UTC):
try: from datetime import timezone utc = timezone.utc except ImportError: #Hi there python2 user class UTC(tzinfo): def utcoffset(self, dt): return timedelta(0) def tzname(self, dt): return "UTC" def dst(self, dt): return timedelta(0) utc = UTC()