Daylight savings time in Python

jmetz picture jmetz · Aug 30, 2012 · Viewed 38.4k times · Source

I am writing a program which deals a lot with timezones and crossing them. The two things I deal with most are creating a datetime object from "now" and then localizing a naive datetime object.

To create a datetime object from now in the pacific timezone, I am currently doing this (python 2.7.2+)

from datetime import datetime
import pytz
la = pytz.timezone("America/Los_Angeles")
now = datetime.now(la)

Is this correct with regards to DST? If not, I suppose I should be doing:

now2 = la.localize(datetime.now())

My question is why? Can anyone show me a case where the first is wrong and the seconds is right?

As for my seconds question, suppose I had a naive date and time from some user input for 9/1/2012 at 8:00am in Los Angeles, CA. Is the right way to make the datetime like this:

la.localize(datetime(2012, 9, 1, 8, 0))

If not, how should I be building these datetimes?

Answer

Mark Ransom picture Mark Ransom · Aug 30, 2012

From the pytz documentation:

The preferred way of dealing with times is to always work in UTC, converting to localtime only when generating output to be read by humans.

So ideally you should be using utcnow instead of now.

Assuming for some reason that your hands are tied and you need to work with local times, you can still run into a problem with trying to localize the current time if you're doing it during the daylight saving transition window. The same datetime might occur twice, once during daylight time and again during standard time, and the localize method doesn't know how to settle the conflict unless you tell it explicitly with the is_dst parameter.

So to get the current UTC time:

utc = pytz.timezone('UTC')
now = utc.localize(datetime.datetime.utcnow())

And to convert it to your local time (but only when you must):

la = pytz.timezone('America/Los_Angeles')
local_time = now.astimezone(la)

Edit: as pointed out in the comments by @J.F. Sebastian, your first example using datetime.now(tz) will work in all cases. Your second example fails during the fall transition as I outlined above. I still advocate using UTC instead of local time for everything except display.