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