44

I am trying to convert ISO to datetime using the code below:

dt = datetime.datetime.strptime("2013-07-23T15:10:59.342107+01:00", "%Y-%m-%dT%H:%M:%S.%f%z") 

and I'm getting the error below:

'z' is a bad directive in format '%Y-%m-%dT%H:%M:%S.%f%z' 

What is the best way to convert an ISO string of above the format to a datetime object? I'm using Python version 2.7.6.

2

2 Answers 2

28

Welcome to Python datetime! Dealing with dates and times is necessarily complex, and Python doesn't come fully with batteries included in this case. You can't use %z in strptime because Python has no classes to represent timezones (you are supposed to implement your own, or better yet include some other libraries).

You want to use pytz and python-dateutil. For more details see here:

Python strptime() and timezones?

Sign up to request clarification or add additional context in comments.

2 Comments

My god python is like the phase of the moon - this week we'll do it this way, next week who cares!
I have to say that the absence of %z is quite disappointing indeed ...
27

problem with python 2.7

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

>>> import datetime, sys >>> datetime.datetime.strptime("2013-07-23T15:10:59.342107+01:00", "%Y-%m-%dT%H:%M:%S.%f%z") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/_strptime.py", line 317, in _strptime (bad_directive, format)) ValueError: 'z' is a bad directive in format '%Y-%m-%dT%H:%M:%S.%f%z' >>> sys.version '2.7.10 (default, Feb 7 2017, 00:08:15) \n[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)]' 

problem with python 3:

If python 2 does not support %z because of the underlying strptime() implementation, then a possible way to fix your issue is to migrate to python 3. But it didn't work for me:

>>> import datetime, sys >>> datetime.datetime.strptime("2013-07-23T15:10:59.342107+01:00", "%Y-%m-%dT%H:%M:%S.%f%z") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/_strptime.py", line 565, in _strptime_datetime tt, fraction = _strptime(data_string, format) File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/_strptime.py", line 362, in _strptime (data_string, format)) ValueError: time data '2013-07-23T15:10:59.342107+01:00' does not match format '%Y-%m-%dT%H:%M:%S.%f%z' >>> sys.version '3.6.3 (v3.6.3:2c5fed86e0, Oct 3 2017, 00:32:08) \n[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]' 

The problem is because is not strictly ISO8601 (note how there was a : in the timezone info).

>>> datetime.datetime.strptime("2013-07-23T15:10:59.342107+0100", "%Y-%m-%dT%H:%M:%S.%f%z") datetime.datetime(2013, 7, 23, 15, 10, 59, 342107, tzinfo=datetime.timezone(datetime.timedelta(0, 3600))) 

solution with django & pytz:

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.

Please note that django does use pytz under the hood for things like the utc singleton.

solution without django & pytz:

If you want a quick and dirty solution, you can use something similar to django without all the requirements.

https://gist.github.com/dnozay/3cd554a818ed768bff804bc04484905d

>>> from datetime_z import parse_datetime >>> parse_datetime("2013-07-23T15:10:59.342107+01:00") datetime.datetime(2013, 7, 23, 15, 10, 59, 342107, tzinfo=+0100) 

Please note: YMMV, there is no support.

4 Comments

This is really great! No 3rd party package or own parser code is needed! I think many people use Django.
This should be the correct answer, given someone uses Django!
Do you have a solution for this question without Django?
Even parse_datetime can't help you if your timezone doesn't have - and :s T_T. I found a roundabout pure python way to do it that I wrote out here: stackoverflow.com/a/25878651/738924

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.