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