1"""Concrete date/time and related types.
2
3See http://www.iana.org/time-zones/repository/tz-link.html for
4time zone and DST data sources.
5"""
6
7__all__ = ("date", "datetime", "time", "timedelta", "timezone", "tzinfo",
8           "MINYEAR", "MAXYEAR", "UTC")
9
10
11import time as _time
12import math as _math
13import sys
14from operator import index as _index
15
16def _cmp(x, y):
17    return 0 if x == y else 1 if x > y else -1
18
19MINYEAR = 1
20MAXYEAR = 9999
21_MAXORDINAL = 3652059  # date.max.toordinal()
22
23# Utility functions, adapted from Python's Demo/classes/Dates.py, which
24# also assumes the current Gregorian calendar indefinitely extended in
25# both directions.  Difference:  Dates.py calls January 1 of year 0 day
26# number 1.  The code here calls January 1 of year 1 day number 1.  This is
27# to match the definition of the "proleptic Gregorian" calendar in Dershowitz
28# and Reingold's "Calendrical Calculations", where it's the base calendar
29# for all computations.  See the book for algorithms for converting between
30# proleptic Gregorian ordinals and many other calendar systems.
31
32# -1 is a placeholder for indexing purposes.
33_DAYS_IN_MONTH = [-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
34
35_DAYS_BEFORE_MONTH = [-1]  # -1 is a placeholder for indexing purposes.
36dbm = 0
37for dim in _DAYS_IN_MONTH[1:]:
38    _DAYS_BEFORE_MONTH.append(dbm)
39    dbm += dim
40del dbm, dim
41
42def _is_leap(year):
43    "year -> 1 if leap year, else 0."
44    return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
45
46def _days_before_year(year):
47    "year -> number of days before January 1st of year."
48    y = year - 1
49    return y*365 + y//4 - y//100 + y//400
50
51def _days_in_month(year, month):
52    "year, month -> number of days in that month in that year."
53    assert 1 <= month <= 12, month
54    if month == 2 and _is_leap(year):
55        return 29
56    return _DAYS_IN_MONTH[month]
57
58def _days_before_month(year, month):
59    "year, month -> number of days in year preceding first day of month."
60    assert 1 <= month <= 12, 'month must be in 1..12'
61    return _DAYS_BEFORE_MONTH[month] + (month > 2 and _is_leap(year))
62
63def _ymd2ord(year, month, day):
64    "year, month, day -> ordinal, considering 01-Jan-0001 as day 1."
65    assert 1 <= month <= 12, 'month must be in 1..12'
66    dim = _days_in_month(year, month)
67    assert 1 <= day <= dim, ('day must be in 1..%d' % dim)
68    return (_days_before_year(year) +
69            _days_before_month(year, month) +
70            day)
71
72_DI400Y = _days_before_year(401)    # number of days in 400 years
73_DI100Y = _days_before_year(101)    #    "    "   "   " 100   "
74_DI4Y   = _days_before_year(5)      #    "    "   "   "   4   "
75
76# A 4-year cycle has an extra leap day over what we'd get from pasting
77# together 4 single years.
78assert _DI4Y == 4 * 365 + 1
79
80# Similarly, a 400-year cycle has an extra leap day over what we'd get from
81# pasting together 4 100-year cycles.
82assert _DI400Y == 4 * _DI100Y + 1
83
84# OTOH, a 100-year cycle has one fewer leap day than we'd get from
85# pasting together 25 4-year cycles.
86assert _DI100Y == 25 * _DI4Y - 1
87
88def _ord2ymd(n):
89    "ordinal -> (year, month, day), considering 01-Jan-0001 as day 1."
90
91    # n is a 1-based index, starting at 1-Jan-1.  The pattern of leap years
92    # repeats exactly every 400 years.  The basic strategy is to find the
93    # closest 400-year boundary at or before n, then work with the offset
94    # from that boundary to n.  Life is much clearer if we subtract 1 from
95    # n first -- then the values of n at 400-year boundaries are exactly
96    # those divisible by _DI400Y:
97    #
98    #     D  M   Y            n              n-1
99    #     -- --- ----        ----------     ----------------
100    #     31 Dec -400        -_DI400Y       -_DI400Y -1
101    #      1 Jan -399         -_DI400Y +1   -_DI400Y      400-year boundary
102    #     ...
103    #     30 Dec  000        -1             -2
104    #     31 Dec  000         0             -1
105    #      1 Jan  001         1              0            400-year boundary
106    #      2 Jan  001         2              1
107    #      3 Jan  001         3              2
108    #     ...
109    #     31 Dec  400         _DI400Y        _DI400Y -1
110    #      1 Jan  401         _DI400Y +1     _DI400Y      400-year boundary
111    n -= 1
112    n400, n = divmod(n, _DI400Y)
113    year = n400 * 400 + 1   # ..., -399, 1, 401, ...
114
115    # Now n is the (non-negative) offset, in days, from January 1 of year, to
116    # the desired date.  Now compute how many 100-year cycles precede n.
117    # Note that it's possible for n100 to equal 4!  In that case 4 full
118    # 100-year cycles precede the desired day, which implies the desired
119    # day is December 31 at the end of a 400-year cycle.
120    n100, n = divmod(n, _DI100Y)
121
122    # Now compute how many 4-year cycles precede it.
123    n4, n = divmod(n, _DI4Y)
124
125    # And now how many single years.  Again n1 can be 4, and again meaning
126    # that the desired day is December 31 at the end of the 4-year cycle.
127    n1, n = divmod(n, 365)
128
129    year += n100 * 100 + n4 * 4 + n1
130    if n1 == 4 or n100 == 4:
131        assert n == 0
132        return year-1, 12, 31
133
134    # Now the year is correct, and n is the offset from January 1.  We find
135    # the month via an estimate that's either exact or one too large.
136    leapyear = n1 == 3 and (n4 != 24 or n100 == 3)
137    assert leapyear == _is_leap(year)
138    month = (n + 50) >> 5
139    preceding = _DAYS_BEFORE_MONTH[month] + (month > 2 and leapyear)
140    if preceding > n:  # estimate is too large
141        month -= 1
142        preceding -= _DAYS_IN_MONTH[month] + (month == 2 and leapyear)
143    n -= preceding
144    assert 0 <= n < _days_in_month(year, month)
145
146    # Now the year and month are correct, and n is the offset from the
147    # start of that month:  we're done!
148    return year, month, n+1
149
150# Month and day names.  For localized versions, see the calendar module.
151_MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
152                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
153_DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
154
155
156def _build_struct_time(y, m, d, hh, mm, ss, dstflag):
157    wday = (_ymd2ord(y, m, d) + 6) % 7
158    dnum = _days_before_month(y, m) + d
159    return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag))
160
161def _format_time(hh, mm, ss, us, timespec='auto'):
162    specs = {
163        'hours': '{:02d}',
164        'minutes': '{:02d}:{:02d}',
165        'seconds': '{:02d}:{:02d}:{:02d}',
166        'milliseconds': '{:02d}:{:02d}:{:02d}.{:03d}',
167        'microseconds': '{:02d}:{:02d}:{:02d}.{:06d}'
168    }
169
170    if timespec == 'auto':
171        # Skip trailing microseconds when us==0.
172        timespec = 'microseconds' if us else 'seconds'
173    elif timespec == 'milliseconds':
174        us //= 1000
175    try:
176        fmt = specs[timespec]
177    except KeyError:
178        raise ValueError('Unknown timespec value')
179    else:
180        return fmt.format(hh, mm, ss, us)
181
182def _format_offset(off):
183    s = ''
184    if off is not None:
185        if off.days < 0:
186            sign = "-"
187            off = -off
188        else:
189            sign = "+"
190        hh, mm = divmod(off, timedelta(hours=1))
191        mm, ss = divmod(mm, timedelta(minutes=1))
192        s += "%s%02d:%02d" % (sign, hh, mm)
193        if ss or ss.microseconds:
194            s += ":%02d" % ss.seconds
195
196            if ss.microseconds:
197                s += '.%06d' % ss.microseconds
198    return s
199
200# Correctly substitute for %z and %Z escapes in strftime formats.
201def _wrap_strftime(object, format, timetuple):
202    # Don't call utcoffset() or tzname() unless actually needed.
203    freplace = None  # the string to use for %f
204    zreplace = None  # the string to use for %z
205    Zreplace = None  # the string to use for %Z
206
207    # Scan format for %z and %Z escapes, replacing as needed.
208    newformat = []
209    push = newformat.append
210    i, n = 0, len(format)
211    while i < n:
212        ch = format[i]
213        i += 1
214        if ch == '%':
215            if i < n:
216                ch = format[i]
217                i += 1
218                if ch == 'f':
219                    if freplace is None:
220                        freplace = '%06d' % getattr(object,
221                                                    'microsecond', 0)
222                    newformat.append(freplace)
223                elif ch == 'z':
224                    if zreplace is None:
225                        zreplace = ""
226                        if hasattr(object, "utcoffset"):
227                            offset = object.utcoffset()
228                            if offset is not None:
229                                sign = '+'
230                                if offset.days < 0:
231                                    offset = -offset
232                                    sign = '-'
233                                h, rest = divmod(offset, timedelta(hours=1))
234                                m, rest = divmod(rest, timedelta(minutes=1))
235                                s = rest.seconds
236                                u = offset.microseconds
237                                if u:
238                                    zreplace = '%c%02d%02d%02d.%06d' % (sign, h, m, s, u)
239                                elif s:
240                                    zreplace = '%c%02d%02d%02d' % (sign, h, m, s)
241                                else:
242                                    zreplace = '%c%02d%02d' % (sign, h, m)
243                    assert '%' not in zreplace
244                    newformat.append(zreplace)
245                elif ch == 'Z':
246                    if Zreplace is None:
247                        Zreplace = ""
248                        if hasattr(object, "tzname"):
249                            s = object.tzname()
250                            if s is not None:
251                                # strftime is going to have at this: escape %
252                                Zreplace = s.replace('%', '%%')
253                    newformat.append(Zreplace)
254                else:
255                    push('%')
256                    push(ch)
257            else:
258                push('%')
259        else:
260            push(ch)
261    newformat = "".join(newformat)
262    return _time.strftime(newformat, timetuple)
263
264# Helpers for parsing the result of isoformat()
265def _is_ascii_digit(c):
266    return c in "0123456789"
267
268def _find_isoformat_datetime_separator(dtstr):
269    # See the comment in _datetimemodule.c:_find_isoformat_datetime_separator
270    len_dtstr = len(dtstr)
271    if len_dtstr == 7:
272        return 7
273
274    assert len_dtstr > 7
275    date_separator = "-"
276    week_indicator = "W"
277
278    if dtstr[4] == date_separator:
279        if dtstr[5] == week_indicator:
280            if len_dtstr < 8:
281                raise ValueError("Invalid ISO string")
282            if len_dtstr > 8 and dtstr[8] == date_separator:
283                if len_dtstr == 9:
284                    raise ValueError("Invalid ISO string")
285                if len_dtstr > 10 and _is_ascii_digit(dtstr[10]):
286                    # This is as far as we need to resolve the ambiguity for
287                    # the moment - if we have YYYY-Www-##, the separator is
288                    # either a hyphen at 8 or a number at 10.
289                    #
290                    # We'll assume it's a hyphen at 8 because it's way more
291                    # likely that someone will use a hyphen as a separator than
292                    # a number, but at this point it's really best effort
293                    # because this is an extension of the spec anyway.
294                    # TODO(pganssle): Document this
295                    return 8
296                return 10
297            else:
298                # YYYY-Www (8)
299                return 8
300        else:
301            # YYYY-MM-DD (10)
302            return 10
303    else:
304        if dtstr[4] == week_indicator:
305            # YYYYWww (7) or YYYYWwwd (8)
306            idx = 7
307            while idx < len_dtstr:
308                if not _is_ascii_digit(dtstr[idx]):
309                    break
310                idx += 1
311
312            if idx < 9:
313                return idx
314
315            if idx % 2 == 0:
316                # If the index of the last number is even, it's YYYYWwwd
317                return 7
318            else:
319                return 8
320        else:
321            # YYYYMMDD (8)
322            return 8
323
324
325def _parse_isoformat_date(dtstr):
326    # It is assumed that this is an ASCII-only string of lengths 7, 8 or 10,
327    # see the comment on Modules/_datetimemodule.c:_find_isoformat_datetime_separator
328    assert len(dtstr) in (7, 8, 10)
329    year = int(dtstr[0:4])
330    has_sep = dtstr[4] == '-'
331
332    pos = 4 + has_sep
333    if dtstr[pos:pos + 1] == "W":
334        # YYYY-?Www-?D?
335        pos += 1
336        weekno = int(dtstr[pos:pos + 2])
337        pos += 2
338
339        dayno = 1
340        if len(dtstr) > pos:
341            if (dtstr[pos:pos + 1] == '-') != has_sep:
342                raise ValueError("Inconsistent use of dash separator")
343
344            pos += has_sep
345
346            dayno = int(dtstr[pos:pos + 1])
347
348        return list(_isoweek_to_gregorian(year, weekno, dayno))
349    else:
350        month = int(dtstr[pos:pos + 2])
351        pos += 2
352        if (dtstr[pos:pos + 1] == "-") != has_sep:
353            raise ValueError("Inconsistent use of dash separator")
354
355        pos += has_sep
356        day = int(dtstr[pos:pos + 2])
357
358        return [year, month, day]
359
360
361_FRACTION_CORRECTION = [100000, 10000, 1000, 100, 10]
362
363
364def _parse_hh_mm_ss_ff(tstr):
365    # Parses things of the form HH[:?MM[:?SS[{.,}fff[fff]]]]
366    len_str = len(tstr)
367
368    time_comps = [0, 0, 0, 0]
369    pos = 0
370    for comp in range(0, 3):
371        if (len_str - pos) < 2:
372            raise ValueError("Incomplete time component")
373
374        time_comps[comp] = int(tstr[pos:pos+2])
375
376        pos += 2
377        next_char = tstr[pos:pos+1]
378
379        if comp == 0:
380            has_sep = next_char == ':'
381
382        if not next_char or comp >= 2:
383            break
384
385        if has_sep and next_char != ':':
386            raise ValueError("Invalid time separator: %c" % next_char)
387
388        pos += has_sep
389
390    if pos < len_str:
391        if tstr[pos] not in '.,':
392            raise ValueError("Invalid microsecond component")
393        else:
394            pos += 1
395
396            len_remainder = len_str - pos
397
398            if len_remainder >= 6:
399                to_parse = 6
400            else:
401                to_parse = len_remainder
402
403            time_comps[3] = int(tstr[pos:(pos+to_parse)])
404            if to_parse < 6:
405                time_comps[3] *= _FRACTION_CORRECTION[to_parse-1]
406            if (len_remainder > to_parse
407                    and not all(map(_is_ascii_digit, tstr[(pos+to_parse):]))):
408                raise ValueError("Non-digit values in unparsed fraction")
409
410    return time_comps
411
412def _parse_isoformat_time(tstr):
413    # Format supported is HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]
414    len_str = len(tstr)
415    if len_str < 2:
416        raise ValueError("Isoformat time too short")
417
418    # This is equivalent to re.search('[+-Z]', tstr), but faster
419    tz_pos = (tstr.find('-') + 1 or tstr.find('+') + 1 or tstr.find('Z') + 1)
420    timestr = tstr[:tz_pos-1] if tz_pos > 0 else tstr
421
422    time_comps = _parse_hh_mm_ss_ff(timestr)
423
424    tzi = None
425    if tz_pos == len_str and tstr[-1] == 'Z':
426        tzi = timezone.utc
427    elif tz_pos > 0:
428        tzstr = tstr[tz_pos:]
429
430        # Valid time zone strings are:
431        # HH                  len: 2
432        # HHMM                len: 4
433        # HH:MM               len: 5
434        # HHMMSS              len: 6
435        # HHMMSS.f+           len: 7+
436        # HH:MM:SS            len: 8
437        # HH:MM:SS.f+         len: 10+
438
439        if len(tzstr) in (0, 1, 3):
440            raise ValueError("Malformed time zone string")
441
442        tz_comps = _parse_hh_mm_ss_ff(tzstr)
443
444        if all(x == 0 for x in tz_comps):
445            tzi = timezone.utc
446        else:
447            tzsign = -1 if tstr[tz_pos - 1] == '-' else 1
448
449            td = timedelta(hours=tz_comps[0], minutes=tz_comps[1],
450                           seconds=tz_comps[2], microseconds=tz_comps[3])
451
452            tzi = timezone(tzsign * td)
453
454    time_comps.append(tzi)
455
456    return time_comps
457
458# tuple[int, int, int] -> tuple[int, int, int] version of date.fromisocalendar
459def _isoweek_to_gregorian(year, week, day):
460    # Year is bounded this way because 9999-12-31 is (9999, 52, 5)
461    if not MINYEAR <= year <= MAXYEAR:
462        raise ValueError(f"Year is out of range: {year}")
463
464    if not 0 < week < 53:
465        out_of_range = True
466
467        if week == 53:
468            # ISO years have 53 weeks in them on years starting with a
469            # Thursday and leap years starting on a Wednesday
470            first_weekday = _ymd2ord(year, 1, 1) % 7
471            if (first_weekday == 4 or (first_weekday == 3 and
472                                       _is_leap(year))):
473                out_of_range = False
474
475        if out_of_range:
476            raise ValueError(f"Invalid week: {week}")
477
478    if not 0 < day < 8:
479        raise ValueError(f"Invalid weekday: {day} (range is [1, 7])")
480
481    # Now compute the offset from (Y, 1, 1) in days:
482    day_offset = (week - 1) * 7 + (day - 1)
483
484    # Calculate the ordinal day for monday, week 1
485    day_1 = _isoweek1monday(year)
486    ord_day = day_1 + day_offset
487
488    return _ord2ymd(ord_day)
489
490
491# Just raise TypeError if the arg isn't None or a string.
492def _check_tzname(name):
493    if name is not None and not isinstance(name, str):
494        raise TypeError("tzinfo.tzname() must return None or string, "
495                        "not '%s'" % type(name))
496
497# name is the offset-producing method, "utcoffset" or "dst".
498# offset is what it returned.
499# If offset isn't None or timedelta, raises TypeError.
500# If offset is None, returns None.
501# Else offset is checked for being in range.
502# If it is, its integer value is returned.  Else ValueError is raised.
503def _check_utc_offset(name, offset):
504    assert name in ("utcoffset", "dst")
505    if offset is None:
506        return
507    if not isinstance(offset, timedelta):
508        raise TypeError("tzinfo.%s() must return None "
509                        "or timedelta, not '%s'" % (name, type(offset)))
510    if not -timedelta(1) < offset < timedelta(1):
511        raise ValueError("%s()=%s, must be strictly between "
512                         "-timedelta(hours=24) and timedelta(hours=24)" %
513                         (name, offset))
514
515def _check_date_fields(year, month, day):
516    year = _index(year)
517    month = _index(month)
518    day = _index(day)
519    if not MINYEAR <= year <= MAXYEAR:
520        raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year)
521    if not 1 <= month <= 12:
522        raise ValueError('month must be in 1..12', month)
523    dim = _days_in_month(year, month)
524    if not 1 <= day <= dim:
525        raise ValueError('day must be in 1..%d' % dim, day)
526    return year, month, day
527
528def _check_time_fields(hour, minute, second, microsecond, fold):
529    hour = _index(hour)
530    minute = _index(minute)
531    second = _index(second)
532    microsecond = _index(microsecond)
533    if not 0 <= hour <= 23:
534        raise ValueError('hour must be in 0..23', hour)
535    if not 0 <= minute <= 59:
536        raise ValueError('minute must be in 0..59', minute)
537    if not 0 <= second <= 59:
538        raise ValueError('second must be in 0..59', second)
539    if not 0 <= microsecond <= 999999:
540        raise ValueError('microsecond must be in 0..999999', microsecond)
541    if fold not in (0, 1):
542        raise ValueError('fold must be either 0 or 1', fold)
543    return hour, minute, second, microsecond, fold
544
545def _check_tzinfo_arg(tz):
546    if tz is not None and not isinstance(tz, tzinfo):
547        raise TypeError("tzinfo argument must be None or of a tzinfo subclass")
548
549def _cmperror(x, y):
550    raise TypeError("can't compare '%s' to '%s'" % (
551                    type(x).__name__, type(y).__name__))
552
553def _divide_and_round(a, b):
554    """divide a by b and round result to the nearest integer
555
556    When the ratio is exactly half-way between two integers,
557    the even integer is returned.
558    """
559    # Based on the reference implementation for divmod_near
560    # in Objects/longobject.c.
561    q, r = divmod(a, b)
562    # round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
563    # The expression r / b > 0.5 is equivalent to 2 * r > b if b is
564    # positive, 2 * r < b if b negative.
565    r *= 2
566    greater_than_half = r > b if b > 0 else r < b
567    if greater_than_half or r == b and q % 2 == 1:
568        q += 1
569
570    return q
571
572
573class timedelta:
574    """Represent the difference between two datetime objects.
575
576    Supported operators:
577
578    - add, subtract timedelta
579    - unary plus, minus, abs
580    - compare to timedelta
581    - multiply, divide by int
582
583    In addition, datetime supports subtraction of two datetime objects
584    returning a timedelta, and addition or subtraction of a datetime
585    and a timedelta giving a datetime.
586
587    Representation: (days, seconds, microseconds).  Why?  Because I
588    felt like it.
589    """
590    __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
591
592    def __new__(cls, days=0, seconds=0, microseconds=0,
593                milliseconds=0, minutes=0, hours=0, weeks=0):
594        # Doing this efficiently and accurately in C is going to be difficult
595        # and error-prone, due to ubiquitous overflow possibilities, and that
596        # C double doesn't have enough bits of precision to represent
597        # microseconds over 10K years faithfully.  The code here tries to make
598        # explicit where go-fast assumptions can be relied on, in order to
599        # guide the C implementation; it's way more convoluted than speed-
600        # ignoring auto-overflow-to-long idiomatic Python could be.
601
602        # XXX Check that all inputs are ints or floats.
603
604        # Final values, all integer.
605        # s and us fit in 32-bit signed ints; d isn't bounded.
606        d = s = us = 0
607
608        # Normalize everything to days, seconds, microseconds.
609        days += weeks*7
610        seconds += minutes*60 + hours*3600
611        microseconds += milliseconds*1000
612
613        # Get rid of all fractions, and normalize s and us.
614        # Take a deep breath <wink>.
615        if isinstance(days, float):
616            dayfrac, days = _math.modf(days)
617            daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
618            assert daysecondswhole == int(daysecondswhole)  # can't overflow
619            s = int(daysecondswhole)
620            assert days == int(days)
621            d = int(days)
622        else:
623            daysecondsfrac = 0.0
624            d = days
625        assert isinstance(daysecondsfrac, float)
626        assert abs(daysecondsfrac) <= 1.0
627        assert isinstance(d, int)
628        assert abs(s) <= 24 * 3600
629        # days isn't referenced again before redefinition
630
631        if isinstance(seconds, float):
632            secondsfrac, seconds = _math.modf(seconds)
633            assert seconds == int(seconds)
634            seconds = int(seconds)
635            secondsfrac += daysecondsfrac
636            assert abs(secondsfrac) <= 2.0
637        else:
638            secondsfrac = daysecondsfrac
639        # daysecondsfrac isn't referenced again
640        assert isinstance(secondsfrac, float)
641        assert abs(secondsfrac) <= 2.0
642
643        assert isinstance(seconds, int)
644        days, seconds = divmod(seconds, 24*3600)
645        d += days
646        s += int(seconds)    # can't overflow
647        assert isinstance(s, int)
648        assert abs(s) <= 2 * 24 * 3600
649        # seconds isn't referenced again before redefinition
650
651        usdouble = secondsfrac * 1e6
652        assert abs(usdouble) < 2.1e6    # exact value not critical
653        # secondsfrac isn't referenced again
654
655        if isinstance(microseconds, float):
656            microseconds = round(microseconds + usdouble)
657            seconds, microseconds = divmod(microseconds, 1000000)
658            days, seconds = divmod(seconds, 24*3600)
659            d += days
660            s += seconds
661        else:
662            microseconds = int(microseconds)
663            seconds, microseconds = divmod(microseconds, 1000000)
664            days, seconds = divmod(seconds, 24*3600)
665            d += days
666            s += seconds
667            microseconds = round(microseconds + usdouble)
668        assert isinstance(s, int)
669        assert isinstance(microseconds, int)
670        assert abs(s) <= 3 * 24 * 3600
671        assert abs(microseconds) < 3.1e6
672
673        # Just a little bit of carrying possible for microseconds and seconds.
674        seconds, us = divmod(microseconds, 1000000)
675        s += seconds
676        days, s = divmod(s, 24*3600)
677        d += days
678
679        assert isinstance(d, int)
680        assert isinstance(s, int) and 0 <= s < 24*3600
681        assert isinstance(us, int) and 0 <= us < 1000000
682
683        if abs(d) > 999999999:
684            raise OverflowError("timedelta # of days is too large: %d" % d)
685
686        self = object.__new__(cls)
687        self._days = d
688        self._seconds = s
689        self._microseconds = us
690        self._hashcode = -1
691        return self
692
693    def __repr__(self):
694        args = []
695        if self._days:
696            args.append("days=%d" % self._days)
697        if self._seconds:
698            args.append("seconds=%d" % self._seconds)
699        if self._microseconds:
700            args.append("microseconds=%d" % self._microseconds)
701        if not args:
702            args.append('0')
703        return "%s.%s(%s)" % (self.__class__.__module__,
704                              self.__class__.__qualname__,
705                              ', '.join(args))
706
707    def __str__(self):
708        mm, ss = divmod(self._seconds, 60)
709        hh, mm = divmod(mm, 60)
710        s = "%d:%02d:%02d" % (hh, mm, ss)
711        if self._days:
712            def plural(n):
713                return n, abs(n) != 1 and "s" or ""
714            s = ("%d day%s, " % plural(self._days)) + s
715        if self._microseconds:
716            s = s + ".%06d" % self._microseconds
717        return s
718
719    def total_seconds(self):
720        """Total seconds in the duration."""
721        return ((self.days * 86400 + self.seconds) * 10**6 +
722                self.microseconds) / 10**6
723
724    # Read-only field accessors
725    @property
726    def days(self):
727        """days"""
728        return self._days
729
730    @property
731    def seconds(self):
732        """seconds"""
733        return self._seconds
734
735    @property
736    def microseconds(self):
737        """microseconds"""
738        return self._microseconds
739
740    def __add__(self, other):
741        if isinstance(other, timedelta):
742            # for CPython compatibility, we cannot use
743            # our __class__ here, but need a real timedelta
744            return timedelta(self._days + other._days,
745                             self._seconds + other._seconds,
746                             self._microseconds + other._microseconds)
747        return NotImplemented
748
749    __radd__ = __add__
750
751    def __sub__(self, other):
752        if isinstance(other, timedelta):
753            # for CPython compatibility, we cannot use
754            # our __class__ here, but need a real timedelta
755            return timedelta(self._days - other._days,
756                             self._seconds - other._seconds,
757                             self._microseconds - other._microseconds)
758        return NotImplemented
759
760    def __rsub__(self, other):
761        if isinstance(other, timedelta):
762            return -self + other
763        return NotImplemented
764
765    def __neg__(self):
766        # for CPython compatibility, we cannot use
767        # our __class__ here, but need a real timedelta
768        return timedelta(-self._days,
769                         -self._seconds,
770                         -self._microseconds)
771
772    def __pos__(self):
773        return self
774
775    def __abs__(self):
776        if self._days < 0:
777            return -self
778        else:
779            return self
780
781    def __mul__(self, other):
782        if isinstance(other, int):
783            # for CPython compatibility, we cannot use
784            # our __class__ here, but need a real timedelta
785            return timedelta(self._days * other,
786                             self._seconds * other,
787                             self._microseconds * other)
788        if isinstance(other, float):
789            usec = self._to_microseconds()
790            a, b = other.as_integer_ratio()
791            return timedelta(0, 0, _divide_and_round(usec * a, b))
792        return NotImplemented
793
794    __rmul__ = __mul__
795
796    def _to_microseconds(self):
797        return ((self._days * (24*3600) + self._seconds) * 1000000 +
798                self._microseconds)
799
800    def __floordiv__(self, other):
801        if not isinstance(other, (int, timedelta)):
802            return NotImplemented
803        usec = self._to_microseconds()
804        if isinstance(other, timedelta):
805            return usec // other._to_microseconds()
806        if isinstance(other, int):
807            return timedelta(0, 0, usec // other)
808
809    def __truediv__(self, other):
810        if not isinstance(other, (int, float, timedelta)):
811            return NotImplemented
812        usec = self._to_microseconds()
813        if isinstance(other, timedelta):
814            return usec / other._to_microseconds()
815        if isinstance(other, int):
816            return timedelta(0, 0, _divide_and_round(usec, other))
817        if isinstance(other, float):
818            a, b = other.as_integer_ratio()
819            return timedelta(0, 0, _divide_and_round(b * usec, a))
820
821    def __mod__(self, other):
822        if isinstance(other, timedelta):
823            r = self._to_microseconds() % other._to_microseconds()
824            return timedelta(0, 0, r)
825        return NotImplemented
826
827    def __divmod__(self, other):
828        if isinstance(other, timedelta):
829            q, r = divmod(self._to_microseconds(),
830                          other._to_microseconds())
831            return q, timedelta(0, 0, r)
832        return NotImplemented
833
834    # Comparisons of timedelta objects with other.
835
836    def __eq__(self, other):
837        if isinstance(other, timedelta):
838            return self._cmp(other) == 0
839        else:
840            return NotImplemented
841
842    def __le__(self, other):
843        if isinstance(other, timedelta):
844            return self._cmp(other) <= 0
845        else:
846            return NotImplemented
847
848    def __lt__(self, other):
849        if isinstance(other, timedelta):
850            return self._cmp(other) < 0
851        else:
852            return NotImplemented
853
854    def __ge__(self, other):
855        if isinstance(other, timedelta):
856            return self._cmp(other) >= 0
857        else:
858            return NotImplemented
859
860    def __gt__(self, other):
861        if isinstance(other, timedelta):
862            return self._cmp(other) > 0
863        else:
864            return NotImplemented
865
866    def _cmp(self, other):
867        assert isinstance(other, timedelta)
868        return _cmp(self._getstate(), other._getstate())
869
870    def __hash__(self):
871        if self._hashcode == -1:
872            self._hashcode = hash(self._getstate())
873        return self._hashcode
874
875    def __bool__(self):
876        return (self._days != 0 or
877                self._seconds != 0 or
878                self._microseconds != 0)
879
880    # Pickle support.
881
882    def _getstate(self):
883        return (self._days, self._seconds, self._microseconds)
884
885    def __reduce__(self):
886        return (self.__class__, self._getstate())
887
888timedelta.min = timedelta(-999999999)
889timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
890                          microseconds=999999)
891timedelta.resolution = timedelta(microseconds=1)
892
893class date:
894    """Concrete date type.
895
896    Constructors:
897
898    __new__()
899    fromtimestamp()
900    today()
901    fromordinal()
902
903    Operators:
904
905    __repr__, __str__
906    __eq__, __le__, __lt__, __ge__, __gt__, __hash__
907    __add__, __radd__, __sub__ (add/radd only with timedelta arg)
908
909    Methods:
910
911    timetuple()
912    toordinal()
913    weekday()
914    isoweekday(), isocalendar(), isoformat()
915    ctime()
916    strftime()
917
918    Properties (readonly):
919    year, month, day
920    """
921    __slots__ = '_year', '_month', '_day', '_hashcode'
922
923    def __new__(cls, year, month=None, day=None):
924        """Constructor.
925
926        Arguments:
927
928        year, month, day (required, base 1)
929        """
930        if (month is None and
931            isinstance(year, (bytes, str)) and len(year) == 4 and
932            1 <= ord(year[2:3]) <= 12):
933            # Pickle support
934            if isinstance(year, str):
935                try:
936                    year = year.encode('latin1')
937                except UnicodeEncodeError:
938                    # More informative error message.
939                    raise ValueError(
940                        "Failed to encode latin1 string when unpickling "
941                        "a date object. "
942                        "pickle.load(data, encoding='latin1') is assumed.")
943            self = object.__new__(cls)
944            self.__setstate(year)
945            self._hashcode = -1
946            return self
947        year, month, day = _check_date_fields(year, month, day)
948        self = object.__new__(cls)
949        self._year = year
950        self._month = month
951        self._day = day
952        self._hashcode = -1
953        return self
954
955    # Additional constructors
956
957    @classmethod
958    def fromtimestamp(cls, t):
959        "Construct a date from a POSIX timestamp (like time.time())."
960        y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
961        return cls(y, m, d)
962
963    @classmethod
964    def today(cls):
965        "Construct a date from time.time()."
966        t = _time.time()
967        return cls.fromtimestamp(t)
968
969    @classmethod
970    def fromordinal(cls, n):
971        """Construct a date from a proleptic Gregorian ordinal.
972
973        January 1 of year 1 is day 1.  Only the year, month and day are
974        non-zero in the result.
975        """
976        y, m, d = _ord2ymd(n)
977        return cls(y, m, d)
978
979    @classmethod
980    def fromisoformat(cls, date_string):
981        """Construct a date from a string in ISO 8601 format."""
982        if not isinstance(date_string, str):
983            raise TypeError('fromisoformat: argument must be str')
984
985        if len(date_string) not in (7, 8, 10):
986            raise ValueError(f'Invalid isoformat string: {date_string!r}')
987
988        try:
989            return cls(*_parse_isoformat_date(date_string))
990        except Exception:
991            raise ValueError(f'Invalid isoformat string: {date_string!r}')
992
993    @classmethod
994    def fromisocalendar(cls, year, week, day):
995        """Construct a date from the ISO year, week number and weekday.
996
997        This is the inverse of the date.isocalendar() function"""
998        return cls(*_isoweek_to_gregorian(year, week, day))
999
1000    # Conversions to string
1001
1002    def __repr__(self):
1003        """Convert to formal string, for repr().
1004
1005        >>> dt = datetime(2010, 1, 1)
1006        >>> repr(dt)
1007        'datetime.datetime(2010, 1, 1, 0, 0)'
1008
1009        >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
1010        >>> repr(dt)
1011        'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
1012        """
1013        return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
1014                                      self.__class__.__qualname__,
1015                                      self._year,
1016                                      self._month,
1017                                      self._day)
1018    # XXX These shouldn't depend on time.localtime(), because that
1019    # clips the usable dates to [1970 .. 2038).  At least ctime() is
1020    # easily done without using strftime() -- that's better too because
1021    # strftime("%c", ...) is locale specific.
1022
1023
1024    def ctime(self):
1025        "Return ctime() style string."
1026        weekday = self.toordinal() % 7 or 7
1027        return "%s %s %2d 00:00:00 %04d" % (
1028            _DAYNAMES[weekday],
1029            _MONTHNAMES[self._month],
1030            self._day, self._year)
1031
1032    def strftime(self, fmt):
1033        """
1034        Format using strftime().
1035
1036        Example: "%d/%m/%Y, %H:%M:%S"
1037        """
1038        return _wrap_strftime(self, fmt, self.timetuple())
1039
1040    def __format__(self, fmt):
1041        if not isinstance(fmt, str):
1042            raise TypeError("must be str, not %s" % type(fmt).__name__)
1043        if len(fmt) != 0:
1044            return self.strftime(fmt)
1045        return str(self)
1046
1047    def isoformat(self):
1048        """Return the date formatted according to ISO.
1049
1050        This is 'YYYY-MM-DD'.
1051
1052        References:
1053        - http://www.w3.org/TR/NOTE-datetime
1054        - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
1055        """
1056        return "%04d-%02d-%02d" % (self._year, self._month, self._day)
1057
1058    __str__ = isoformat
1059
1060    # Read-only field accessors
1061    @property
1062    def year(self):
1063        """year (1-9999)"""
1064        return self._year
1065
1066    @property
1067    def month(self):
1068        """month (1-12)"""
1069        return self._month
1070
1071    @property
1072    def day(self):
1073        """day (1-31)"""
1074        return self._day
1075
1076    # Standard conversions, __eq__, __le__, __lt__, __ge__, __gt__,
1077    # __hash__ (and helpers)
1078
1079    def timetuple(self):
1080        "Return local time tuple compatible with time.localtime()."
1081        return _build_struct_time(self._year, self._month, self._day,
1082                                  0, 0, 0, -1)
1083
1084    def toordinal(self):
1085        """Return proleptic Gregorian ordinal for the year, month and day.
1086
1087        January 1 of year 1 is day 1.  Only the year, month and day values
1088        contribute to the result.
1089        """
1090        return _ymd2ord(self._year, self._month, self._day)
1091
1092    def replace(self, year=None, month=None, day=None):
1093        """Return a new date with new values for the specified fields."""
1094        if year is None:
1095            year = self._year
1096        if month is None:
1097            month = self._month
1098        if day is None:
1099            day = self._day
1100        return type(self)(year, month, day)
1101
1102    # Comparisons of date objects with other.
1103
1104    def __eq__(self, other):
1105        if isinstance(other, date):
1106            return self._cmp(other) == 0
1107        return NotImplemented
1108
1109    def __le__(self, other):
1110        if isinstance(other, date):
1111            return self._cmp(other) <= 0
1112        return NotImplemented
1113
1114    def __lt__(self, other):
1115        if isinstance(other, date):
1116            return self._cmp(other) < 0
1117        return NotImplemented
1118
1119    def __ge__(self, other):
1120        if isinstance(other, date):
1121            return self._cmp(other) >= 0
1122        return NotImplemented
1123
1124    def __gt__(self, other):
1125        if isinstance(other, date):
1126            return self._cmp(other) > 0
1127        return NotImplemented
1128
1129    def _cmp(self, other):
1130        assert isinstance(other, date)
1131        y, m, d = self._year, self._month, self._day
1132        y2, m2, d2 = other._year, other._month, other._day
1133        return _cmp((y, m, d), (y2, m2, d2))
1134
1135    def __hash__(self):
1136        "Hash."
1137        if self._hashcode == -1:
1138            self._hashcode = hash(self._getstate())
1139        return self._hashcode
1140
1141    # Computations
1142
1143    def __add__(self, other):
1144        "Add a date to a timedelta."
1145        if isinstance(other, timedelta):
1146            o = self.toordinal() + other.days
1147            if 0 < o <= _MAXORDINAL:
1148                return type(self).fromordinal(o)
1149            raise OverflowError("result out of range")
1150        return NotImplemented
1151
1152    __radd__ = __add__
1153
1154    def __sub__(self, other):
1155        """Subtract two dates, or a date and a timedelta."""
1156        if isinstance(other, timedelta):
1157            return self + timedelta(-other.days)
1158        if isinstance(other, date):
1159            days1 = self.toordinal()
1160            days2 = other.toordinal()
1161            return timedelta(days1 - days2)
1162        return NotImplemented
1163
1164    def weekday(self):
1165        "Return day of the week, where Monday == 0 ... Sunday == 6."
1166        return (self.toordinal() + 6) % 7
1167
1168    # Day-of-the-week and week-of-the-year, according to ISO
1169
1170    def isoweekday(self):
1171        "Return day of the week, where Monday == 1 ... Sunday == 7."
1172        # 1-Jan-0001 is a Monday
1173        return self.toordinal() % 7 or 7
1174
1175    def isocalendar(self):
1176        """Return a named tuple containing ISO year, week number, and weekday.
1177
1178        The first ISO week of the year is the (Mon-Sun) week
1179        containing the year's first Thursday; everything else derives
1180        from that.
1181
1182        The first week is 1; Monday is 1 ... Sunday is 7.
1183
1184        ISO calendar algorithm taken from
1185        http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
1186        (used with permission)
1187        """
1188        year = self._year
1189        week1monday = _isoweek1monday(year)
1190        today = _ymd2ord(self._year, self._month, self._day)
1191        # Internally, week and day have origin 0
1192        week, day = divmod(today - week1monday, 7)
1193        if week < 0:
1194            year -= 1
1195            week1monday = _isoweek1monday(year)
1196            week, day = divmod(today - week1monday, 7)
1197        elif week >= 52:
1198            if today >= _isoweek1monday(year+1):
1199                year += 1
1200                week = 0
1201        return _IsoCalendarDate(year, week+1, day+1)
1202
1203    # Pickle support.
1204
1205    def _getstate(self):
1206        yhi, ylo = divmod(self._year, 256)
1207        return bytes([yhi, ylo, self._month, self._day]),
1208
1209    def __setstate(self, string):
1210        yhi, ylo, self._month, self._day = string
1211        self._year = yhi * 256 + ylo
1212
1213    def __reduce__(self):
1214        return (self.__class__, self._getstate())
1215
1216_date_class = date  # so functions w/ args named "date" can get at the class
1217
1218date.min = date(1, 1, 1)
1219date.max = date(9999, 12, 31)
1220date.resolution = timedelta(days=1)
1221
1222
1223class tzinfo:
1224    """Abstract base class for time zone info classes.
1225
1226    Subclasses must override the name(), utcoffset() and dst() methods.
1227    """
1228    __slots__ = ()
1229
1230    def tzname(self, dt):
1231        "datetime -> string name of time zone."
1232        raise NotImplementedError("tzinfo subclass must override tzname()")
1233
1234    def utcoffset(self, dt):
1235        "datetime -> timedelta, positive for east of UTC, negative for west of UTC"
1236        raise NotImplementedError("tzinfo subclass must override utcoffset()")
1237
1238    def dst(self, dt):
1239        """datetime -> DST offset as timedelta, positive for east of UTC.
1240
1241        Return 0 if DST not in effect.  utcoffset() must include the DST
1242        offset.
1243        """
1244        raise NotImplementedError("tzinfo subclass must override dst()")
1245
1246    def fromutc(self, dt):
1247        "datetime in UTC -> datetime in local time."
1248
1249        if not isinstance(dt, datetime):
1250            raise TypeError("fromutc() requires a datetime argument")
1251        if dt.tzinfo is not self:
1252            raise ValueError("dt.tzinfo is not self")
1253
1254        dtoff = dt.utcoffset()
1255        if dtoff is None:
1256            raise ValueError("fromutc() requires a non-None utcoffset() "
1257                             "result")
1258
1259        # See the long comment block at the end of this file for an
1260        # explanation of this algorithm.
1261        dtdst = dt.dst()
1262        if dtdst is None:
1263            raise ValueError("fromutc() requires a non-None dst() result")
1264        delta = dtoff - dtdst
1265        if delta:
1266            dt += delta
1267            dtdst = dt.dst()
1268            if dtdst is None:
1269                raise ValueError("fromutc(): dt.dst gave inconsistent "
1270                                 "results; cannot convert")
1271        return dt + dtdst
1272
1273    # Pickle support.
1274
1275    def __reduce__(self):
1276        getinitargs = getattr(self, "__getinitargs__", None)
1277        if getinitargs:
1278            args = getinitargs()
1279        else:
1280            args = ()
1281        return (self.__class__, args, self.__getstate__())
1282
1283
1284class IsoCalendarDate(tuple):
1285
1286    def __new__(cls, year, week, weekday, /):
1287        return super().__new__(cls, (year, week, weekday))
1288
1289    @property
1290    def year(self):
1291        return self[0]
1292
1293    @property
1294    def week(self):
1295        return self[1]
1296
1297    @property
1298    def weekday(self):
1299        return self[2]
1300
1301    def __reduce__(self):
1302        # This code is intended to pickle the object without making the
1303        # class public. See https://bugs.python.org/msg352381
1304        return (tuple, (tuple(self),))
1305
1306    def __repr__(self):
1307        return (f'{self.__class__.__name__}'
1308                f'(year={self[0]}, week={self[1]}, weekday={self[2]})')
1309
1310
1311_IsoCalendarDate = IsoCalendarDate
1312del IsoCalendarDate
1313_tzinfo_class = tzinfo
1314
1315class time:
1316    """Time with time zone.
1317
1318    Constructors:
1319
1320    __new__()
1321
1322    Operators:
1323
1324    __repr__, __str__
1325    __eq__, __le__, __lt__, __ge__, __gt__, __hash__
1326
1327    Methods:
1328
1329    strftime()
1330    isoformat()
1331    utcoffset()
1332    tzname()
1333    dst()
1334
1335    Properties (readonly):
1336    hour, minute, second, microsecond, tzinfo, fold
1337    """
1338    __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode', '_fold'
1339
1340    def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
1341        """Constructor.
1342
1343        Arguments:
1344
1345        hour, minute (required)
1346        second, microsecond (default to zero)
1347        tzinfo (default to None)
1348        fold (keyword only, default to zero)
1349        """
1350        if (isinstance(hour, (bytes, str)) and len(hour) == 6 and
1351            ord(hour[0:1])&0x7F < 24):
1352            # Pickle support
1353            if isinstance(hour, str):
1354                try:
1355                    hour = hour.encode('latin1')
1356                except UnicodeEncodeError:
1357                    # More informative error message.
1358                    raise ValueError(
1359                        "Failed to encode latin1 string when unpickling "
1360                        "a time object. "
1361                        "pickle.load(data, encoding='latin1') is assumed.")
1362            self = object.__new__(cls)
1363            self.__setstate(hour, minute or None)
1364            self._hashcode = -1
1365            return self
1366        hour, minute, second, microsecond, fold = _check_time_fields(
1367            hour, minute, second, microsecond, fold)
1368        _check_tzinfo_arg(tzinfo)
1369        self = object.__new__(cls)
1370        self._hour = hour
1371        self._minute = minute
1372        self._second = second
1373        self._microsecond = microsecond
1374        self._tzinfo = tzinfo
1375        self._hashcode = -1
1376        self._fold = fold
1377        return self
1378
1379    # Read-only field accessors
1380    @property
1381    def hour(self):
1382        """hour (0-23)"""
1383        return self._hour
1384
1385    @property
1386    def minute(self):
1387        """minute (0-59)"""
1388        return self._minute
1389
1390    @property
1391    def second(self):
1392        """second (0-59)"""
1393        return self._second
1394
1395    @property
1396    def microsecond(self):
1397        """microsecond (0-999999)"""
1398        return self._microsecond
1399
1400    @property
1401    def tzinfo(self):
1402        """timezone info object"""
1403        return self._tzinfo
1404
1405    @property
1406    def fold(self):
1407        return self._fold
1408
1409    # Standard conversions, __hash__ (and helpers)
1410
1411    # Comparisons of time objects with other.
1412
1413    def __eq__(self, other):
1414        if isinstance(other, time):
1415            return self._cmp(other, allow_mixed=True) == 0
1416        else:
1417            return NotImplemented
1418
1419    def __le__(self, other):
1420        if isinstance(other, time):
1421            return self._cmp(other) <= 0
1422        else:
1423            return NotImplemented
1424
1425    def __lt__(self, other):
1426        if isinstance(other, time):
1427            return self._cmp(other) < 0
1428        else:
1429            return NotImplemented
1430
1431    def __ge__(self, other):
1432        if isinstance(other, time):
1433            return self._cmp(other) >= 0
1434        else:
1435            return NotImplemented
1436
1437    def __gt__(self, other):
1438        if isinstance(other, time):
1439            return self._cmp(other) > 0
1440        else:
1441            return NotImplemented
1442
1443    def _cmp(self, other, allow_mixed=False):
1444        assert isinstance(other, time)
1445        mytz = self._tzinfo
1446        ottz = other._tzinfo
1447        myoff = otoff = None
1448
1449        if mytz is ottz:
1450            base_compare = True
1451        else:
1452            myoff = self.utcoffset()
1453            otoff = other.utcoffset()
1454            base_compare = myoff == otoff
1455
1456        if base_compare:
1457            return _cmp((self._hour, self._minute, self._second,
1458                         self._microsecond),
1459                        (other._hour, other._minute, other._second,
1460                         other._microsecond))
1461        if myoff is None or otoff is None:
1462            if allow_mixed:
1463                return 2 # arbitrary non-zero value
1464            else:
1465                raise TypeError("cannot compare naive and aware times")
1466        myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1467        othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1468        return _cmp((myhhmm, self._second, self._microsecond),
1469                    (othhmm, other._second, other._microsecond))
1470
1471    def __hash__(self):
1472        """Hash."""
1473        if self._hashcode == -1:
1474            if self.fold:
1475                t = self.replace(fold=0)
1476            else:
1477                t = self
1478            tzoff = t.utcoffset()
1479            if not tzoff:  # zero or None
1480                self._hashcode = hash(t._getstate()[0])
1481            else:
1482                h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1483                              timedelta(hours=1))
1484                assert not m % timedelta(minutes=1), "whole minute"
1485                m //= timedelta(minutes=1)
1486                if 0 <= h < 24:
1487                    self._hashcode = hash(time(h, m, self.second, self.microsecond))
1488                else:
1489                    self._hashcode = hash((h, m, self.second, self.microsecond))
1490        return self._hashcode
1491
1492    # Conversion to string
1493
1494    def _tzstr(self):
1495        """Return formatted timezone offset (+xx:xx) or an empty string."""
1496        off = self.utcoffset()
1497        return _format_offset(off)
1498
1499    def __repr__(self):
1500        """Convert to formal string, for repr()."""
1501        if self._microsecond != 0:
1502            s = ", %d, %d" % (self._second, self._microsecond)
1503        elif self._second != 0:
1504            s = ", %d" % self._second
1505        else:
1506            s = ""
1507        s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1508                                self.__class__.__qualname__,
1509                                self._hour, self._minute, s)
1510        if self._tzinfo is not None:
1511            assert s[-1:] == ")"
1512            s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
1513        if self._fold:
1514            assert s[-1:] == ")"
1515            s = s[:-1] + ", fold=1)"
1516        return s
1517
1518    def isoformat(self, timespec='auto'):
1519        """Return the time formatted according to ISO.
1520
1521        The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional
1522        part is omitted if self.microsecond == 0.
1523
1524        The optional argument timespec specifies the number of additional
1525        terms of the time to include. Valid options are 'auto', 'hours',
1526        'minutes', 'seconds', 'milliseconds' and 'microseconds'.
1527        """
1528        s = _format_time(self._hour, self._minute, self._second,
1529                          self._microsecond, timespec)
1530        tz = self._tzstr()
1531        if tz:
1532            s += tz
1533        return s
1534
1535    __str__ = isoformat
1536
1537    @classmethod
1538    def fromisoformat(cls, time_string):
1539        """Construct a time from a string in one of the ISO 8601 formats."""
1540        if not isinstance(time_string, str):
1541            raise TypeError('fromisoformat: argument must be str')
1542
1543        # The spec actually requires that time-only ISO 8601 strings start with
1544        # T, but the extended format allows this to be omitted as long as there
1545        # is no ambiguity with date strings.
1546        time_string = time_string.removeprefix('T')
1547
1548        try:
1549            return cls(*_parse_isoformat_time(time_string))
1550        except Exception:
1551            raise ValueError(f'Invalid isoformat string: {time_string!r}')
1552
1553
1554    def strftime(self, fmt):
1555        """Format using strftime().  The date part of the timestamp passed
1556        to underlying strftime should not be used.
1557        """
1558        # The year must be >= 1000 else Python's strftime implementation
1559        # can raise a bogus exception.
1560        timetuple = (1900, 1, 1,
1561                     self._hour, self._minute, self._second,
1562                     0, 1, -1)
1563        return _wrap_strftime(self, fmt, timetuple)
1564
1565    def __format__(self, fmt):
1566        if not isinstance(fmt, str):
1567            raise TypeError("must be str, not %s" % type(fmt).__name__)
1568        if len(fmt) != 0:
1569            return self.strftime(fmt)
1570        return str(self)
1571
1572    # Timezone functions
1573
1574    def utcoffset(self):
1575        """Return the timezone offset as timedelta, positive east of UTC
1576         (negative west of UTC)."""
1577        if self._tzinfo is None:
1578            return None
1579        offset = self._tzinfo.utcoffset(None)
1580        _check_utc_offset("utcoffset", offset)
1581        return offset
1582
1583    def tzname(self):
1584        """Return the timezone name.
1585
1586        Note that the name is 100% informational -- there's no requirement that
1587        it mean anything in particular. For example, "GMT", "UTC", "-500",
1588        "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1589        """
1590        if self._tzinfo is None:
1591            return None
1592        name = self._tzinfo.tzname(None)
1593        _check_tzname(name)
1594        return name
1595
1596    def dst(self):
1597        """Return 0 if DST is not in effect, or the DST offset (as timedelta
1598        positive eastward) if DST is in effect.
1599
1600        This is purely informational; the DST offset has already been added to
1601        the UTC offset returned by utcoffset() if applicable, so there's no
1602        need to consult dst() unless you're interested in displaying the DST
1603        info.
1604        """
1605        if self._tzinfo is None:
1606            return None
1607        offset = self._tzinfo.dst(None)
1608        _check_utc_offset("dst", offset)
1609        return offset
1610
1611    def replace(self, hour=None, minute=None, second=None, microsecond=None,
1612                tzinfo=True, *, fold=None):
1613        """Return a new time with new values for the specified fields."""
1614        if hour is None:
1615            hour = self.hour
1616        if minute is None:
1617            minute = self.minute
1618        if second is None:
1619            second = self.second
1620        if microsecond is None:
1621            microsecond = self.microsecond
1622        if tzinfo is True:
1623            tzinfo = self.tzinfo
1624        if fold is None:
1625            fold = self._fold
1626        return type(self)(hour, minute, second, microsecond, tzinfo, fold=fold)
1627
1628    # Pickle support.
1629
1630    def _getstate(self, protocol=3):
1631        us2, us3 = divmod(self._microsecond, 256)
1632        us1, us2 = divmod(us2, 256)
1633        h = self._hour
1634        if self._fold and protocol > 3:
1635            h += 128
1636        basestate = bytes([h, self._minute, self._second,
1637                           us1, us2, us3])
1638        if self._tzinfo is None:
1639            return (basestate,)
1640        else:
1641            return (basestate, self._tzinfo)
1642
1643    def __setstate(self, string, tzinfo):
1644        if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1645            raise TypeError("bad tzinfo state arg")
1646        h, self._minute, self._second, us1, us2, us3 = string
1647        if h > 127:
1648            self._fold = 1
1649            self._hour = h - 128
1650        else:
1651            self._fold = 0
1652            self._hour = h
1653        self._microsecond = (((us1 << 8) | us2) << 8) | us3
1654        self._tzinfo = tzinfo
1655
1656    def __reduce_ex__(self, protocol):
1657        return (self.__class__, self._getstate(protocol))
1658
1659    def __reduce__(self):
1660        return self.__reduce_ex__(2)
1661
1662_time_class = time  # so functions w/ args named "time" can get at the class
1663
1664time.min = time(0, 0, 0)
1665time.max = time(23, 59, 59, 999999)
1666time.resolution = timedelta(microseconds=1)
1667
1668
1669class datetime(date):
1670    """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1671
1672    The year, month and day arguments are required. tzinfo may be None, or an
1673    instance of a tzinfo subclass. The remaining arguments may be ints.
1674    """
1675    __slots__ = date.__slots__ + time.__slots__
1676
1677    def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
1678                microsecond=0, tzinfo=None, *, fold=0):
1679        if (isinstance(year, (bytes, str)) and len(year) == 10 and
1680            1 <= ord(year[2:3])&0x7F <= 12):
1681            # Pickle support
1682            if isinstance(year, str):
1683                try:
1684                    year = bytes(year, 'latin1')
1685                except UnicodeEncodeError:
1686                    # More informative error message.
1687                    raise ValueError(
1688                        "Failed to encode latin1 string when unpickling "
1689                        "a datetime object. "
1690                        "pickle.load(data, encoding='latin1') is assumed.")
1691            self = object.__new__(cls)
1692            self.__setstate(year, month)
1693            self._hashcode = -1
1694            return self
1695        year, month, day = _check_date_fields(year, month, day)
1696        hour, minute, second, microsecond, fold = _check_time_fields(
1697            hour, minute, second, microsecond, fold)
1698        _check_tzinfo_arg(tzinfo)
1699        self = object.__new__(cls)
1700        self._year = year
1701        self._month = month
1702        self._day = day
1703        self._hour = hour
1704        self._minute = minute
1705        self._second = second
1706        self._microsecond = microsecond
1707        self._tzinfo = tzinfo
1708        self._hashcode = -1
1709        self._fold = fold
1710        return self
1711
1712    # Read-only field accessors
1713    @property
1714    def hour(self):
1715        """hour (0-23)"""
1716        return self._hour
1717
1718    @property
1719    def minute(self):
1720        """minute (0-59)"""
1721        return self._minute
1722
1723    @property
1724    def second(self):
1725        """second (0-59)"""
1726        return self._second
1727
1728    @property
1729    def microsecond(self):
1730        """microsecond (0-999999)"""
1731        return self._microsecond
1732
1733    @property
1734    def tzinfo(self):
1735        """timezone info object"""
1736        return self._tzinfo
1737
1738    @property
1739    def fold(self):
1740        return self._fold
1741
1742    @classmethod
1743    def _fromtimestamp(cls, t, utc, tz):
1744        """Construct a datetime from a POSIX timestamp (like time.time()).
1745
1746        A timezone info object may be passed in as well.
1747        """
1748        frac, t = _math.modf(t)
1749        us = round(frac * 1e6)
1750        if us >= 1000000:
1751            t += 1
1752            us -= 1000000
1753        elif us < 0:
1754            t -= 1
1755            us += 1000000
1756
1757        converter = _time.gmtime if utc else _time.localtime
1758        y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1759        ss = min(ss, 59)    # clamp out leap seconds if the platform has them
1760        result = cls(y, m, d, hh, mm, ss, us, tz)
1761        if tz is None and not utc:
1762            # As of version 2015f max fold in IANA database is
1763            # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
1764            # Let's probe 24 hours in the past to detect a transition:
1765            max_fold_seconds = 24 * 3600
1766
1767            # On Windows localtime_s throws an OSError for negative values,
1768            # thus we can't perform fold detection for values of time less
1769            # than the max time fold. See comments in _datetimemodule's
1770            # version of this method for more details.
1771            if t < max_fold_seconds and sys.platform.startswith("win"):
1772                return result
1773
1774            y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1775            probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1776            trans = result - probe1 - timedelta(0, max_fold_seconds)
1777            if trans.days < 0:
1778                y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
1779                probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1780                if probe2 == result:
1781                    result._fold = 1
1782        elif tz is not None:
1783            result = tz.fromutc(result)
1784        return result
1785
1786    @classmethod
1787    def fromtimestamp(cls, t, tz=None):
1788        """Construct a datetime from a POSIX timestamp (like time.time()).
1789
1790        A timezone info object may be passed in as well.
1791        """
1792        _check_tzinfo_arg(tz)
1793
1794        return cls._fromtimestamp(t, tz is not None, tz)
1795
1796    @classmethod
1797    def utcfromtimestamp(cls, t):
1798        """Construct a naive UTC datetime from a POSIX timestamp."""
1799        return cls._fromtimestamp(t, True, None)
1800
1801    @classmethod
1802    def now(cls, tz=None):
1803        "Construct a datetime from time.time() and optional time zone info."
1804        t = _time.time()
1805        return cls.fromtimestamp(t, tz)
1806
1807    @classmethod
1808    def utcnow(cls):
1809        "Construct a UTC datetime from time.time()."
1810        t = _time.time()
1811        return cls.utcfromtimestamp(t)
1812
1813    @classmethod
1814    def combine(cls, date, time, tzinfo=True):
1815        "Construct a datetime from a given date and a given time."
1816        if not isinstance(date, _date_class):
1817            raise TypeError("date argument must be a date instance")
1818        if not isinstance(time, _time_class):
1819            raise TypeError("time argument must be a time instance")
1820        if tzinfo is True:
1821            tzinfo = time.tzinfo
1822        return cls(date.year, date.month, date.day,
1823                   time.hour, time.minute, time.second, time.microsecond,
1824                   tzinfo, fold=time.fold)
1825
1826    @classmethod
1827    def fromisoformat(cls, date_string):
1828        """Construct a datetime from a string in one of the ISO 8601 formats."""
1829        if not isinstance(date_string, str):
1830            raise TypeError('fromisoformat: argument must be str')
1831
1832        if len(date_string) < 7:
1833            raise ValueError(f'Invalid isoformat string: {date_string!r}')
1834
1835        # Split this at the separator
1836        try:
1837            separator_location = _find_isoformat_datetime_separator(date_string)
1838            dstr = date_string[0:separator_location]
1839            tstr = date_string[(separator_location+1):]
1840
1841            date_components = _parse_isoformat_date(dstr)
1842        except ValueError:
1843            raise ValueError(
1844                f'Invalid isoformat string: {date_string!r}') from None
1845
1846        if tstr:
1847            try:
1848                time_components = _parse_isoformat_time(tstr)
1849            except ValueError:
1850                raise ValueError(
1851                    f'Invalid isoformat string: {date_string!r}') from None
1852        else:
1853            time_components = [0, 0, 0, 0, None]
1854
1855        return cls(*(date_components + time_components))
1856
1857    def timetuple(self):
1858        "Return local time tuple compatible with time.localtime()."
1859        dst = self.dst()
1860        if dst is None:
1861            dst = -1
1862        elif dst:
1863            dst = 1
1864        else:
1865            dst = 0
1866        return _build_struct_time(self.year, self.month, self.day,
1867                                  self.hour, self.minute, self.second,
1868                                  dst)
1869
1870    def _mktime(self):
1871        """Return integer POSIX timestamp."""
1872        epoch = datetime(1970, 1, 1)
1873        max_fold_seconds = 24 * 3600
1874        t = (self - epoch) // timedelta(0, 1)
1875        def local(u):
1876            y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1877            return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1878
1879        # Our goal is to solve t = local(u) for u.
1880        a = local(t) - t
1881        u1 = t - a
1882        t1 = local(u1)
1883        if t1 == t:
1884            # We found one solution, but it may not be the one we need.
1885            # Look for an earlier solution (if `fold` is 0), or a
1886            # later one (if `fold` is 1).
1887            u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1888            b = local(u2) - u2
1889            if a == b:
1890                return u1
1891        else:
1892            b = t1 - u1
1893            assert a != b
1894        u2 = t - b
1895        t2 = local(u2)
1896        if t2 == t:
1897            return u2
1898        if t1 == t:
1899            return u1
1900        # We have found both offsets a and b, but neither t - a nor t - b is
1901        # a solution.  This means t is in the gap.
1902        return (max, min)[self.fold](u1, u2)
1903
1904
1905    def timestamp(self):
1906        "Return POSIX timestamp as float"
1907        if self._tzinfo is None:
1908            s = self._mktime()
1909            return s + self.microsecond / 1e6
1910        else:
1911            return (self - _EPOCH).total_seconds()
1912
1913    def utctimetuple(self):
1914        "Return UTC time tuple compatible with time.gmtime()."
1915        offset = self.utcoffset()
1916        if offset:
1917            self -= offset
1918        y, m, d = self.year, self.month, self.day
1919        hh, mm, ss = self.hour, self.minute, self.second
1920        return _build_struct_time(y, m, d, hh, mm, ss, 0)
1921
1922    def date(self):
1923        "Return the date part."
1924        return date(self._year, self._month, self._day)
1925
1926    def time(self):
1927        "Return the time part, with tzinfo None."
1928        return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
1929
1930    def timetz(self):
1931        "Return the time part, with same tzinfo."
1932        return time(self.hour, self.minute, self.second, self.microsecond,
1933                    self._tzinfo, fold=self.fold)
1934
1935    def replace(self, year=None, month=None, day=None, hour=None,
1936                minute=None, second=None, microsecond=None, tzinfo=True,
1937                *, fold=None):
1938        """Return a new datetime with new values for the specified fields."""
1939        if year is None:
1940            year = self.year
1941        if month is None:
1942            month = self.month
1943        if day is None:
1944            day = self.day
1945        if hour is None:
1946            hour = self.hour
1947        if minute is None:
1948            minute = self.minute
1949        if second is None:
1950            second = self.second
1951        if microsecond is None:
1952            microsecond = self.microsecond
1953        if tzinfo is True:
1954            tzinfo = self.tzinfo
1955        if fold is None:
1956            fold = self.fold
1957        return type(self)(year, month, day, hour, minute, second,
1958                          microsecond, tzinfo, fold=fold)
1959
1960    def _local_timezone(self):
1961        if self.tzinfo is None:
1962            ts = self._mktime()
1963        else:
1964            ts = (self - _EPOCH) // timedelta(seconds=1)
1965        localtm = _time.localtime(ts)
1966        local = datetime(*localtm[:6])
1967        # Extract TZ data
1968        gmtoff = localtm.tm_gmtoff
1969        zone = localtm.tm_zone
1970        return timezone(timedelta(seconds=gmtoff), zone)
1971
1972    def astimezone(self, tz=None):
1973        if tz is None:
1974            tz = self._local_timezone()
1975        elif not isinstance(tz, tzinfo):
1976            raise TypeError("tz argument must be an instance of tzinfo")
1977
1978        mytz = self.tzinfo
1979        if mytz is None:
1980            mytz = self._local_timezone()
1981            myoffset = mytz.utcoffset(self)
1982        else:
1983            myoffset = mytz.utcoffset(self)
1984            if myoffset is None:
1985                mytz = self.replace(tzinfo=None)._local_timezone()
1986                myoffset = mytz.utcoffset(self)
1987
1988        if tz is mytz:
1989            return self
1990
1991        # Convert self to UTC, and attach the new time zone object.
1992        utc = (self - myoffset).replace(tzinfo=tz)
1993
1994        # Convert from UTC to tz's local time.
1995        return tz.fromutc(utc)
1996
1997    # Ways to produce a string.
1998
1999    def ctime(self):
2000        "Return ctime() style string."
2001        weekday = self.toordinal() % 7 or 7
2002        return "%s %s %2d %02d:%02d:%02d %04d" % (
2003            _DAYNAMES[weekday],
2004            _MONTHNAMES[self._month],
2005            self._day,
2006            self._hour, self._minute, self._second,
2007            self._year)
2008
2009    def isoformat(self, sep='T', timespec='auto'):
2010        """Return the time formatted according to ISO.
2011
2012        The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
2013        By default, the fractional part is omitted if self.microsecond == 0.
2014
2015        If self.tzinfo is not None, the UTC offset is also attached, giving
2016        giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
2017
2018        Optional argument sep specifies the separator between date and
2019        time, default 'T'.
2020
2021        The optional argument timespec specifies the number of additional
2022        terms of the time to include. Valid options are 'auto', 'hours',
2023        'minutes', 'seconds', 'milliseconds' and 'microseconds'.
2024        """
2025        s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
2026             _format_time(self._hour, self._minute, self._second,
2027                          self._microsecond, timespec))
2028
2029        off = self.utcoffset()
2030        tz = _format_offset(off)
2031        if tz:
2032            s += tz
2033
2034        return s
2035
2036    def __repr__(self):
2037        """Convert to formal string, for repr()."""
2038        L = [self._year, self._month, self._day,  # These are never zero
2039             self._hour, self._minute, self._second, self._microsecond]
2040        if L[-1] == 0:
2041            del L[-1]
2042        if L[-1] == 0:
2043            del L[-1]
2044        s = "%s.%s(%s)" % (self.__class__.__module__,
2045                           self.__class__.__qualname__,
2046                           ", ".join(map(str, L)))
2047        if self._tzinfo is not None:
2048            assert s[-1:] == ")"
2049            s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
2050        if self._fold:
2051            assert s[-1:] == ")"
2052            s = s[:-1] + ", fold=1)"
2053        return s
2054
2055    def __str__(self):
2056        "Convert to string, for str()."
2057        return self.isoformat(sep=' ')
2058
2059    @classmethod
2060    def strptime(cls, date_string, format):
2061        'string, format -> new datetime parsed from a string (like time.strptime()).'
2062        import _strptime
2063        return _strptime._strptime_datetime(cls, date_string, format)
2064
2065    def utcoffset(self):
2066        """Return the timezone offset as timedelta positive east of UTC (negative west of
2067        UTC)."""
2068        if self._tzinfo is None:
2069            return None
2070        offset = self._tzinfo.utcoffset(self)
2071        _check_utc_offset("utcoffset", offset)
2072        return offset
2073
2074    def tzname(self):
2075        """Return the timezone name.
2076
2077        Note that the name is 100% informational -- there's no requirement that
2078        it mean anything in particular. For example, "GMT", "UTC", "-500",
2079        "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
2080        """
2081        if self._tzinfo is None:
2082            return None
2083        name = self._tzinfo.tzname(self)
2084        _check_tzname(name)
2085        return name
2086
2087    def dst(self):
2088        """Return 0 if DST is not in effect, or the DST offset (as timedelta
2089        positive eastward) if DST is in effect.
2090
2091        This is purely informational; the DST offset has already been added to
2092        the UTC offset returned by utcoffset() if applicable, so there's no
2093        need to consult dst() unless you're interested in displaying the DST
2094        info.
2095        """
2096        if self._tzinfo is None:
2097            return None
2098        offset = self._tzinfo.dst(self)
2099        _check_utc_offset("dst", offset)
2100        return offset
2101
2102    # Comparisons of datetime objects with other.
2103
2104    def __eq__(self, other):
2105        if isinstance(other, datetime):
2106            return self._cmp(other, allow_mixed=True) == 0
2107        elif not isinstance(other, date):
2108            return NotImplemented
2109        else:
2110            return False
2111
2112    def __le__(self, other):
2113        if isinstance(other, datetime):
2114            return self._cmp(other) <= 0
2115        elif not isinstance(other, date):
2116            return NotImplemented
2117        else:
2118            _cmperror(self, other)
2119
2120    def __lt__(self, other):
2121        if isinstance(other, datetime):
2122            return self._cmp(other) < 0
2123        elif not isinstance(other, date):
2124            return NotImplemented
2125        else:
2126            _cmperror(self, other)
2127
2128    def __ge__(self, other):
2129        if isinstance(other, datetime):
2130            return self._cmp(other) >= 0
2131        elif not isinstance(other, date):
2132            return NotImplemented
2133        else:
2134            _cmperror(self, other)
2135
2136    def __gt__(self, other):
2137        if isinstance(other, datetime):
2138            return self._cmp(other) > 0
2139        elif not isinstance(other, date):
2140            return NotImplemented
2141        else:
2142            _cmperror(self, other)
2143
2144    def _cmp(self, other, allow_mixed=False):
2145        assert isinstance(other, datetime)
2146        mytz = self._tzinfo
2147        ottz = other._tzinfo
2148        myoff = otoff = None
2149
2150        if mytz is ottz:
2151            base_compare = True
2152        else:
2153            myoff = self.utcoffset()
2154            otoff = other.utcoffset()
2155            # Assume that allow_mixed means that we are called from __eq__
2156            if allow_mixed:
2157                if myoff != self.replace(fold=not self.fold).utcoffset():
2158                    return 2
2159                if otoff != other.replace(fold=not other.fold).utcoffset():
2160                    return 2
2161            base_compare = myoff == otoff
2162
2163        if base_compare:
2164            return _cmp((self._year, self._month, self._day,
2165                         self._hour, self._minute, self._second,
2166                         self._microsecond),
2167                        (other._year, other._month, other._day,
2168                         other._hour, other._minute, other._second,
2169                         other._microsecond))
2170        if myoff is None or otoff is None:
2171            if allow_mixed:
2172                return 2 # arbitrary non-zero value
2173            else:
2174                raise TypeError("cannot compare naive and aware datetimes")
2175        # XXX What follows could be done more efficiently...
2176        diff = self - other     # this will take offsets into account
2177        if diff.days < 0:
2178            return -1
2179        return diff and 1 or 0
2180
2181    def __add__(self, other):
2182        "Add a datetime and a timedelta."
2183        if not isinstance(other, timedelta):
2184            return NotImplemented
2185        delta = timedelta(self.toordinal(),
2186                          hours=self._hour,
2187                          minutes=self._minute,
2188                          seconds=self._second,
2189                          microseconds=self._microsecond)
2190        delta += other
2191        hour, rem = divmod(delta.seconds, 3600)
2192        minute, second = divmod(rem, 60)
2193        if 0 < delta.days <= _MAXORDINAL:
2194            return type(self).combine(date.fromordinal(delta.days),
2195                                      time(hour, minute, second,
2196                                           delta.microseconds,
2197                                           tzinfo=self._tzinfo))
2198        raise OverflowError("result out of range")
2199
2200    __radd__ = __add__
2201
2202    def __sub__(self, other):
2203        "Subtract two datetimes, or a datetime and a timedelta."
2204        if not isinstance(other, datetime):
2205            if isinstance(other, timedelta):
2206                return self + -other
2207            return NotImplemented
2208
2209        days1 = self.toordinal()
2210        days2 = other.toordinal()
2211        secs1 = self._second + self._minute * 60 + self._hour * 3600
2212        secs2 = other._second + other._minute * 60 + other._hour * 3600
2213        base = timedelta(days1 - days2,
2214                         secs1 - secs2,
2215                         self._microsecond - other._microsecond)
2216        if self._tzinfo is other._tzinfo:
2217            return base
2218        myoff = self.utcoffset()
2219        otoff = other.utcoffset()
2220        if myoff == otoff:
2221            return base
2222        if myoff is None or otoff is None:
2223            raise TypeError("cannot mix naive and timezone-aware time")
2224        return base + otoff - myoff
2225
2226    def __hash__(self):
2227        if self._hashcode == -1:
2228            if self.fold:
2229                t = self.replace(fold=0)
2230            else:
2231                t = self
2232            tzoff = t.utcoffset()
2233            if tzoff is None:
2234                self._hashcode = hash(t._getstate()[0])
2235            else:
2236                days = _ymd2ord(self.year, self.month, self.day)
2237                seconds = self.hour * 3600 + self.minute * 60 + self.second
2238                self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
2239        return self._hashcode
2240
2241    # Pickle support.
2242
2243    def _getstate(self, protocol=3):
2244        yhi, ylo = divmod(self._year, 256)
2245        us2, us3 = divmod(self._microsecond, 256)
2246        us1, us2 = divmod(us2, 256)
2247        m = self._month
2248        if self._fold and protocol > 3:
2249            m += 128
2250        basestate = bytes([yhi, ylo, m, self._day,
2251                           self._hour, self._minute, self._second,
2252                           us1, us2, us3])
2253        if self._tzinfo is None:
2254            return (basestate,)
2255        else:
2256            return (basestate, self._tzinfo)
2257
2258    def __setstate(self, string, tzinfo):
2259        if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
2260            raise TypeError("bad tzinfo state arg")
2261        (yhi, ylo, m, self._day, self._hour,
2262         self._minute, self._second, us1, us2, us3) = string
2263        if m > 127:
2264            self._fold = 1
2265            self._month = m - 128
2266        else:
2267            self._fold = 0
2268            self._month = m
2269        self._year = yhi * 256 + ylo
2270        self._microsecond = (((us1 << 8) | us2) << 8) | us3
2271        self._tzinfo = tzinfo
2272
2273    def __reduce_ex__(self, protocol):
2274        return (self.__class__, self._getstate(protocol))
2275
2276    def __reduce__(self):
2277        return self.__reduce_ex__(2)
2278
2279
2280datetime.min = datetime(1, 1, 1)
2281datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
2282datetime.resolution = timedelta(microseconds=1)
2283
2284
2285def _isoweek1monday(year):
2286    # Helper to calculate the day number of the Monday starting week 1
2287    # XXX This could be done more efficiently
2288    THURSDAY = 3
2289    firstday = _ymd2ord(year, 1, 1)
2290    firstweekday = (firstday + 6) % 7  # See weekday() above
2291    week1monday = firstday - firstweekday
2292    if firstweekday > THURSDAY:
2293        week1monday += 7
2294    return week1monday
2295
2296
2297class timezone(tzinfo):
2298    __slots__ = '_offset', '_name'
2299
2300    # Sentinel value to disallow None
2301    _Omitted = object()
2302    def __new__(cls, offset, name=_Omitted):
2303        if not isinstance(offset, timedelta):
2304            raise TypeError("offset must be a timedelta")
2305        if name is cls._Omitted:
2306            if not offset:
2307                return cls.utc
2308            name = None
2309        elif not isinstance(name, str):
2310            raise TypeError("name must be a string")
2311        if not cls._minoffset <= offset <= cls._maxoffset:
2312            raise ValueError("offset must be a timedelta "
2313                             "strictly between -timedelta(hours=24) and "
2314                             "timedelta(hours=24).")
2315        return cls._create(offset, name)
2316
2317    @classmethod
2318    def _create(cls, offset, name=None):
2319        self = tzinfo.__new__(cls)
2320        self._offset = offset
2321        self._name = name
2322        return self
2323
2324    def __getinitargs__(self):
2325        """pickle support"""
2326        if self._name is None:
2327            return (self._offset,)
2328        return (self._offset, self._name)
2329
2330    def __eq__(self, other):
2331        if isinstance(other, timezone):
2332            return self._offset == other._offset
2333        return NotImplemented
2334
2335    def __hash__(self):
2336        return hash(self._offset)
2337
2338    def __repr__(self):
2339        """Convert to formal string, for repr().
2340
2341        >>> tz = timezone.utc
2342        >>> repr(tz)
2343        'datetime.timezone.utc'
2344        >>> tz = timezone(timedelta(hours=-5), 'EST')
2345        >>> repr(tz)
2346        "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
2347        """
2348        if self is self.utc:
2349            return 'datetime.timezone.utc'
2350        if self._name is None:
2351            return "%s.%s(%r)" % (self.__class__.__module__,
2352                                  self.__class__.__qualname__,
2353                                  self._offset)
2354        return "%s.%s(%r, %r)" % (self.__class__.__module__,
2355                                  self.__class__.__qualname__,
2356                                  self._offset, self._name)
2357
2358    def __str__(self):
2359        return self.tzname(None)
2360
2361    def utcoffset(self, dt):
2362        if isinstance(dt, datetime) or dt is None:
2363            return self._offset
2364        raise TypeError("utcoffset() argument must be a datetime instance"
2365                        " or None")
2366
2367    def tzname(self, dt):
2368        if isinstance(dt, datetime) or dt is None:
2369            if self._name is None:
2370                return self._name_from_offset(self._offset)
2371            return self._name
2372        raise TypeError("tzname() argument must be a datetime instance"
2373                        " or None")
2374
2375    def dst(self, dt):
2376        if isinstance(dt, datetime) or dt is None:
2377            return None
2378        raise TypeError("dst() argument must be a datetime instance"
2379                        " or None")
2380
2381    def fromutc(self, dt):
2382        if isinstance(dt, datetime):
2383            if dt.tzinfo is not self:
2384                raise ValueError("fromutc: dt.tzinfo "
2385                                 "is not self")
2386            return dt + self._offset
2387        raise TypeError("fromutc() argument must be a datetime instance"
2388                        " or None")
2389
2390    _maxoffset = timedelta(hours=24, microseconds=-1)
2391    _minoffset = -_maxoffset
2392
2393    @staticmethod
2394    def _name_from_offset(delta):
2395        if not delta:
2396            return 'UTC'
2397        if delta < timedelta(0):
2398            sign = '-'
2399            delta = -delta
2400        else:
2401            sign = '+'
2402        hours, rest = divmod(delta, timedelta(hours=1))
2403        minutes, rest = divmod(rest, timedelta(minutes=1))
2404        seconds = rest.seconds
2405        microseconds = rest.microseconds
2406        if microseconds:
2407            return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2408                    f'.{microseconds:06d}')
2409        if seconds:
2410            return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2411        return f'UTC{sign}{hours:02d}:{minutes:02d}'
2412
2413UTC = timezone.utc = timezone._create(timedelta(0))
2414
2415# bpo-37642: These attributes are rounded to the nearest minute for backwards
2416# compatibility, even though the constructor will accept a wider range of
2417# values. This may change in the future.
2418timezone.min = timezone._create(-timedelta(hours=23, minutes=59))
2419timezone.max = timezone._create(timedelta(hours=23, minutes=59))
2420_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
2421
2422# Some time zone algebra.  For a datetime x, let
2423#     x.n = x stripped of its timezone -- its naive time.
2424#     x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2425#           return None
2426#     x.d = x.dst(), and assuming that doesn't raise an exception or
2427#           return None
2428#     x.s = x's standard offset, x.o - x.d
2429#
2430# Now some derived rules, where k is a duration (timedelta).
2431#
2432# 1. x.o = x.s + x.d
2433#    This follows from the definition of x.s.
2434#
2435# 2. If x and y have the same tzinfo member, x.s = y.s.
2436#    This is actually a requirement, an assumption we need to make about
2437#    sane tzinfo classes.
2438#
2439# 3. The naive UTC time corresponding to x is x.n - x.o.
2440#    This is again a requirement for a sane tzinfo class.
2441#
2442# 4. (x+k).s = x.s
2443#    This follows from #2, and that datetime.timetz+timedelta preserves tzinfo.
2444#
2445# 5. (x+k).n = x.n + k
2446#    Again follows from how arithmetic is defined.
2447#
2448# Now we can explain tz.fromutc(x).  Let's assume it's an interesting case
2449# (meaning that the various tzinfo methods exist, and don't blow up or return
2450# None when called).
2451#
2452# The function wants to return a datetime y with timezone tz, equivalent to x.
2453# x is already in UTC.
2454#
2455# By #3, we want
2456#
2457#     y.n - y.o = x.n                             [1]
2458#
2459# The algorithm starts by attaching tz to x.n, and calling that y.  So
2460# x.n = y.n at the start.  Then it wants to add a duration k to y, so that [1]
2461# becomes true; in effect, we want to solve [2] for k:
2462#
2463#    (y+k).n - (y+k).o = x.n                      [2]
2464#
2465# By #1, this is the same as
2466#
2467#    (y+k).n - ((y+k).s + (y+k).d) = x.n          [3]
2468#
2469# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2470# Substituting that into [3],
2471#
2472#    x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2473#    k - (y+k).s - (y+k).d = 0; rearranging,
2474#    k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2475#    k = y.s - (y+k).d
2476#
2477# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2478# approximate k by ignoring the (y+k).d term at first.  Note that k can't be
2479# very large, since all offset-returning methods return a duration of magnitude
2480# less than 24 hours.  For that reason, if y is firmly in std time, (y+k).d must
2481# be 0, so ignoring it has no consequence then.
2482#
2483# In any case, the new value is
2484#
2485#     z = y + y.s                                 [4]
2486#
2487# It's helpful to step back at look at [4] from a higher level:  it's simply
2488# mapping from UTC to tz's standard time.
2489#
2490# At this point, if
2491#
2492#     z.n - z.o = x.n                             [5]
2493#
2494# we have an equivalent time, and are almost done.  The insecurity here is
2495# at the start of daylight time.  Picture US Eastern for concreteness.  The wall
2496# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2497# sense then.  The docs ask that an Eastern tzinfo class consider such a time to
2498# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2499# on the day DST starts.  We want to return the 1:MM EST spelling because that's
2500# the only spelling that makes sense on the local wall clock.
2501#
2502# In fact, if [5] holds at this point, we do have the standard-time spelling,
2503# but that takes a bit of proof.  We first prove a stronger result.  What's the
2504# difference between the LHS and RHS of [5]?  Let
2505#
2506#     diff = x.n - (z.n - z.o)                    [6]
2507#
2508# Now
2509#     z.n =                       by [4]
2510#     (y + y.s).n =               by #5
2511#     y.n + y.s =                 since y.n = x.n
2512#     x.n + y.s =                 since z and y are have the same tzinfo member,
2513#                                     y.s = z.s by #2
2514#     x.n + z.s
2515#
2516# Plugging that back into [6] gives
2517#
2518#     diff =
2519#     x.n - ((x.n + z.s) - z.o) =     expanding
2520#     x.n - x.n - z.s + z.o =         cancelling
2521#     - z.s + z.o =                   by #2
2522#     z.d
2523#
2524# So diff = z.d.
2525#
2526# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2527# spelling we wanted in the endcase described above.  We're done.  Contrarily,
2528# if z.d = 0, then we have a UTC equivalent, and are also done.
2529#
2530# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2531# add to z (in effect, z is in tz's standard time, and we need to shift the
2532# local clock into tz's daylight time).
2533#
2534# Let
2535#
2536#     z' = z + z.d = z + diff                     [7]
2537#
2538# and we can again ask whether
2539#
2540#     z'.n - z'.o = x.n                           [8]
2541#
2542# If so, we're done.  If not, the tzinfo class is insane, according to the
2543# assumptions we've made.  This also requires a bit of proof.  As before, let's
2544# compute the difference between the LHS and RHS of [8] (and skipping some of
2545# the justifications for the kinds of substitutions we've done several times
2546# already):
2547#
2548#     diff' = x.n - (z'.n - z'.o) =           replacing z'.n via [7]
2549#             x.n  - (z.n + diff - z'.o) =    replacing diff via [6]
2550#             x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2551#             x.n - z.n - x.n + z.n - z.o + z'.o =    cancel x.n
2552#             - z.n + z.n - z.o + z'.o =              cancel z.n
2553#             - z.o + z'.o =                      #1 twice
2554#             -z.s - z.d + z'.s + z'.d =          z and z' have same tzinfo
2555#             z'.d - z.d
2556#
2557# So z' is UTC-equivalent to x iff z'.d = z.d at this point.  If they are equal,
2558# we've found the UTC-equivalent so are done.  In fact, we stop with [7] and
2559# return z', not bothering to compute z'.d.
2560#
2561# How could z.d and z'd differ?  z' = z + z.d [7], so merely moving z' by
2562# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2563# would have to change the result dst() returns:  we start in DST, and moving
2564# a little further into it takes us out of DST.
2565#
2566# There isn't a sane case where this can happen.  The closest it gets is at
2567# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2568# tzinfo class.  In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT.  During
2569# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2570# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2571# time (4:MM UTC).  There is no local time mapping to 5:MM UTC.  The local
2572# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2573# standard time.  Since that's what the local clock *does*, we want to map both
2574# UTC hours 5:MM and 6:MM to 1:MM Eastern.  The result is ambiguous
2575# in local time, but so it goes -- it's the way the local clock works.
2576#
2577# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2578# so z=0:MM.  z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2579# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2580# (correctly) concludes that z' is not UTC-equivalent to x.
2581#
2582# Because we know z.d said z was in daylight time (else [5] would have held and
2583# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2584# and we have stopped then), and there are only 2 possible values dst() can
2585# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2586# but the reasoning doesn't depend on the example -- it depends on there being
2587# two possible dst() outcomes, one zero and the other non-zero).  Therefore
2588# z' must be in standard time, and is the spelling we want in this case.
2589#
2590# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2591# concerned (because it takes z' as being in standard time rather than the
2592# daylight time we intend here), but returning it gives the real-life "local
2593# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2594# tz.
2595#
2596# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2597# the 1:MM standard time spelling we want.
2598#
2599# So how can this break?  One of the assumptions must be violated.  Two
2600# possibilities:
2601#
2602# 1) [2] effectively says that y.s is invariant across all y belong to a given
2603#    time zone.  This isn't true if, for political reasons or continental drift,
2604#    a region decides to change its base offset from UTC.
2605#
2606# 2) There may be versions of "double daylight" time where the tail end of
2607#    the analysis gives up a step too early.  I haven't thought about that
2608#    enough to say.
2609#
2610# In any case, it's clear that the default fromutc() is strong enough to handle
2611# "almost all" time zones:  so long as the standard offset is invariant, it
2612# doesn't matter if daylight time transition points change from year to year, or
2613# if daylight time is skipped in some years; it doesn't matter how large or
2614# small dst() may get within its bounds; and it doesn't even matter if some
2615# perverse time zone returns a negative dst()).  So a breaking case must be
2616# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
2617
2618try:
2619    from _datetime import *
2620except ImportError:
2621    pass
2622else:
2623    # Clean up unused names
2624    del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2625         _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2626         _check_date_fields, _check_time_fields,
2627         _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2628         _date_class, _days_before_month, _days_before_year, _days_in_month,
2629         _format_time, _format_offset, _index, _is_leap, _isoweek1monday, _math,
2630         _ord2ymd, _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord,
2631         _divide_and_round, _parse_isoformat_date, _parse_isoformat_time,
2632         _parse_hh_mm_ss_ff, _IsoCalendarDate, _isoweek_to_gregorian,
2633         _find_isoformat_datetime_separator, _FRACTION_CORRECTION,
2634         _is_ascii_digit)
2635    # XXX Since import * above excludes names that start with _,
2636    # docstring does not get overwritten. In the future, it may be
2637    # appropriate to maintain a single module level docstring and
2638    # remove the following line.
2639    from _datetime import __doc__
2640