Convert Timestamps With Offset to Datetime Obj Using Strptime

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 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)))

Converting string with UTC offset to a datetime object

It looks as if strptime doesn't always support %z. Python appears to just call the C function, and strptime doesn't support %z on your platform.

Note: from Python 3.2 onwards it will always work.

Convert string to python date type object with timezone offset using strptime

Nominally you would want to be able to use the %z (lowercase z) to convert the TZ offset, however support for this is sketchy. So you can DIY it:

import datetime as dt
import re
PARSE_TIMESTAMP = re.compile('(.*) ([+-]?\d+) \(.*\)$')

def my_datetime_parse(timestamp):
''' return a naive datetime relative to UTC '''

# find the standard time stamp, and the TZ offset and remove extra end
matches = PARSE_TIMESTAMP.match(timestamp).groups()

# convert the timestamp element
timestamp = dt.datetime.strptime(matches[0], '%a %b %d %Y %H:%M:%S %Z')

# calculate the timezone offset
tz_offset = matches[1]
sign = '+'
if tz_offset[0] in '-+':
sign = tz_offset[0]
tz_offset = tz_offset[1:]
tz_offset += '0' * (4 - len(tz_offset))
minutes = int(tz_offset[0:2]) * 60 + int(tz_offset[2:])
if sign == '-':
minutes = -minutes

# add the timezone offset to our time
timestamp += dt.timedelta(minutes=minutes)
return timestamp

date_string = 'Tue Jan 10 2017 13:00:13 GMT +0800 (Taipei Standard Time)'
print(my_datetime_parse(date_string))

This code produces:

2017-01-10 21:00:13

The code removes the (Taipei Standard Time) since it is redundant with the +0800.

How to convert a timezone aware string to datetime in Python without dateutil?

As of Python 3.7, datetime.datetime.fromisoformat() can handle your format:

>>> import datetime
>>> datetime.datetime.fromisoformat('2012-11-01T04:16:13-04:00')
datetime.datetime(2012, 11, 1, 4, 16, 13, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=72000)))

In older Python versions you can't, not without a whole lot of painstaking manual timezone defining.

Python does not include a timezone database, because it would be outdated too quickly. Instead, Python relies on external libraries, which can have a far faster release cycle, to provide properly configured timezones for you.

As a side-effect, this means that timezone parsing also needs to be an external library. If dateutil is too heavy-weight for you, use iso8601 instead, it'll parse your specific format just fine:

>>> import iso8601
>>> iso8601.parse_date('2012-11-01T04:16:13-04:00')
datetime.datetime(2012, 11, 1, 4, 16, 13, tzinfo=<FixedOffset '-04:00'>)

iso8601 is a whopping 4KB small. Compare that tot python-dateutil's 148KB.

As of Python 3.2 Python can handle simple offset-based timezones, and %z will parse -hhmm and +hhmm timezone offsets in a timestamp. That means that for a ISO 8601 timestamp you'd have to remove the : in the timezone:

>>> from datetime import datetime
>>> iso_ts = '2012-11-01T04:16:13-04:00'
>>> datetime.strptime(''.join(iso_ts.rsplit(':', 1)), '%Y-%m-%dT%H:%M:%S%z')
datetime.datetime(2012, 11, 1, 4, 16, 13, tzinfo=datetime.timezone(datetime.timedelta(-1, 72000)))

The lack of proper ISO 8601 parsing is being tracked in Python issue 15873.

datetime: get timestamp with timezone offset

Please note Inconsistent datetime parse timezone in Python. Your problem is %Z, it makes strptime accept certain strings (GMT, UTC and any value in time.tzname - docs), but doesn't actually make anything out of it. The returned datetime object is naive - which is why Python will assume it's local time if you call the timestamp() method of it.

You can use dateutil's parser instead:

from dateutil.parser import parse

for s in ("Mon, 23 Nov 2020 19:00:00 GMT", "Mon, 23 Nov 2020 20:00:00 +0100"):
dt = parse(s)
print(repr(dt), dt.timestamp())

# datetime.datetime(2020, 11, 23, 19, 0, tzinfo=tzutc()) 1606158000.0
# datetime.datetime(2020, 11, 23, 20, 0, tzinfo=tzoffset(None, 3600)) 1606158000.0

How to convert a datetime ('2019-06-05T10:37:29.353+0100') to UTC timestamp using Python3?

here's some more explanations (see comments) how to convert back and forth between timestamps as strings with UTC offset and POSIX timestamps.

from datetime import datetime, timezone

s = '2019-06-05T10:37:29.353+0100'
# to datetime object
dt = datetime.strptime('2019-06-05T10:37:29.353+0100', '%Y-%m-%dT%H:%M:%S.%f%z')
# note that the object has tzinfo set to a specific timedelta:
print(repr(dt))
>>> datetime.datetime(2019, 6, 5, 10, 37, 29, 353000, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600)))

# you could store this info
dt_UTCoffset = dt.utcoffset() # datetime.timedelta(seconds=3600)

# to get POSIX seconds since the epoch:
ts = dt.timestamp()

# and back to datetime:
dt_from_ts = datetime.fromtimestamp(ts, tz=timezone.utc)
# note that this is a UTC timestamp; the UTC offset is zero:
print(dt_from_ts.isoformat())
>>> 2019-06-05T09:37:29.353000+00:00

# instead of UTC, you could also set a UTC offset:
dt_from_ts = datetime.fromtimestamp(ts, tz=timezone(dt_UTCoffset))
print(dt_from_ts.isoformat())
>>> 2019-06-05T10:37:29.353000+01:00

...And a note on a pitfall when working with datetime in Python: if you convert from timestamp to datetime and don't set the tz property, local time is returned (same applies the other way 'round!):

print(datetime.fromtimestamp(ts)) # I'm on CEST at the moment, so UTC+2
>>> 2019-06-05 11:37:29.353000

How to parse Fri, 25 Jun 2021 12:06:16 +0000 (UTC) to datetime object?

How does it not work? Which version of python are you using?
I just ran the following in python 3.9:

datetime.datetime.strptime("Fri, 25 Jun 2021 12:06:16 +0000 (UTC)", "%a, %d %b %Y %X %z (%Z)")

Which created this datetime object:

datetime.datetime(2021, 6, 25, 12, 6, 16, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC'))

How to convert this date string into a datetime date object?

%Z is the wrong directive here.

Try this

datetime.strptime('2013-11-05T20:24:51+0000', '%Y-%m-%dT%H:%M:%S+%f')

More here

Demo:

>>> from datetime import datetime
>>> datetime.strptime('2013-11-05T20:24:51+0000', '%Y-%m-%dT%H:%M:%S%Z')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/_strptime.py", line 325, in _strptime
(data_string, format))
ValueError: time data '2013-11-05T20:24:51+0000' does not match format '%Y-%m-%dT%H:%M:%S%Z'
>>> datetime.strptime('2013-11-05T20:24:51+0000', '%Y-%m-%dT%H:%M:%S+%f')
datetime.datetime(2013, 11, 5, 20, 24, 51)


Related Topics



Leave a reply



Submit