1"""Concrete date/time and related types.
2
3See http://www.iana.org/time-zones/repository/tz-link.html for
4time zone and DST data sources.
5"""
6
7import time as _time
8import math as _math
9
10def _cmp(x, y):
11    return 0 if x == y else 1 if x > y else -1
12
13MINYEAR = 1
14MAXYEAR = 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.
30dbm = 0
31for dim in _DAYS_IN_MONTH[1:]:
32    _DAYS_BEFORE_MONTH.append(dbm)
33    dbm += dim
34del dbm, dim
35
36def _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
40def _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
45def _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
52def _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
57def _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.
72assert _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.
76assert _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.
80assert _DI100Y == 25 * _DI4Y - 1
81
82def _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
150def _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
155def _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.
177def _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.
235def _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.
246def _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
261def _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
278def _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
291def _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
308def _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
312def _cmperror(x, y):
313    raise TypeError("can't compare '%s' to '%s'" % (
314                    type(x).__name__, type(y).__name__))
315
316def _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
336class 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
653timedelta.min = timedelta(-999999999)
654timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
655                          microseconds=999999)
656timedelta.resolution = timedelta(microseconds=1)
657
658class 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
948date.min = date(1, 1, 1)
949date.max = date(9999, 12, 31)
950date.resolution = timedelta(days=1)
951
952
953class 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
1023class 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
1356time.min = time(0, 0, 0)
1357time.max = time(23, 59, 59, 999999)
1358time.resolution = timedelta(microseconds=1)
1359
1360class 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
1933datetime.min = datetime(1, 1, 1)
1934datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1935datetime.resolution = timedelta(microseconds=1)
1936
1937
1938def _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
1949class 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
2061timezone.utc = timezone._create(timedelta(0))
2062timezone.min = timezone._create(timezone._minoffset)
2063timezone.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
2262try:
2263    from _datetime import *
2264except ImportError:
2265    pass
2266else:
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