blob: 6f9fb055eb4065ad99d9d0886814064e4c3142fc [file] [log] [blame]
import re
from datetime import date
from datetime import datetime
from datetime import time
from datetime import timedelta
from ._compat import timezone
RFC_3339_DATETIME = re.compile(
"^"
"([0-9]+)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])" # Date
"[T ]" # Separator
"([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.([0-9]+))?" # Time
"((Z)|([\+|\-]([01][0-9]|2[0-3]):([0-5][0-9])))?" # Timezone
"$"
)
RFC_3339_DATE = re.compile("^([0-9]+)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$")
RFC_3339_TIME = re.compile(
"^([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.([0-9]+))?$"
)
_utc = timezone(timedelta(), "UTC")
def parse_rfc3339(string): # type: (str) -> Union[datetime, date, time]
m = RFC_3339_DATETIME.match(string)
if m:
year = int(m.group(1))
month = int(m.group(2))
day = int(m.group(3))
hour = int(m.group(4))
minute = int(m.group(5))
second = int(m.group(6))
microsecond = 0
if m.group(7):
microsecond = int(("{:<06s}".format(m.group(8)))[:6])
dt = datetime(year, month, day, hour, minute, second, microsecond)
if m.group(9):
# Timezone
tz = m.group(9)
if tz == "Z":
tzinfo = _utc
else:
sign = m.group(11)[0]
hour_offset, minute_offset = int(m.group(12)), int(m.group(13))
offset = timedelta(seconds=hour_offset * 3600 + minute_offset * 60)
if sign == "-":
offset = -offset
tzinfo = timezone(
offset, "{}{}:{}".format(sign, m.group(12), m.group(13))
)
return datetime(
year, month, day, hour, minute, second, microsecond, tzinfo=tzinfo
)
else:
return datetime(year, month, day, hour, minute, second, microsecond)
m = RFC_3339_DATE.match(string)
if m:
year = int(m.group(1))
month = int(m.group(2))
day = int(m.group(3))
return date(year, month, day)
m = RFC_3339_TIME.match(string)
if m:
hour = int(m.group(1))
minute = int(m.group(2))
second = int(m.group(3))
microsecond = 0
if m.group(4):
microsecond = int(("{:<06s}".format(m.group(5)))[:6])
return time(hour, minute, second, microsecond)
raise ValueError("Invalid RFC 339 string")