1*cda5da8dSAndroid Build Coastguard Worker# SPDX-License-Identifier: MIT 2*cda5da8dSAndroid Build Coastguard Worker# SPDX-FileCopyrightText: 2021 Taneli Hukkinen 3*cda5da8dSAndroid Build Coastguard Worker# Licensed to PSF under a Contributor Agreement. 4*cda5da8dSAndroid Build Coastguard Worker 5*cda5da8dSAndroid Build Coastguard Workerfrom __future__ import annotations 6*cda5da8dSAndroid Build Coastguard Worker 7*cda5da8dSAndroid Build Coastguard Workerfrom datetime import date, datetime, time, timedelta, timezone, tzinfo 8*cda5da8dSAndroid Build Coastguard Workerfrom functools import lru_cache 9*cda5da8dSAndroid Build Coastguard Workerimport re 10*cda5da8dSAndroid Build Coastguard Workerfrom typing import Any 11*cda5da8dSAndroid Build Coastguard Worker 12*cda5da8dSAndroid Build Coastguard Workerfrom ._types import ParseFloat 13*cda5da8dSAndroid Build Coastguard Worker 14*cda5da8dSAndroid Build Coastguard Worker# E.g. 15*cda5da8dSAndroid Build Coastguard Worker# - 00:32:00.999999 16*cda5da8dSAndroid Build Coastguard Worker# - 00:32:00 17*cda5da8dSAndroid Build Coastguard Worker_TIME_RE_STR = r"([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(?:\.([0-9]{1,6})[0-9]*)?" 18*cda5da8dSAndroid Build Coastguard Worker 19*cda5da8dSAndroid Build Coastguard WorkerRE_NUMBER = re.compile( 20*cda5da8dSAndroid Build Coastguard Worker r""" 21*cda5da8dSAndroid Build Coastguard Worker0 22*cda5da8dSAndroid Build Coastguard Worker(?: 23*cda5da8dSAndroid Build Coastguard Worker x[0-9A-Fa-f](?:_?[0-9A-Fa-f])* # hex 24*cda5da8dSAndroid Build Coastguard Worker | 25*cda5da8dSAndroid Build Coastguard Worker b[01](?:_?[01])* # bin 26*cda5da8dSAndroid Build Coastguard Worker | 27*cda5da8dSAndroid Build Coastguard Worker o[0-7](?:_?[0-7])* # oct 28*cda5da8dSAndroid Build Coastguard Worker) 29*cda5da8dSAndroid Build Coastguard Worker| 30*cda5da8dSAndroid Build Coastguard Worker[+-]?(?:0|[1-9](?:_?[0-9])*) # dec, integer part 31*cda5da8dSAndroid Build Coastguard Worker(?P<floatpart> 32*cda5da8dSAndroid Build Coastguard Worker (?:\.[0-9](?:_?[0-9])*)? # optional fractional part 33*cda5da8dSAndroid Build Coastguard Worker (?:[eE][+-]?[0-9](?:_?[0-9])*)? # optional exponent part 34*cda5da8dSAndroid Build Coastguard Worker) 35*cda5da8dSAndroid Build Coastguard Worker""", 36*cda5da8dSAndroid Build Coastguard Worker flags=re.VERBOSE, 37*cda5da8dSAndroid Build Coastguard Worker) 38*cda5da8dSAndroid Build Coastguard WorkerRE_LOCALTIME = re.compile(_TIME_RE_STR) 39*cda5da8dSAndroid Build Coastguard WorkerRE_DATETIME = re.compile( 40*cda5da8dSAndroid Build Coastguard Worker rf""" 41*cda5da8dSAndroid Build Coastguard Worker([0-9]{{4}})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]) # date, e.g. 1988-10-27 42*cda5da8dSAndroid Build Coastguard Worker(?: 43*cda5da8dSAndroid Build Coastguard Worker [Tt ] 44*cda5da8dSAndroid Build Coastguard Worker {_TIME_RE_STR} 45*cda5da8dSAndroid Build Coastguard Worker (?:([Zz])|([+-])([01][0-9]|2[0-3]):([0-5][0-9]))? # optional time offset 46*cda5da8dSAndroid Build Coastguard Worker)? 47*cda5da8dSAndroid Build Coastguard Worker""", 48*cda5da8dSAndroid Build Coastguard Worker flags=re.VERBOSE, 49*cda5da8dSAndroid Build Coastguard Worker) 50*cda5da8dSAndroid Build Coastguard Worker 51*cda5da8dSAndroid Build Coastguard Worker 52*cda5da8dSAndroid Build Coastguard Workerdef match_to_datetime(match: re.Match) -> datetime | date: 53*cda5da8dSAndroid Build Coastguard Worker """Convert a `RE_DATETIME` match to `datetime.datetime` or `datetime.date`. 54*cda5da8dSAndroid Build Coastguard Worker 55*cda5da8dSAndroid Build Coastguard Worker Raises ValueError if the match does not correspond to a valid date 56*cda5da8dSAndroid Build Coastguard Worker or datetime. 57*cda5da8dSAndroid Build Coastguard Worker """ 58*cda5da8dSAndroid Build Coastguard Worker ( 59*cda5da8dSAndroid Build Coastguard Worker year_str, 60*cda5da8dSAndroid Build Coastguard Worker month_str, 61*cda5da8dSAndroid Build Coastguard Worker day_str, 62*cda5da8dSAndroid Build Coastguard Worker hour_str, 63*cda5da8dSAndroid Build Coastguard Worker minute_str, 64*cda5da8dSAndroid Build Coastguard Worker sec_str, 65*cda5da8dSAndroid Build Coastguard Worker micros_str, 66*cda5da8dSAndroid Build Coastguard Worker zulu_time, 67*cda5da8dSAndroid Build Coastguard Worker offset_sign_str, 68*cda5da8dSAndroid Build Coastguard Worker offset_hour_str, 69*cda5da8dSAndroid Build Coastguard Worker offset_minute_str, 70*cda5da8dSAndroid Build Coastguard Worker ) = match.groups() 71*cda5da8dSAndroid Build Coastguard Worker year, month, day = int(year_str), int(month_str), int(day_str) 72*cda5da8dSAndroid Build Coastguard Worker if hour_str is None: 73*cda5da8dSAndroid Build Coastguard Worker return date(year, month, day) 74*cda5da8dSAndroid Build Coastguard Worker hour, minute, sec = int(hour_str), int(minute_str), int(sec_str) 75*cda5da8dSAndroid Build Coastguard Worker micros = int(micros_str.ljust(6, "0")) if micros_str else 0 76*cda5da8dSAndroid Build Coastguard Worker if offset_sign_str: 77*cda5da8dSAndroid Build Coastguard Worker tz: tzinfo | None = cached_tz( 78*cda5da8dSAndroid Build Coastguard Worker offset_hour_str, offset_minute_str, offset_sign_str 79*cda5da8dSAndroid Build Coastguard Worker ) 80*cda5da8dSAndroid Build Coastguard Worker elif zulu_time: 81*cda5da8dSAndroid Build Coastguard Worker tz = timezone.utc 82*cda5da8dSAndroid Build Coastguard Worker else: # local date-time 83*cda5da8dSAndroid Build Coastguard Worker tz = None 84*cda5da8dSAndroid Build Coastguard Worker return datetime(year, month, day, hour, minute, sec, micros, tzinfo=tz) 85*cda5da8dSAndroid Build Coastguard Worker 86*cda5da8dSAndroid Build Coastguard Worker 87*cda5da8dSAndroid Build Coastguard Worker@lru_cache(maxsize=None) 88*cda5da8dSAndroid Build Coastguard Workerdef cached_tz(hour_str: str, minute_str: str, sign_str: str) -> timezone: 89*cda5da8dSAndroid Build Coastguard Worker sign = 1 if sign_str == "+" else -1 90*cda5da8dSAndroid Build Coastguard Worker return timezone( 91*cda5da8dSAndroid Build Coastguard Worker timedelta( 92*cda5da8dSAndroid Build Coastguard Worker hours=sign * int(hour_str), 93*cda5da8dSAndroid Build Coastguard Worker minutes=sign * int(minute_str), 94*cda5da8dSAndroid Build Coastguard Worker ) 95*cda5da8dSAndroid Build Coastguard Worker ) 96*cda5da8dSAndroid Build Coastguard Worker 97*cda5da8dSAndroid Build Coastguard Worker 98*cda5da8dSAndroid Build Coastguard Workerdef match_to_localtime(match: re.Match) -> time: 99*cda5da8dSAndroid Build Coastguard Worker hour_str, minute_str, sec_str, micros_str = match.groups() 100*cda5da8dSAndroid Build Coastguard Worker micros = int(micros_str.ljust(6, "0")) if micros_str else 0 101*cda5da8dSAndroid Build Coastguard Worker return time(int(hour_str), int(minute_str), int(sec_str), micros) 102*cda5da8dSAndroid Build Coastguard Worker 103*cda5da8dSAndroid Build Coastguard Worker 104*cda5da8dSAndroid Build Coastguard Workerdef match_to_number(match: re.Match, parse_float: ParseFloat) -> Any: 105*cda5da8dSAndroid Build Coastguard Worker if match.group("floatpart"): 106*cda5da8dSAndroid Build Coastguard Worker return parse_float(match.group()) 107*cda5da8dSAndroid Build Coastguard Worker return int(match.group(), 0) 108