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