github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/third_party/pypy/datetime.py (about)

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