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