Arnab Datta
Arnab Datta

Reputation: 5236

Convert a UTC time to epoch

I am looking to analyze traffic flow with relation to weather data. The traffic data has a UNIX timestamp (aka epoch), but I am running into trouble with converting the timestamp (in the weather data) to epoch. The problem is that I am in Norway and the UTC timestamp in the weather data isn't in the same timezone as me (GMT+1).

My initial approach

I first tried converting it into epoch and treating the data as if it was in the GMT+1 timezone. Then I compensated by subtracting the difference in number of seconds between UTC and GMT+1.

Problems with the approach

I realize first of all that this approach is very primitive and not very elegant (in fact probably it is at best an ugly hack). However, the biggest problem here is that the difference between UTC and GMT+1 is not constant (due to daylight savings).

Question

Is there any reliable way of turning UTC time to a UNIX time stamp in python (taking into account that my machine is in GMT+1)? The timestamp is in the following format:

Y-m-d HH:MM:SS

Edit: Tried rmunns' solution:

def convert_UTC_to_epoch(timestamp):
  tz_UTC = pytz.timezone('UTC')
  time_format = "%Y-%m-%d %H:%M:%S"
  naive_timestamp = datetime.datetime.strptime(timestamp, time_format)
  aware_timestamp = tz_UTC.localize(naive_timestamp)
  epoch = aware_timestamp.strftime("%s")
  return (int) (epoch)

This does not work properly as evidenced below:

#Current time at time of the edit is 15:55:00 UTC on June 9th 2014.
>>> diff = time.time() - convert_UTC_to_epoch("2014-06-09 15:55:00")
>>> diff
3663.25887799263
>>> #This is about an hour off.

Upvotes: 2

Views: 23289

Answers (4)

rmunn
rmunn

Reputation: 36698

The pytz module will probably help you. It allows you to write code like:

import pytz
import datetime
tz_oslo = pytz.timezone('Europe/Oslo')
time_format = "%Y-%m-%d %H:%M:%S"
naive_timestamp = datetime.datetime(2014, 6, 4, 12, 34, 56)
# Or:
naive_timestamp = datetime.datetime.strptime("2014-06-04 12:34:56", time_format)
aware_timestamp = tz_oslo.localize(naive_timestamp)
print(aware_timestamp.strftime(time_format + " %Z%z"))

This should print "2014-06-04 14:34:56 CEST+0200".

Do note the following from the pytz manual:

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 keep that in mind as you write your code: do the conversion to local time once and once only, and you'll have a much easier time doing, say, comparisons between two timestamps correctly.

Update: Here are a couple of videos you may find useful:

  • What you need to know about datetimes, a PyCon 2012 presentation by Taavi Burns (30 minutes)
  • Drive-in Double Header: Datetimes and Log Analysis, a two-part presentation. (Caution: annoying buzz in the video, but I couldn't find a copy with better sound). The first part is the "What you need to know about datetimes" presentation I linked just above, and the second part has some practical tips for parsing log files and doing useful things with them. (50 minutes)

Update 2: The convert_UTC_to_epoch() function you mention in your updated question (which I've reproduced below) is returning local time, not UTC:

def convert_UTC_to_epoch(timestamp):
  tz_UTC = pytz.timezone('UTC')
  time_format = "%Y-%m-%d %H:%M:%S"
  naive_timestamp = datetime.datetime.strptime(timestamp, time_format)
  aware_timestamp = tz_UTC.localize(naive_timestamp)
  epoch = aware_timestamp.strftime("%s")
  return (int) (epoch)

The problem is that you're using strftime("%s"), which is undocumented and is returning the wrong result. Python doesn't support the %s parameter, but it appears to work because it gets passed to your system's strftime() function, which does support the %s parameter -- but it returns local time! You're taking a UTC timestamp and parsing it as local time, which is why it's an hour off. (The mystery is why it isn't two hours off -- isn't Norway in daylight savings time right now? Shouldn't you be at UTC+2?)

As you can see from the interactive Python session below, I'm in the UTC+7 timezone and your convert_UTC_to_epoch() function is seven hours off for me.

# Current time is 02:42 UTC on June 10th 2014, 09:42 local time
>>> time.timezone
-25200
>>> time.time() - convert_UTC_to_epoch("2014-06-10 02:42:00")
25204.16531395912
>>> time.time() + time.timezone - convert_UTC_to_epoch("2014-06-10 02:42:00")
6.813306093215942

The strftime("%s") call is interpreting 02:42 on June 10th as being in local time, which would be 19:42 UTC on June 9th. Subtracting 19:42 UTC on June 9th from 02:42 UTC June 10th (which is what time.time() returns) gives a difference of seven hours. See Convert python datetime to epoch with strftime for more details on why you should never use strftime("%s").

(By the way, if you saw what I had previously written under the heading "Update 2", where I claimed that time.time() was returning local time, ignore that -- I got it wrong. I was fooled at first by the strftime("%s") bug just like you were.)

Upvotes: 3

Arnab Datta
Arnab Datta

Reputation: 5236

The solution was to use the calendar module (inspired from here)

>>>#Quick and dirty demo
>>>print calendar.timegm(datetime.datetime.utcnow().utctimetuple()) - time.time()
>>>-0.6182510852813721

And here is the conversion function:

import calendar, datetime, time

#Timestamp is a datetime object in UTC time
def UTC_time_to_epoch(timestamp):
  epoch = calendar.timegm(timestamp.utctimetuple())
  return epoch

Upvotes: 6

monkut
monkut

Reputation: 43840

An alternative, datetime has it's own .strptime() method.

http://en.wikipedia.org/wiki/Unix_time

The Unix epoch is the time 00:00:00 UTC on 1 January 1970 (or 1970-01-01T00:00:00Z ISO 8601).

import datetime
unix_epoch = datetime.datetime(1970, 1, 1)
log_dt = datetime.datetime.strptime("14-05-07 12:14:16", "%y-%m-%d %H:%M:%S")
seconds_from_epoch = (log_dt - unix_epoch).total_seconds()
>>> 1399490056.0

Upvotes: 3

A.J. Uppal
A.J. Uppal

Reputation: 19264

You can use the time and datetime modules:

import time, datetime
date = "14-05-07 12:14:16" #Change to whatever date you want
date = time.strptime(date, "%y-%m-%d %H:%M:%S")
epoch = datetime.datetime.fromtimestamp(time.mktime(date)).strftime('%s')

This runs as:

>>> import time, datetime
>>> date = "14-05-07 12:14:16"
>>> date = time.strptime(date, "%y-%m-%d %H:%M:%S")
>>> epoch = datetime.datetime.fromtimestamp(time.mktime(date)).strftime('%s')
>>> epoch
'1399490056'
>>> 

Upvotes: 0

Related Questions