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