Convert timestamps with offset to datetime obj using strptime
The Python 2 strptime()
function indeed does not support the %z
format for timezones (because the underlying time.strptime()
function doesn't support it). You have two options:
Ignore the timezone when parsing with
strptime
:time_obj = datetime.datetime.strptime(time_str[:19], '%Y-%m-%dT%H:%M:%S')
use the
dateutil
module, it's parse function does deal with timezones:from dateutil.parser import parsetime_obj = parse(time_str)
Quick demo on the command prompt:
>>> from dateutil.parser import parse>>> parse("2012-07-24T23:14:29-07:00")datetime.datetime(2012, 7, 24, 23, 14, 29, tzinfo=tzoffset(None, -25200))
You could also upgrade to Python 3.2 or newer, where timezone support has been improved to the point that %z
would work, provided you remove the last :
from the input, and the -
from before the %z
:
>>> import datetime>>> time_str = "2012-07-24T23:14:29-07:00">>> datetime.datetime.strptime(time_str, '%Y-%m-%dT%H:%M:%S%z')Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Users/mj/Development/Library/buildout.python/parts/opt/lib/python3.4/_strptime.py", line 500, in _strptime_datetime tt, fraction = _strptime(data_string, format) File "/Users/mj/Development/Library/buildout.python/parts/opt/lib/python3.4/_strptime.py", line 337, in _strptime (data_string, format))ValueError: time data '2012-07-24T23:14:29-07:00' does not match format '%Y-%m-%dT%H:%M:%S%z'>>> ''.join(time_str.rsplit(':', 1))'2012-07-24T23:14:29-0700'>>> datetime.datetime.strptime(''.join(time_str.rsplit(':', 1)), '%Y-%m-%dT%H:%M:%S%z')datetime.datetime(2012, 7, 24, 23, 14, 29, tzinfo=datetime.timezone(datetime.timedelta(-1, 61200)))
In Python 3.7+:
from datetime import datetimetime_str = "2012-07-24T23:14:29-07:00"dt_aware = datetime.fromisoformat(time_str)print(dt_aware.isoformat('T'))# -> 2012-07-24T23:14:29-07:00
In Python 3.2+:
from datetime import datetimetime_str = "2012-07-24T23:14:29-0700"dt_aware = datetime.strptime(time_str, '%Y-%m-%dT%H:%M:%S%z')print(dt_aware.isoformat('T'))# -> 2012-07-24T23:14:29-07:00
Note: Before Python 3.7 this variant didn't support :
in the -0700
part (both formats are allowed by rfc 3339). See datetime: add ability to parse RFC 3339 dates and times.
On older Python versions such as Python 2.7, you could parse the utc offset manually:
from datetime import datetimetime_str = "2012-07-24T23:14:29-0700"# split the utc offset partnaive_time_str, offset_str = time_str[:-5], time_str[-5:]# parse the naive date/time partnaive_dt = datetime.strptime(naive_time_str, '%Y-%m-%dT%H:%M:%S')# parse the utc offsetoffset = int(offset_str[-4:-2])*60 + int(offset_str[-2:])if offset_str[0] == "-": offset = -offsetdt = naive_dt.replace(tzinfo=FixedOffset(offset))print(dt.isoformat('T'))
ValueError: 'z' is a bad directive in format...
(note: I have to stick to python 2.7 in my case)
I have had a similar problem parsing commit dates from the output of git log --date=iso8601
which actually isn't the ISO8601 format (hence the addition of --date=iso8601-strict
in a later version).
Since I am using django
I can leverage the utilities there.
https://github.com/django/django/blob/master/django/utils/dateparse.py
>>> from django.utils.dateparse import parse_datetime>>> parse_datetime('2013-07-23T15:10:59.342107+01:00')datetime.datetime(2013, 7, 23, 15, 10, 59, 342107, tzinfo=+0100)
Instead of strptime
you could use your own regular expression.