Date and time representations in Python
A moment in time may be presented in different ways in python code (although some of them aren't python related, one still has to deal with them). This post is about dealing with the formats and converting from one format to another.
datetime class (not to be confused with the
datetime module!) object represents a specific moment in time with up to microsecond precision,
date is similar but without the “time” part. Instances of both classes can be either “aware” (containing information about the timezone) or so-called “naive” without any notion of timezones. Apparently there is no way to convert a naive instance to an aware instance automatically: you have to specify a timezone in order to make an instance “aware”:
import datetime import pytz # Auxiliary module for easy generation of timezone instances # A naive object containing the system time at the point of generation # It is assumed that this time value is the current local time in Moscow now = datetime.datetime.now() # An aware object (having timezone information) now_in_moscow = datetime.datetime.now(tz=pytz.timezone('Europe/Moscow')) # Translate the aware object's time value to a different timezone # (the object will still represent the same global time) amsterdam_tz = pytz.timezone('Europe/Amsterdam') now_in_amsterdam = now_in_moscow.astimezone(amsterdam_tz) # Strip the object from the timezone information another_now = now_in_amsterdam.replace(tzinfo=None)
Now note that
now contains the current local time in Moscow, and
another_now contains the current local time in Amsterdam, but these objects themselves do not contain any timezone information.
The daylight saving time problem
Let's say that we want to have the naive time object representing 28 October 2012 2:30:00 and we know that this is the current local time in Asterdam. The problem is that due to daylight saving times, there exist two moments of time when it's 02:30:00 on 28 October 2012 in Amsterdam. So one ought to pass the boolean
is_dst parameter to the
localize method to specify whether it's summer or winter time. Default value of the parameter is
False, which is not always correct.
import datetime import pytz # 28 October 2012, 2:30:00 naive = datetime.datetime(2012, 10, 28, 2, 30, 00) amsterdam_tz = pytz.timezone('Europe/Amsterdam') aware_1 = amsterdam_tz.localize(naive, is_dst=False) # datetime.datetime(2012, 10, 28, 2, 30, tzinfo=<DstTzInfo 'Europe/Amsterdam' CET+1:00:00 STD>) aware_2 = amsterdam_tz.localize(naive, is_dst=True) # datetime.datetime(2012, 10, 28, 2, 30, tzinfo=<DstTzInfo 'Europe/Amsterdam' CEST+2:00:00 DST>) aware_1 - aware_2 # datetime.timedelta(0, 3600)
If we pass
is_dst=None along with such an ambiguous time value, the
AmbiguousTimeError exception will be raised. Note that as certain moments of time may exist twice, certain moments of time may also never exist, so even specifying
is_dst won't protect you from getting a
Storing datetime objects
Armin Ronacher recommends storing and handling of datetime objects in UTC as naive objects and convertem them to aware objects for specific timezones only in the rendering stage. He also gives an explicit explanation of what a pain in the ass dealing with timezones may be. Localizing a naive datetime object to the UTC timezone is safe, as UTC doesn't have daylight saving times:
import pytz # ... utc_datetime = pytz.UTC.localize(naive_datetime) # Now you can present it to a user in a custom timezone: local_datetime = user_timezone.normalize(utc_datetime)
To get current time in UTC as a naive object, one should use the
Other datetime representations
Here you can find shortcuts for converting between different representations of moments in time.
Timestamp is just a number — integer or float — representing the amount of seconds passed since the Epoch — 1 January 1970 0:00 UTC.
Timetuple is an object with a tuple's interface (or it could be just a tuple) containing time information. Unlike datetime, timetuple doesn't have any timezone information, but can have a daylight saving time flag.
The following example illustrates conversions between various time formats. It ignores the daylight saving time flag, as we assume that we are working with the local time only.
import datetime import time # Generate a datetime object now = datetime.datetime.now() # datetime.datetime(2012, 1, 11, 2, 48, 23, 606702) # Convert to a timetuple now_timetuple = now.timetuple() # It is possible to get a common tuple if needed now_tuple = tuple(now_timetuple) # (2012, 1, 11, 2, 48, 23, 2, 11, -1) # Convert to a timestamp now_timestamp = time.mktime(now_timetuple) # 1326239303.0 # Convert back to a datetime another_now = datetime.datetime.fromtimestamp(now_timestamp) # datetime.datetime(2012, 1, 11, 2, 48, 23)
The original object is almost restored, except for the microsecond part, which is not stored in a timetuple.
- Armin Ronacher's blog post
- pytz documentation
datetimestandard module documentation
timestandard module documentation