Convert timestamps with offset to datetime obj using strptime

Posted on

Solving problem is about exposing yourself to as many situations as possible like Convert timestamps with offset to datetime obj using strptime and practice these strategies over and over. With time, it becomes second nature and a natural way you approach any problems in general. Big or small, always start with a plan, use other strategies mentioned here till you are confident and ready to code the solution.
In this post, my aim is to share an overview the topic about Convert timestamps with offset to datetime obj using strptime, which can be followed any time. Take easy to follow this discuss.

Convert timestamps with offset to datetime obj using strptime

I am trying to convert time-stamps of the format “2012-07-24T23:14:29-07:00”
to datetime objects in python using strptime method. The problem is with the time offset at the end(-07:00). Without the offset i can successfully do

time_str = "2012-07-24T23:14:29"
time_obj=datetime.datetime.strptime(time_str,'%Y-%m-%dT%H:%M:%S')

But with the offset i tried

time_str = "2012-07-24T23:14:29-07:00"
time_obj=datetime.datetime.strptime(time_str,'%Y-%m-%dT%H:%M:%S-%z').

But it gives a Value error saying “z” is a bad directive.

Any ideas for a work around?

Asked By: auny

||

Answer #1:

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 parse
    time_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)))
Answered By: Martijn Pieters

Answer #2:

In Python 3.7+:

from datetime import datetime
time_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 datetime
time_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 datetime
time_str = "2012-07-24T23:14:29-0700"
# split the utc offset part
naive_time_str, offset_str = time_str[:-5], time_str[-5:]
# parse the naive date/time part
naive_dt = datetime.strptime(naive_time_str, '%Y-%m-%dT%H:%M:%S')
# parse the utc offset
offset = int(offset_str[-4:-2])*60 + int(offset_str[-2:])
if offset_str[0] == "-":
   offset = -offset
dt = naive_dt.replace(tzinfo=FixedOffset(offset))
print(dt.isoformat('T'))

where FixedOffset class is defined here.

Answered By: jfs

Answer #3:

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.

Answered By: dnozay

Answer #4:

With python 3.5.2
To convert 26 Sep 2000 05:11:00 -0700

from datetime import datetime
dt_obj = datetime.strptime("26 Sep 2000 05:11:00 -0700", '%d %b %Y %H:%M:%S %z')

To convert 2012-07-24T23:14:29 -0700

dt_obj = datetime.strptime('2012-07-24T23:14:29 -0700', '%Y-%m-%dT%H:%M:%S %z')

Python 3.5.2 doesn’t support -07:00 time offset ‘:’ should be removed

Answered By: H S Rathore
The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Leave a Reply

Your email address will not be published.