Timezones in Python

One of the most important parts of digital forensics is working out when things happened. When did a file get last accessed or modified? When did a user access this website? What was happened yesterday at 4.30PM? This would be very easy if the entire world was based in UTC, or at least all operating systems and log files stored time in UTC in the same format. Instead, we have various mixtures of UTC and local time, stored in Windows time format (100 nanosecond intervals since Jan 1st 1601) or Unix epoch format (seconds since Jan 1st 1970), a plain string format or however each programming language decides to encode time. This is especially important when doing forensics for global companies where the investigation can be carried out on several computers spanning different timezones, and the investigator is in a different timezone too. Establishing a common timezone is imperative, so not to get lost with local times and correlating evidence. Even on the same machine this is difficult – the Windows registry is in UTC, but setupapi.log and other important log file are in localtime.

I have been writing a couple of forensic tools at work which deal with correlating evidence, and therefore the time must be in a consistent timezone. Unfortunately, Python 2’s datetime and time libraries are not very good at timezones (I have heard Python 3 is much improved, but it’ll be a while yet before Python 3 is widely accepted). The problem starts with that datetime objects are always assumed to be in localtime. Assume you have a date 23rd January 2009, 13:45:51 which you know is localtime in New York. When you create a datetime(2009, 1, 23, 13, 45, 51) on a computer not in New York’s timezone, this is no longer the correct time. You are able to add an optional timezone, tzinfo, but you need to know the timezone offset. Most countries change half way through the year to be +/- an hour, and this is not always on a fixed date. Anyway, you shouldn’t be needing to do this – the programming language should be able to deal with this.

A second problem comes with inconsistent opposite functions. time.gmtime(seconds) converts a Unix epoch time to a UTC time tuple. time.mktime(time tuple) converts a localtime time tuple to Unix epoch time. You would expect this to accept a UTC time tuple, not localtime, and without reading this in the documentation this can cause lots of timezone problems! time.gmtime(seconds)’s opposite function is actually calendar.timegm(UTC time tuple). It seems even the Python documentation is unsure why this function is in the calendar module, describing the function as: “An unrelated but handy function…

All is not lost however if you use the Python standard library functions with caution as well as using the handiest timezone library I’ve seen yet: pytz. Pytz knows all timezones and given any date and a timezone string, will return the date in UTC. Pytz knows when daylights savings happen etc. All your Python code that deals with timezones should contain a function similar to this:

import pytz
from datetime import datetime

def get_epoch_time(local_time, timezone):
	from calendar import timegm
	utc_time = timezone.normalize(timezone.\
	unix_epoch = timegm(utc_time.timetuple())
	return unix_epoch

timezone = pytz.timezone('America/New_York') 
# you can check if a string exists as a timezone by trying: 
#	'Europe/London' in pytz.all_timezones
local_time = datetime.now()
print get_epoch_time(local_time, timezone)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s