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