|
|
- import datetime
- import re
-
- rfc3339_re = re.compile(r'(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(?:Z|([+-]\d{2}):(\d{2}))')
-
- def parse_rfc3339(v):
- m = rfc3339_re.match(v)
- if not m or m.group(0) != v:
- return None
- return parse_rfc3339_re(m)
-
- def parse_rfc3339_re(m):
- r = map(int, m.groups()[:6])
- if m.group(7):
- micro = float(m.group(7))
- else:
- micro = 0
-
- if m.group(8):
- g = int(m.group(8), 10) * 60 + int(m.group(9), 10)
- tz = _TimeZone(datetime.timedelta(0, g * 60))
- else:
- tz = _TimeZone(datetime.timedelta(0, 0))
-
- y, m, d, H, M, S = r
- return datetime.datetime(y, m, d, H, M, S, int(micro * 1000000), tz)
-
-
- def format_rfc3339(v):
- offs = v.utcoffset()
- offs = int(offs.total_seconds()) // 60 if offs is not None else 0
-
- if offs == 0:
- suffix = 'Z'
- else:
- if offs > 0:
- suffix = '+'
- else:
- suffix = '-'
- offs = -offs
- suffix = '{0}{1:02}:{2:02}'.format(suffix, offs // 60, offs % 60)
-
- if v.microsecond:
- return v.strftime('%Y-%m-%dT%H:%M:%S.%f') + suffix
- else:
- return v.strftime('%Y-%m-%dT%H:%M:%S') + suffix
-
- class _TimeZone(datetime.tzinfo):
- def __init__(self, offset):
- self._offset = offset
-
- def utcoffset(self, dt):
- return self._offset
-
- def dst(self, dt):
- return None
-
- def tzname(self, dt):
- m = self._offset.total_seconds() // 60
- if m < 0:
- res = '-'
- m = -m
- else:
- res = '+'
- h = m // 60
- m = m - h * 60
- return '{}{:.02}{:.02}'.format(res, h, m)
|