raise DataError(f"time not supported by Python: hour={h}")
-class TimeTzLoader(TimeLoader):
+class TimeTzLoader(Loader):
format = Format.TEXT
- _format = "%H:%M:%S.%f%z"
- _format_no_micro = _format.replace(".%f", "")
+ _py37 = sys.version_info >= (3, 7)
- def _load(self, data: Buffer) -> time:
- if isinstance(data, memoryview):
- data = bytes(data)
-
- # Hack to convert +HH in +HHMM
- if data[-3] in (43, 45):
- data += b"00"
-
- fmt = self._format if b"." in data else self._format_no_micro
- try:
- dt = datetime.strptime(data.decode("utf8"), fmt)
- except ValueError as e:
- return self._raise_error(data, e)
+ _re_format = re.compile(
+ rb"""(?ix)
+ ^
+ (\d+) : (\d+) : (\d+) (?: \. (\d+) )? # Time and micros
+ (-|\+) (\d+) (?: : (\d+) )? (?: : (\d+) )? # Timezone
+ $
+ """
+ )
- return dt.time().replace(tzinfo=dt.tzinfo)
+ def load(self, data: Buffer) -> time:
+ m = self._re_format.match(data)
+ if not m:
+ s = bytes(data).decode("utf8", "replace")
+ raise DataError(f"can't parse timetz {s!r}")
- def _load_py36(self, data: Buffer) -> time:
- if isinstance(data, memoryview):
- data = bytes(data)
- # Drop seconds from timezone for Python 3.6
- # Also, Python 3.6 doesn't support HHMM, only HH:MM
- if data[-6] in (43, 45): # +-HH:MM -> +-HHMM
- data = data[:-3] + data[-2:]
- elif data[-9] in (43, 45): # +-HH:MM:SS -> +-HHMM
- data = data[:-6] + data[-5:-3]
+ ho, mi, se, ms, sgn, oh, om, os = m.groups()
- return self._load(data)
+ # Pad the fraction of second to get millis
+ if ms:
+ if len(ms) == 6:
+ ims = int(ms)
+ else:
+ ims = int(ms + _ms_trail[len(ms)])
+ else:
+ ims = 0
+ # Calculate timezone
+ off = 60 * 60 * int(oh)
+ if om:
+ off += 60 * int(om)
+ if os and self._py37:
+ off += int(os)
+ tz = timezone(timedelta(0, off if sgn == b"+" else -off))
-if sys.version_info >= (3, 7):
- setattr(TimeTzLoader, "load", TimeTzLoader._load)
-else:
- setattr(TimeTzLoader, "load", TimeTzLoader._load_py36)
+ try:
+ return time(int(ho), int(mi), int(se), ims, tz)
+ except ValueError as e:
+ s = bytes(data).decode("utf8", "replace")
+ raise DataError(f"can't manage timetz {s!r}: {e}")
class TimeTzBinaryLoader(Loader):