Last active
October 10, 2017 07:57
-
-
Save bruno-rino/e2eb03c45d00965a32650769ea2710a4 to your computer and use it in GitHub Desktop.
Convert a ISO 8601 formatted datetime string to a python datetime. Supports basic and extended ISO 8601 formatting.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import re | |
from datetime import datetime, timedelta | |
from decimal import Decimal | |
def datetime_from_iso(text): | |
''' | |
Convert a ISO 8601 formatted datetime string to a python datetime | |
NOTE: this function is intentionally *not* timezone-aware; providing timezone information beyond 'Z' will fail. | |
NOTE: the parsing is sligthly too permissive; you can mix and match basic and extended ISO 8601 formatting (could be solved by using two regexes instead of one). | |
''' | |
m = re.match(r'(?P<year>\d{4})-?(?P<month>\d{2})-?(?P<day>\d{2})(T(?P<hours>\d{2})(:?(?P<minutes>\d{2})(:?(?P<seconds>\d{2}))?)?([,.](?P<fractional>\d+))?Z?)?', text) | |
# only keep fields that are present in the input text | |
data = {k: int(v) for k, v in m.groupdict().items() if v is not None} | |
# handle fractional time part | |
if 'fractional' in data: | |
if 'seconds' in data: | |
# fractional seconds | |
data['microseconds'] = int(str(data['fractional']).ljust(6, '0')) | |
elif 'minutes' in data: | |
# fractional minutes | |
value = Decimal('0.' + str(data['fractional'])) * 60 # minutes to seconds | |
data['seconds'] = int(value) | |
if value != int(value): | |
data['microseconds'] = int((value - int(value))*10**6) | |
else: | |
# fractional hours | |
value = Decimal('0.' + str(data['fractional'])) * 60 # hours to minutes | |
data['minutes'] = int(value) | |
if value != int(value): | |
value = (value - int(value)) * 60 # minutes to seconds | |
data['seconds'] = int(value) | |
if value != int(value): | |
data['microseconds'] = int((value - int(value))*10**6) | |
return datetime( | |
data.get('year', 0), | |
data.get('month', 0), | |
data.get('day', 0), | |
data.get('hours', 0), | |
data.get('minutes', 0), | |
data.get('seconds', 0), | |
data.get('microseconds', 0), | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment