Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ISO to datetime object: 'z' is a bad directive [duplicate]

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.

like image 555
user2667326 Avatar asked Nov 25 '13 13:11

user2667326


People also ask

How do I get an ISO 8601 date in string format in Python?

This string is converted into an ISO format string by using the . strftime() method. Here as we know that ISO format is YYYY-MM-DD so we convert it into this format by using the following format code- “%Y-%m-%dT%H:%M:%S. %f%z”.

What is Strftime and Strptime in Python?

strptime is short for "parse time" where strftime is for "formatting time". That is, strptime is the opposite of strftime though they use, conveniently, the same formatting specification.

How do I convert a string to a datetime in Python?

We can convert a string to datetime using strptime() function. This function is available in datetime and time modules to parse a string to datetime and time objects respectively.


2 Answers

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?

like image 95
Max Avatar answered Sep 28 '22 21:09

Max


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.

like image 22
dnozay Avatar answered Sep 28 '22 22:09

dnozay