I want to write a function that takes a string and returns True
if it is a valid ISO-8601 datetime--precise to microseconds, including a timezone offset--False
otherwise.
I have found other questions that provide different ways of parsing datetime strings, but I want to return True
in the case of ISO-8601 format only. Parsing doesn't help me unless I can get it to throw an error for formats that don't match ISO-8601.
(I am using the nice arrow library elsewhere in my code. A solution that uses arrow
would be welcome.)
EDIT: It appears that a general solution to "is this string a valid ISO 8601 datetime" does not exist among the common Python datetime packages.
So, to make this question narrower, more concrete and answerable, I will settle for a format string that will validate a datetime string in this form:
'2016-12-13T21:20:37.593194+00:00'
Currently I am using:
format_string = '%Y-%m-%dT%H:%M:%S.%f%z'
datetime.datetime.strptime(my_timestamp, format_string)
This gives:
ValueError: time data '2016-12-13T21:20:37.593194+00:00' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
The problem seems to lie with the colon in the UTC offset (+00:00
). If I use an offset without a colon (e.g. '2016-12-13T21:20:37.593194+0000'
), this parses properly as expected. This is apparently because datetime
's %z
token does not respect the UTC offset form that has a colon, only the form without, even though both are valid per the spec.
if variable_name is str: print('string format! ') else: print('not a string! ') you can print the information and then check if the date is formatted in accordance with the ISO standard(en.wikipedia.org/wiki/ISO_8601).
ISO 8601 Formats ISO 8601 represents date and time by starting with the year, followed by the month, the day, the hour, the minutes, seconds and milliseconds. For example, 2020-07-10 15:00:00.000, represents the 10th of July 2020 at 3 p.m. (in local time as there is no time zone offset specified—more on that below).
Yes, it is valid. It's basically extended in terms of subsecond support, but that's allowed by the standard.
To convert datetime to ISO 8601 format use the isoformat() method. It returns a string representing the date in ISO 8601 format. this ISO string contains the date, time, and UTC offset to the corresponding time zone.
https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9781449327453/ch04s07.html
give many variants for validating date and times in ISO8601 format (e.g., 2008-08-30T01:45:36 or 2008-08-30T01:45:36.123Z). The regex for the XML Schema dateTime type is given as:
>>> regex = r'^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$'
So in order to validate you could do:
import re
match_iso8601 = re.compile(regex).match
def validate_iso8601(str_val):
try:
if match_iso8601( str_val ) is not None:
return True
except:
pass
return False
Some examples:
>>> validate_iso8601('2017-01-01')
False
>>> validate_iso8601('2008-08-30T01:45:36.123Z')
True
>>> validate_iso8601('2016-12-13T21:20:37.593194+00:00')
True
Recent versions of Python (from 3.7 onwards) have a fromisoformat()
function in the datetime
standard library. See: https://docs.python.org/3.7/library/datetime.html
So this will do the trick:
from datetime import datetime
def datetime_valid(dt_str):
try:
datetime.fromisoformat(dt_str)
except:
return False
return True
Update:
I learned that Python does not recognize the 'Z'-suffix as valid. As I wanted to support this in my API, I'm now using:
from datetime import datetime
def datetime_valid(dt_str):
try:
datetime.fromisoformat(dt_str)
except:
try:
datetime.fromisoformat(dt_str.replace('Z', '+00:00'))
except:
return False
return True
return True
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With