← main page

Date and time representations in Python

, 15 January 2012


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.

The datetime class

A 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 NonExistantTimeError exception.

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 datetime.datetime.utcnow() classmethod.

Other datetime representations

Here you can find shortcuts for converting between different representations of moments in time.

Timestamp

Timestamp is just a number — integer or float — representing the amount of seconds passed since the Epoch — 1 January 1970 0:00 UTC.

Timetuple

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.

Links related

comments powered by Disqus
Tags: python
Digital Ocean