17db96d56Sopenharmony_ci# SPDX-License-Identifier: MIT 27db96d56Sopenharmony_ci# SPDX-FileCopyrightText: 2021 Taneli Hukkinen 37db96d56Sopenharmony_ci# Licensed to PSF under a Contributor Agreement. 47db96d56Sopenharmony_ci 57db96d56Sopenharmony_cifrom __future__ import annotations 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_cifrom datetime import date, datetime, time, timedelta, timezone, tzinfo 87db96d56Sopenharmony_cifrom functools import lru_cache 97db96d56Sopenharmony_ciimport re 107db96d56Sopenharmony_cifrom typing import Any 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_cifrom ._types import ParseFloat 137db96d56Sopenharmony_ci 147db96d56Sopenharmony_ci# E.g. 157db96d56Sopenharmony_ci# - 00:32:00.999999 167db96d56Sopenharmony_ci# - 00:32:00 177db96d56Sopenharmony_ci_TIME_RE_STR = r"([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(?:\.([0-9]{1,6})[0-9]*)?" 187db96d56Sopenharmony_ci 197db96d56Sopenharmony_ciRE_NUMBER = re.compile( 207db96d56Sopenharmony_ci r""" 217db96d56Sopenharmony_ci0 227db96d56Sopenharmony_ci(?: 237db96d56Sopenharmony_ci x[0-9A-Fa-f](?:_?[0-9A-Fa-f])* # hex 247db96d56Sopenharmony_ci | 257db96d56Sopenharmony_ci b[01](?:_?[01])* # bin 267db96d56Sopenharmony_ci | 277db96d56Sopenharmony_ci o[0-7](?:_?[0-7])* # oct 287db96d56Sopenharmony_ci) 297db96d56Sopenharmony_ci| 307db96d56Sopenharmony_ci[+-]?(?:0|[1-9](?:_?[0-9])*) # dec, integer part 317db96d56Sopenharmony_ci(?P<floatpart> 327db96d56Sopenharmony_ci (?:\.[0-9](?:_?[0-9])*)? # optional fractional part 337db96d56Sopenharmony_ci (?:[eE][+-]?[0-9](?:_?[0-9])*)? # optional exponent part 347db96d56Sopenharmony_ci) 357db96d56Sopenharmony_ci""", 367db96d56Sopenharmony_ci flags=re.VERBOSE, 377db96d56Sopenharmony_ci) 387db96d56Sopenharmony_ciRE_LOCALTIME = re.compile(_TIME_RE_STR) 397db96d56Sopenharmony_ciRE_DATETIME = re.compile( 407db96d56Sopenharmony_ci rf""" 417db96d56Sopenharmony_ci([0-9]{{4}})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]) # date, e.g. 1988-10-27 427db96d56Sopenharmony_ci(?: 437db96d56Sopenharmony_ci [Tt ] 447db96d56Sopenharmony_ci {_TIME_RE_STR} 457db96d56Sopenharmony_ci (?:([Zz])|([+-])([01][0-9]|2[0-3]):([0-5][0-9]))? # optional time offset 467db96d56Sopenharmony_ci)? 477db96d56Sopenharmony_ci""", 487db96d56Sopenharmony_ci flags=re.VERBOSE, 497db96d56Sopenharmony_ci) 507db96d56Sopenharmony_ci 517db96d56Sopenharmony_ci 527db96d56Sopenharmony_cidef match_to_datetime(match: re.Match) -> datetime | date: 537db96d56Sopenharmony_ci """Convert a `RE_DATETIME` match to `datetime.datetime` or `datetime.date`. 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_ci Raises ValueError if the match does not correspond to a valid date 567db96d56Sopenharmony_ci or datetime. 577db96d56Sopenharmony_ci """ 587db96d56Sopenharmony_ci ( 597db96d56Sopenharmony_ci year_str, 607db96d56Sopenharmony_ci month_str, 617db96d56Sopenharmony_ci day_str, 627db96d56Sopenharmony_ci hour_str, 637db96d56Sopenharmony_ci minute_str, 647db96d56Sopenharmony_ci sec_str, 657db96d56Sopenharmony_ci micros_str, 667db96d56Sopenharmony_ci zulu_time, 677db96d56Sopenharmony_ci offset_sign_str, 687db96d56Sopenharmony_ci offset_hour_str, 697db96d56Sopenharmony_ci offset_minute_str, 707db96d56Sopenharmony_ci ) = match.groups() 717db96d56Sopenharmony_ci year, month, day = int(year_str), int(month_str), int(day_str) 727db96d56Sopenharmony_ci if hour_str is None: 737db96d56Sopenharmony_ci return date(year, month, day) 747db96d56Sopenharmony_ci hour, minute, sec = int(hour_str), int(minute_str), int(sec_str) 757db96d56Sopenharmony_ci micros = int(micros_str.ljust(6, "0")) if micros_str else 0 767db96d56Sopenharmony_ci if offset_sign_str: 777db96d56Sopenharmony_ci tz: tzinfo | None = cached_tz( 787db96d56Sopenharmony_ci offset_hour_str, offset_minute_str, offset_sign_str 797db96d56Sopenharmony_ci ) 807db96d56Sopenharmony_ci elif zulu_time: 817db96d56Sopenharmony_ci tz = timezone.utc 827db96d56Sopenharmony_ci else: # local date-time 837db96d56Sopenharmony_ci tz = None 847db96d56Sopenharmony_ci return datetime(year, month, day, hour, minute, sec, micros, tzinfo=tz) 857db96d56Sopenharmony_ci 867db96d56Sopenharmony_ci 877db96d56Sopenharmony_ci@lru_cache(maxsize=None) 887db96d56Sopenharmony_cidef cached_tz(hour_str: str, minute_str: str, sign_str: str) -> timezone: 897db96d56Sopenharmony_ci sign = 1 if sign_str == "+" else -1 907db96d56Sopenharmony_ci return timezone( 917db96d56Sopenharmony_ci timedelta( 927db96d56Sopenharmony_ci hours=sign * int(hour_str), 937db96d56Sopenharmony_ci minutes=sign * int(minute_str), 947db96d56Sopenharmony_ci ) 957db96d56Sopenharmony_ci ) 967db96d56Sopenharmony_ci 977db96d56Sopenharmony_ci 987db96d56Sopenharmony_cidef match_to_localtime(match: re.Match) -> time: 997db96d56Sopenharmony_ci hour_str, minute_str, sec_str, micros_str = match.groups() 1007db96d56Sopenharmony_ci micros = int(micros_str.ljust(6, "0")) if micros_str else 0 1017db96d56Sopenharmony_ci return time(int(hour_str), int(minute_str), int(sec_str), micros) 1027db96d56Sopenharmony_ci 1037db96d56Sopenharmony_ci 1047db96d56Sopenharmony_cidef match_to_number(match: re.Match, parse_float: ParseFloat) -> Any: 1057db96d56Sopenharmony_ci if match.group("floatpart"): 1067db96d56Sopenharmony_ci return parse_float(match.group()) 1077db96d56Sopenharmony_ci return int(match.group(), 0) 108