58

I have a date and I need to make it time zone aware.

local_tz = timezone('Asia/Tokyo')
start_date = '2012-09-27'
start_date = datetime.strptime(start_date, "%Y-%m-%d")   
start_date = start_date.astimezone(local_tz)


now_utc = datetime.now(timezone('UTC'))
local_now = now_utc.astimezone(local_tz)

I need to find if this is true:

print start_date>local_now

But I get this error.

   start_date = start_date.astimezone(local_tz)
   ValueError: astimezone() cannot be applied to a naive datetime

I convert utc to tokyo with no issue. I need to make start_date timezone aware ad well in tokyo.

Thanks

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Tampa
  • 75,446
  • 119
  • 278
  • 425
  • 4
    Since version 3.6, astimezone works with naive (timezone unawared) datetime. If you still working on lower version (<=3.5), timezone unawared datetime has to be awared by calling pytz.localize() . – Lyle Apr 13 '18 at 02:26

3 Answers3

60

For pytz timezones, use their .localize() method to turn a naive datetime object into one with a timezone:

start_date = local_tz.localize(start_date)

For timezones without a DST transition, the .replace() method to attach a timezone to a naive datetime object should normally also work:

start_date = start_date.replace(tzinfo=local_tz)

See the localized times and date arithmetic of the pytz documentation for more details.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 10
    [pytz docs](http://pytz.sourceforge.net/) say that using tzinfo attribute directly fails for many timezones. tz.localize() should be used instead. – jfs Oct 03 '12 at 16:55
  • @J.F.Sebastian for a good example of how badly it can fail see http://stackoverflow.com/questions/11442183/pytz-timezone-shows-weird-results-for-asia-calcutta and notice that it has nothing to do with DST. – Mark Ransom Oct 03 '12 at 17:07
  • @J.F.Sebastian: Interesting. Updated the answer. – Martijn Pieters Oct 03 '12 at 17:07
  • @MarkRansom: I know. pytz uses 'Europe/Amsterdam' as an example of that. – jfs Oct 03 '12 at 17:18
  • Another WTF for python! – Kevin Parker Nov 19 '14 at 19:23
  • `start_date.replace(tzinfo=local_tz)` is wrong for any `local_tz` with a non-fixed utc offset (for any reason, not just DST e.g., Europe/Moscow has changed UTC offset recently). @Kevin: do you know a better datetime/timezone API in Python or any language (serious question: when I'd researched the question my conclusion was: "time zones are complicated". Your code may be also complicated or be simple and wrong (many people don't mind that the computer can't tell the correct time). The tz database (provided by pytz) is a good trade-off between the complexity and the correctness). – jfs Jun 15 '16 at 11:52
17

You could use local_tz.localize(naive_dt, is_dst=None) to convert a naive datetime object to timezone-aware one.

from datetime import datetime
import pytz

local_tz = pytz.timezone('Asia/Tokyo')

start_date = local_tz.localize(datetime(2012, 9, 27), is_dst=None)
now_utc = datetime.utcnow().replace(tzinfo=pytz.utc)

print start_date > now_utc

is_dst=None forces .localize() to raise an exception if given local time is ambiguous.

jfs
  • 399,953
  • 195
  • 994
  • 1,670
1

If you are using Django Rest Framework you could override the DateTimeField class like:

class DateTimeFieldOverridden(serializers.DateTimeField):

def to_representation(self, value):
    local_tz = pytz.timezone(TIME_ZONE)
    value = local_tz.localize(value)
    return super(DateTimeFieldOverridden, self).to_representation(value)

And you use it like this in your serializer:

date_time = DateTimeFieldOverridden(format='%d-%b-%Y', read_only=True)

Hope this helps someone.

Joseph Daudi
  • 1,557
  • 3
  • 17
  • 33