Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a timezone aware datetime object in Python?

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 How do I get a value of datetime.today() in Python 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.

Context

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.

like image 371
Mark Tozzi Avatar asked Aug 15 '11 12:08

Mark Tozzi


People also ask

Does Python datetime have timezone?

One of the modules that helps you work with date and time in Python is datetime . With the datetime module, you can get the current date and time, or the current date and time in a particular time zone.


2 Answers

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) 

works. (.replace returns a new datetime; it does not modify unaware.)

like image 147
unutbu Avatar answered Sep 30 '22 03:09

unutbu


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, timezone  dt = datetime.now() dt = dt.replace(tzinfo=timezone.utc)  print(dt.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() 
like image 21
kang Avatar answered Sep 30 '22 02:09

kang