Recipe 3.9. Converting Time Zones
Credit: Gustavo Niemeyer
You are in Spain and want to get the correct local (Spanish) time for an event in China.
Time zone support for datetime is available in the third-party dateutil package. Here's one way to set the local time zone, then print the current time to check that it worked properly:
from dateutil import tz import datetime posixstr = "CET-1CEST-2,M3.5.0/02:00,M10.5.0/03:00" spaintz = tz.tzstr(posixstr) print datetime.datetime.now(spaintz).ctime( )
Conversion between different time zones is also possible, and often necessary in our expanding world. For instance, let's find out when the next Olympic Games will start, according to a Spanish clock:
chinatz = tz.tzoffset("China", 60*60*8) olympicgames = datetime.datetime(2008, 8, 8, 20, 0, tzinfo=chinatz) print olympicgames.astimezone(spaintz)
The cryptic string named posixstr is a POSIX-style representation for the time zone currently being used in Spain. This string provides the standard and daylight saving time zone names (CST and CEST), their offsets (UTC+1 and UTC+2), and the day and hour when DST starts and ends (the last Sunday of March at 2 a.m., and the last Sunday of October at 3 a.m., respectively). We may check the DST zone bounds to ensure they are correct:
assert spaintz.tzname(datetime.datetime(2004, 03, 28, 1, 59)) == "CET" assert spaintz.tzname(datetime.datetime(2004, 03, 28, 2, 00)) == "CEST" assert spaintz.tzname(datetime.datetime(2004, 10, 31, 1, 59)) == "CEST" assert spaintz.tzname(datetime.datetime(2004, 10, 31, 2, 00)) == "CET"
All of these asserts should pass silently, confirming that the time zone name switches between the right strings at the right times.
Observe that even though the return to the standard time zone is scheduled to 3a.m., the moment of the change is marked as 2 a.m. This happens because of a one-hour gap, between 2 a.m. and 3 a.m., that is ambiguous. That hour of time happens twice: once in the time zone CEST, and then again in the time zone CET. Currently, expressing this moment in an unambiguous way, using the standard Python date and time support, is not possible. This is why it is recommended that you store datetime instances in UTC, which is unambiguous, and only use time zone conversion for display purposes.
To do the conversion from China to Spain, we've used tzoffset to express the fact that China is eight hours ahead of UTC time (tzoffset is always compared to UTC, not to a particular time zone). Notice how the datetime instance is created with the time zone information. This is always necessary for converting between two different time zones, even if the given time is in the local time zone. If you don't create the instance with the time zone information, you'll get a ValueError: astimezone( ) cannot be applied to a naive datetime. datetime instances are always created naivethey ignore time zone issues entirelyunless you explicitly create them with a time zone. For this purpose, dateutil provides the tzlocal type, which creates instances representing the platform's idea of the local time zone.
Besides the types we have seen so far, dateutil also provides tzutc, which creates instances representing UTC; tzfile, which allows using standard binary time zone files; tzical, which creates instances representing iCalendar time zones; and many more besides.
Documentation about the dateutil module can be found at https://moin.conectiva.com.br/DateUtil?action=highlight&value=DateUtil, and datetime documentation in the Library Reference.