17db96d56Sopenharmony_ci"""Concrete date/time and related types.
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ciSee http://www.iana.org/time-zones/repository/tz-link.html for
47db96d56Sopenharmony_citime zone and DST data sources.
57db96d56Sopenharmony_ci"""
67db96d56Sopenharmony_ci
77db96d56Sopenharmony_ci__all__ = ("date", "datetime", "time", "timedelta", "timezone", "tzinfo",
87db96d56Sopenharmony_ci           "MINYEAR", "MAXYEAR", "UTC")
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ci
117db96d56Sopenharmony_ciimport time as _time
127db96d56Sopenharmony_ciimport math as _math
137db96d56Sopenharmony_ciimport sys
147db96d56Sopenharmony_cifrom operator import index as _index
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_cidef _cmp(x, y):
177db96d56Sopenharmony_ci    return 0 if x == y else 1 if x > y else -1
187db96d56Sopenharmony_ci
197db96d56Sopenharmony_ciMINYEAR = 1
207db96d56Sopenharmony_ciMAXYEAR = 9999
217db96d56Sopenharmony_ci_MAXORDINAL = 3652059  # date.max.toordinal()
227db96d56Sopenharmony_ci
237db96d56Sopenharmony_ci# Utility functions, adapted from Python's Demo/classes/Dates.py, which
247db96d56Sopenharmony_ci# also assumes the current Gregorian calendar indefinitely extended in
257db96d56Sopenharmony_ci# both directions.  Difference:  Dates.py calls January 1 of year 0 day
267db96d56Sopenharmony_ci# number 1.  The code here calls January 1 of year 1 day number 1.  This is
277db96d56Sopenharmony_ci# to match the definition of the "proleptic Gregorian" calendar in Dershowitz
287db96d56Sopenharmony_ci# and Reingold's "Calendrical Calculations", where it's the base calendar
297db96d56Sopenharmony_ci# for all computations.  See the book for algorithms for converting between
307db96d56Sopenharmony_ci# proleptic Gregorian ordinals and many other calendar systems.
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ci# -1 is a placeholder for indexing purposes.
337db96d56Sopenharmony_ci_DAYS_IN_MONTH = [-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_ci_DAYS_BEFORE_MONTH = [-1]  # -1 is a placeholder for indexing purposes.
367db96d56Sopenharmony_cidbm = 0
377db96d56Sopenharmony_cifor dim in _DAYS_IN_MONTH[1:]:
387db96d56Sopenharmony_ci    _DAYS_BEFORE_MONTH.append(dbm)
397db96d56Sopenharmony_ci    dbm += dim
407db96d56Sopenharmony_cidel dbm, dim
417db96d56Sopenharmony_ci
427db96d56Sopenharmony_cidef _is_leap(year):
437db96d56Sopenharmony_ci    "year -> 1 if leap year, else 0."
447db96d56Sopenharmony_ci    return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
457db96d56Sopenharmony_ci
467db96d56Sopenharmony_cidef _days_before_year(year):
477db96d56Sopenharmony_ci    "year -> number of days before January 1st of year."
487db96d56Sopenharmony_ci    y = year - 1
497db96d56Sopenharmony_ci    return y*365 + y//4 - y//100 + y//400
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_cidef _days_in_month(year, month):
527db96d56Sopenharmony_ci    "year, month -> number of days in that month in that year."
537db96d56Sopenharmony_ci    assert 1 <= month <= 12, month
547db96d56Sopenharmony_ci    if month == 2 and _is_leap(year):
557db96d56Sopenharmony_ci        return 29
567db96d56Sopenharmony_ci    return _DAYS_IN_MONTH[month]
577db96d56Sopenharmony_ci
587db96d56Sopenharmony_cidef _days_before_month(year, month):
597db96d56Sopenharmony_ci    "year, month -> number of days in year preceding first day of month."
607db96d56Sopenharmony_ci    assert 1 <= month <= 12, 'month must be in 1..12'
617db96d56Sopenharmony_ci    return _DAYS_BEFORE_MONTH[month] + (month > 2 and _is_leap(year))
627db96d56Sopenharmony_ci
637db96d56Sopenharmony_cidef _ymd2ord(year, month, day):
647db96d56Sopenharmony_ci    "year, month, day -> ordinal, considering 01-Jan-0001 as day 1."
657db96d56Sopenharmony_ci    assert 1 <= month <= 12, 'month must be in 1..12'
667db96d56Sopenharmony_ci    dim = _days_in_month(year, month)
677db96d56Sopenharmony_ci    assert 1 <= day <= dim, ('day must be in 1..%d' % dim)
687db96d56Sopenharmony_ci    return (_days_before_year(year) +
697db96d56Sopenharmony_ci            _days_before_month(year, month) +
707db96d56Sopenharmony_ci            day)
717db96d56Sopenharmony_ci
727db96d56Sopenharmony_ci_DI400Y = _days_before_year(401)    # number of days in 400 years
737db96d56Sopenharmony_ci_DI100Y = _days_before_year(101)    #    "    "   "   " 100   "
747db96d56Sopenharmony_ci_DI4Y   = _days_before_year(5)      #    "    "   "   "   4   "
757db96d56Sopenharmony_ci
767db96d56Sopenharmony_ci# A 4-year cycle has an extra leap day over what we'd get from pasting
777db96d56Sopenharmony_ci# together 4 single years.
787db96d56Sopenharmony_ciassert _DI4Y == 4 * 365 + 1
797db96d56Sopenharmony_ci
807db96d56Sopenharmony_ci# Similarly, a 400-year cycle has an extra leap day over what we'd get from
817db96d56Sopenharmony_ci# pasting together 4 100-year cycles.
827db96d56Sopenharmony_ciassert _DI400Y == 4 * _DI100Y + 1
837db96d56Sopenharmony_ci
847db96d56Sopenharmony_ci# OTOH, a 100-year cycle has one fewer leap day than we'd get from
857db96d56Sopenharmony_ci# pasting together 25 4-year cycles.
867db96d56Sopenharmony_ciassert _DI100Y == 25 * _DI4Y - 1
877db96d56Sopenharmony_ci
887db96d56Sopenharmony_cidef _ord2ymd(n):
897db96d56Sopenharmony_ci    "ordinal -> (year, month, day), considering 01-Jan-0001 as day 1."
907db96d56Sopenharmony_ci
917db96d56Sopenharmony_ci    # n is a 1-based index, starting at 1-Jan-1.  The pattern of leap years
927db96d56Sopenharmony_ci    # repeats exactly every 400 years.  The basic strategy is to find the
937db96d56Sopenharmony_ci    # closest 400-year boundary at or before n, then work with the offset
947db96d56Sopenharmony_ci    # from that boundary to n.  Life is much clearer if we subtract 1 from
957db96d56Sopenharmony_ci    # n first -- then the values of n at 400-year boundaries are exactly
967db96d56Sopenharmony_ci    # those divisible by _DI400Y:
977db96d56Sopenharmony_ci    #
987db96d56Sopenharmony_ci    #     D  M   Y            n              n-1
997db96d56Sopenharmony_ci    #     -- --- ----        ----------     ----------------
1007db96d56Sopenharmony_ci    #     31 Dec -400        -_DI400Y       -_DI400Y -1
1017db96d56Sopenharmony_ci    #      1 Jan -399         -_DI400Y +1   -_DI400Y      400-year boundary
1027db96d56Sopenharmony_ci    #     ...
1037db96d56Sopenharmony_ci    #     30 Dec  000        -1             -2
1047db96d56Sopenharmony_ci    #     31 Dec  000         0             -1
1057db96d56Sopenharmony_ci    #      1 Jan  001         1              0            400-year boundary
1067db96d56Sopenharmony_ci    #      2 Jan  001         2              1
1077db96d56Sopenharmony_ci    #      3 Jan  001         3              2
1087db96d56Sopenharmony_ci    #     ...
1097db96d56Sopenharmony_ci    #     31 Dec  400         _DI400Y        _DI400Y -1
1107db96d56Sopenharmony_ci    #      1 Jan  401         _DI400Y +1     _DI400Y      400-year boundary
1117db96d56Sopenharmony_ci    n -= 1
1127db96d56Sopenharmony_ci    n400, n = divmod(n, _DI400Y)
1137db96d56Sopenharmony_ci    year = n400 * 400 + 1   # ..., -399, 1, 401, ...
1147db96d56Sopenharmony_ci
1157db96d56Sopenharmony_ci    # Now n is the (non-negative) offset, in days, from January 1 of year, to
1167db96d56Sopenharmony_ci    # the desired date.  Now compute how many 100-year cycles precede n.
1177db96d56Sopenharmony_ci    # Note that it's possible for n100 to equal 4!  In that case 4 full
1187db96d56Sopenharmony_ci    # 100-year cycles precede the desired day, which implies the desired
1197db96d56Sopenharmony_ci    # day is December 31 at the end of a 400-year cycle.
1207db96d56Sopenharmony_ci    n100, n = divmod(n, _DI100Y)
1217db96d56Sopenharmony_ci
1227db96d56Sopenharmony_ci    # Now compute how many 4-year cycles precede it.
1237db96d56Sopenharmony_ci    n4, n = divmod(n, _DI4Y)
1247db96d56Sopenharmony_ci
1257db96d56Sopenharmony_ci    # And now how many single years.  Again n1 can be 4, and again meaning
1267db96d56Sopenharmony_ci    # that the desired day is December 31 at the end of the 4-year cycle.
1277db96d56Sopenharmony_ci    n1, n = divmod(n, 365)
1287db96d56Sopenharmony_ci
1297db96d56Sopenharmony_ci    year += n100 * 100 + n4 * 4 + n1
1307db96d56Sopenharmony_ci    if n1 == 4 or n100 == 4:
1317db96d56Sopenharmony_ci        assert n == 0
1327db96d56Sopenharmony_ci        return year-1, 12, 31
1337db96d56Sopenharmony_ci
1347db96d56Sopenharmony_ci    # Now the year is correct, and n is the offset from January 1.  We find
1357db96d56Sopenharmony_ci    # the month via an estimate that's either exact or one too large.
1367db96d56Sopenharmony_ci    leapyear = n1 == 3 and (n4 != 24 or n100 == 3)
1377db96d56Sopenharmony_ci    assert leapyear == _is_leap(year)
1387db96d56Sopenharmony_ci    month = (n + 50) >> 5
1397db96d56Sopenharmony_ci    preceding = _DAYS_BEFORE_MONTH[month] + (month > 2 and leapyear)
1407db96d56Sopenharmony_ci    if preceding > n:  # estimate is too large
1417db96d56Sopenharmony_ci        month -= 1
1427db96d56Sopenharmony_ci        preceding -= _DAYS_IN_MONTH[month] + (month == 2 and leapyear)
1437db96d56Sopenharmony_ci    n -= preceding
1447db96d56Sopenharmony_ci    assert 0 <= n < _days_in_month(year, month)
1457db96d56Sopenharmony_ci
1467db96d56Sopenharmony_ci    # Now the year and month are correct, and n is the offset from the
1477db96d56Sopenharmony_ci    # start of that month:  we're done!
1487db96d56Sopenharmony_ci    return year, month, n+1
1497db96d56Sopenharmony_ci
1507db96d56Sopenharmony_ci# Month and day names.  For localized versions, see the calendar module.
1517db96d56Sopenharmony_ci_MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1527db96d56Sopenharmony_ci                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
1537db96d56Sopenharmony_ci_DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
1547db96d56Sopenharmony_ci
1557db96d56Sopenharmony_ci
1567db96d56Sopenharmony_cidef _build_struct_time(y, m, d, hh, mm, ss, dstflag):
1577db96d56Sopenharmony_ci    wday = (_ymd2ord(y, m, d) + 6) % 7
1587db96d56Sopenharmony_ci    dnum = _days_before_month(y, m) + d
1597db96d56Sopenharmony_ci    return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag))
1607db96d56Sopenharmony_ci
1617db96d56Sopenharmony_cidef _format_time(hh, mm, ss, us, timespec='auto'):
1627db96d56Sopenharmony_ci    specs = {
1637db96d56Sopenharmony_ci        'hours': '{:02d}',
1647db96d56Sopenharmony_ci        'minutes': '{:02d}:{:02d}',
1657db96d56Sopenharmony_ci        'seconds': '{:02d}:{:02d}:{:02d}',
1667db96d56Sopenharmony_ci        'milliseconds': '{:02d}:{:02d}:{:02d}.{:03d}',
1677db96d56Sopenharmony_ci        'microseconds': '{:02d}:{:02d}:{:02d}.{:06d}'
1687db96d56Sopenharmony_ci    }
1697db96d56Sopenharmony_ci
1707db96d56Sopenharmony_ci    if timespec == 'auto':
1717db96d56Sopenharmony_ci        # Skip trailing microseconds when us==0.
1727db96d56Sopenharmony_ci        timespec = 'microseconds' if us else 'seconds'
1737db96d56Sopenharmony_ci    elif timespec == 'milliseconds':
1747db96d56Sopenharmony_ci        us //= 1000
1757db96d56Sopenharmony_ci    try:
1767db96d56Sopenharmony_ci        fmt = specs[timespec]
1777db96d56Sopenharmony_ci    except KeyError:
1787db96d56Sopenharmony_ci        raise ValueError('Unknown timespec value')
1797db96d56Sopenharmony_ci    else:
1807db96d56Sopenharmony_ci        return fmt.format(hh, mm, ss, us)
1817db96d56Sopenharmony_ci
1827db96d56Sopenharmony_cidef _format_offset(off):
1837db96d56Sopenharmony_ci    s = ''
1847db96d56Sopenharmony_ci    if off is not None:
1857db96d56Sopenharmony_ci        if off.days < 0:
1867db96d56Sopenharmony_ci            sign = "-"
1877db96d56Sopenharmony_ci            off = -off
1887db96d56Sopenharmony_ci        else:
1897db96d56Sopenharmony_ci            sign = "+"
1907db96d56Sopenharmony_ci        hh, mm = divmod(off, timedelta(hours=1))
1917db96d56Sopenharmony_ci        mm, ss = divmod(mm, timedelta(minutes=1))
1927db96d56Sopenharmony_ci        s += "%s%02d:%02d" % (sign, hh, mm)
1937db96d56Sopenharmony_ci        if ss or ss.microseconds:
1947db96d56Sopenharmony_ci            s += ":%02d" % ss.seconds
1957db96d56Sopenharmony_ci
1967db96d56Sopenharmony_ci            if ss.microseconds:
1977db96d56Sopenharmony_ci                s += '.%06d' % ss.microseconds
1987db96d56Sopenharmony_ci    return s
1997db96d56Sopenharmony_ci
2007db96d56Sopenharmony_ci# Correctly substitute for %z and %Z escapes in strftime formats.
2017db96d56Sopenharmony_cidef _wrap_strftime(object, format, timetuple):
2027db96d56Sopenharmony_ci    # Don't call utcoffset() or tzname() unless actually needed.
2037db96d56Sopenharmony_ci    freplace = None  # the string to use for %f
2047db96d56Sopenharmony_ci    zreplace = None  # the string to use for %z
2057db96d56Sopenharmony_ci    Zreplace = None  # the string to use for %Z
2067db96d56Sopenharmony_ci
2077db96d56Sopenharmony_ci    # Scan format for %z and %Z escapes, replacing as needed.
2087db96d56Sopenharmony_ci    newformat = []
2097db96d56Sopenharmony_ci    push = newformat.append
2107db96d56Sopenharmony_ci    i, n = 0, len(format)
2117db96d56Sopenharmony_ci    while i < n:
2127db96d56Sopenharmony_ci        ch = format[i]
2137db96d56Sopenharmony_ci        i += 1
2147db96d56Sopenharmony_ci        if ch == '%':
2157db96d56Sopenharmony_ci            if i < n:
2167db96d56Sopenharmony_ci                ch = format[i]
2177db96d56Sopenharmony_ci                i += 1
2187db96d56Sopenharmony_ci                if ch == 'f':
2197db96d56Sopenharmony_ci                    if freplace is None:
2207db96d56Sopenharmony_ci                        freplace = '%06d' % getattr(object,
2217db96d56Sopenharmony_ci                                                    'microsecond', 0)
2227db96d56Sopenharmony_ci                    newformat.append(freplace)
2237db96d56Sopenharmony_ci                elif ch == 'z':
2247db96d56Sopenharmony_ci                    if zreplace is None:
2257db96d56Sopenharmony_ci                        zreplace = ""
2267db96d56Sopenharmony_ci                        if hasattr(object, "utcoffset"):
2277db96d56Sopenharmony_ci                            offset = object.utcoffset()
2287db96d56Sopenharmony_ci                            if offset is not None:
2297db96d56Sopenharmony_ci                                sign = '+'
2307db96d56Sopenharmony_ci                                if offset.days < 0:
2317db96d56Sopenharmony_ci                                    offset = -offset
2327db96d56Sopenharmony_ci                                    sign = '-'
2337db96d56Sopenharmony_ci                                h, rest = divmod(offset, timedelta(hours=1))
2347db96d56Sopenharmony_ci                                m, rest = divmod(rest, timedelta(minutes=1))
2357db96d56Sopenharmony_ci                                s = rest.seconds
2367db96d56Sopenharmony_ci                                u = offset.microseconds
2377db96d56Sopenharmony_ci                                if u:
2387db96d56Sopenharmony_ci                                    zreplace = '%c%02d%02d%02d.%06d' % (sign, h, m, s, u)
2397db96d56Sopenharmony_ci                                elif s:
2407db96d56Sopenharmony_ci                                    zreplace = '%c%02d%02d%02d' % (sign, h, m, s)
2417db96d56Sopenharmony_ci                                else:
2427db96d56Sopenharmony_ci                                    zreplace = '%c%02d%02d' % (sign, h, m)
2437db96d56Sopenharmony_ci                    assert '%' not in zreplace
2447db96d56Sopenharmony_ci                    newformat.append(zreplace)
2457db96d56Sopenharmony_ci                elif ch == 'Z':
2467db96d56Sopenharmony_ci                    if Zreplace is None:
2477db96d56Sopenharmony_ci                        Zreplace = ""
2487db96d56Sopenharmony_ci                        if hasattr(object, "tzname"):
2497db96d56Sopenharmony_ci                            s = object.tzname()
2507db96d56Sopenharmony_ci                            if s is not None:
2517db96d56Sopenharmony_ci                                # strftime is going to have at this: escape %
2527db96d56Sopenharmony_ci                                Zreplace = s.replace('%', '%%')
2537db96d56Sopenharmony_ci                    newformat.append(Zreplace)
2547db96d56Sopenharmony_ci                else:
2557db96d56Sopenharmony_ci                    push('%')
2567db96d56Sopenharmony_ci                    push(ch)
2577db96d56Sopenharmony_ci            else:
2587db96d56Sopenharmony_ci                push('%')
2597db96d56Sopenharmony_ci        else:
2607db96d56Sopenharmony_ci            push(ch)
2617db96d56Sopenharmony_ci    newformat = "".join(newformat)
2627db96d56Sopenharmony_ci    return _time.strftime(newformat, timetuple)
2637db96d56Sopenharmony_ci
2647db96d56Sopenharmony_ci# Helpers for parsing the result of isoformat()
2657db96d56Sopenharmony_cidef _is_ascii_digit(c):
2667db96d56Sopenharmony_ci    return c in "0123456789"
2677db96d56Sopenharmony_ci
2687db96d56Sopenharmony_cidef _find_isoformat_datetime_separator(dtstr):
2697db96d56Sopenharmony_ci    # See the comment in _datetimemodule.c:_find_isoformat_datetime_separator
2707db96d56Sopenharmony_ci    len_dtstr = len(dtstr)
2717db96d56Sopenharmony_ci    if len_dtstr == 7:
2727db96d56Sopenharmony_ci        return 7
2737db96d56Sopenharmony_ci
2747db96d56Sopenharmony_ci    assert len_dtstr > 7
2757db96d56Sopenharmony_ci    date_separator = "-"
2767db96d56Sopenharmony_ci    week_indicator = "W"
2777db96d56Sopenharmony_ci
2787db96d56Sopenharmony_ci    if dtstr[4] == date_separator:
2797db96d56Sopenharmony_ci        if dtstr[5] == week_indicator:
2807db96d56Sopenharmony_ci            if len_dtstr < 8:
2817db96d56Sopenharmony_ci                raise ValueError("Invalid ISO string")
2827db96d56Sopenharmony_ci            if len_dtstr > 8 and dtstr[8] == date_separator:
2837db96d56Sopenharmony_ci                if len_dtstr == 9:
2847db96d56Sopenharmony_ci                    raise ValueError("Invalid ISO string")
2857db96d56Sopenharmony_ci                if len_dtstr > 10 and _is_ascii_digit(dtstr[10]):
2867db96d56Sopenharmony_ci                    # This is as far as we need to resolve the ambiguity for
2877db96d56Sopenharmony_ci                    # the moment - if we have YYYY-Www-##, the separator is
2887db96d56Sopenharmony_ci                    # either a hyphen at 8 or a number at 10.
2897db96d56Sopenharmony_ci                    #
2907db96d56Sopenharmony_ci                    # We'll assume it's a hyphen at 8 because it's way more
2917db96d56Sopenharmony_ci                    # likely that someone will use a hyphen as a separator than
2927db96d56Sopenharmony_ci                    # a number, but at this point it's really best effort
2937db96d56Sopenharmony_ci                    # because this is an extension of the spec anyway.
2947db96d56Sopenharmony_ci                    # TODO(pganssle): Document this
2957db96d56Sopenharmony_ci                    return 8
2967db96d56Sopenharmony_ci                return 10
2977db96d56Sopenharmony_ci            else:
2987db96d56Sopenharmony_ci                # YYYY-Www (8)
2997db96d56Sopenharmony_ci                return 8
3007db96d56Sopenharmony_ci        else:
3017db96d56Sopenharmony_ci            # YYYY-MM-DD (10)
3027db96d56Sopenharmony_ci            return 10
3037db96d56Sopenharmony_ci    else:
3047db96d56Sopenharmony_ci        if dtstr[4] == week_indicator:
3057db96d56Sopenharmony_ci            # YYYYWww (7) or YYYYWwwd (8)
3067db96d56Sopenharmony_ci            idx = 7
3077db96d56Sopenharmony_ci            while idx < len_dtstr:
3087db96d56Sopenharmony_ci                if not _is_ascii_digit(dtstr[idx]):
3097db96d56Sopenharmony_ci                    break
3107db96d56Sopenharmony_ci                idx += 1
3117db96d56Sopenharmony_ci
3127db96d56Sopenharmony_ci            if idx < 9:
3137db96d56Sopenharmony_ci                return idx
3147db96d56Sopenharmony_ci
3157db96d56Sopenharmony_ci            if idx % 2 == 0:
3167db96d56Sopenharmony_ci                # If the index of the last number is even, it's YYYYWwwd
3177db96d56Sopenharmony_ci                return 7
3187db96d56Sopenharmony_ci            else:
3197db96d56Sopenharmony_ci                return 8
3207db96d56Sopenharmony_ci        else:
3217db96d56Sopenharmony_ci            # YYYYMMDD (8)
3227db96d56Sopenharmony_ci            return 8
3237db96d56Sopenharmony_ci
3247db96d56Sopenharmony_ci
3257db96d56Sopenharmony_cidef _parse_isoformat_date(dtstr):
3267db96d56Sopenharmony_ci    # It is assumed that this is an ASCII-only string of lengths 7, 8 or 10,
3277db96d56Sopenharmony_ci    # see the comment on Modules/_datetimemodule.c:_find_isoformat_datetime_separator
3287db96d56Sopenharmony_ci    assert len(dtstr) in (7, 8, 10)
3297db96d56Sopenharmony_ci    year = int(dtstr[0:4])
3307db96d56Sopenharmony_ci    has_sep = dtstr[4] == '-'
3317db96d56Sopenharmony_ci
3327db96d56Sopenharmony_ci    pos = 4 + has_sep
3337db96d56Sopenharmony_ci    if dtstr[pos:pos + 1] == "W":
3347db96d56Sopenharmony_ci        # YYYY-?Www-?D?
3357db96d56Sopenharmony_ci        pos += 1
3367db96d56Sopenharmony_ci        weekno = int(dtstr[pos:pos + 2])
3377db96d56Sopenharmony_ci        pos += 2
3387db96d56Sopenharmony_ci
3397db96d56Sopenharmony_ci        dayno = 1
3407db96d56Sopenharmony_ci        if len(dtstr) > pos:
3417db96d56Sopenharmony_ci            if (dtstr[pos:pos + 1] == '-') != has_sep:
3427db96d56Sopenharmony_ci                raise ValueError("Inconsistent use of dash separator")
3437db96d56Sopenharmony_ci
3447db96d56Sopenharmony_ci            pos += has_sep
3457db96d56Sopenharmony_ci
3467db96d56Sopenharmony_ci            dayno = int(dtstr[pos:pos + 1])
3477db96d56Sopenharmony_ci
3487db96d56Sopenharmony_ci        return list(_isoweek_to_gregorian(year, weekno, dayno))
3497db96d56Sopenharmony_ci    else:
3507db96d56Sopenharmony_ci        month = int(dtstr[pos:pos + 2])
3517db96d56Sopenharmony_ci        pos += 2
3527db96d56Sopenharmony_ci        if (dtstr[pos:pos + 1] == "-") != has_sep:
3537db96d56Sopenharmony_ci            raise ValueError("Inconsistent use of dash separator")
3547db96d56Sopenharmony_ci
3557db96d56Sopenharmony_ci        pos += has_sep
3567db96d56Sopenharmony_ci        day = int(dtstr[pos:pos + 2])
3577db96d56Sopenharmony_ci
3587db96d56Sopenharmony_ci        return [year, month, day]
3597db96d56Sopenharmony_ci
3607db96d56Sopenharmony_ci
3617db96d56Sopenharmony_ci_FRACTION_CORRECTION = [100000, 10000, 1000, 100, 10]
3627db96d56Sopenharmony_ci
3637db96d56Sopenharmony_ci
3647db96d56Sopenharmony_cidef _parse_hh_mm_ss_ff(tstr):
3657db96d56Sopenharmony_ci    # Parses things of the form HH[:?MM[:?SS[{.,}fff[fff]]]]
3667db96d56Sopenharmony_ci    len_str = len(tstr)
3677db96d56Sopenharmony_ci
3687db96d56Sopenharmony_ci    time_comps = [0, 0, 0, 0]
3697db96d56Sopenharmony_ci    pos = 0
3707db96d56Sopenharmony_ci    for comp in range(0, 3):
3717db96d56Sopenharmony_ci        if (len_str - pos) < 2:
3727db96d56Sopenharmony_ci            raise ValueError("Incomplete time component")
3737db96d56Sopenharmony_ci
3747db96d56Sopenharmony_ci        time_comps[comp] = int(tstr[pos:pos+2])
3757db96d56Sopenharmony_ci
3767db96d56Sopenharmony_ci        pos += 2
3777db96d56Sopenharmony_ci        next_char = tstr[pos:pos+1]
3787db96d56Sopenharmony_ci
3797db96d56Sopenharmony_ci        if comp == 0:
3807db96d56Sopenharmony_ci            has_sep = next_char == ':'
3817db96d56Sopenharmony_ci
3827db96d56Sopenharmony_ci        if not next_char or comp >= 2:
3837db96d56Sopenharmony_ci            break
3847db96d56Sopenharmony_ci
3857db96d56Sopenharmony_ci        if has_sep and next_char != ':':
3867db96d56Sopenharmony_ci            raise ValueError("Invalid time separator: %c" % next_char)
3877db96d56Sopenharmony_ci
3887db96d56Sopenharmony_ci        pos += has_sep
3897db96d56Sopenharmony_ci
3907db96d56Sopenharmony_ci    if pos < len_str:
3917db96d56Sopenharmony_ci        if tstr[pos] not in '.,':
3927db96d56Sopenharmony_ci            raise ValueError("Invalid microsecond component")
3937db96d56Sopenharmony_ci        else:
3947db96d56Sopenharmony_ci            pos += 1
3957db96d56Sopenharmony_ci
3967db96d56Sopenharmony_ci            len_remainder = len_str - pos
3977db96d56Sopenharmony_ci
3987db96d56Sopenharmony_ci            if len_remainder >= 6:
3997db96d56Sopenharmony_ci                to_parse = 6
4007db96d56Sopenharmony_ci            else:
4017db96d56Sopenharmony_ci                to_parse = len_remainder
4027db96d56Sopenharmony_ci
4037db96d56Sopenharmony_ci            time_comps[3] = int(tstr[pos:(pos+to_parse)])
4047db96d56Sopenharmony_ci            if to_parse < 6:
4057db96d56Sopenharmony_ci                time_comps[3] *= _FRACTION_CORRECTION[to_parse-1]
4067db96d56Sopenharmony_ci            if (len_remainder > to_parse
4077db96d56Sopenharmony_ci                    and not all(map(_is_ascii_digit, tstr[(pos+to_parse):]))):
4087db96d56Sopenharmony_ci                raise ValueError("Non-digit values in unparsed fraction")
4097db96d56Sopenharmony_ci
4107db96d56Sopenharmony_ci    return time_comps
4117db96d56Sopenharmony_ci
4127db96d56Sopenharmony_cidef _parse_isoformat_time(tstr):
4137db96d56Sopenharmony_ci    # Format supported is HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]
4147db96d56Sopenharmony_ci    len_str = len(tstr)
4157db96d56Sopenharmony_ci    if len_str < 2:
4167db96d56Sopenharmony_ci        raise ValueError("Isoformat time too short")
4177db96d56Sopenharmony_ci
4187db96d56Sopenharmony_ci    # This is equivalent to re.search('[+-Z]', tstr), but faster
4197db96d56Sopenharmony_ci    tz_pos = (tstr.find('-') + 1 or tstr.find('+') + 1 or tstr.find('Z') + 1)
4207db96d56Sopenharmony_ci    timestr = tstr[:tz_pos-1] if tz_pos > 0 else tstr
4217db96d56Sopenharmony_ci
4227db96d56Sopenharmony_ci    time_comps = _parse_hh_mm_ss_ff(timestr)
4237db96d56Sopenharmony_ci
4247db96d56Sopenharmony_ci    tzi = None
4257db96d56Sopenharmony_ci    if tz_pos == len_str and tstr[-1] == 'Z':
4267db96d56Sopenharmony_ci        tzi = timezone.utc
4277db96d56Sopenharmony_ci    elif tz_pos > 0:
4287db96d56Sopenharmony_ci        tzstr = tstr[tz_pos:]
4297db96d56Sopenharmony_ci
4307db96d56Sopenharmony_ci        # Valid time zone strings are:
4317db96d56Sopenharmony_ci        # HH                  len: 2
4327db96d56Sopenharmony_ci        # HHMM                len: 4
4337db96d56Sopenharmony_ci        # HH:MM               len: 5
4347db96d56Sopenharmony_ci        # HHMMSS              len: 6
4357db96d56Sopenharmony_ci        # HHMMSS.f+           len: 7+
4367db96d56Sopenharmony_ci        # HH:MM:SS            len: 8
4377db96d56Sopenharmony_ci        # HH:MM:SS.f+         len: 10+
4387db96d56Sopenharmony_ci
4397db96d56Sopenharmony_ci        if len(tzstr) in (0, 1, 3):
4407db96d56Sopenharmony_ci            raise ValueError("Malformed time zone string")
4417db96d56Sopenharmony_ci
4427db96d56Sopenharmony_ci        tz_comps = _parse_hh_mm_ss_ff(tzstr)
4437db96d56Sopenharmony_ci
4447db96d56Sopenharmony_ci        if all(x == 0 for x in tz_comps):
4457db96d56Sopenharmony_ci            tzi = timezone.utc
4467db96d56Sopenharmony_ci        else:
4477db96d56Sopenharmony_ci            tzsign = -1 if tstr[tz_pos - 1] == '-' else 1
4487db96d56Sopenharmony_ci
4497db96d56Sopenharmony_ci            td = timedelta(hours=tz_comps[0], minutes=tz_comps[1],
4507db96d56Sopenharmony_ci                           seconds=tz_comps[2], microseconds=tz_comps[3])
4517db96d56Sopenharmony_ci
4527db96d56Sopenharmony_ci            tzi = timezone(tzsign * td)
4537db96d56Sopenharmony_ci
4547db96d56Sopenharmony_ci    time_comps.append(tzi)
4557db96d56Sopenharmony_ci
4567db96d56Sopenharmony_ci    return time_comps
4577db96d56Sopenharmony_ci
4587db96d56Sopenharmony_ci# tuple[int, int, int] -> tuple[int, int, int] version of date.fromisocalendar
4597db96d56Sopenharmony_cidef _isoweek_to_gregorian(year, week, day):
4607db96d56Sopenharmony_ci    # Year is bounded this way because 9999-12-31 is (9999, 52, 5)
4617db96d56Sopenharmony_ci    if not MINYEAR <= year <= MAXYEAR:
4627db96d56Sopenharmony_ci        raise ValueError(f"Year is out of range: {year}")
4637db96d56Sopenharmony_ci
4647db96d56Sopenharmony_ci    if not 0 < week < 53:
4657db96d56Sopenharmony_ci        out_of_range = True
4667db96d56Sopenharmony_ci
4677db96d56Sopenharmony_ci        if week == 53:
4687db96d56Sopenharmony_ci            # ISO years have 53 weeks in them on years starting with a
4697db96d56Sopenharmony_ci            # Thursday and leap years starting on a Wednesday
4707db96d56Sopenharmony_ci            first_weekday = _ymd2ord(year, 1, 1) % 7
4717db96d56Sopenharmony_ci            if (first_weekday == 4 or (first_weekday == 3 and
4727db96d56Sopenharmony_ci                                       _is_leap(year))):
4737db96d56Sopenharmony_ci                out_of_range = False
4747db96d56Sopenharmony_ci
4757db96d56Sopenharmony_ci        if out_of_range:
4767db96d56Sopenharmony_ci            raise ValueError(f"Invalid week: {week}")
4777db96d56Sopenharmony_ci
4787db96d56Sopenharmony_ci    if not 0 < day < 8:
4797db96d56Sopenharmony_ci        raise ValueError(f"Invalid weekday: {day} (range is [1, 7])")
4807db96d56Sopenharmony_ci
4817db96d56Sopenharmony_ci    # Now compute the offset from (Y, 1, 1) in days:
4827db96d56Sopenharmony_ci    day_offset = (week - 1) * 7 + (day - 1)
4837db96d56Sopenharmony_ci
4847db96d56Sopenharmony_ci    # Calculate the ordinal day for monday, week 1
4857db96d56Sopenharmony_ci    day_1 = _isoweek1monday(year)
4867db96d56Sopenharmony_ci    ord_day = day_1 + day_offset
4877db96d56Sopenharmony_ci
4887db96d56Sopenharmony_ci    return _ord2ymd(ord_day)
4897db96d56Sopenharmony_ci
4907db96d56Sopenharmony_ci
4917db96d56Sopenharmony_ci# Just raise TypeError if the arg isn't None or a string.
4927db96d56Sopenharmony_cidef _check_tzname(name):
4937db96d56Sopenharmony_ci    if name is not None and not isinstance(name, str):
4947db96d56Sopenharmony_ci        raise TypeError("tzinfo.tzname() must return None or string, "
4957db96d56Sopenharmony_ci                        "not '%s'" % type(name))
4967db96d56Sopenharmony_ci
4977db96d56Sopenharmony_ci# name is the offset-producing method, "utcoffset" or "dst".
4987db96d56Sopenharmony_ci# offset is what it returned.
4997db96d56Sopenharmony_ci# If offset isn't None or timedelta, raises TypeError.
5007db96d56Sopenharmony_ci# If offset is None, returns None.
5017db96d56Sopenharmony_ci# Else offset is checked for being in range.
5027db96d56Sopenharmony_ci# If it is, its integer value is returned.  Else ValueError is raised.
5037db96d56Sopenharmony_cidef _check_utc_offset(name, offset):
5047db96d56Sopenharmony_ci    assert name in ("utcoffset", "dst")
5057db96d56Sopenharmony_ci    if offset is None:
5067db96d56Sopenharmony_ci        return
5077db96d56Sopenharmony_ci    if not isinstance(offset, timedelta):
5087db96d56Sopenharmony_ci        raise TypeError("tzinfo.%s() must return None "
5097db96d56Sopenharmony_ci                        "or timedelta, not '%s'" % (name, type(offset)))
5107db96d56Sopenharmony_ci    if not -timedelta(1) < offset < timedelta(1):
5117db96d56Sopenharmony_ci        raise ValueError("%s()=%s, must be strictly between "
5127db96d56Sopenharmony_ci                         "-timedelta(hours=24) and timedelta(hours=24)" %
5137db96d56Sopenharmony_ci                         (name, offset))
5147db96d56Sopenharmony_ci
5157db96d56Sopenharmony_cidef _check_date_fields(year, month, day):
5167db96d56Sopenharmony_ci    year = _index(year)
5177db96d56Sopenharmony_ci    month = _index(month)
5187db96d56Sopenharmony_ci    day = _index(day)
5197db96d56Sopenharmony_ci    if not MINYEAR <= year <= MAXYEAR:
5207db96d56Sopenharmony_ci        raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year)
5217db96d56Sopenharmony_ci    if not 1 <= month <= 12:
5227db96d56Sopenharmony_ci        raise ValueError('month must be in 1..12', month)
5237db96d56Sopenharmony_ci    dim = _days_in_month(year, month)
5247db96d56Sopenharmony_ci    if not 1 <= day <= dim:
5257db96d56Sopenharmony_ci        raise ValueError('day must be in 1..%d' % dim, day)
5267db96d56Sopenharmony_ci    return year, month, day
5277db96d56Sopenharmony_ci
5287db96d56Sopenharmony_cidef _check_time_fields(hour, minute, second, microsecond, fold):
5297db96d56Sopenharmony_ci    hour = _index(hour)
5307db96d56Sopenharmony_ci    minute = _index(minute)
5317db96d56Sopenharmony_ci    second = _index(second)
5327db96d56Sopenharmony_ci    microsecond = _index(microsecond)
5337db96d56Sopenharmony_ci    if not 0 <= hour <= 23:
5347db96d56Sopenharmony_ci        raise ValueError('hour must be in 0..23', hour)
5357db96d56Sopenharmony_ci    if not 0 <= minute <= 59:
5367db96d56Sopenharmony_ci        raise ValueError('minute must be in 0..59', minute)
5377db96d56Sopenharmony_ci    if not 0 <= second <= 59:
5387db96d56Sopenharmony_ci        raise ValueError('second must be in 0..59', second)
5397db96d56Sopenharmony_ci    if not 0 <= microsecond <= 999999:
5407db96d56Sopenharmony_ci        raise ValueError('microsecond must be in 0..999999', microsecond)
5417db96d56Sopenharmony_ci    if fold not in (0, 1):
5427db96d56Sopenharmony_ci        raise ValueError('fold must be either 0 or 1', fold)
5437db96d56Sopenharmony_ci    return hour, minute, second, microsecond, fold
5447db96d56Sopenharmony_ci
5457db96d56Sopenharmony_cidef _check_tzinfo_arg(tz):
5467db96d56Sopenharmony_ci    if tz is not None and not isinstance(tz, tzinfo):
5477db96d56Sopenharmony_ci        raise TypeError("tzinfo argument must be None or of a tzinfo subclass")
5487db96d56Sopenharmony_ci
5497db96d56Sopenharmony_cidef _cmperror(x, y):
5507db96d56Sopenharmony_ci    raise TypeError("can't compare '%s' to '%s'" % (
5517db96d56Sopenharmony_ci                    type(x).__name__, type(y).__name__))
5527db96d56Sopenharmony_ci
5537db96d56Sopenharmony_cidef _divide_and_round(a, b):
5547db96d56Sopenharmony_ci    """divide a by b and round result to the nearest integer
5557db96d56Sopenharmony_ci
5567db96d56Sopenharmony_ci    When the ratio is exactly half-way between two integers,
5577db96d56Sopenharmony_ci    the even integer is returned.
5587db96d56Sopenharmony_ci    """
5597db96d56Sopenharmony_ci    # Based on the reference implementation for divmod_near
5607db96d56Sopenharmony_ci    # in Objects/longobject.c.
5617db96d56Sopenharmony_ci    q, r = divmod(a, b)
5627db96d56Sopenharmony_ci    # round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
5637db96d56Sopenharmony_ci    # The expression r / b > 0.5 is equivalent to 2 * r > b if b is
5647db96d56Sopenharmony_ci    # positive, 2 * r < b if b negative.
5657db96d56Sopenharmony_ci    r *= 2
5667db96d56Sopenharmony_ci    greater_than_half = r > b if b > 0 else r < b
5677db96d56Sopenharmony_ci    if greater_than_half or r == b and q % 2 == 1:
5687db96d56Sopenharmony_ci        q += 1
5697db96d56Sopenharmony_ci
5707db96d56Sopenharmony_ci    return q
5717db96d56Sopenharmony_ci
5727db96d56Sopenharmony_ci
5737db96d56Sopenharmony_ciclass timedelta:
5747db96d56Sopenharmony_ci    """Represent the difference between two datetime objects.
5757db96d56Sopenharmony_ci
5767db96d56Sopenharmony_ci    Supported operators:
5777db96d56Sopenharmony_ci
5787db96d56Sopenharmony_ci    - add, subtract timedelta
5797db96d56Sopenharmony_ci    - unary plus, minus, abs
5807db96d56Sopenharmony_ci    - compare to timedelta
5817db96d56Sopenharmony_ci    - multiply, divide by int
5827db96d56Sopenharmony_ci
5837db96d56Sopenharmony_ci    In addition, datetime supports subtraction of two datetime objects
5847db96d56Sopenharmony_ci    returning a timedelta, and addition or subtraction of a datetime
5857db96d56Sopenharmony_ci    and a timedelta giving a datetime.
5867db96d56Sopenharmony_ci
5877db96d56Sopenharmony_ci    Representation: (days, seconds, microseconds).  Why?  Because I
5887db96d56Sopenharmony_ci    felt like it.
5897db96d56Sopenharmony_ci    """
5907db96d56Sopenharmony_ci    __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
5917db96d56Sopenharmony_ci
5927db96d56Sopenharmony_ci    def __new__(cls, days=0, seconds=0, microseconds=0,
5937db96d56Sopenharmony_ci                milliseconds=0, minutes=0, hours=0, weeks=0):
5947db96d56Sopenharmony_ci        # Doing this efficiently and accurately in C is going to be difficult
5957db96d56Sopenharmony_ci        # and error-prone, due to ubiquitous overflow possibilities, and that
5967db96d56Sopenharmony_ci        # C double doesn't have enough bits of precision to represent
5977db96d56Sopenharmony_ci        # microseconds over 10K years faithfully.  The code here tries to make
5987db96d56Sopenharmony_ci        # explicit where go-fast assumptions can be relied on, in order to
5997db96d56Sopenharmony_ci        # guide the C implementation; it's way more convoluted than speed-
6007db96d56Sopenharmony_ci        # ignoring auto-overflow-to-long idiomatic Python could be.
6017db96d56Sopenharmony_ci
6027db96d56Sopenharmony_ci        # XXX Check that all inputs are ints or floats.
6037db96d56Sopenharmony_ci
6047db96d56Sopenharmony_ci        # Final values, all integer.
6057db96d56Sopenharmony_ci        # s and us fit in 32-bit signed ints; d isn't bounded.
6067db96d56Sopenharmony_ci        d = s = us = 0
6077db96d56Sopenharmony_ci
6087db96d56Sopenharmony_ci        # Normalize everything to days, seconds, microseconds.
6097db96d56Sopenharmony_ci        days += weeks*7
6107db96d56Sopenharmony_ci        seconds += minutes*60 + hours*3600
6117db96d56Sopenharmony_ci        microseconds += milliseconds*1000
6127db96d56Sopenharmony_ci
6137db96d56Sopenharmony_ci        # Get rid of all fractions, and normalize s and us.
6147db96d56Sopenharmony_ci        # Take a deep breath <wink>.
6157db96d56Sopenharmony_ci        if isinstance(days, float):
6167db96d56Sopenharmony_ci            dayfrac, days = _math.modf(days)
6177db96d56Sopenharmony_ci            daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
6187db96d56Sopenharmony_ci            assert daysecondswhole == int(daysecondswhole)  # can't overflow
6197db96d56Sopenharmony_ci            s = int(daysecondswhole)
6207db96d56Sopenharmony_ci            assert days == int(days)
6217db96d56Sopenharmony_ci            d = int(days)
6227db96d56Sopenharmony_ci        else:
6237db96d56Sopenharmony_ci            daysecondsfrac = 0.0
6247db96d56Sopenharmony_ci            d = days
6257db96d56Sopenharmony_ci        assert isinstance(daysecondsfrac, float)
6267db96d56Sopenharmony_ci        assert abs(daysecondsfrac) <= 1.0
6277db96d56Sopenharmony_ci        assert isinstance(d, int)
6287db96d56Sopenharmony_ci        assert abs(s) <= 24 * 3600
6297db96d56Sopenharmony_ci        # days isn't referenced again before redefinition
6307db96d56Sopenharmony_ci
6317db96d56Sopenharmony_ci        if isinstance(seconds, float):
6327db96d56Sopenharmony_ci            secondsfrac, seconds = _math.modf(seconds)
6337db96d56Sopenharmony_ci            assert seconds == int(seconds)
6347db96d56Sopenharmony_ci            seconds = int(seconds)
6357db96d56Sopenharmony_ci            secondsfrac += daysecondsfrac
6367db96d56Sopenharmony_ci            assert abs(secondsfrac) <= 2.0
6377db96d56Sopenharmony_ci        else:
6387db96d56Sopenharmony_ci            secondsfrac = daysecondsfrac
6397db96d56Sopenharmony_ci        # daysecondsfrac isn't referenced again
6407db96d56Sopenharmony_ci        assert isinstance(secondsfrac, float)
6417db96d56Sopenharmony_ci        assert abs(secondsfrac) <= 2.0
6427db96d56Sopenharmony_ci
6437db96d56Sopenharmony_ci        assert isinstance(seconds, int)
6447db96d56Sopenharmony_ci        days, seconds = divmod(seconds, 24*3600)
6457db96d56Sopenharmony_ci        d += days
6467db96d56Sopenharmony_ci        s += int(seconds)    # can't overflow
6477db96d56Sopenharmony_ci        assert isinstance(s, int)
6487db96d56Sopenharmony_ci        assert abs(s) <= 2 * 24 * 3600
6497db96d56Sopenharmony_ci        # seconds isn't referenced again before redefinition
6507db96d56Sopenharmony_ci
6517db96d56Sopenharmony_ci        usdouble = secondsfrac * 1e6
6527db96d56Sopenharmony_ci        assert abs(usdouble) < 2.1e6    # exact value not critical
6537db96d56Sopenharmony_ci        # secondsfrac isn't referenced again
6547db96d56Sopenharmony_ci
6557db96d56Sopenharmony_ci        if isinstance(microseconds, float):
6567db96d56Sopenharmony_ci            microseconds = round(microseconds + usdouble)
6577db96d56Sopenharmony_ci            seconds, microseconds = divmod(microseconds, 1000000)
6587db96d56Sopenharmony_ci            days, seconds = divmod(seconds, 24*3600)
6597db96d56Sopenharmony_ci            d += days
6607db96d56Sopenharmony_ci            s += seconds
6617db96d56Sopenharmony_ci        else:
6627db96d56Sopenharmony_ci            microseconds = int(microseconds)
6637db96d56Sopenharmony_ci            seconds, microseconds = divmod(microseconds, 1000000)
6647db96d56Sopenharmony_ci            days, seconds = divmod(seconds, 24*3600)
6657db96d56Sopenharmony_ci            d += days
6667db96d56Sopenharmony_ci            s += seconds
6677db96d56Sopenharmony_ci            microseconds = round(microseconds + usdouble)
6687db96d56Sopenharmony_ci        assert isinstance(s, int)
6697db96d56Sopenharmony_ci        assert isinstance(microseconds, int)
6707db96d56Sopenharmony_ci        assert abs(s) <= 3 * 24 * 3600
6717db96d56Sopenharmony_ci        assert abs(microseconds) < 3.1e6
6727db96d56Sopenharmony_ci
6737db96d56Sopenharmony_ci        # Just a little bit of carrying possible for microseconds and seconds.
6747db96d56Sopenharmony_ci        seconds, us = divmod(microseconds, 1000000)
6757db96d56Sopenharmony_ci        s += seconds
6767db96d56Sopenharmony_ci        days, s = divmod(s, 24*3600)
6777db96d56Sopenharmony_ci        d += days
6787db96d56Sopenharmony_ci
6797db96d56Sopenharmony_ci        assert isinstance(d, int)
6807db96d56Sopenharmony_ci        assert isinstance(s, int) and 0 <= s < 24*3600
6817db96d56Sopenharmony_ci        assert isinstance(us, int) and 0 <= us < 1000000
6827db96d56Sopenharmony_ci
6837db96d56Sopenharmony_ci        if abs(d) > 999999999:
6847db96d56Sopenharmony_ci            raise OverflowError("timedelta # of days is too large: %d" % d)
6857db96d56Sopenharmony_ci
6867db96d56Sopenharmony_ci        self = object.__new__(cls)
6877db96d56Sopenharmony_ci        self._days = d
6887db96d56Sopenharmony_ci        self._seconds = s
6897db96d56Sopenharmony_ci        self._microseconds = us
6907db96d56Sopenharmony_ci        self._hashcode = -1
6917db96d56Sopenharmony_ci        return self
6927db96d56Sopenharmony_ci
6937db96d56Sopenharmony_ci    def __repr__(self):
6947db96d56Sopenharmony_ci        args = []
6957db96d56Sopenharmony_ci        if self._days:
6967db96d56Sopenharmony_ci            args.append("days=%d" % self._days)
6977db96d56Sopenharmony_ci        if self._seconds:
6987db96d56Sopenharmony_ci            args.append("seconds=%d" % self._seconds)
6997db96d56Sopenharmony_ci        if self._microseconds:
7007db96d56Sopenharmony_ci            args.append("microseconds=%d" % self._microseconds)
7017db96d56Sopenharmony_ci        if not args:
7027db96d56Sopenharmony_ci            args.append('0')
7037db96d56Sopenharmony_ci        return "%s.%s(%s)" % (self.__class__.__module__,
7047db96d56Sopenharmony_ci                              self.__class__.__qualname__,
7057db96d56Sopenharmony_ci                              ', '.join(args))
7067db96d56Sopenharmony_ci
7077db96d56Sopenharmony_ci    def __str__(self):
7087db96d56Sopenharmony_ci        mm, ss = divmod(self._seconds, 60)
7097db96d56Sopenharmony_ci        hh, mm = divmod(mm, 60)
7107db96d56Sopenharmony_ci        s = "%d:%02d:%02d" % (hh, mm, ss)
7117db96d56Sopenharmony_ci        if self._days:
7127db96d56Sopenharmony_ci            def plural(n):
7137db96d56Sopenharmony_ci                return n, abs(n) != 1 and "s" or ""
7147db96d56Sopenharmony_ci            s = ("%d day%s, " % plural(self._days)) + s
7157db96d56Sopenharmony_ci        if self._microseconds:
7167db96d56Sopenharmony_ci            s = s + ".%06d" % self._microseconds
7177db96d56Sopenharmony_ci        return s
7187db96d56Sopenharmony_ci
7197db96d56Sopenharmony_ci    def total_seconds(self):
7207db96d56Sopenharmony_ci        """Total seconds in the duration."""
7217db96d56Sopenharmony_ci        return ((self.days * 86400 + self.seconds) * 10**6 +
7227db96d56Sopenharmony_ci                self.microseconds) / 10**6
7237db96d56Sopenharmony_ci
7247db96d56Sopenharmony_ci    # Read-only field accessors
7257db96d56Sopenharmony_ci    @property
7267db96d56Sopenharmony_ci    def days(self):
7277db96d56Sopenharmony_ci        """days"""
7287db96d56Sopenharmony_ci        return self._days
7297db96d56Sopenharmony_ci
7307db96d56Sopenharmony_ci    @property
7317db96d56Sopenharmony_ci    def seconds(self):
7327db96d56Sopenharmony_ci        """seconds"""
7337db96d56Sopenharmony_ci        return self._seconds
7347db96d56Sopenharmony_ci
7357db96d56Sopenharmony_ci    @property
7367db96d56Sopenharmony_ci    def microseconds(self):
7377db96d56Sopenharmony_ci        """microseconds"""
7387db96d56Sopenharmony_ci        return self._microseconds
7397db96d56Sopenharmony_ci
7407db96d56Sopenharmony_ci    def __add__(self, other):
7417db96d56Sopenharmony_ci        if isinstance(other, timedelta):
7427db96d56Sopenharmony_ci            # for CPython compatibility, we cannot use
7437db96d56Sopenharmony_ci            # our __class__ here, but need a real timedelta
7447db96d56Sopenharmony_ci            return timedelta(self._days + other._days,
7457db96d56Sopenharmony_ci                             self._seconds + other._seconds,
7467db96d56Sopenharmony_ci                             self._microseconds + other._microseconds)
7477db96d56Sopenharmony_ci        return NotImplemented
7487db96d56Sopenharmony_ci
7497db96d56Sopenharmony_ci    __radd__ = __add__
7507db96d56Sopenharmony_ci
7517db96d56Sopenharmony_ci    def __sub__(self, other):
7527db96d56Sopenharmony_ci        if isinstance(other, timedelta):
7537db96d56Sopenharmony_ci            # for CPython compatibility, we cannot use
7547db96d56Sopenharmony_ci            # our __class__ here, but need a real timedelta
7557db96d56Sopenharmony_ci            return timedelta(self._days - other._days,
7567db96d56Sopenharmony_ci                             self._seconds - other._seconds,
7577db96d56Sopenharmony_ci                             self._microseconds - other._microseconds)
7587db96d56Sopenharmony_ci        return NotImplemented
7597db96d56Sopenharmony_ci
7607db96d56Sopenharmony_ci    def __rsub__(self, other):
7617db96d56Sopenharmony_ci        if isinstance(other, timedelta):
7627db96d56Sopenharmony_ci            return -self + other
7637db96d56Sopenharmony_ci        return NotImplemented
7647db96d56Sopenharmony_ci
7657db96d56Sopenharmony_ci    def __neg__(self):
7667db96d56Sopenharmony_ci        # for CPython compatibility, we cannot use
7677db96d56Sopenharmony_ci        # our __class__ here, but need a real timedelta
7687db96d56Sopenharmony_ci        return timedelta(-self._days,
7697db96d56Sopenharmony_ci                         -self._seconds,
7707db96d56Sopenharmony_ci                         -self._microseconds)
7717db96d56Sopenharmony_ci
7727db96d56Sopenharmony_ci    def __pos__(self):
7737db96d56Sopenharmony_ci        return self
7747db96d56Sopenharmony_ci
7757db96d56Sopenharmony_ci    def __abs__(self):
7767db96d56Sopenharmony_ci        if self._days < 0:
7777db96d56Sopenharmony_ci            return -self
7787db96d56Sopenharmony_ci        else:
7797db96d56Sopenharmony_ci            return self
7807db96d56Sopenharmony_ci
7817db96d56Sopenharmony_ci    def __mul__(self, other):
7827db96d56Sopenharmony_ci        if isinstance(other, int):
7837db96d56Sopenharmony_ci            # for CPython compatibility, we cannot use
7847db96d56Sopenharmony_ci            # our __class__ here, but need a real timedelta
7857db96d56Sopenharmony_ci            return timedelta(self._days * other,
7867db96d56Sopenharmony_ci                             self._seconds * other,
7877db96d56Sopenharmony_ci                             self._microseconds * other)
7887db96d56Sopenharmony_ci        if isinstance(other, float):
7897db96d56Sopenharmony_ci            usec = self._to_microseconds()
7907db96d56Sopenharmony_ci            a, b = other.as_integer_ratio()
7917db96d56Sopenharmony_ci            return timedelta(0, 0, _divide_and_round(usec * a, b))
7927db96d56Sopenharmony_ci        return NotImplemented
7937db96d56Sopenharmony_ci
7947db96d56Sopenharmony_ci    __rmul__ = __mul__
7957db96d56Sopenharmony_ci
7967db96d56Sopenharmony_ci    def _to_microseconds(self):
7977db96d56Sopenharmony_ci        return ((self._days * (24*3600) + self._seconds) * 1000000 +
7987db96d56Sopenharmony_ci                self._microseconds)
7997db96d56Sopenharmony_ci
8007db96d56Sopenharmony_ci    def __floordiv__(self, other):
8017db96d56Sopenharmony_ci        if not isinstance(other, (int, timedelta)):
8027db96d56Sopenharmony_ci            return NotImplemented
8037db96d56Sopenharmony_ci        usec = self._to_microseconds()
8047db96d56Sopenharmony_ci        if isinstance(other, timedelta):
8057db96d56Sopenharmony_ci            return usec // other._to_microseconds()
8067db96d56Sopenharmony_ci        if isinstance(other, int):
8077db96d56Sopenharmony_ci            return timedelta(0, 0, usec // other)
8087db96d56Sopenharmony_ci
8097db96d56Sopenharmony_ci    def __truediv__(self, other):
8107db96d56Sopenharmony_ci        if not isinstance(other, (int, float, timedelta)):
8117db96d56Sopenharmony_ci            return NotImplemented
8127db96d56Sopenharmony_ci        usec = self._to_microseconds()
8137db96d56Sopenharmony_ci        if isinstance(other, timedelta):
8147db96d56Sopenharmony_ci            return usec / other._to_microseconds()
8157db96d56Sopenharmony_ci        if isinstance(other, int):
8167db96d56Sopenharmony_ci            return timedelta(0, 0, _divide_and_round(usec, other))
8177db96d56Sopenharmony_ci        if isinstance(other, float):
8187db96d56Sopenharmony_ci            a, b = other.as_integer_ratio()
8197db96d56Sopenharmony_ci            return timedelta(0, 0, _divide_and_round(b * usec, a))
8207db96d56Sopenharmony_ci
8217db96d56Sopenharmony_ci    def __mod__(self, other):
8227db96d56Sopenharmony_ci        if isinstance(other, timedelta):
8237db96d56Sopenharmony_ci            r = self._to_microseconds() % other._to_microseconds()
8247db96d56Sopenharmony_ci            return timedelta(0, 0, r)
8257db96d56Sopenharmony_ci        return NotImplemented
8267db96d56Sopenharmony_ci
8277db96d56Sopenharmony_ci    def __divmod__(self, other):
8287db96d56Sopenharmony_ci        if isinstance(other, timedelta):
8297db96d56Sopenharmony_ci            q, r = divmod(self._to_microseconds(),
8307db96d56Sopenharmony_ci                          other._to_microseconds())
8317db96d56Sopenharmony_ci            return q, timedelta(0, 0, r)
8327db96d56Sopenharmony_ci        return NotImplemented
8337db96d56Sopenharmony_ci
8347db96d56Sopenharmony_ci    # Comparisons of timedelta objects with other.
8357db96d56Sopenharmony_ci
8367db96d56Sopenharmony_ci    def __eq__(self, other):
8377db96d56Sopenharmony_ci        if isinstance(other, timedelta):
8387db96d56Sopenharmony_ci            return self._cmp(other) == 0
8397db96d56Sopenharmony_ci        else:
8407db96d56Sopenharmony_ci            return NotImplemented
8417db96d56Sopenharmony_ci
8427db96d56Sopenharmony_ci    def __le__(self, other):
8437db96d56Sopenharmony_ci        if isinstance(other, timedelta):
8447db96d56Sopenharmony_ci            return self._cmp(other) <= 0
8457db96d56Sopenharmony_ci        else:
8467db96d56Sopenharmony_ci            return NotImplemented
8477db96d56Sopenharmony_ci
8487db96d56Sopenharmony_ci    def __lt__(self, other):
8497db96d56Sopenharmony_ci        if isinstance(other, timedelta):
8507db96d56Sopenharmony_ci            return self._cmp(other) < 0
8517db96d56Sopenharmony_ci        else:
8527db96d56Sopenharmony_ci            return NotImplemented
8537db96d56Sopenharmony_ci
8547db96d56Sopenharmony_ci    def __ge__(self, other):
8557db96d56Sopenharmony_ci        if isinstance(other, timedelta):
8567db96d56Sopenharmony_ci            return self._cmp(other) >= 0
8577db96d56Sopenharmony_ci        else:
8587db96d56Sopenharmony_ci            return NotImplemented
8597db96d56Sopenharmony_ci
8607db96d56Sopenharmony_ci    def __gt__(self, other):
8617db96d56Sopenharmony_ci        if isinstance(other, timedelta):
8627db96d56Sopenharmony_ci            return self._cmp(other) > 0
8637db96d56Sopenharmony_ci        else:
8647db96d56Sopenharmony_ci            return NotImplemented
8657db96d56Sopenharmony_ci
8667db96d56Sopenharmony_ci    def _cmp(self, other):
8677db96d56Sopenharmony_ci        assert isinstance(other, timedelta)
8687db96d56Sopenharmony_ci        return _cmp(self._getstate(), other._getstate())
8697db96d56Sopenharmony_ci
8707db96d56Sopenharmony_ci    def __hash__(self):
8717db96d56Sopenharmony_ci        if self._hashcode == -1:
8727db96d56Sopenharmony_ci            self._hashcode = hash(self._getstate())
8737db96d56Sopenharmony_ci        return self._hashcode
8747db96d56Sopenharmony_ci
8757db96d56Sopenharmony_ci    def __bool__(self):
8767db96d56Sopenharmony_ci        return (self._days != 0 or
8777db96d56Sopenharmony_ci                self._seconds != 0 or
8787db96d56Sopenharmony_ci                self._microseconds != 0)
8797db96d56Sopenharmony_ci
8807db96d56Sopenharmony_ci    # Pickle support.
8817db96d56Sopenharmony_ci
8827db96d56Sopenharmony_ci    def _getstate(self):
8837db96d56Sopenharmony_ci        return (self._days, self._seconds, self._microseconds)
8847db96d56Sopenharmony_ci
8857db96d56Sopenharmony_ci    def __reduce__(self):
8867db96d56Sopenharmony_ci        return (self.__class__, self._getstate())
8877db96d56Sopenharmony_ci
8887db96d56Sopenharmony_citimedelta.min = timedelta(-999999999)
8897db96d56Sopenharmony_citimedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
8907db96d56Sopenharmony_ci                          microseconds=999999)
8917db96d56Sopenharmony_citimedelta.resolution = timedelta(microseconds=1)
8927db96d56Sopenharmony_ci
8937db96d56Sopenharmony_ciclass date:
8947db96d56Sopenharmony_ci    """Concrete date type.
8957db96d56Sopenharmony_ci
8967db96d56Sopenharmony_ci    Constructors:
8977db96d56Sopenharmony_ci
8987db96d56Sopenharmony_ci    __new__()
8997db96d56Sopenharmony_ci    fromtimestamp()
9007db96d56Sopenharmony_ci    today()
9017db96d56Sopenharmony_ci    fromordinal()
9027db96d56Sopenharmony_ci
9037db96d56Sopenharmony_ci    Operators:
9047db96d56Sopenharmony_ci
9057db96d56Sopenharmony_ci    __repr__, __str__
9067db96d56Sopenharmony_ci    __eq__, __le__, __lt__, __ge__, __gt__, __hash__
9077db96d56Sopenharmony_ci    __add__, __radd__, __sub__ (add/radd only with timedelta arg)
9087db96d56Sopenharmony_ci
9097db96d56Sopenharmony_ci    Methods:
9107db96d56Sopenharmony_ci
9117db96d56Sopenharmony_ci    timetuple()
9127db96d56Sopenharmony_ci    toordinal()
9137db96d56Sopenharmony_ci    weekday()
9147db96d56Sopenharmony_ci    isoweekday(), isocalendar(), isoformat()
9157db96d56Sopenharmony_ci    ctime()
9167db96d56Sopenharmony_ci    strftime()
9177db96d56Sopenharmony_ci
9187db96d56Sopenharmony_ci    Properties (readonly):
9197db96d56Sopenharmony_ci    year, month, day
9207db96d56Sopenharmony_ci    """
9217db96d56Sopenharmony_ci    __slots__ = '_year', '_month', '_day', '_hashcode'
9227db96d56Sopenharmony_ci
9237db96d56Sopenharmony_ci    def __new__(cls, year, month=None, day=None):
9247db96d56Sopenharmony_ci        """Constructor.
9257db96d56Sopenharmony_ci
9267db96d56Sopenharmony_ci        Arguments:
9277db96d56Sopenharmony_ci
9287db96d56Sopenharmony_ci        year, month, day (required, base 1)
9297db96d56Sopenharmony_ci        """
9307db96d56Sopenharmony_ci        if (month is None and
9317db96d56Sopenharmony_ci            isinstance(year, (bytes, str)) and len(year) == 4 and
9327db96d56Sopenharmony_ci            1 <= ord(year[2:3]) <= 12):
9337db96d56Sopenharmony_ci            # Pickle support
9347db96d56Sopenharmony_ci            if isinstance(year, str):
9357db96d56Sopenharmony_ci                try:
9367db96d56Sopenharmony_ci                    year = year.encode('latin1')
9377db96d56Sopenharmony_ci                except UnicodeEncodeError:
9387db96d56Sopenharmony_ci                    # More informative error message.
9397db96d56Sopenharmony_ci                    raise ValueError(
9407db96d56Sopenharmony_ci                        "Failed to encode latin1 string when unpickling "
9417db96d56Sopenharmony_ci                        "a date object. "
9427db96d56Sopenharmony_ci                        "pickle.load(data, encoding='latin1') is assumed.")
9437db96d56Sopenharmony_ci            self = object.__new__(cls)
9447db96d56Sopenharmony_ci            self.__setstate(year)
9457db96d56Sopenharmony_ci            self._hashcode = -1
9467db96d56Sopenharmony_ci            return self
9477db96d56Sopenharmony_ci        year, month, day = _check_date_fields(year, month, day)
9487db96d56Sopenharmony_ci        self = object.__new__(cls)
9497db96d56Sopenharmony_ci        self._year = year
9507db96d56Sopenharmony_ci        self._month = month
9517db96d56Sopenharmony_ci        self._day = day
9527db96d56Sopenharmony_ci        self._hashcode = -1
9537db96d56Sopenharmony_ci        return self
9547db96d56Sopenharmony_ci
9557db96d56Sopenharmony_ci    # Additional constructors
9567db96d56Sopenharmony_ci
9577db96d56Sopenharmony_ci    @classmethod
9587db96d56Sopenharmony_ci    def fromtimestamp(cls, t):
9597db96d56Sopenharmony_ci        "Construct a date from a POSIX timestamp (like time.time())."
9607db96d56Sopenharmony_ci        y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
9617db96d56Sopenharmony_ci        return cls(y, m, d)
9627db96d56Sopenharmony_ci
9637db96d56Sopenharmony_ci    @classmethod
9647db96d56Sopenharmony_ci    def today(cls):
9657db96d56Sopenharmony_ci        "Construct a date from time.time()."
9667db96d56Sopenharmony_ci        t = _time.time()
9677db96d56Sopenharmony_ci        return cls.fromtimestamp(t)
9687db96d56Sopenharmony_ci
9697db96d56Sopenharmony_ci    @classmethod
9707db96d56Sopenharmony_ci    def fromordinal(cls, n):
9717db96d56Sopenharmony_ci        """Construct a date from a proleptic Gregorian ordinal.
9727db96d56Sopenharmony_ci
9737db96d56Sopenharmony_ci        January 1 of year 1 is day 1.  Only the year, month and day are
9747db96d56Sopenharmony_ci        non-zero in the result.
9757db96d56Sopenharmony_ci        """
9767db96d56Sopenharmony_ci        y, m, d = _ord2ymd(n)
9777db96d56Sopenharmony_ci        return cls(y, m, d)
9787db96d56Sopenharmony_ci
9797db96d56Sopenharmony_ci    @classmethod
9807db96d56Sopenharmony_ci    def fromisoformat(cls, date_string):
9817db96d56Sopenharmony_ci        """Construct a date from a string in ISO 8601 format."""
9827db96d56Sopenharmony_ci        if not isinstance(date_string, str):
9837db96d56Sopenharmony_ci            raise TypeError('fromisoformat: argument must be str')
9847db96d56Sopenharmony_ci
9857db96d56Sopenharmony_ci        if len(date_string) not in (7, 8, 10):
9867db96d56Sopenharmony_ci            raise ValueError(f'Invalid isoformat string: {date_string!r}')
9877db96d56Sopenharmony_ci
9887db96d56Sopenharmony_ci        try:
9897db96d56Sopenharmony_ci            return cls(*_parse_isoformat_date(date_string))
9907db96d56Sopenharmony_ci        except Exception:
9917db96d56Sopenharmony_ci            raise ValueError(f'Invalid isoformat string: {date_string!r}')
9927db96d56Sopenharmony_ci
9937db96d56Sopenharmony_ci    @classmethod
9947db96d56Sopenharmony_ci    def fromisocalendar(cls, year, week, day):
9957db96d56Sopenharmony_ci        """Construct a date from the ISO year, week number and weekday.
9967db96d56Sopenharmony_ci
9977db96d56Sopenharmony_ci        This is the inverse of the date.isocalendar() function"""
9987db96d56Sopenharmony_ci        return cls(*_isoweek_to_gregorian(year, week, day))
9997db96d56Sopenharmony_ci
10007db96d56Sopenharmony_ci    # Conversions to string
10017db96d56Sopenharmony_ci
10027db96d56Sopenharmony_ci    def __repr__(self):
10037db96d56Sopenharmony_ci        """Convert to formal string, for repr().
10047db96d56Sopenharmony_ci
10057db96d56Sopenharmony_ci        >>> dt = datetime(2010, 1, 1)
10067db96d56Sopenharmony_ci        >>> repr(dt)
10077db96d56Sopenharmony_ci        'datetime.datetime(2010, 1, 1, 0, 0)'
10087db96d56Sopenharmony_ci
10097db96d56Sopenharmony_ci        >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
10107db96d56Sopenharmony_ci        >>> repr(dt)
10117db96d56Sopenharmony_ci        'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
10127db96d56Sopenharmony_ci        """
10137db96d56Sopenharmony_ci        return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
10147db96d56Sopenharmony_ci                                      self.__class__.__qualname__,
10157db96d56Sopenharmony_ci                                      self._year,
10167db96d56Sopenharmony_ci                                      self._month,
10177db96d56Sopenharmony_ci                                      self._day)
10187db96d56Sopenharmony_ci    # XXX These shouldn't depend on time.localtime(), because that
10197db96d56Sopenharmony_ci    # clips the usable dates to [1970 .. 2038).  At least ctime() is
10207db96d56Sopenharmony_ci    # easily done without using strftime() -- that's better too because
10217db96d56Sopenharmony_ci    # strftime("%c", ...) is locale specific.
10227db96d56Sopenharmony_ci
10237db96d56Sopenharmony_ci
10247db96d56Sopenharmony_ci    def ctime(self):
10257db96d56Sopenharmony_ci        "Return ctime() style string."
10267db96d56Sopenharmony_ci        weekday = self.toordinal() % 7 or 7
10277db96d56Sopenharmony_ci        return "%s %s %2d 00:00:00 %04d" % (
10287db96d56Sopenharmony_ci            _DAYNAMES[weekday],
10297db96d56Sopenharmony_ci            _MONTHNAMES[self._month],
10307db96d56Sopenharmony_ci            self._day, self._year)
10317db96d56Sopenharmony_ci
10327db96d56Sopenharmony_ci    def strftime(self, fmt):
10337db96d56Sopenharmony_ci        """
10347db96d56Sopenharmony_ci        Format using strftime().
10357db96d56Sopenharmony_ci
10367db96d56Sopenharmony_ci        Example: "%d/%m/%Y, %H:%M:%S"
10377db96d56Sopenharmony_ci        """
10387db96d56Sopenharmony_ci        return _wrap_strftime(self, fmt, self.timetuple())
10397db96d56Sopenharmony_ci
10407db96d56Sopenharmony_ci    def __format__(self, fmt):
10417db96d56Sopenharmony_ci        if not isinstance(fmt, str):
10427db96d56Sopenharmony_ci            raise TypeError("must be str, not %s" % type(fmt).__name__)
10437db96d56Sopenharmony_ci        if len(fmt) != 0:
10447db96d56Sopenharmony_ci            return self.strftime(fmt)
10457db96d56Sopenharmony_ci        return str(self)
10467db96d56Sopenharmony_ci
10477db96d56Sopenharmony_ci    def isoformat(self):
10487db96d56Sopenharmony_ci        """Return the date formatted according to ISO.
10497db96d56Sopenharmony_ci
10507db96d56Sopenharmony_ci        This is 'YYYY-MM-DD'.
10517db96d56Sopenharmony_ci
10527db96d56Sopenharmony_ci        References:
10537db96d56Sopenharmony_ci        - http://www.w3.org/TR/NOTE-datetime
10547db96d56Sopenharmony_ci        - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
10557db96d56Sopenharmony_ci        """
10567db96d56Sopenharmony_ci        return "%04d-%02d-%02d" % (self._year, self._month, self._day)
10577db96d56Sopenharmony_ci
10587db96d56Sopenharmony_ci    __str__ = isoformat
10597db96d56Sopenharmony_ci
10607db96d56Sopenharmony_ci    # Read-only field accessors
10617db96d56Sopenharmony_ci    @property
10627db96d56Sopenharmony_ci    def year(self):
10637db96d56Sopenharmony_ci        """year (1-9999)"""
10647db96d56Sopenharmony_ci        return self._year
10657db96d56Sopenharmony_ci
10667db96d56Sopenharmony_ci    @property
10677db96d56Sopenharmony_ci    def month(self):
10687db96d56Sopenharmony_ci        """month (1-12)"""
10697db96d56Sopenharmony_ci        return self._month
10707db96d56Sopenharmony_ci
10717db96d56Sopenharmony_ci    @property
10727db96d56Sopenharmony_ci    def day(self):
10737db96d56Sopenharmony_ci        """day (1-31)"""
10747db96d56Sopenharmony_ci        return self._day
10757db96d56Sopenharmony_ci
10767db96d56Sopenharmony_ci    # Standard conversions, __eq__, __le__, __lt__, __ge__, __gt__,
10777db96d56Sopenharmony_ci    # __hash__ (and helpers)
10787db96d56Sopenharmony_ci
10797db96d56Sopenharmony_ci    def timetuple(self):
10807db96d56Sopenharmony_ci        "Return local time tuple compatible with time.localtime()."
10817db96d56Sopenharmony_ci        return _build_struct_time(self._year, self._month, self._day,
10827db96d56Sopenharmony_ci                                  0, 0, 0, -1)
10837db96d56Sopenharmony_ci
10847db96d56Sopenharmony_ci    def toordinal(self):
10857db96d56Sopenharmony_ci        """Return proleptic Gregorian ordinal for the year, month and day.
10867db96d56Sopenharmony_ci
10877db96d56Sopenharmony_ci        January 1 of year 1 is day 1.  Only the year, month and day values
10887db96d56Sopenharmony_ci        contribute to the result.
10897db96d56Sopenharmony_ci        """
10907db96d56Sopenharmony_ci        return _ymd2ord(self._year, self._month, self._day)
10917db96d56Sopenharmony_ci
10927db96d56Sopenharmony_ci    def replace(self, year=None, month=None, day=None):
10937db96d56Sopenharmony_ci        """Return a new date with new values for the specified fields."""
10947db96d56Sopenharmony_ci        if year is None:
10957db96d56Sopenharmony_ci            year = self._year
10967db96d56Sopenharmony_ci        if month is None:
10977db96d56Sopenharmony_ci            month = self._month
10987db96d56Sopenharmony_ci        if day is None:
10997db96d56Sopenharmony_ci            day = self._day
11007db96d56Sopenharmony_ci        return type(self)(year, month, day)
11017db96d56Sopenharmony_ci
11027db96d56Sopenharmony_ci    # Comparisons of date objects with other.
11037db96d56Sopenharmony_ci
11047db96d56Sopenharmony_ci    def __eq__(self, other):
11057db96d56Sopenharmony_ci        if isinstance(other, date):
11067db96d56Sopenharmony_ci            return self._cmp(other) == 0
11077db96d56Sopenharmony_ci        return NotImplemented
11087db96d56Sopenharmony_ci
11097db96d56Sopenharmony_ci    def __le__(self, other):
11107db96d56Sopenharmony_ci        if isinstance(other, date):
11117db96d56Sopenharmony_ci            return self._cmp(other) <= 0
11127db96d56Sopenharmony_ci        return NotImplemented
11137db96d56Sopenharmony_ci
11147db96d56Sopenharmony_ci    def __lt__(self, other):
11157db96d56Sopenharmony_ci        if isinstance(other, date):
11167db96d56Sopenharmony_ci            return self._cmp(other) < 0
11177db96d56Sopenharmony_ci        return NotImplemented
11187db96d56Sopenharmony_ci
11197db96d56Sopenharmony_ci    def __ge__(self, other):
11207db96d56Sopenharmony_ci        if isinstance(other, date):
11217db96d56Sopenharmony_ci            return self._cmp(other) >= 0
11227db96d56Sopenharmony_ci        return NotImplemented
11237db96d56Sopenharmony_ci
11247db96d56Sopenharmony_ci    def __gt__(self, other):
11257db96d56Sopenharmony_ci        if isinstance(other, date):
11267db96d56Sopenharmony_ci            return self._cmp(other) > 0
11277db96d56Sopenharmony_ci        return NotImplemented
11287db96d56Sopenharmony_ci
11297db96d56Sopenharmony_ci    def _cmp(self, other):
11307db96d56Sopenharmony_ci        assert isinstance(other, date)
11317db96d56Sopenharmony_ci        y, m, d = self._year, self._month, self._day
11327db96d56Sopenharmony_ci        y2, m2, d2 = other._year, other._month, other._day
11337db96d56Sopenharmony_ci        return _cmp((y, m, d), (y2, m2, d2))
11347db96d56Sopenharmony_ci
11357db96d56Sopenharmony_ci    def __hash__(self):
11367db96d56Sopenharmony_ci        "Hash."
11377db96d56Sopenharmony_ci        if self._hashcode == -1:
11387db96d56Sopenharmony_ci            self._hashcode = hash(self._getstate())
11397db96d56Sopenharmony_ci        return self._hashcode
11407db96d56Sopenharmony_ci
11417db96d56Sopenharmony_ci    # Computations
11427db96d56Sopenharmony_ci
11437db96d56Sopenharmony_ci    def __add__(self, other):
11447db96d56Sopenharmony_ci        "Add a date to a timedelta."
11457db96d56Sopenharmony_ci        if isinstance(other, timedelta):
11467db96d56Sopenharmony_ci            o = self.toordinal() + other.days
11477db96d56Sopenharmony_ci            if 0 < o <= _MAXORDINAL:
11487db96d56Sopenharmony_ci                return type(self).fromordinal(o)
11497db96d56Sopenharmony_ci            raise OverflowError("result out of range")
11507db96d56Sopenharmony_ci        return NotImplemented
11517db96d56Sopenharmony_ci
11527db96d56Sopenharmony_ci    __radd__ = __add__
11537db96d56Sopenharmony_ci
11547db96d56Sopenharmony_ci    def __sub__(self, other):
11557db96d56Sopenharmony_ci        """Subtract two dates, or a date and a timedelta."""
11567db96d56Sopenharmony_ci        if isinstance(other, timedelta):
11577db96d56Sopenharmony_ci            return self + timedelta(-other.days)
11587db96d56Sopenharmony_ci        if isinstance(other, date):
11597db96d56Sopenharmony_ci            days1 = self.toordinal()
11607db96d56Sopenharmony_ci            days2 = other.toordinal()
11617db96d56Sopenharmony_ci            return timedelta(days1 - days2)
11627db96d56Sopenharmony_ci        return NotImplemented
11637db96d56Sopenharmony_ci
11647db96d56Sopenharmony_ci    def weekday(self):
11657db96d56Sopenharmony_ci        "Return day of the week, where Monday == 0 ... Sunday == 6."
11667db96d56Sopenharmony_ci        return (self.toordinal() + 6) % 7
11677db96d56Sopenharmony_ci
11687db96d56Sopenharmony_ci    # Day-of-the-week and week-of-the-year, according to ISO
11697db96d56Sopenharmony_ci
11707db96d56Sopenharmony_ci    def isoweekday(self):
11717db96d56Sopenharmony_ci        "Return day of the week, where Monday == 1 ... Sunday == 7."
11727db96d56Sopenharmony_ci        # 1-Jan-0001 is a Monday
11737db96d56Sopenharmony_ci        return self.toordinal() % 7 or 7
11747db96d56Sopenharmony_ci
11757db96d56Sopenharmony_ci    def isocalendar(self):
11767db96d56Sopenharmony_ci        """Return a named tuple containing ISO year, week number, and weekday.
11777db96d56Sopenharmony_ci
11787db96d56Sopenharmony_ci        The first ISO week of the year is the (Mon-Sun) week
11797db96d56Sopenharmony_ci        containing the year's first Thursday; everything else derives
11807db96d56Sopenharmony_ci        from that.
11817db96d56Sopenharmony_ci
11827db96d56Sopenharmony_ci        The first week is 1; Monday is 1 ... Sunday is 7.
11837db96d56Sopenharmony_ci
11847db96d56Sopenharmony_ci        ISO calendar algorithm taken from
11857db96d56Sopenharmony_ci        http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
11867db96d56Sopenharmony_ci        (used with permission)
11877db96d56Sopenharmony_ci        """
11887db96d56Sopenharmony_ci        year = self._year
11897db96d56Sopenharmony_ci        week1monday = _isoweek1monday(year)
11907db96d56Sopenharmony_ci        today = _ymd2ord(self._year, self._month, self._day)
11917db96d56Sopenharmony_ci        # Internally, week and day have origin 0
11927db96d56Sopenharmony_ci        week, day = divmod(today - week1monday, 7)
11937db96d56Sopenharmony_ci        if week < 0:
11947db96d56Sopenharmony_ci            year -= 1
11957db96d56Sopenharmony_ci            week1monday = _isoweek1monday(year)
11967db96d56Sopenharmony_ci            week, day = divmod(today - week1monday, 7)
11977db96d56Sopenharmony_ci        elif week >= 52:
11987db96d56Sopenharmony_ci            if today >= _isoweek1monday(year+1):
11997db96d56Sopenharmony_ci                year += 1
12007db96d56Sopenharmony_ci                week = 0
12017db96d56Sopenharmony_ci        return _IsoCalendarDate(year, week+1, day+1)
12027db96d56Sopenharmony_ci
12037db96d56Sopenharmony_ci    # Pickle support.
12047db96d56Sopenharmony_ci
12057db96d56Sopenharmony_ci    def _getstate(self):
12067db96d56Sopenharmony_ci        yhi, ylo = divmod(self._year, 256)
12077db96d56Sopenharmony_ci        return bytes([yhi, ylo, self._month, self._day]),
12087db96d56Sopenharmony_ci
12097db96d56Sopenharmony_ci    def __setstate(self, string):
12107db96d56Sopenharmony_ci        yhi, ylo, self._month, self._day = string
12117db96d56Sopenharmony_ci        self._year = yhi * 256 + ylo
12127db96d56Sopenharmony_ci
12137db96d56Sopenharmony_ci    def __reduce__(self):
12147db96d56Sopenharmony_ci        return (self.__class__, self._getstate())
12157db96d56Sopenharmony_ci
12167db96d56Sopenharmony_ci_date_class = date  # so functions w/ args named "date" can get at the class
12177db96d56Sopenharmony_ci
12187db96d56Sopenharmony_cidate.min = date(1, 1, 1)
12197db96d56Sopenharmony_cidate.max = date(9999, 12, 31)
12207db96d56Sopenharmony_cidate.resolution = timedelta(days=1)
12217db96d56Sopenharmony_ci
12227db96d56Sopenharmony_ci
12237db96d56Sopenharmony_ciclass tzinfo:
12247db96d56Sopenharmony_ci    """Abstract base class for time zone info classes.
12257db96d56Sopenharmony_ci
12267db96d56Sopenharmony_ci    Subclasses must override the name(), utcoffset() and dst() methods.
12277db96d56Sopenharmony_ci    """
12287db96d56Sopenharmony_ci    __slots__ = ()
12297db96d56Sopenharmony_ci
12307db96d56Sopenharmony_ci    def tzname(self, dt):
12317db96d56Sopenharmony_ci        "datetime -> string name of time zone."
12327db96d56Sopenharmony_ci        raise NotImplementedError("tzinfo subclass must override tzname()")
12337db96d56Sopenharmony_ci
12347db96d56Sopenharmony_ci    def utcoffset(self, dt):
12357db96d56Sopenharmony_ci        "datetime -> timedelta, positive for east of UTC, negative for west of UTC"
12367db96d56Sopenharmony_ci        raise NotImplementedError("tzinfo subclass must override utcoffset()")
12377db96d56Sopenharmony_ci
12387db96d56Sopenharmony_ci    def dst(self, dt):
12397db96d56Sopenharmony_ci        """datetime -> DST offset as timedelta, positive for east of UTC.
12407db96d56Sopenharmony_ci
12417db96d56Sopenharmony_ci        Return 0 if DST not in effect.  utcoffset() must include the DST
12427db96d56Sopenharmony_ci        offset.
12437db96d56Sopenharmony_ci        """
12447db96d56Sopenharmony_ci        raise NotImplementedError("tzinfo subclass must override dst()")
12457db96d56Sopenharmony_ci
12467db96d56Sopenharmony_ci    def fromutc(self, dt):
12477db96d56Sopenharmony_ci        "datetime in UTC -> datetime in local time."
12487db96d56Sopenharmony_ci
12497db96d56Sopenharmony_ci        if not isinstance(dt, datetime):
12507db96d56Sopenharmony_ci            raise TypeError("fromutc() requires a datetime argument")
12517db96d56Sopenharmony_ci        if dt.tzinfo is not self:
12527db96d56Sopenharmony_ci            raise ValueError("dt.tzinfo is not self")
12537db96d56Sopenharmony_ci
12547db96d56Sopenharmony_ci        dtoff = dt.utcoffset()
12557db96d56Sopenharmony_ci        if dtoff is None:
12567db96d56Sopenharmony_ci            raise ValueError("fromutc() requires a non-None utcoffset() "
12577db96d56Sopenharmony_ci                             "result")
12587db96d56Sopenharmony_ci
12597db96d56Sopenharmony_ci        # See the long comment block at the end of this file for an
12607db96d56Sopenharmony_ci        # explanation of this algorithm.
12617db96d56Sopenharmony_ci        dtdst = dt.dst()
12627db96d56Sopenharmony_ci        if dtdst is None:
12637db96d56Sopenharmony_ci            raise ValueError("fromutc() requires a non-None dst() result")
12647db96d56Sopenharmony_ci        delta = dtoff - dtdst
12657db96d56Sopenharmony_ci        if delta:
12667db96d56Sopenharmony_ci            dt += delta
12677db96d56Sopenharmony_ci            dtdst = dt.dst()
12687db96d56Sopenharmony_ci            if dtdst is None:
12697db96d56Sopenharmony_ci                raise ValueError("fromutc(): dt.dst gave inconsistent "
12707db96d56Sopenharmony_ci                                 "results; cannot convert")
12717db96d56Sopenharmony_ci        return dt + dtdst
12727db96d56Sopenharmony_ci
12737db96d56Sopenharmony_ci    # Pickle support.
12747db96d56Sopenharmony_ci
12757db96d56Sopenharmony_ci    def __reduce__(self):
12767db96d56Sopenharmony_ci        getinitargs = getattr(self, "__getinitargs__", None)
12777db96d56Sopenharmony_ci        if getinitargs:
12787db96d56Sopenharmony_ci            args = getinitargs()
12797db96d56Sopenharmony_ci        else:
12807db96d56Sopenharmony_ci            args = ()
12817db96d56Sopenharmony_ci        return (self.__class__, args, self.__getstate__())
12827db96d56Sopenharmony_ci
12837db96d56Sopenharmony_ci
12847db96d56Sopenharmony_ciclass IsoCalendarDate(tuple):
12857db96d56Sopenharmony_ci
12867db96d56Sopenharmony_ci    def __new__(cls, year, week, weekday, /):
12877db96d56Sopenharmony_ci        return super().__new__(cls, (year, week, weekday))
12887db96d56Sopenharmony_ci
12897db96d56Sopenharmony_ci    @property
12907db96d56Sopenharmony_ci    def year(self):
12917db96d56Sopenharmony_ci        return self[0]
12927db96d56Sopenharmony_ci
12937db96d56Sopenharmony_ci    @property
12947db96d56Sopenharmony_ci    def week(self):
12957db96d56Sopenharmony_ci        return self[1]
12967db96d56Sopenharmony_ci
12977db96d56Sopenharmony_ci    @property
12987db96d56Sopenharmony_ci    def weekday(self):
12997db96d56Sopenharmony_ci        return self[2]
13007db96d56Sopenharmony_ci
13017db96d56Sopenharmony_ci    def __reduce__(self):
13027db96d56Sopenharmony_ci        # This code is intended to pickle the object without making the
13037db96d56Sopenharmony_ci        # class public. See https://bugs.python.org/msg352381
13047db96d56Sopenharmony_ci        return (tuple, (tuple(self),))
13057db96d56Sopenharmony_ci
13067db96d56Sopenharmony_ci    def __repr__(self):
13077db96d56Sopenharmony_ci        return (f'{self.__class__.__name__}'
13087db96d56Sopenharmony_ci                f'(year={self[0]}, week={self[1]}, weekday={self[2]})')
13097db96d56Sopenharmony_ci
13107db96d56Sopenharmony_ci
13117db96d56Sopenharmony_ci_IsoCalendarDate = IsoCalendarDate
13127db96d56Sopenharmony_cidel IsoCalendarDate
13137db96d56Sopenharmony_ci_tzinfo_class = tzinfo
13147db96d56Sopenharmony_ci
13157db96d56Sopenharmony_ciclass time:
13167db96d56Sopenharmony_ci    """Time with time zone.
13177db96d56Sopenharmony_ci
13187db96d56Sopenharmony_ci    Constructors:
13197db96d56Sopenharmony_ci
13207db96d56Sopenharmony_ci    __new__()
13217db96d56Sopenharmony_ci
13227db96d56Sopenharmony_ci    Operators:
13237db96d56Sopenharmony_ci
13247db96d56Sopenharmony_ci    __repr__, __str__
13257db96d56Sopenharmony_ci    __eq__, __le__, __lt__, __ge__, __gt__, __hash__
13267db96d56Sopenharmony_ci
13277db96d56Sopenharmony_ci    Methods:
13287db96d56Sopenharmony_ci
13297db96d56Sopenharmony_ci    strftime()
13307db96d56Sopenharmony_ci    isoformat()
13317db96d56Sopenharmony_ci    utcoffset()
13327db96d56Sopenharmony_ci    tzname()
13337db96d56Sopenharmony_ci    dst()
13347db96d56Sopenharmony_ci
13357db96d56Sopenharmony_ci    Properties (readonly):
13367db96d56Sopenharmony_ci    hour, minute, second, microsecond, tzinfo, fold
13377db96d56Sopenharmony_ci    """
13387db96d56Sopenharmony_ci    __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode', '_fold'
13397db96d56Sopenharmony_ci
13407db96d56Sopenharmony_ci    def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
13417db96d56Sopenharmony_ci        """Constructor.
13427db96d56Sopenharmony_ci
13437db96d56Sopenharmony_ci        Arguments:
13447db96d56Sopenharmony_ci
13457db96d56Sopenharmony_ci        hour, minute (required)
13467db96d56Sopenharmony_ci        second, microsecond (default to zero)
13477db96d56Sopenharmony_ci        tzinfo (default to None)
13487db96d56Sopenharmony_ci        fold (keyword only, default to zero)
13497db96d56Sopenharmony_ci        """
13507db96d56Sopenharmony_ci        if (isinstance(hour, (bytes, str)) and len(hour) == 6 and
13517db96d56Sopenharmony_ci            ord(hour[0:1])&0x7F < 24):
13527db96d56Sopenharmony_ci            # Pickle support
13537db96d56Sopenharmony_ci            if isinstance(hour, str):
13547db96d56Sopenharmony_ci                try:
13557db96d56Sopenharmony_ci                    hour = hour.encode('latin1')
13567db96d56Sopenharmony_ci                except UnicodeEncodeError:
13577db96d56Sopenharmony_ci                    # More informative error message.
13587db96d56Sopenharmony_ci                    raise ValueError(
13597db96d56Sopenharmony_ci                        "Failed to encode latin1 string when unpickling "
13607db96d56Sopenharmony_ci                        "a time object. "
13617db96d56Sopenharmony_ci                        "pickle.load(data, encoding='latin1') is assumed.")
13627db96d56Sopenharmony_ci            self = object.__new__(cls)
13637db96d56Sopenharmony_ci            self.__setstate(hour, minute or None)
13647db96d56Sopenharmony_ci            self._hashcode = -1
13657db96d56Sopenharmony_ci            return self
13667db96d56Sopenharmony_ci        hour, minute, second, microsecond, fold = _check_time_fields(
13677db96d56Sopenharmony_ci            hour, minute, second, microsecond, fold)
13687db96d56Sopenharmony_ci        _check_tzinfo_arg(tzinfo)
13697db96d56Sopenharmony_ci        self = object.__new__(cls)
13707db96d56Sopenharmony_ci        self._hour = hour
13717db96d56Sopenharmony_ci        self._minute = minute
13727db96d56Sopenharmony_ci        self._second = second
13737db96d56Sopenharmony_ci        self._microsecond = microsecond
13747db96d56Sopenharmony_ci        self._tzinfo = tzinfo
13757db96d56Sopenharmony_ci        self._hashcode = -1
13767db96d56Sopenharmony_ci        self._fold = fold
13777db96d56Sopenharmony_ci        return self
13787db96d56Sopenharmony_ci
13797db96d56Sopenharmony_ci    # Read-only field accessors
13807db96d56Sopenharmony_ci    @property
13817db96d56Sopenharmony_ci    def hour(self):
13827db96d56Sopenharmony_ci        """hour (0-23)"""
13837db96d56Sopenharmony_ci        return self._hour
13847db96d56Sopenharmony_ci
13857db96d56Sopenharmony_ci    @property
13867db96d56Sopenharmony_ci    def minute(self):
13877db96d56Sopenharmony_ci        """minute (0-59)"""
13887db96d56Sopenharmony_ci        return self._minute
13897db96d56Sopenharmony_ci
13907db96d56Sopenharmony_ci    @property
13917db96d56Sopenharmony_ci    def second(self):
13927db96d56Sopenharmony_ci        """second (0-59)"""
13937db96d56Sopenharmony_ci        return self._second
13947db96d56Sopenharmony_ci
13957db96d56Sopenharmony_ci    @property
13967db96d56Sopenharmony_ci    def microsecond(self):
13977db96d56Sopenharmony_ci        """microsecond (0-999999)"""
13987db96d56Sopenharmony_ci        return self._microsecond
13997db96d56Sopenharmony_ci
14007db96d56Sopenharmony_ci    @property
14017db96d56Sopenharmony_ci    def tzinfo(self):
14027db96d56Sopenharmony_ci        """timezone info object"""
14037db96d56Sopenharmony_ci        return self._tzinfo
14047db96d56Sopenharmony_ci
14057db96d56Sopenharmony_ci    @property
14067db96d56Sopenharmony_ci    def fold(self):
14077db96d56Sopenharmony_ci        return self._fold
14087db96d56Sopenharmony_ci
14097db96d56Sopenharmony_ci    # Standard conversions, __hash__ (and helpers)
14107db96d56Sopenharmony_ci
14117db96d56Sopenharmony_ci    # Comparisons of time objects with other.
14127db96d56Sopenharmony_ci
14137db96d56Sopenharmony_ci    def __eq__(self, other):
14147db96d56Sopenharmony_ci        if isinstance(other, time):
14157db96d56Sopenharmony_ci            return self._cmp(other, allow_mixed=True) == 0
14167db96d56Sopenharmony_ci        else:
14177db96d56Sopenharmony_ci            return NotImplemented
14187db96d56Sopenharmony_ci
14197db96d56Sopenharmony_ci    def __le__(self, other):
14207db96d56Sopenharmony_ci        if isinstance(other, time):
14217db96d56Sopenharmony_ci            return self._cmp(other) <= 0
14227db96d56Sopenharmony_ci        else:
14237db96d56Sopenharmony_ci            return NotImplemented
14247db96d56Sopenharmony_ci
14257db96d56Sopenharmony_ci    def __lt__(self, other):
14267db96d56Sopenharmony_ci        if isinstance(other, time):
14277db96d56Sopenharmony_ci            return self._cmp(other) < 0
14287db96d56Sopenharmony_ci        else:
14297db96d56Sopenharmony_ci            return NotImplemented
14307db96d56Sopenharmony_ci
14317db96d56Sopenharmony_ci    def __ge__(self, other):
14327db96d56Sopenharmony_ci        if isinstance(other, time):
14337db96d56Sopenharmony_ci            return self._cmp(other) >= 0
14347db96d56Sopenharmony_ci        else:
14357db96d56Sopenharmony_ci            return NotImplemented
14367db96d56Sopenharmony_ci
14377db96d56Sopenharmony_ci    def __gt__(self, other):
14387db96d56Sopenharmony_ci        if isinstance(other, time):
14397db96d56Sopenharmony_ci            return self._cmp(other) > 0
14407db96d56Sopenharmony_ci        else:
14417db96d56Sopenharmony_ci            return NotImplemented
14427db96d56Sopenharmony_ci
14437db96d56Sopenharmony_ci    def _cmp(self, other, allow_mixed=False):
14447db96d56Sopenharmony_ci        assert isinstance(other, time)
14457db96d56Sopenharmony_ci        mytz = self._tzinfo
14467db96d56Sopenharmony_ci        ottz = other._tzinfo
14477db96d56Sopenharmony_ci        myoff = otoff = None
14487db96d56Sopenharmony_ci
14497db96d56Sopenharmony_ci        if mytz is ottz:
14507db96d56Sopenharmony_ci            base_compare = True
14517db96d56Sopenharmony_ci        else:
14527db96d56Sopenharmony_ci            myoff = self.utcoffset()
14537db96d56Sopenharmony_ci            otoff = other.utcoffset()
14547db96d56Sopenharmony_ci            base_compare = myoff == otoff
14557db96d56Sopenharmony_ci
14567db96d56Sopenharmony_ci        if base_compare:
14577db96d56Sopenharmony_ci            return _cmp((self._hour, self._minute, self._second,
14587db96d56Sopenharmony_ci                         self._microsecond),
14597db96d56Sopenharmony_ci                        (other._hour, other._minute, other._second,
14607db96d56Sopenharmony_ci                         other._microsecond))
14617db96d56Sopenharmony_ci        if myoff is None or otoff is None:
14627db96d56Sopenharmony_ci            if allow_mixed:
14637db96d56Sopenharmony_ci                return 2 # arbitrary non-zero value
14647db96d56Sopenharmony_ci            else:
14657db96d56Sopenharmony_ci                raise TypeError("cannot compare naive and aware times")
14667db96d56Sopenharmony_ci        myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
14677db96d56Sopenharmony_ci        othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
14687db96d56Sopenharmony_ci        return _cmp((myhhmm, self._second, self._microsecond),
14697db96d56Sopenharmony_ci                    (othhmm, other._second, other._microsecond))
14707db96d56Sopenharmony_ci
14717db96d56Sopenharmony_ci    def __hash__(self):
14727db96d56Sopenharmony_ci        """Hash."""
14737db96d56Sopenharmony_ci        if self._hashcode == -1:
14747db96d56Sopenharmony_ci            if self.fold:
14757db96d56Sopenharmony_ci                t = self.replace(fold=0)
14767db96d56Sopenharmony_ci            else:
14777db96d56Sopenharmony_ci                t = self
14787db96d56Sopenharmony_ci            tzoff = t.utcoffset()
14797db96d56Sopenharmony_ci            if not tzoff:  # zero or None
14807db96d56Sopenharmony_ci                self._hashcode = hash(t._getstate()[0])
14817db96d56Sopenharmony_ci            else:
14827db96d56Sopenharmony_ci                h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
14837db96d56Sopenharmony_ci                              timedelta(hours=1))
14847db96d56Sopenharmony_ci                assert not m % timedelta(minutes=1), "whole minute"
14857db96d56Sopenharmony_ci                m //= timedelta(minutes=1)
14867db96d56Sopenharmony_ci                if 0 <= h < 24:
14877db96d56Sopenharmony_ci                    self._hashcode = hash(time(h, m, self.second, self.microsecond))
14887db96d56Sopenharmony_ci                else:
14897db96d56Sopenharmony_ci                    self._hashcode = hash((h, m, self.second, self.microsecond))
14907db96d56Sopenharmony_ci        return self._hashcode
14917db96d56Sopenharmony_ci
14927db96d56Sopenharmony_ci    # Conversion to string
14937db96d56Sopenharmony_ci
14947db96d56Sopenharmony_ci    def _tzstr(self):
14957db96d56Sopenharmony_ci        """Return formatted timezone offset (+xx:xx) or an empty string."""
14967db96d56Sopenharmony_ci        off = self.utcoffset()
14977db96d56Sopenharmony_ci        return _format_offset(off)
14987db96d56Sopenharmony_ci
14997db96d56Sopenharmony_ci    def __repr__(self):
15007db96d56Sopenharmony_ci        """Convert to formal string, for repr()."""
15017db96d56Sopenharmony_ci        if self._microsecond != 0:
15027db96d56Sopenharmony_ci            s = ", %d, %d" % (self._second, self._microsecond)
15037db96d56Sopenharmony_ci        elif self._second != 0:
15047db96d56Sopenharmony_ci            s = ", %d" % self._second
15057db96d56Sopenharmony_ci        else:
15067db96d56Sopenharmony_ci            s = ""
15077db96d56Sopenharmony_ci        s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
15087db96d56Sopenharmony_ci                                self.__class__.__qualname__,
15097db96d56Sopenharmony_ci                                self._hour, self._minute, s)
15107db96d56Sopenharmony_ci        if self._tzinfo is not None:
15117db96d56Sopenharmony_ci            assert s[-1:] == ")"
15127db96d56Sopenharmony_ci            s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
15137db96d56Sopenharmony_ci        if self._fold:
15147db96d56Sopenharmony_ci            assert s[-1:] == ")"
15157db96d56Sopenharmony_ci            s = s[:-1] + ", fold=1)"
15167db96d56Sopenharmony_ci        return s
15177db96d56Sopenharmony_ci
15187db96d56Sopenharmony_ci    def isoformat(self, timespec='auto'):
15197db96d56Sopenharmony_ci        """Return the time formatted according to ISO.
15207db96d56Sopenharmony_ci
15217db96d56Sopenharmony_ci        The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional
15227db96d56Sopenharmony_ci        part is omitted if self.microsecond == 0.
15237db96d56Sopenharmony_ci
15247db96d56Sopenharmony_ci        The optional argument timespec specifies the number of additional
15257db96d56Sopenharmony_ci        terms of the time to include. Valid options are 'auto', 'hours',
15267db96d56Sopenharmony_ci        'minutes', 'seconds', 'milliseconds' and 'microseconds'.
15277db96d56Sopenharmony_ci        """
15287db96d56Sopenharmony_ci        s = _format_time(self._hour, self._minute, self._second,
15297db96d56Sopenharmony_ci                          self._microsecond, timespec)
15307db96d56Sopenharmony_ci        tz = self._tzstr()
15317db96d56Sopenharmony_ci        if tz:
15327db96d56Sopenharmony_ci            s += tz
15337db96d56Sopenharmony_ci        return s
15347db96d56Sopenharmony_ci
15357db96d56Sopenharmony_ci    __str__ = isoformat
15367db96d56Sopenharmony_ci
15377db96d56Sopenharmony_ci    @classmethod
15387db96d56Sopenharmony_ci    def fromisoformat(cls, time_string):
15397db96d56Sopenharmony_ci        """Construct a time from a string in one of the ISO 8601 formats."""
15407db96d56Sopenharmony_ci        if not isinstance(time_string, str):
15417db96d56Sopenharmony_ci            raise TypeError('fromisoformat: argument must be str')
15427db96d56Sopenharmony_ci
15437db96d56Sopenharmony_ci        # The spec actually requires that time-only ISO 8601 strings start with
15447db96d56Sopenharmony_ci        # T, but the extended format allows this to be omitted as long as there
15457db96d56Sopenharmony_ci        # is no ambiguity with date strings.
15467db96d56Sopenharmony_ci        time_string = time_string.removeprefix('T')
15477db96d56Sopenharmony_ci
15487db96d56Sopenharmony_ci        try:
15497db96d56Sopenharmony_ci            return cls(*_parse_isoformat_time(time_string))
15507db96d56Sopenharmony_ci        except Exception:
15517db96d56Sopenharmony_ci            raise ValueError(f'Invalid isoformat string: {time_string!r}')
15527db96d56Sopenharmony_ci
15537db96d56Sopenharmony_ci
15547db96d56Sopenharmony_ci    def strftime(self, fmt):
15557db96d56Sopenharmony_ci        """Format using strftime().  The date part of the timestamp passed
15567db96d56Sopenharmony_ci        to underlying strftime should not be used.
15577db96d56Sopenharmony_ci        """
15587db96d56Sopenharmony_ci        # The year must be >= 1000 else Python's strftime implementation
15597db96d56Sopenharmony_ci        # can raise a bogus exception.
15607db96d56Sopenharmony_ci        timetuple = (1900, 1, 1,
15617db96d56Sopenharmony_ci                     self._hour, self._minute, self._second,
15627db96d56Sopenharmony_ci                     0, 1, -1)
15637db96d56Sopenharmony_ci        return _wrap_strftime(self, fmt, timetuple)
15647db96d56Sopenharmony_ci
15657db96d56Sopenharmony_ci    def __format__(self, fmt):
15667db96d56Sopenharmony_ci        if not isinstance(fmt, str):
15677db96d56Sopenharmony_ci            raise TypeError("must be str, not %s" % type(fmt).__name__)
15687db96d56Sopenharmony_ci        if len(fmt) != 0:
15697db96d56Sopenharmony_ci            return self.strftime(fmt)
15707db96d56Sopenharmony_ci        return str(self)
15717db96d56Sopenharmony_ci
15727db96d56Sopenharmony_ci    # Timezone functions
15737db96d56Sopenharmony_ci
15747db96d56Sopenharmony_ci    def utcoffset(self):
15757db96d56Sopenharmony_ci        """Return the timezone offset as timedelta, positive east of UTC
15767db96d56Sopenharmony_ci         (negative west of UTC)."""
15777db96d56Sopenharmony_ci        if self._tzinfo is None:
15787db96d56Sopenharmony_ci            return None
15797db96d56Sopenharmony_ci        offset = self._tzinfo.utcoffset(None)
15807db96d56Sopenharmony_ci        _check_utc_offset("utcoffset", offset)
15817db96d56Sopenharmony_ci        return offset
15827db96d56Sopenharmony_ci
15837db96d56Sopenharmony_ci    def tzname(self):
15847db96d56Sopenharmony_ci        """Return the timezone name.
15857db96d56Sopenharmony_ci
15867db96d56Sopenharmony_ci        Note that the name is 100% informational -- there's no requirement that
15877db96d56Sopenharmony_ci        it mean anything in particular. For example, "GMT", "UTC", "-500",
15887db96d56Sopenharmony_ci        "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
15897db96d56Sopenharmony_ci        """
15907db96d56Sopenharmony_ci        if self._tzinfo is None:
15917db96d56Sopenharmony_ci            return None
15927db96d56Sopenharmony_ci        name = self._tzinfo.tzname(None)
15937db96d56Sopenharmony_ci        _check_tzname(name)
15947db96d56Sopenharmony_ci        return name
15957db96d56Sopenharmony_ci
15967db96d56Sopenharmony_ci    def dst(self):
15977db96d56Sopenharmony_ci        """Return 0 if DST is not in effect, or the DST offset (as timedelta
15987db96d56Sopenharmony_ci        positive eastward) if DST is in effect.
15997db96d56Sopenharmony_ci
16007db96d56Sopenharmony_ci        This is purely informational; the DST offset has already been added to
16017db96d56Sopenharmony_ci        the UTC offset returned by utcoffset() if applicable, so there's no
16027db96d56Sopenharmony_ci        need to consult dst() unless you're interested in displaying the DST
16037db96d56Sopenharmony_ci        info.
16047db96d56Sopenharmony_ci        """
16057db96d56Sopenharmony_ci        if self._tzinfo is None:
16067db96d56Sopenharmony_ci            return None
16077db96d56Sopenharmony_ci        offset = self._tzinfo.dst(None)
16087db96d56Sopenharmony_ci        _check_utc_offset("dst", offset)
16097db96d56Sopenharmony_ci        return offset
16107db96d56Sopenharmony_ci
16117db96d56Sopenharmony_ci    def replace(self, hour=None, minute=None, second=None, microsecond=None,
16127db96d56Sopenharmony_ci                tzinfo=True, *, fold=None):
16137db96d56Sopenharmony_ci        """Return a new time with new values for the specified fields."""
16147db96d56Sopenharmony_ci        if hour is None:
16157db96d56Sopenharmony_ci            hour = self.hour
16167db96d56Sopenharmony_ci        if minute is None:
16177db96d56Sopenharmony_ci            minute = self.minute
16187db96d56Sopenharmony_ci        if second is None:
16197db96d56Sopenharmony_ci            second = self.second
16207db96d56Sopenharmony_ci        if microsecond is None:
16217db96d56Sopenharmony_ci            microsecond = self.microsecond
16227db96d56Sopenharmony_ci        if tzinfo is True:
16237db96d56Sopenharmony_ci            tzinfo = self.tzinfo
16247db96d56Sopenharmony_ci        if fold is None:
16257db96d56Sopenharmony_ci            fold = self._fold
16267db96d56Sopenharmony_ci        return type(self)(hour, minute, second, microsecond, tzinfo, fold=fold)
16277db96d56Sopenharmony_ci
16287db96d56Sopenharmony_ci    # Pickle support.
16297db96d56Sopenharmony_ci
16307db96d56Sopenharmony_ci    def _getstate(self, protocol=3):
16317db96d56Sopenharmony_ci        us2, us3 = divmod(self._microsecond, 256)
16327db96d56Sopenharmony_ci        us1, us2 = divmod(us2, 256)
16337db96d56Sopenharmony_ci        h = self._hour
16347db96d56Sopenharmony_ci        if self._fold and protocol > 3:
16357db96d56Sopenharmony_ci            h += 128
16367db96d56Sopenharmony_ci        basestate = bytes([h, self._minute, self._second,
16377db96d56Sopenharmony_ci                           us1, us2, us3])
16387db96d56Sopenharmony_ci        if self._tzinfo is None:
16397db96d56Sopenharmony_ci            return (basestate,)
16407db96d56Sopenharmony_ci        else:
16417db96d56Sopenharmony_ci            return (basestate, self._tzinfo)
16427db96d56Sopenharmony_ci
16437db96d56Sopenharmony_ci    def __setstate(self, string, tzinfo):
16447db96d56Sopenharmony_ci        if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
16457db96d56Sopenharmony_ci            raise TypeError("bad tzinfo state arg")
16467db96d56Sopenharmony_ci        h, self._minute, self._second, us1, us2, us3 = string
16477db96d56Sopenharmony_ci        if h > 127:
16487db96d56Sopenharmony_ci            self._fold = 1
16497db96d56Sopenharmony_ci            self._hour = h - 128
16507db96d56Sopenharmony_ci        else:
16517db96d56Sopenharmony_ci            self._fold = 0
16527db96d56Sopenharmony_ci            self._hour = h
16537db96d56Sopenharmony_ci        self._microsecond = (((us1 << 8) | us2) << 8) | us3
16547db96d56Sopenharmony_ci        self._tzinfo = tzinfo
16557db96d56Sopenharmony_ci
16567db96d56Sopenharmony_ci    def __reduce_ex__(self, protocol):
16577db96d56Sopenharmony_ci        return (self.__class__, self._getstate(protocol))
16587db96d56Sopenharmony_ci
16597db96d56Sopenharmony_ci    def __reduce__(self):
16607db96d56Sopenharmony_ci        return self.__reduce_ex__(2)
16617db96d56Sopenharmony_ci
16627db96d56Sopenharmony_ci_time_class = time  # so functions w/ args named "time" can get at the class
16637db96d56Sopenharmony_ci
16647db96d56Sopenharmony_citime.min = time(0, 0, 0)
16657db96d56Sopenharmony_citime.max = time(23, 59, 59, 999999)
16667db96d56Sopenharmony_citime.resolution = timedelta(microseconds=1)
16677db96d56Sopenharmony_ci
16687db96d56Sopenharmony_ci
16697db96d56Sopenharmony_ciclass datetime(date):
16707db96d56Sopenharmony_ci    """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
16717db96d56Sopenharmony_ci
16727db96d56Sopenharmony_ci    The year, month and day arguments are required. tzinfo may be None, or an
16737db96d56Sopenharmony_ci    instance of a tzinfo subclass. The remaining arguments may be ints.
16747db96d56Sopenharmony_ci    """
16757db96d56Sopenharmony_ci    __slots__ = date.__slots__ + time.__slots__
16767db96d56Sopenharmony_ci
16777db96d56Sopenharmony_ci    def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
16787db96d56Sopenharmony_ci                microsecond=0, tzinfo=None, *, fold=0):
16797db96d56Sopenharmony_ci        if (isinstance(year, (bytes, str)) and len(year) == 10 and
16807db96d56Sopenharmony_ci            1 <= ord(year[2:3])&0x7F <= 12):
16817db96d56Sopenharmony_ci            # Pickle support
16827db96d56Sopenharmony_ci            if isinstance(year, str):
16837db96d56Sopenharmony_ci                try:
16847db96d56Sopenharmony_ci                    year = bytes(year, 'latin1')
16857db96d56Sopenharmony_ci                except UnicodeEncodeError:
16867db96d56Sopenharmony_ci                    # More informative error message.
16877db96d56Sopenharmony_ci                    raise ValueError(
16887db96d56Sopenharmony_ci                        "Failed to encode latin1 string when unpickling "
16897db96d56Sopenharmony_ci                        "a datetime object. "
16907db96d56Sopenharmony_ci                        "pickle.load(data, encoding='latin1') is assumed.")
16917db96d56Sopenharmony_ci            self = object.__new__(cls)
16927db96d56Sopenharmony_ci            self.__setstate(year, month)
16937db96d56Sopenharmony_ci            self._hashcode = -1
16947db96d56Sopenharmony_ci            return self
16957db96d56Sopenharmony_ci        year, month, day = _check_date_fields(year, month, day)
16967db96d56Sopenharmony_ci        hour, minute, second, microsecond, fold = _check_time_fields(
16977db96d56Sopenharmony_ci            hour, minute, second, microsecond, fold)
16987db96d56Sopenharmony_ci        _check_tzinfo_arg(tzinfo)
16997db96d56Sopenharmony_ci        self = object.__new__(cls)
17007db96d56Sopenharmony_ci        self._year = year
17017db96d56Sopenharmony_ci        self._month = month
17027db96d56Sopenharmony_ci        self._day = day
17037db96d56Sopenharmony_ci        self._hour = hour
17047db96d56Sopenharmony_ci        self._minute = minute
17057db96d56Sopenharmony_ci        self._second = second
17067db96d56Sopenharmony_ci        self._microsecond = microsecond
17077db96d56Sopenharmony_ci        self._tzinfo = tzinfo
17087db96d56Sopenharmony_ci        self._hashcode = -1
17097db96d56Sopenharmony_ci        self._fold = fold
17107db96d56Sopenharmony_ci        return self
17117db96d56Sopenharmony_ci
17127db96d56Sopenharmony_ci    # Read-only field accessors
17137db96d56Sopenharmony_ci    @property
17147db96d56Sopenharmony_ci    def hour(self):
17157db96d56Sopenharmony_ci        """hour (0-23)"""
17167db96d56Sopenharmony_ci        return self._hour
17177db96d56Sopenharmony_ci
17187db96d56Sopenharmony_ci    @property
17197db96d56Sopenharmony_ci    def minute(self):
17207db96d56Sopenharmony_ci        """minute (0-59)"""
17217db96d56Sopenharmony_ci        return self._minute
17227db96d56Sopenharmony_ci
17237db96d56Sopenharmony_ci    @property
17247db96d56Sopenharmony_ci    def second(self):
17257db96d56Sopenharmony_ci        """second (0-59)"""
17267db96d56Sopenharmony_ci        return self._second
17277db96d56Sopenharmony_ci
17287db96d56Sopenharmony_ci    @property
17297db96d56Sopenharmony_ci    def microsecond(self):
17307db96d56Sopenharmony_ci        """microsecond (0-999999)"""
17317db96d56Sopenharmony_ci        return self._microsecond
17327db96d56Sopenharmony_ci
17337db96d56Sopenharmony_ci    @property
17347db96d56Sopenharmony_ci    def tzinfo(self):
17357db96d56Sopenharmony_ci        """timezone info object"""
17367db96d56Sopenharmony_ci        return self._tzinfo
17377db96d56Sopenharmony_ci
17387db96d56Sopenharmony_ci    @property
17397db96d56Sopenharmony_ci    def fold(self):
17407db96d56Sopenharmony_ci        return self._fold
17417db96d56Sopenharmony_ci
17427db96d56Sopenharmony_ci    @classmethod
17437db96d56Sopenharmony_ci    def _fromtimestamp(cls, t, utc, tz):
17447db96d56Sopenharmony_ci        """Construct a datetime from a POSIX timestamp (like time.time()).
17457db96d56Sopenharmony_ci
17467db96d56Sopenharmony_ci        A timezone info object may be passed in as well.
17477db96d56Sopenharmony_ci        """
17487db96d56Sopenharmony_ci        frac, t = _math.modf(t)
17497db96d56Sopenharmony_ci        us = round(frac * 1e6)
17507db96d56Sopenharmony_ci        if us >= 1000000:
17517db96d56Sopenharmony_ci            t += 1
17527db96d56Sopenharmony_ci            us -= 1000000
17537db96d56Sopenharmony_ci        elif us < 0:
17547db96d56Sopenharmony_ci            t -= 1
17557db96d56Sopenharmony_ci            us += 1000000
17567db96d56Sopenharmony_ci
17577db96d56Sopenharmony_ci        converter = _time.gmtime if utc else _time.localtime
17587db96d56Sopenharmony_ci        y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
17597db96d56Sopenharmony_ci        ss = min(ss, 59)    # clamp out leap seconds if the platform has them
17607db96d56Sopenharmony_ci        result = cls(y, m, d, hh, mm, ss, us, tz)
17617db96d56Sopenharmony_ci        if tz is None and not utc:
17627db96d56Sopenharmony_ci            # As of version 2015f max fold in IANA database is
17637db96d56Sopenharmony_ci            # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
17647db96d56Sopenharmony_ci            # Let's probe 24 hours in the past to detect a transition:
17657db96d56Sopenharmony_ci            max_fold_seconds = 24 * 3600
17667db96d56Sopenharmony_ci
17677db96d56Sopenharmony_ci            # On Windows localtime_s throws an OSError for negative values,
17687db96d56Sopenharmony_ci            # thus we can't perform fold detection for values of time less
17697db96d56Sopenharmony_ci            # than the max time fold. See comments in _datetimemodule's
17707db96d56Sopenharmony_ci            # version of this method for more details.
17717db96d56Sopenharmony_ci            if t < max_fold_seconds and sys.platform.startswith("win"):
17727db96d56Sopenharmony_ci                return result
17737db96d56Sopenharmony_ci
17747db96d56Sopenharmony_ci            y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
17757db96d56Sopenharmony_ci            probe1 = cls(y, m, d, hh, mm, ss, us, tz)
17767db96d56Sopenharmony_ci            trans = result - probe1 - timedelta(0, max_fold_seconds)
17777db96d56Sopenharmony_ci            if trans.days < 0:
17787db96d56Sopenharmony_ci                y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
17797db96d56Sopenharmony_ci                probe2 = cls(y, m, d, hh, mm, ss, us, tz)
17807db96d56Sopenharmony_ci                if probe2 == result:
17817db96d56Sopenharmony_ci                    result._fold = 1
17827db96d56Sopenharmony_ci        elif tz is not None:
17837db96d56Sopenharmony_ci            result = tz.fromutc(result)
17847db96d56Sopenharmony_ci        return result
17857db96d56Sopenharmony_ci
17867db96d56Sopenharmony_ci    @classmethod
17877db96d56Sopenharmony_ci    def fromtimestamp(cls, t, tz=None):
17887db96d56Sopenharmony_ci        """Construct a datetime from a POSIX timestamp (like time.time()).
17897db96d56Sopenharmony_ci
17907db96d56Sopenharmony_ci        A timezone info object may be passed in as well.
17917db96d56Sopenharmony_ci        """
17927db96d56Sopenharmony_ci        _check_tzinfo_arg(tz)
17937db96d56Sopenharmony_ci
17947db96d56Sopenharmony_ci        return cls._fromtimestamp(t, tz is not None, tz)
17957db96d56Sopenharmony_ci
17967db96d56Sopenharmony_ci    @classmethod
17977db96d56Sopenharmony_ci    def utcfromtimestamp(cls, t):
17987db96d56Sopenharmony_ci        """Construct a naive UTC datetime from a POSIX timestamp."""
17997db96d56Sopenharmony_ci        return cls._fromtimestamp(t, True, None)
18007db96d56Sopenharmony_ci
18017db96d56Sopenharmony_ci    @classmethod
18027db96d56Sopenharmony_ci    def now(cls, tz=None):
18037db96d56Sopenharmony_ci        "Construct a datetime from time.time() and optional time zone info."
18047db96d56Sopenharmony_ci        t = _time.time()
18057db96d56Sopenharmony_ci        return cls.fromtimestamp(t, tz)
18067db96d56Sopenharmony_ci
18077db96d56Sopenharmony_ci    @classmethod
18087db96d56Sopenharmony_ci    def utcnow(cls):
18097db96d56Sopenharmony_ci        "Construct a UTC datetime from time.time()."
18107db96d56Sopenharmony_ci        t = _time.time()
18117db96d56Sopenharmony_ci        return cls.utcfromtimestamp(t)
18127db96d56Sopenharmony_ci
18137db96d56Sopenharmony_ci    @classmethod
18147db96d56Sopenharmony_ci    def combine(cls, date, time, tzinfo=True):
18157db96d56Sopenharmony_ci        "Construct a datetime from a given date and a given time."
18167db96d56Sopenharmony_ci        if not isinstance(date, _date_class):
18177db96d56Sopenharmony_ci            raise TypeError("date argument must be a date instance")
18187db96d56Sopenharmony_ci        if not isinstance(time, _time_class):
18197db96d56Sopenharmony_ci            raise TypeError("time argument must be a time instance")
18207db96d56Sopenharmony_ci        if tzinfo is True:
18217db96d56Sopenharmony_ci            tzinfo = time.tzinfo
18227db96d56Sopenharmony_ci        return cls(date.year, date.month, date.day,
18237db96d56Sopenharmony_ci                   time.hour, time.minute, time.second, time.microsecond,
18247db96d56Sopenharmony_ci                   tzinfo, fold=time.fold)
18257db96d56Sopenharmony_ci
18267db96d56Sopenharmony_ci    @classmethod
18277db96d56Sopenharmony_ci    def fromisoformat(cls, date_string):
18287db96d56Sopenharmony_ci        """Construct a datetime from a string in one of the ISO 8601 formats."""
18297db96d56Sopenharmony_ci        if not isinstance(date_string, str):
18307db96d56Sopenharmony_ci            raise TypeError('fromisoformat: argument must be str')
18317db96d56Sopenharmony_ci
18327db96d56Sopenharmony_ci        if len(date_string) < 7:
18337db96d56Sopenharmony_ci            raise ValueError(f'Invalid isoformat string: {date_string!r}')
18347db96d56Sopenharmony_ci
18357db96d56Sopenharmony_ci        # Split this at the separator
18367db96d56Sopenharmony_ci        try:
18377db96d56Sopenharmony_ci            separator_location = _find_isoformat_datetime_separator(date_string)
18387db96d56Sopenharmony_ci            dstr = date_string[0:separator_location]
18397db96d56Sopenharmony_ci            tstr = date_string[(separator_location+1):]
18407db96d56Sopenharmony_ci
18417db96d56Sopenharmony_ci            date_components = _parse_isoformat_date(dstr)
18427db96d56Sopenharmony_ci        except ValueError:
18437db96d56Sopenharmony_ci            raise ValueError(
18447db96d56Sopenharmony_ci                f'Invalid isoformat string: {date_string!r}') from None
18457db96d56Sopenharmony_ci
18467db96d56Sopenharmony_ci        if tstr:
18477db96d56Sopenharmony_ci            try:
18487db96d56Sopenharmony_ci                time_components = _parse_isoformat_time(tstr)
18497db96d56Sopenharmony_ci            except ValueError:
18507db96d56Sopenharmony_ci                raise ValueError(
18517db96d56Sopenharmony_ci                    f'Invalid isoformat string: {date_string!r}') from None
18527db96d56Sopenharmony_ci        else:
18537db96d56Sopenharmony_ci            time_components = [0, 0, 0, 0, None]
18547db96d56Sopenharmony_ci
18557db96d56Sopenharmony_ci        return cls(*(date_components + time_components))
18567db96d56Sopenharmony_ci
18577db96d56Sopenharmony_ci    def timetuple(self):
18587db96d56Sopenharmony_ci        "Return local time tuple compatible with time.localtime()."
18597db96d56Sopenharmony_ci        dst = self.dst()
18607db96d56Sopenharmony_ci        if dst is None:
18617db96d56Sopenharmony_ci            dst = -1
18627db96d56Sopenharmony_ci        elif dst:
18637db96d56Sopenharmony_ci            dst = 1
18647db96d56Sopenharmony_ci        else:
18657db96d56Sopenharmony_ci            dst = 0
18667db96d56Sopenharmony_ci        return _build_struct_time(self.year, self.month, self.day,
18677db96d56Sopenharmony_ci                                  self.hour, self.minute, self.second,
18687db96d56Sopenharmony_ci                                  dst)
18697db96d56Sopenharmony_ci
18707db96d56Sopenharmony_ci    def _mktime(self):
18717db96d56Sopenharmony_ci        """Return integer POSIX timestamp."""
18727db96d56Sopenharmony_ci        epoch = datetime(1970, 1, 1)
18737db96d56Sopenharmony_ci        max_fold_seconds = 24 * 3600
18747db96d56Sopenharmony_ci        t = (self - epoch) // timedelta(0, 1)
18757db96d56Sopenharmony_ci        def local(u):
18767db96d56Sopenharmony_ci            y, m, d, hh, mm, ss = _time.localtime(u)[:6]
18777db96d56Sopenharmony_ci            return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
18787db96d56Sopenharmony_ci
18797db96d56Sopenharmony_ci        # Our goal is to solve t = local(u) for u.
18807db96d56Sopenharmony_ci        a = local(t) - t
18817db96d56Sopenharmony_ci        u1 = t - a
18827db96d56Sopenharmony_ci        t1 = local(u1)
18837db96d56Sopenharmony_ci        if t1 == t:
18847db96d56Sopenharmony_ci            # We found one solution, but it may not be the one we need.
18857db96d56Sopenharmony_ci            # Look for an earlier solution (if `fold` is 0), or a
18867db96d56Sopenharmony_ci            # later one (if `fold` is 1).
18877db96d56Sopenharmony_ci            u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
18887db96d56Sopenharmony_ci            b = local(u2) - u2
18897db96d56Sopenharmony_ci            if a == b:
18907db96d56Sopenharmony_ci                return u1
18917db96d56Sopenharmony_ci        else:
18927db96d56Sopenharmony_ci            b = t1 - u1
18937db96d56Sopenharmony_ci            assert a != b
18947db96d56Sopenharmony_ci        u2 = t - b
18957db96d56Sopenharmony_ci        t2 = local(u2)
18967db96d56Sopenharmony_ci        if t2 == t:
18977db96d56Sopenharmony_ci            return u2
18987db96d56Sopenharmony_ci        if t1 == t:
18997db96d56Sopenharmony_ci            return u1
19007db96d56Sopenharmony_ci        # We have found both offsets a and b, but neither t - a nor t - b is
19017db96d56Sopenharmony_ci        # a solution.  This means t is in the gap.
19027db96d56Sopenharmony_ci        return (max, min)[self.fold](u1, u2)
19037db96d56Sopenharmony_ci
19047db96d56Sopenharmony_ci
19057db96d56Sopenharmony_ci    def timestamp(self):
19067db96d56Sopenharmony_ci        "Return POSIX timestamp as float"
19077db96d56Sopenharmony_ci        if self._tzinfo is None:
19087db96d56Sopenharmony_ci            s = self._mktime()
19097db96d56Sopenharmony_ci            return s + self.microsecond / 1e6
19107db96d56Sopenharmony_ci        else:
19117db96d56Sopenharmony_ci            return (self - _EPOCH).total_seconds()
19127db96d56Sopenharmony_ci
19137db96d56Sopenharmony_ci    def utctimetuple(self):
19147db96d56Sopenharmony_ci        "Return UTC time tuple compatible with time.gmtime()."
19157db96d56Sopenharmony_ci        offset = self.utcoffset()
19167db96d56Sopenharmony_ci        if offset:
19177db96d56Sopenharmony_ci            self -= offset
19187db96d56Sopenharmony_ci        y, m, d = self.year, self.month, self.day
19197db96d56Sopenharmony_ci        hh, mm, ss = self.hour, self.minute, self.second
19207db96d56Sopenharmony_ci        return _build_struct_time(y, m, d, hh, mm, ss, 0)
19217db96d56Sopenharmony_ci
19227db96d56Sopenharmony_ci    def date(self):
19237db96d56Sopenharmony_ci        "Return the date part."
19247db96d56Sopenharmony_ci        return date(self._year, self._month, self._day)
19257db96d56Sopenharmony_ci
19267db96d56Sopenharmony_ci    def time(self):
19277db96d56Sopenharmony_ci        "Return the time part, with tzinfo None."
19287db96d56Sopenharmony_ci        return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
19297db96d56Sopenharmony_ci
19307db96d56Sopenharmony_ci    def timetz(self):
19317db96d56Sopenharmony_ci        "Return the time part, with same tzinfo."
19327db96d56Sopenharmony_ci        return time(self.hour, self.minute, self.second, self.microsecond,
19337db96d56Sopenharmony_ci                    self._tzinfo, fold=self.fold)
19347db96d56Sopenharmony_ci
19357db96d56Sopenharmony_ci    def replace(self, year=None, month=None, day=None, hour=None,
19367db96d56Sopenharmony_ci                minute=None, second=None, microsecond=None, tzinfo=True,
19377db96d56Sopenharmony_ci                *, fold=None):
19387db96d56Sopenharmony_ci        """Return a new datetime with new values for the specified fields."""
19397db96d56Sopenharmony_ci        if year is None:
19407db96d56Sopenharmony_ci            year = self.year
19417db96d56Sopenharmony_ci        if month is None:
19427db96d56Sopenharmony_ci            month = self.month
19437db96d56Sopenharmony_ci        if day is None:
19447db96d56Sopenharmony_ci            day = self.day
19457db96d56Sopenharmony_ci        if hour is None:
19467db96d56Sopenharmony_ci            hour = self.hour
19477db96d56Sopenharmony_ci        if minute is None:
19487db96d56Sopenharmony_ci            minute = self.minute
19497db96d56Sopenharmony_ci        if second is None:
19507db96d56Sopenharmony_ci            second = self.second
19517db96d56Sopenharmony_ci        if microsecond is None:
19527db96d56Sopenharmony_ci            microsecond = self.microsecond
19537db96d56Sopenharmony_ci        if tzinfo is True:
19547db96d56Sopenharmony_ci            tzinfo = self.tzinfo
19557db96d56Sopenharmony_ci        if fold is None:
19567db96d56Sopenharmony_ci            fold = self.fold
19577db96d56Sopenharmony_ci        return type(self)(year, month, day, hour, minute, second,
19587db96d56Sopenharmony_ci                          microsecond, tzinfo, fold=fold)
19597db96d56Sopenharmony_ci
19607db96d56Sopenharmony_ci    def _local_timezone(self):
19617db96d56Sopenharmony_ci        if self.tzinfo is None:
19627db96d56Sopenharmony_ci            ts = self._mktime()
19637db96d56Sopenharmony_ci        else:
19647db96d56Sopenharmony_ci            ts = (self - _EPOCH) // timedelta(seconds=1)
19657db96d56Sopenharmony_ci        localtm = _time.localtime(ts)
19667db96d56Sopenharmony_ci        local = datetime(*localtm[:6])
19677db96d56Sopenharmony_ci        # Extract TZ data
19687db96d56Sopenharmony_ci        gmtoff = localtm.tm_gmtoff
19697db96d56Sopenharmony_ci        zone = localtm.tm_zone
19707db96d56Sopenharmony_ci        return timezone(timedelta(seconds=gmtoff), zone)
19717db96d56Sopenharmony_ci
19727db96d56Sopenharmony_ci    def astimezone(self, tz=None):
19737db96d56Sopenharmony_ci        if tz is None:
19747db96d56Sopenharmony_ci            tz = self._local_timezone()
19757db96d56Sopenharmony_ci        elif not isinstance(tz, tzinfo):
19767db96d56Sopenharmony_ci            raise TypeError("tz argument must be an instance of tzinfo")
19777db96d56Sopenharmony_ci
19787db96d56Sopenharmony_ci        mytz = self.tzinfo
19797db96d56Sopenharmony_ci        if mytz is None:
19807db96d56Sopenharmony_ci            mytz = self._local_timezone()
19817db96d56Sopenharmony_ci            myoffset = mytz.utcoffset(self)
19827db96d56Sopenharmony_ci        else:
19837db96d56Sopenharmony_ci            myoffset = mytz.utcoffset(self)
19847db96d56Sopenharmony_ci            if myoffset is None:
19857db96d56Sopenharmony_ci                mytz = self.replace(tzinfo=None)._local_timezone()
19867db96d56Sopenharmony_ci                myoffset = mytz.utcoffset(self)
19877db96d56Sopenharmony_ci
19887db96d56Sopenharmony_ci        if tz is mytz:
19897db96d56Sopenharmony_ci            return self
19907db96d56Sopenharmony_ci
19917db96d56Sopenharmony_ci        # Convert self to UTC, and attach the new time zone object.
19927db96d56Sopenharmony_ci        utc = (self - myoffset).replace(tzinfo=tz)
19937db96d56Sopenharmony_ci
19947db96d56Sopenharmony_ci        # Convert from UTC to tz's local time.
19957db96d56Sopenharmony_ci        return tz.fromutc(utc)
19967db96d56Sopenharmony_ci
19977db96d56Sopenharmony_ci    # Ways to produce a string.
19987db96d56Sopenharmony_ci
19997db96d56Sopenharmony_ci    def ctime(self):
20007db96d56Sopenharmony_ci        "Return ctime() style string."
20017db96d56Sopenharmony_ci        weekday = self.toordinal() % 7 or 7
20027db96d56Sopenharmony_ci        return "%s %s %2d %02d:%02d:%02d %04d" % (
20037db96d56Sopenharmony_ci            _DAYNAMES[weekday],
20047db96d56Sopenharmony_ci            _MONTHNAMES[self._month],
20057db96d56Sopenharmony_ci            self._day,
20067db96d56Sopenharmony_ci            self._hour, self._minute, self._second,
20077db96d56Sopenharmony_ci            self._year)
20087db96d56Sopenharmony_ci
20097db96d56Sopenharmony_ci    def isoformat(self, sep='T', timespec='auto'):
20107db96d56Sopenharmony_ci        """Return the time formatted according to ISO.
20117db96d56Sopenharmony_ci
20127db96d56Sopenharmony_ci        The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
20137db96d56Sopenharmony_ci        By default, the fractional part is omitted if self.microsecond == 0.
20147db96d56Sopenharmony_ci
20157db96d56Sopenharmony_ci        If self.tzinfo is not None, the UTC offset is also attached, giving
20167db96d56Sopenharmony_ci        giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
20177db96d56Sopenharmony_ci
20187db96d56Sopenharmony_ci        Optional argument sep specifies the separator between date and
20197db96d56Sopenharmony_ci        time, default 'T'.
20207db96d56Sopenharmony_ci
20217db96d56Sopenharmony_ci        The optional argument timespec specifies the number of additional
20227db96d56Sopenharmony_ci        terms of the time to include. Valid options are 'auto', 'hours',
20237db96d56Sopenharmony_ci        'minutes', 'seconds', 'milliseconds' and 'microseconds'.
20247db96d56Sopenharmony_ci        """
20257db96d56Sopenharmony_ci        s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
20267db96d56Sopenharmony_ci             _format_time(self._hour, self._minute, self._second,
20277db96d56Sopenharmony_ci                          self._microsecond, timespec))
20287db96d56Sopenharmony_ci
20297db96d56Sopenharmony_ci        off = self.utcoffset()
20307db96d56Sopenharmony_ci        tz = _format_offset(off)
20317db96d56Sopenharmony_ci        if tz:
20327db96d56Sopenharmony_ci            s += tz
20337db96d56Sopenharmony_ci
20347db96d56Sopenharmony_ci        return s
20357db96d56Sopenharmony_ci
20367db96d56Sopenharmony_ci    def __repr__(self):
20377db96d56Sopenharmony_ci        """Convert to formal string, for repr()."""
20387db96d56Sopenharmony_ci        L = [self._year, self._month, self._day,  # These are never zero
20397db96d56Sopenharmony_ci             self._hour, self._minute, self._second, self._microsecond]
20407db96d56Sopenharmony_ci        if L[-1] == 0:
20417db96d56Sopenharmony_ci            del L[-1]
20427db96d56Sopenharmony_ci        if L[-1] == 0:
20437db96d56Sopenharmony_ci            del L[-1]
20447db96d56Sopenharmony_ci        s = "%s.%s(%s)" % (self.__class__.__module__,
20457db96d56Sopenharmony_ci                           self.__class__.__qualname__,
20467db96d56Sopenharmony_ci                           ", ".join(map(str, L)))
20477db96d56Sopenharmony_ci        if self._tzinfo is not None:
20487db96d56Sopenharmony_ci            assert s[-1:] == ")"
20497db96d56Sopenharmony_ci            s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
20507db96d56Sopenharmony_ci        if self._fold:
20517db96d56Sopenharmony_ci            assert s[-1:] == ")"
20527db96d56Sopenharmony_ci            s = s[:-1] + ", fold=1)"
20537db96d56Sopenharmony_ci        return s
20547db96d56Sopenharmony_ci
20557db96d56Sopenharmony_ci    def __str__(self):
20567db96d56Sopenharmony_ci        "Convert to string, for str()."
20577db96d56Sopenharmony_ci        return self.isoformat(sep=' ')
20587db96d56Sopenharmony_ci
20597db96d56Sopenharmony_ci    @classmethod
20607db96d56Sopenharmony_ci    def strptime(cls, date_string, format):
20617db96d56Sopenharmony_ci        'string, format -> new datetime parsed from a string (like time.strptime()).'
20627db96d56Sopenharmony_ci        import _strptime
20637db96d56Sopenharmony_ci        return _strptime._strptime_datetime(cls, date_string, format)
20647db96d56Sopenharmony_ci
20657db96d56Sopenharmony_ci    def utcoffset(self):
20667db96d56Sopenharmony_ci        """Return the timezone offset as timedelta positive east of UTC (negative west of
20677db96d56Sopenharmony_ci        UTC)."""
20687db96d56Sopenharmony_ci        if self._tzinfo is None:
20697db96d56Sopenharmony_ci            return None
20707db96d56Sopenharmony_ci        offset = self._tzinfo.utcoffset(self)
20717db96d56Sopenharmony_ci        _check_utc_offset("utcoffset", offset)
20727db96d56Sopenharmony_ci        return offset
20737db96d56Sopenharmony_ci
20747db96d56Sopenharmony_ci    def tzname(self):
20757db96d56Sopenharmony_ci        """Return the timezone name.
20767db96d56Sopenharmony_ci
20777db96d56Sopenharmony_ci        Note that the name is 100% informational -- there's no requirement that
20787db96d56Sopenharmony_ci        it mean anything in particular. For example, "GMT", "UTC", "-500",
20797db96d56Sopenharmony_ci        "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
20807db96d56Sopenharmony_ci        """
20817db96d56Sopenharmony_ci        if self._tzinfo is None:
20827db96d56Sopenharmony_ci            return None
20837db96d56Sopenharmony_ci        name = self._tzinfo.tzname(self)
20847db96d56Sopenharmony_ci        _check_tzname(name)
20857db96d56Sopenharmony_ci        return name
20867db96d56Sopenharmony_ci
20877db96d56Sopenharmony_ci    def dst(self):
20887db96d56Sopenharmony_ci        """Return 0 if DST is not in effect, or the DST offset (as timedelta
20897db96d56Sopenharmony_ci        positive eastward) if DST is in effect.
20907db96d56Sopenharmony_ci
20917db96d56Sopenharmony_ci        This is purely informational; the DST offset has already been added to
20927db96d56Sopenharmony_ci        the UTC offset returned by utcoffset() if applicable, so there's no
20937db96d56Sopenharmony_ci        need to consult dst() unless you're interested in displaying the DST
20947db96d56Sopenharmony_ci        info.
20957db96d56Sopenharmony_ci        """
20967db96d56Sopenharmony_ci        if self._tzinfo is None:
20977db96d56Sopenharmony_ci            return None
20987db96d56Sopenharmony_ci        offset = self._tzinfo.dst(self)
20997db96d56Sopenharmony_ci        _check_utc_offset("dst", offset)
21007db96d56Sopenharmony_ci        return offset
21017db96d56Sopenharmony_ci
21027db96d56Sopenharmony_ci    # Comparisons of datetime objects with other.
21037db96d56Sopenharmony_ci
21047db96d56Sopenharmony_ci    def __eq__(self, other):
21057db96d56Sopenharmony_ci        if isinstance(other, datetime):
21067db96d56Sopenharmony_ci            return self._cmp(other, allow_mixed=True) == 0
21077db96d56Sopenharmony_ci        elif not isinstance(other, date):
21087db96d56Sopenharmony_ci            return NotImplemented
21097db96d56Sopenharmony_ci        else:
21107db96d56Sopenharmony_ci            return False
21117db96d56Sopenharmony_ci
21127db96d56Sopenharmony_ci    def __le__(self, other):
21137db96d56Sopenharmony_ci        if isinstance(other, datetime):
21147db96d56Sopenharmony_ci            return self._cmp(other) <= 0
21157db96d56Sopenharmony_ci        elif not isinstance(other, date):
21167db96d56Sopenharmony_ci            return NotImplemented
21177db96d56Sopenharmony_ci        else:
21187db96d56Sopenharmony_ci            _cmperror(self, other)
21197db96d56Sopenharmony_ci
21207db96d56Sopenharmony_ci    def __lt__(self, other):
21217db96d56Sopenharmony_ci        if isinstance(other, datetime):
21227db96d56Sopenharmony_ci            return self._cmp(other) < 0
21237db96d56Sopenharmony_ci        elif not isinstance(other, date):
21247db96d56Sopenharmony_ci            return NotImplemented
21257db96d56Sopenharmony_ci        else:
21267db96d56Sopenharmony_ci            _cmperror(self, other)
21277db96d56Sopenharmony_ci
21287db96d56Sopenharmony_ci    def __ge__(self, other):
21297db96d56Sopenharmony_ci        if isinstance(other, datetime):
21307db96d56Sopenharmony_ci            return self._cmp(other) >= 0
21317db96d56Sopenharmony_ci        elif not isinstance(other, date):
21327db96d56Sopenharmony_ci            return NotImplemented
21337db96d56Sopenharmony_ci        else:
21347db96d56Sopenharmony_ci            _cmperror(self, other)
21357db96d56Sopenharmony_ci
21367db96d56Sopenharmony_ci    def __gt__(self, other):
21377db96d56Sopenharmony_ci        if isinstance(other, datetime):
21387db96d56Sopenharmony_ci            return self._cmp(other) > 0
21397db96d56Sopenharmony_ci        elif not isinstance(other, date):
21407db96d56Sopenharmony_ci            return NotImplemented
21417db96d56Sopenharmony_ci        else:
21427db96d56Sopenharmony_ci            _cmperror(self, other)
21437db96d56Sopenharmony_ci
21447db96d56Sopenharmony_ci    def _cmp(self, other, allow_mixed=False):
21457db96d56Sopenharmony_ci        assert isinstance(other, datetime)
21467db96d56Sopenharmony_ci        mytz = self._tzinfo
21477db96d56Sopenharmony_ci        ottz = other._tzinfo
21487db96d56Sopenharmony_ci        myoff = otoff = None
21497db96d56Sopenharmony_ci
21507db96d56Sopenharmony_ci        if mytz is ottz:
21517db96d56Sopenharmony_ci            base_compare = True
21527db96d56Sopenharmony_ci        else:
21537db96d56Sopenharmony_ci            myoff = self.utcoffset()
21547db96d56Sopenharmony_ci            otoff = other.utcoffset()
21557db96d56Sopenharmony_ci            # Assume that allow_mixed means that we are called from __eq__
21567db96d56Sopenharmony_ci            if allow_mixed:
21577db96d56Sopenharmony_ci                if myoff != self.replace(fold=not self.fold).utcoffset():
21587db96d56Sopenharmony_ci                    return 2
21597db96d56Sopenharmony_ci                if otoff != other.replace(fold=not other.fold).utcoffset():
21607db96d56Sopenharmony_ci                    return 2
21617db96d56Sopenharmony_ci            base_compare = myoff == otoff
21627db96d56Sopenharmony_ci
21637db96d56Sopenharmony_ci        if base_compare:
21647db96d56Sopenharmony_ci            return _cmp((self._year, self._month, self._day,
21657db96d56Sopenharmony_ci                         self._hour, self._minute, self._second,
21667db96d56Sopenharmony_ci                         self._microsecond),
21677db96d56Sopenharmony_ci                        (other._year, other._month, other._day,
21687db96d56Sopenharmony_ci                         other._hour, other._minute, other._second,
21697db96d56Sopenharmony_ci                         other._microsecond))
21707db96d56Sopenharmony_ci        if myoff is None or otoff is None:
21717db96d56Sopenharmony_ci            if allow_mixed:
21727db96d56Sopenharmony_ci                return 2 # arbitrary non-zero value
21737db96d56Sopenharmony_ci            else:
21747db96d56Sopenharmony_ci                raise TypeError("cannot compare naive and aware datetimes")
21757db96d56Sopenharmony_ci        # XXX What follows could be done more efficiently...
21767db96d56Sopenharmony_ci        diff = self - other     # this will take offsets into account
21777db96d56Sopenharmony_ci        if diff.days < 0:
21787db96d56Sopenharmony_ci            return -1
21797db96d56Sopenharmony_ci        return diff and 1 or 0
21807db96d56Sopenharmony_ci
21817db96d56Sopenharmony_ci    def __add__(self, other):
21827db96d56Sopenharmony_ci        "Add a datetime and a timedelta."
21837db96d56Sopenharmony_ci        if not isinstance(other, timedelta):
21847db96d56Sopenharmony_ci            return NotImplemented
21857db96d56Sopenharmony_ci        delta = timedelta(self.toordinal(),
21867db96d56Sopenharmony_ci                          hours=self._hour,
21877db96d56Sopenharmony_ci                          minutes=self._minute,
21887db96d56Sopenharmony_ci                          seconds=self._second,
21897db96d56Sopenharmony_ci                          microseconds=self._microsecond)
21907db96d56Sopenharmony_ci        delta += other
21917db96d56Sopenharmony_ci        hour, rem = divmod(delta.seconds, 3600)
21927db96d56Sopenharmony_ci        minute, second = divmod(rem, 60)
21937db96d56Sopenharmony_ci        if 0 < delta.days <= _MAXORDINAL:
21947db96d56Sopenharmony_ci            return type(self).combine(date.fromordinal(delta.days),
21957db96d56Sopenharmony_ci                                      time(hour, minute, second,
21967db96d56Sopenharmony_ci                                           delta.microseconds,
21977db96d56Sopenharmony_ci                                           tzinfo=self._tzinfo))
21987db96d56Sopenharmony_ci        raise OverflowError("result out of range")
21997db96d56Sopenharmony_ci
22007db96d56Sopenharmony_ci    __radd__ = __add__
22017db96d56Sopenharmony_ci
22027db96d56Sopenharmony_ci    def __sub__(self, other):
22037db96d56Sopenharmony_ci        "Subtract two datetimes, or a datetime and a timedelta."
22047db96d56Sopenharmony_ci        if not isinstance(other, datetime):
22057db96d56Sopenharmony_ci            if isinstance(other, timedelta):
22067db96d56Sopenharmony_ci                return self + -other
22077db96d56Sopenharmony_ci            return NotImplemented
22087db96d56Sopenharmony_ci
22097db96d56Sopenharmony_ci        days1 = self.toordinal()
22107db96d56Sopenharmony_ci        days2 = other.toordinal()
22117db96d56Sopenharmony_ci        secs1 = self._second + self._minute * 60 + self._hour * 3600
22127db96d56Sopenharmony_ci        secs2 = other._second + other._minute * 60 + other._hour * 3600
22137db96d56Sopenharmony_ci        base = timedelta(days1 - days2,
22147db96d56Sopenharmony_ci                         secs1 - secs2,
22157db96d56Sopenharmony_ci                         self._microsecond - other._microsecond)
22167db96d56Sopenharmony_ci        if self._tzinfo is other._tzinfo:
22177db96d56Sopenharmony_ci            return base
22187db96d56Sopenharmony_ci        myoff = self.utcoffset()
22197db96d56Sopenharmony_ci        otoff = other.utcoffset()
22207db96d56Sopenharmony_ci        if myoff == otoff:
22217db96d56Sopenharmony_ci            return base
22227db96d56Sopenharmony_ci        if myoff is None or otoff is None:
22237db96d56Sopenharmony_ci            raise TypeError("cannot mix naive and timezone-aware time")
22247db96d56Sopenharmony_ci        return base + otoff - myoff
22257db96d56Sopenharmony_ci
22267db96d56Sopenharmony_ci    def __hash__(self):
22277db96d56Sopenharmony_ci        if self._hashcode == -1:
22287db96d56Sopenharmony_ci            if self.fold:
22297db96d56Sopenharmony_ci                t = self.replace(fold=0)
22307db96d56Sopenharmony_ci            else:
22317db96d56Sopenharmony_ci                t = self
22327db96d56Sopenharmony_ci            tzoff = t.utcoffset()
22337db96d56Sopenharmony_ci            if tzoff is None:
22347db96d56Sopenharmony_ci                self._hashcode = hash(t._getstate()[0])
22357db96d56Sopenharmony_ci            else:
22367db96d56Sopenharmony_ci                days = _ymd2ord(self.year, self.month, self.day)
22377db96d56Sopenharmony_ci                seconds = self.hour * 3600 + self.minute * 60 + self.second
22387db96d56Sopenharmony_ci                self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
22397db96d56Sopenharmony_ci        return self._hashcode
22407db96d56Sopenharmony_ci
22417db96d56Sopenharmony_ci    # Pickle support.
22427db96d56Sopenharmony_ci
22437db96d56Sopenharmony_ci    def _getstate(self, protocol=3):
22447db96d56Sopenharmony_ci        yhi, ylo = divmod(self._year, 256)
22457db96d56Sopenharmony_ci        us2, us3 = divmod(self._microsecond, 256)
22467db96d56Sopenharmony_ci        us1, us2 = divmod(us2, 256)
22477db96d56Sopenharmony_ci        m = self._month
22487db96d56Sopenharmony_ci        if self._fold and protocol > 3:
22497db96d56Sopenharmony_ci            m += 128
22507db96d56Sopenharmony_ci        basestate = bytes([yhi, ylo, m, self._day,
22517db96d56Sopenharmony_ci                           self._hour, self._minute, self._second,
22527db96d56Sopenharmony_ci                           us1, us2, us3])
22537db96d56Sopenharmony_ci        if self._tzinfo is None:
22547db96d56Sopenharmony_ci            return (basestate,)
22557db96d56Sopenharmony_ci        else:
22567db96d56Sopenharmony_ci            return (basestate, self._tzinfo)
22577db96d56Sopenharmony_ci
22587db96d56Sopenharmony_ci    def __setstate(self, string, tzinfo):
22597db96d56Sopenharmony_ci        if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
22607db96d56Sopenharmony_ci            raise TypeError("bad tzinfo state arg")
22617db96d56Sopenharmony_ci        (yhi, ylo, m, self._day, self._hour,
22627db96d56Sopenharmony_ci         self._minute, self._second, us1, us2, us3) = string
22637db96d56Sopenharmony_ci        if m > 127:
22647db96d56Sopenharmony_ci            self._fold = 1
22657db96d56Sopenharmony_ci            self._month = m - 128
22667db96d56Sopenharmony_ci        else:
22677db96d56Sopenharmony_ci            self._fold = 0
22687db96d56Sopenharmony_ci            self._month = m
22697db96d56Sopenharmony_ci        self._year = yhi * 256 + ylo
22707db96d56Sopenharmony_ci        self._microsecond = (((us1 << 8) | us2) << 8) | us3
22717db96d56Sopenharmony_ci        self._tzinfo = tzinfo
22727db96d56Sopenharmony_ci
22737db96d56Sopenharmony_ci    def __reduce_ex__(self, protocol):
22747db96d56Sopenharmony_ci        return (self.__class__, self._getstate(protocol))
22757db96d56Sopenharmony_ci
22767db96d56Sopenharmony_ci    def __reduce__(self):
22777db96d56Sopenharmony_ci        return self.__reduce_ex__(2)
22787db96d56Sopenharmony_ci
22797db96d56Sopenharmony_ci
22807db96d56Sopenharmony_cidatetime.min = datetime(1, 1, 1)
22817db96d56Sopenharmony_cidatetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
22827db96d56Sopenharmony_cidatetime.resolution = timedelta(microseconds=1)
22837db96d56Sopenharmony_ci
22847db96d56Sopenharmony_ci
22857db96d56Sopenharmony_cidef _isoweek1monday(year):
22867db96d56Sopenharmony_ci    # Helper to calculate the day number of the Monday starting week 1
22877db96d56Sopenharmony_ci    # XXX This could be done more efficiently
22887db96d56Sopenharmony_ci    THURSDAY = 3
22897db96d56Sopenharmony_ci    firstday = _ymd2ord(year, 1, 1)
22907db96d56Sopenharmony_ci    firstweekday = (firstday + 6) % 7  # See weekday() above
22917db96d56Sopenharmony_ci    week1monday = firstday - firstweekday
22927db96d56Sopenharmony_ci    if firstweekday > THURSDAY:
22937db96d56Sopenharmony_ci        week1monday += 7
22947db96d56Sopenharmony_ci    return week1monday
22957db96d56Sopenharmony_ci
22967db96d56Sopenharmony_ci
22977db96d56Sopenharmony_ciclass timezone(tzinfo):
22987db96d56Sopenharmony_ci    __slots__ = '_offset', '_name'
22997db96d56Sopenharmony_ci
23007db96d56Sopenharmony_ci    # Sentinel value to disallow None
23017db96d56Sopenharmony_ci    _Omitted = object()
23027db96d56Sopenharmony_ci    def __new__(cls, offset, name=_Omitted):
23037db96d56Sopenharmony_ci        if not isinstance(offset, timedelta):
23047db96d56Sopenharmony_ci            raise TypeError("offset must be a timedelta")
23057db96d56Sopenharmony_ci        if name is cls._Omitted:
23067db96d56Sopenharmony_ci            if not offset:
23077db96d56Sopenharmony_ci                return cls.utc
23087db96d56Sopenharmony_ci            name = None
23097db96d56Sopenharmony_ci        elif not isinstance(name, str):
23107db96d56Sopenharmony_ci            raise TypeError("name must be a string")
23117db96d56Sopenharmony_ci        if not cls._minoffset <= offset <= cls._maxoffset:
23127db96d56Sopenharmony_ci            raise ValueError("offset must be a timedelta "
23137db96d56Sopenharmony_ci                             "strictly between -timedelta(hours=24) and "
23147db96d56Sopenharmony_ci                             "timedelta(hours=24).")
23157db96d56Sopenharmony_ci        return cls._create(offset, name)
23167db96d56Sopenharmony_ci
23177db96d56Sopenharmony_ci    @classmethod
23187db96d56Sopenharmony_ci    def _create(cls, offset, name=None):
23197db96d56Sopenharmony_ci        self = tzinfo.__new__(cls)
23207db96d56Sopenharmony_ci        self._offset = offset
23217db96d56Sopenharmony_ci        self._name = name
23227db96d56Sopenharmony_ci        return self
23237db96d56Sopenharmony_ci
23247db96d56Sopenharmony_ci    def __getinitargs__(self):
23257db96d56Sopenharmony_ci        """pickle support"""
23267db96d56Sopenharmony_ci        if self._name is None:
23277db96d56Sopenharmony_ci            return (self._offset,)
23287db96d56Sopenharmony_ci        return (self._offset, self._name)
23297db96d56Sopenharmony_ci
23307db96d56Sopenharmony_ci    def __eq__(self, other):
23317db96d56Sopenharmony_ci        if isinstance(other, timezone):
23327db96d56Sopenharmony_ci            return self._offset == other._offset
23337db96d56Sopenharmony_ci        return NotImplemented
23347db96d56Sopenharmony_ci
23357db96d56Sopenharmony_ci    def __hash__(self):
23367db96d56Sopenharmony_ci        return hash(self._offset)
23377db96d56Sopenharmony_ci
23387db96d56Sopenharmony_ci    def __repr__(self):
23397db96d56Sopenharmony_ci        """Convert to formal string, for repr().
23407db96d56Sopenharmony_ci
23417db96d56Sopenharmony_ci        >>> tz = timezone.utc
23427db96d56Sopenharmony_ci        >>> repr(tz)
23437db96d56Sopenharmony_ci        'datetime.timezone.utc'
23447db96d56Sopenharmony_ci        >>> tz = timezone(timedelta(hours=-5), 'EST')
23457db96d56Sopenharmony_ci        >>> repr(tz)
23467db96d56Sopenharmony_ci        "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
23477db96d56Sopenharmony_ci        """
23487db96d56Sopenharmony_ci        if self is self.utc:
23497db96d56Sopenharmony_ci            return 'datetime.timezone.utc'
23507db96d56Sopenharmony_ci        if self._name is None:
23517db96d56Sopenharmony_ci            return "%s.%s(%r)" % (self.__class__.__module__,
23527db96d56Sopenharmony_ci                                  self.__class__.__qualname__,
23537db96d56Sopenharmony_ci                                  self._offset)
23547db96d56Sopenharmony_ci        return "%s.%s(%r, %r)" % (self.__class__.__module__,
23557db96d56Sopenharmony_ci                                  self.__class__.__qualname__,
23567db96d56Sopenharmony_ci                                  self._offset, self._name)
23577db96d56Sopenharmony_ci
23587db96d56Sopenharmony_ci    def __str__(self):
23597db96d56Sopenharmony_ci        return self.tzname(None)
23607db96d56Sopenharmony_ci
23617db96d56Sopenharmony_ci    def utcoffset(self, dt):
23627db96d56Sopenharmony_ci        if isinstance(dt, datetime) or dt is None:
23637db96d56Sopenharmony_ci            return self._offset
23647db96d56Sopenharmony_ci        raise TypeError("utcoffset() argument must be a datetime instance"
23657db96d56Sopenharmony_ci                        " or None")
23667db96d56Sopenharmony_ci
23677db96d56Sopenharmony_ci    def tzname(self, dt):
23687db96d56Sopenharmony_ci        if isinstance(dt, datetime) or dt is None:
23697db96d56Sopenharmony_ci            if self._name is None:
23707db96d56Sopenharmony_ci                return self._name_from_offset(self._offset)
23717db96d56Sopenharmony_ci            return self._name
23727db96d56Sopenharmony_ci        raise TypeError("tzname() argument must be a datetime instance"
23737db96d56Sopenharmony_ci                        " or None")
23747db96d56Sopenharmony_ci
23757db96d56Sopenharmony_ci    def dst(self, dt):
23767db96d56Sopenharmony_ci        if isinstance(dt, datetime) or dt is None:
23777db96d56Sopenharmony_ci            return None
23787db96d56Sopenharmony_ci        raise TypeError("dst() argument must be a datetime instance"
23797db96d56Sopenharmony_ci                        " or None")
23807db96d56Sopenharmony_ci
23817db96d56Sopenharmony_ci    def fromutc(self, dt):
23827db96d56Sopenharmony_ci        if isinstance(dt, datetime):
23837db96d56Sopenharmony_ci            if dt.tzinfo is not self:
23847db96d56Sopenharmony_ci                raise ValueError("fromutc: dt.tzinfo "
23857db96d56Sopenharmony_ci                                 "is not self")
23867db96d56Sopenharmony_ci            return dt + self._offset
23877db96d56Sopenharmony_ci        raise TypeError("fromutc() argument must be a datetime instance"
23887db96d56Sopenharmony_ci                        " or None")
23897db96d56Sopenharmony_ci
23907db96d56Sopenharmony_ci    _maxoffset = timedelta(hours=24, microseconds=-1)
23917db96d56Sopenharmony_ci    _minoffset = -_maxoffset
23927db96d56Sopenharmony_ci
23937db96d56Sopenharmony_ci    @staticmethod
23947db96d56Sopenharmony_ci    def _name_from_offset(delta):
23957db96d56Sopenharmony_ci        if not delta:
23967db96d56Sopenharmony_ci            return 'UTC'
23977db96d56Sopenharmony_ci        if delta < timedelta(0):
23987db96d56Sopenharmony_ci            sign = '-'
23997db96d56Sopenharmony_ci            delta = -delta
24007db96d56Sopenharmony_ci        else:
24017db96d56Sopenharmony_ci            sign = '+'
24027db96d56Sopenharmony_ci        hours, rest = divmod(delta, timedelta(hours=1))
24037db96d56Sopenharmony_ci        minutes, rest = divmod(rest, timedelta(minutes=1))
24047db96d56Sopenharmony_ci        seconds = rest.seconds
24057db96d56Sopenharmony_ci        microseconds = rest.microseconds
24067db96d56Sopenharmony_ci        if microseconds:
24077db96d56Sopenharmony_ci            return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
24087db96d56Sopenharmony_ci                    f'.{microseconds:06d}')
24097db96d56Sopenharmony_ci        if seconds:
24107db96d56Sopenharmony_ci            return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
24117db96d56Sopenharmony_ci        return f'UTC{sign}{hours:02d}:{minutes:02d}'
24127db96d56Sopenharmony_ci
24137db96d56Sopenharmony_ciUTC = timezone.utc = timezone._create(timedelta(0))
24147db96d56Sopenharmony_ci
24157db96d56Sopenharmony_ci# bpo-37642: These attributes are rounded to the nearest minute for backwards
24167db96d56Sopenharmony_ci# compatibility, even though the constructor will accept a wider range of
24177db96d56Sopenharmony_ci# values. This may change in the future.
24187db96d56Sopenharmony_citimezone.min = timezone._create(-timedelta(hours=23, minutes=59))
24197db96d56Sopenharmony_citimezone.max = timezone._create(timedelta(hours=23, minutes=59))
24207db96d56Sopenharmony_ci_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
24217db96d56Sopenharmony_ci
24227db96d56Sopenharmony_ci# Some time zone algebra.  For a datetime x, let
24237db96d56Sopenharmony_ci#     x.n = x stripped of its timezone -- its naive time.
24247db96d56Sopenharmony_ci#     x.o = x.utcoffset(), and assuming that doesn't raise an exception or
24257db96d56Sopenharmony_ci#           return None
24267db96d56Sopenharmony_ci#     x.d = x.dst(), and assuming that doesn't raise an exception or
24277db96d56Sopenharmony_ci#           return None
24287db96d56Sopenharmony_ci#     x.s = x's standard offset, x.o - x.d
24297db96d56Sopenharmony_ci#
24307db96d56Sopenharmony_ci# Now some derived rules, where k is a duration (timedelta).
24317db96d56Sopenharmony_ci#
24327db96d56Sopenharmony_ci# 1. x.o = x.s + x.d
24337db96d56Sopenharmony_ci#    This follows from the definition of x.s.
24347db96d56Sopenharmony_ci#
24357db96d56Sopenharmony_ci# 2. If x and y have the same tzinfo member, x.s = y.s.
24367db96d56Sopenharmony_ci#    This is actually a requirement, an assumption we need to make about
24377db96d56Sopenharmony_ci#    sane tzinfo classes.
24387db96d56Sopenharmony_ci#
24397db96d56Sopenharmony_ci# 3. The naive UTC time corresponding to x is x.n - x.o.
24407db96d56Sopenharmony_ci#    This is again a requirement for a sane tzinfo class.
24417db96d56Sopenharmony_ci#
24427db96d56Sopenharmony_ci# 4. (x+k).s = x.s
24437db96d56Sopenharmony_ci#    This follows from #2, and that datetime.timetz+timedelta preserves tzinfo.
24447db96d56Sopenharmony_ci#
24457db96d56Sopenharmony_ci# 5. (x+k).n = x.n + k
24467db96d56Sopenharmony_ci#    Again follows from how arithmetic is defined.
24477db96d56Sopenharmony_ci#
24487db96d56Sopenharmony_ci# Now we can explain tz.fromutc(x).  Let's assume it's an interesting case
24497db96d56Sopenharmony_ci# (meaning that the various tzinfo methods exist, and don't blow up or return
24507db96d56Sopenharmony_ci# None when called).
24517db96d56Sopenharmony_ci#
24527db96d56Sopenharmony_ci# The function wants to return a datetime y with timezone tz, equivalent to x.
24537db96d56Sopenharmony_ci# x is already in UTC.
24547db96d56Sopenharmony_ci#
24557db96d56Sopenharmony_ci# By #3, we want
24567db96d56Sopenharmony_ci#
24577db96d56Sopenharmony_ci#     y.n - y.o = x.n                             [1]
24587db96d56Sopenharmony_ci#
24597db96d56Sopenharmony_ci# The algorithm starts by attaching tz to x.n, and calling that y.  So
24607db96d56Sopenharmony_ci# x.n = y.n at the start.  Then it wants to add a duration k to y, so that [1]
24617db96d56Sopenharmony_ci# becomes true; in effect, we want to solve [2] for k:
24627db96d56Sopenharmony_ci#
24637db96d56Sopenharmony_ci#    (y+k).n - (y+k).o = x.n                      [2]
24647db96d56Sopenharmony_ci#
24657db96d56Sopenharmony_ci# By #1, this is the same as
24667db96d56Sopenharmony_ci#
24677db96d56Sopenharmony_ci#    (y+k).n - ((y+k).s + (y+k).d) = x.n          [3]
24687db96d56Sopenharmony_ci#
24697db96d56Sopenharmony_ci# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
24707db96d56Sopenharmony_ci# Substituting that into [3],
24717db96d56Sopenharmony_ci#
24727db96d56Sopenharmony_ci#    x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
24737db96d56Sopenharmony_ci#    k - (y+k).s - (y+k).d = 0; rearranging,
24747db96d56Sopenharmony_ci#    k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
24757db96d56Sopenharmony_ci#    k = y.s - (y+k).d
24767db96d56Sopenharmony_ci#
24777db96d56Sopenharmony_ci# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
24787db96d56Sopenharmony_ci# approximate k by ignoring the (y+k).d term at first.  Note that k can't be
24797db96d56Sopenharmony_ci# very large, since all offset-returning methods return a duration of magnitude
24807db96d56Sopenharmony_ci# less than 24 hours.  For that reason, if y is firmly in std time, (y+k).d must
24817db96d56Sopenharmony_ci# be 0, so ignoring it has no consequence then.
24827db96d56Sopenharmony_ci#
24837db96d56Sopenharmony_ci# In any case, the new value is
24847db96d56Sopenharmony_ci#
24857db96d56Sopenharmony_ci#     z = y + y.s                                 [4]
24867db96d56Sopenharmony_ci#
24877db96d56Sopenharmony_ci# It's helpful to step back at look at [4] from a higher level:  it's simply
24887db96d56Sopenharmony_ci# mapping from UTC to tz's standard time.
24897db96d56Sopenharmony_ci#
24907db96d56Sopenharmony_ci# At this point, if
24917db96d56Sopenharmony_ci#
24927db96d56Sopenharmony_ci#     z.n - z.o = x.n                             [5]
24937db96d56Sopenharmony_ci#
24947db96d56Sopenharmony_ci# we have an equivalent time, and are almost done.  The insecurity here is
24957db96d56Sopenharmony_ci# at the start of daylight time.  Picture US Eastern for concreteness.  The wall
24967db96d56Sopenharmony_ci# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
24977db96d56Sopenharmony_ci# sense then.  The docs ask that an Eastern tzinfo class consider such a time to
24987db96d56Sopenharmony_ci# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
24997db96d56Sopenharmony_ci# on the day DST starts.  We want to return the 1:MM EST spelling because that's
25007db96d56Sopenharmony_ci# the only spelling that makes sense on the local wall clock.
25017db96d56Sopenharmony_ci#
25027db96d56Sopenharmony_ci# In fact, if [5] holds at this point, we do have the standard-time spelling,
25037db96d56Sopenharmony_ci# but that takes a bit of proof.  We first prove a stronger result.  What's the
25047db96d56Sopenharmony_ci# difference between the LHS and RHS of [5]?  Let
25057db96d56Sopenharmony_ci#
25067db96d56Sopenharmony_ci#     diff = x.n - (z.n - z.o)                    [6]
25077db96d56Sopenharmony_ci#
25087db96d56Sopenharmony_ci# Now
25097db96d56Sopenharmony_ci#     z.n =                       by [4]
25107db96d56Sopenharmony_ci#     (y + y.s).n =               by #5
25117db96d56Sopenharmony_ci#     y.n + y.s =                 since y.n = x.n
25127db96d56Sopenharmony_ci#     x.n + y.s =                 since z and y are have the same tzinfo member,
25137db96d56Sopenharmony_ci#                                     y.s = z.s by #2
25147db96d56Sopenharmony_ci#     x.n + z.s
25157db96d56Sopenharmony_ci#
25167db96d56Sopenharmony_ci# Plugging that back into [6] gives
25177db96d56Sopenharmony_ci#
25187db96d56Sopenharmony_ci#     diff =
25197db96d56Sopenharmony_ci#     x.n - ((x.n + z.s) - z.o) =     expanding
25207db96d56Sopenharmony_ci#     x.n - x.n - z.s + z.o =         cancelling
25217db96d56Sopenharmony_ci#     - z.s + z.o =                   by #2
25227db96d56Sopenharmony_ci#     z.d
25237db96d56Sopenharmony_ci#
25247db96d56Sopenharmony_ci# So diff = z.d.
25257db96d56Sopenharmony_ci#
25267db96d56Sopenharmony_ci# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
25277db96d56Sopenharmony_ci# spelling we wanted in the endcase described above.  We're done.  Contrarily,
25287db96d56Sopenharmony_ci# if z.d = 0, then we have a UTC equivalent, and are also done.
25297db96d56Sopenharmony_ci#
25307db96d56Sopenharmony_ci# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
25317db96d56Sopenharmony_ci# add to z (in effect, z is in tz's standard time, and we need to shift the
25327db96d56Sopenharmony_ci# local clock into tz's daylight time).
25337db96d56Sopenharmony_ci#
25347db96d56Sopenharmony_ci# Let
25357db96d56Sopenharmony_ci#
25367db96d56Sopenharmony_ci#     z' = z + z.d = z + diff                     [7]
25377db96d56Sopenharmony_ci#
25387db96d56Sopenharmony_ci# and we can again ask whether
25397db96d56Sopenharmony_ci#
25407db96d56Sopenharmony_ci#     z'.n - z'.o = x.n                           [8]
25417db96d56Sopenharmony_ci#
25427db96d56Sopenharmony_ci# If so, we're done.  If not, the tzinfo class is insane, according to the
25437db96d56Sopenharmony_ci# assumptions we've made.  This also requires a bit of proof.  As before, let's
25447db96d56Sopenharmony_ci# compute the difference between the LHS and RHS of [8] (and skipping some of
25457db96d56Sopenharmony_ci# the justifications for the kinds of substitutions we've done several times
25467db96d56Sopenharmony_ci# already):
25477db96d56Sopenharmony_ci#
25487db96d56Sopenharmony_ci#     diff' = x.n - (z'.n - z'.o) =           replacing z'.n via [7]
25497db96d56Sopenharmony_ci#             x.n  - (z.n + diff - z'.o) =    replacing diff via [6]
25507db96d56Sopenharmony_ci#             x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
25517db96d56Sopenharmony_ci#             x.n - z.n - x.n + z.n - z.o + z'.o =    cancel x.n
25527db96d56Sopenharmony_ci#             - z.n + z.n - z.o + z'.o =              cancel z.n
25537db96d56Sopenharmony_ci#             - z.o + z'.o =                      #1 twice
25547db96d56Sopenharmony_ci#             -z.s - z.d + z'.s + z'.d =          z and z' have same tzinfo
25557db96d56Sopenharmony_ci#             z'.d - z.d
25567db96d56Sopenharmony_ci#
25577db96d56Sopenharmony_ci# So z' is UTC-equivalent to x iff z'.d = z.d at this point.  If they are equal,
25587db96d56Sopenharmony_ci# we've found the UTC-equivalent so are done.  In fact, we stop with [7] and
25597db96d56Sopenharmony_ci# return z', not bothering to compute z'.d.
25607db96d56Sopenharmony_ci#
25617db96d56Sopenharmony_ci# How could z.d and z'd differ?  z' = z + z.d [7], so merely moving z' by
25627db96d56Sopenharmony_ci# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
25637db96d56Sopenharmony_ci# would have to change the result dst() returns:  we start in DST, and moving
25647db96d56Sopenharmony_ci# a little further into it takes us out of DST.
25657db96d56Sopenharmony_ci#
25667db96d56Sopenharmony_ci# There isn't a sane case where this can happen.  The closest it gets is at
25677db96d56Sopenharmony_ci# the end of DST, where there's an hour in UTC with no spelling in a hybrid
25687db96d56Sopenharmony_ci# tzinfo class.  In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT.  During
25697db96d56Sopenharmony_ci# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
25707db96d56Sopenharmony_ci# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
25717db96d56Sopenharmony_ci# time (4:MM UTC).  There is no local time mapping to 5:MM UTC.  The local
25727db96d56Sopenharmony_ci# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
25737db96d56Sopenharmony_ci# standard time.  Since that's what the local clock *does*, we want to map both
25747db96d56Sopenharmony_ci# UTC hours 5:MM and 6:MM to 1:MM Eastern.  The result is ambiguous
25757db96d56Sopenharmony_ci# in local time, but so it goes -- it's the way the local clock works.
25767db96d56Sopenharmony_ci#
25777db96d56Sopenharmony_ci# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
25787db96d56Sopenharmony_ci# so z=0:MM.  z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
25797db96d56Sopenharmony_ci# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
25807db96d56Sopenharmony_ci# (correctly) concludes that z' is not UTC-equivalent to x.
25817db96d56Sopenharmony_ci#
25827db96d56Sopenharmony_ci# Because we know z.d said z was in daylight time (else [5] would have held and
25837db96d56Sopenharmony_ci# we would have stopped then), and we know z.d != z'.d (else [8] would have held
25847db96d56Sopenharmony_ci# and we have stopped then), and there are only 2 possible values dst() can
25857db96d56Sopenharmony_ci# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
25867db96d56Sopenharmony_ci# but the reasoning doesn't depend on the example -- it depends on there being
25877db96d56Sopenharmony_ci# two possible dst() outcomes, one zero and the other non-zero).  Therefore
25887db96d56Sopenharmony_ci# z' must be in standard time, and is the spelling we want in this case.
25897db96d56Sopenharmony_ci#
25907db96d56Sopenharmony_ci# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
25917db96d56Sopenharmony_ci# concerned (because it takes z' as being in standard time rather than the
25927db96d56Sopenharmony_ci# daylight time we intend here), but returning it gives the real-life "local
25937db96d56Sopenharmony_ci# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
25947db96d56Sopenharmony_ci# tz.
25957db96d56Sopenharmony_ci#
25967db96d56Sopenharmony_ci# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
25977db96d56Sopenharmony_ci# the 1:MM standard time spelling we want.
25987db96d56Sopenharmony_ci#
25997db96d56Sopenharmony_ci# So how can this break?  One of the assumptions must be violated.  Two
26007db96d56Sopenharmony_ci# possibilities:
26017db96d56Sopenharmony_ci#
26027db96d56Sopenharmony_ci# 1) [2] effectively says that y.s is invariant across all y belong to a given
26037db96d56Sopenharmony_ci#    time zone.  This isn't true if, for political reasons or continental drift,
26047db96d56Sopenharmony_ci#    a region decides to change its base offset from UTC.
26057db96d56Sopenharmony_ci#
26067db96d56Sopenharmony_ci# 2) There may be versions of "double daylight" time where the tail end of
26077db96d56Sopenharmony_ci#    the analysis gives up a step too early.  I haven't thought about that
26087db96d56Sopenharmony_ci#    enough to say.
26097db96d56Sopenharmony_ci#
26107db96d56Sopenharmony_ci# In any case, it's clear that the default fromutc() is strong enough to handle
26117db96d56Sopenharmony_ci# "almost all" time zones:  so long as the standard offset is invariant, it
26127db96d56Sopenharmony_ci# doesn't matter if daylight time transition points change from year to year, or
26137db96d56Sopenharmony_ci# if daylight time is skipped in some years; it doesn't matter how large or
26147db96d56Sopenharmony_ci# small dst() may get within its bounds; and it doesn't even matter if some
26157db96d56Sopenharmony_ci# perverse time zone returns a negative dst()).  So a breaking case must be
26167db96d56Sopenharmony_ci# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
26177db96d56Sopenharmony_ci
26187db96d56Sopenharmony_citry:
26197db96d56Sopenharmony_ci    from _datetime import *
26207db96d56Sopenharmony_ciexcept ImportError:
26217db96d56Sopenharmony_ci    pass
26227db96d56Sopenharmony_cielse:
26237db96d56Sopenharmony_ci    # Clean up unused names
26247db96d56Sopenharmony_ci    del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
26257db96d56Sopenharmony_ci         _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
26267db96d56Sopenharmony_ci         _check_date_fields, _check_time_fields,
26277db96d56Sopenharmony_ci         _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
26287db96d56Sopenharmony_ci         _date_class, _days_before_month, _days_before_year, _days_in_month,
26297db96d56Sopenharmony_ci         _format_time, _format_offset, _index, _is_leap, _isoweek1monday, _math,
26307db96d56Sopenharmony_ci         _ord2ymd, _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord,
26317db96d56Sopenharmony_ci         _divide_and_round, _parse_isoformat_date, _parse_isoformat_time,
26327db96d56Sopenharmony_ci         _parse_hh_mm_ss_ff, _IsoCalendarDate, _isoweek_to_gregorian,
26337db96d56Sopenharmony_ci         _find_isoformat_datetime_separator, _FRACTION_CORRECTION,
26347db96d56Sopenharmony_ci         _is_ascii_digit)
26357db96d56Sopenharmony_ci    # XXX Since import * above excludes names that start with _,
26367db96d56Sopenharmony_ci    # docstring does not get overwritten. In the future, it may be
26377db96d56Sopenharmony_ci    # appropriate to maintain a single module level docstring and
26387db96d56Sopenharmony_ci    # remove the following line.
26397db96d56Sopenharmony_ci    from _datetime import __doc__
2640