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