| 
									
										
										
										
											2010-07-23 19:25:47 +00:00
										 |  |  | """Concrete date/time and related types -- prototype implemented in Python.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | See http://www.zope.org/Members/fdrake/DateTimeWiki/FrontPage | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | See also http://dir.yahoo.com/Reference/calendars/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For a primer on DST, including many current DST rules, see | 
					
						
							|  |  |  | http://webexhibits.org/daylightsaving/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For more about DST than you ever wanted to know, see | 
					
						
							|  |  |  | ftp://elsie.nci.nih.gov/pub/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Sources for time zone and DST data: http://www.twinsun.com/tz/tz-link.htm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This was originally copied from the sandbox of the CPython CVS repository. | 
					
						
							|  |  |  | Thanks to Tim Peters for suggesting using it. | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import time as _time | 
					
						
							|  |  |  | import math as _math | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _cmp(x, y): | 
					
						
							|  |  |  |     return 0 if x == y else 1 if x > y else -1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MINYEAR = 1 | 
					
						
							|  |  |  | MAXYEAR = 9999 | 
					
						
							|  |  |  | _MAXORDINAL = 3652059 # date.max.toordinal() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Utility functions, adapted from Python's Demo/classes/Dates.py, which | 
					
						
							|  |  |  | # also assumes the current Gregorian calendar indefinitely extended in | 
					
						
							|  |  |  | # both directions.  Difference:  Dates.py calls January 1 of year 0 day | 
					
						
							|  |  |  | # number 1.  The code here calls January 1 of year 1 day number 1.  This is | 
					
						
							|  |  |  | # to match the definition of the "proleptic Gregorian" calendar in Dershowitz | 
					
						
							|  |  |  | # and Reingold's "Calendrical Calculations", where it's the base calendar | 
					
						
							|  |  |  | # for all computations.  See the book for algorithms for converting between | 
					
						
							|  |  |  | # proleptic Gregorian ordinals and many other calendar systems. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _DAYS_IN_MONTH = [None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _DAYS_BEFORE_MONTH = [None] | 
					
						
							|  |  |  | dbm = 0 | 
					
						
							|  |  |  | for dim in _DAYS_IN_MONTH[1:]: | 
					
						
							|  |  |  |     _DAYS_BEFORE_MONTH.append(dbm) | 
					
						
							|  |  |  |     dbm += dim | 
					
						
							|  |  |  | del dbm, dim | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _is_leap(year): | 
					
						
							|  |  |  |     "year -> 1 if leap year, else 0." | 
					
						
							|  |  |  |     return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _days_before_year(year): | 
					
						
							|  |  |  |     "year -> number of days before January 1st of year." | 
					
						
							|  |  |  |     y = year - 1 | 
					
						
							|  |  |  |     return y*365 + y//4 - y//100 + y//400 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _days_in_month(year, month): | 
					
						
							|  |  |  |     "year, month -> number of days in that month in that year." | 
					
						
							|  |  |  |     assert 1 <= month <= 12, month | 
					
						
							|  |  |  |     if month == 2 and _is_leap(year): | 
					
						
							|  |  |  |         return 29 | 
					
						
							|  |  |  |     return _DAYS_IN_MONTH[month] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _days_before_month(year, month): | 
					
						
							|  |  |  |     "year, month -> number of days in year preceeding first day of month." | 
					
						
							|  |  |  |     assert 1 <= month <= 12, 'month must be in 1..12' | 
					
						
							|  |  |  |     return _DAYS_BEFORE_MONTH[month] + (month > 2 and _is_leap(year)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _ymd2ord(year, month, day): | 
					
						
							|  |  |  |     "year, month, day -> ordinal, considering 01-Jan-0001 as day 1." | 
					
						
							|  |  |  |     assert 1 <= month <= 12, 'month must be in 1..12' | 
					
						
							|  |  |  |     dim = _days_in_month(year, month) | 
					
						
							|  |  |  |     assert 1 <= day <= dim, ('day must be in 1..%d' % dim) | 
					
						
							|  |  |  |     return (_days_before_year(year) + | 
					
						
							|  |  |  |             _days_before_month(year, month) + | 
					
						
							|  |  |  |             day) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _DI400Y = _days_before_year(401)    # number of days in 400 years | 
					
						
							|  |  |  | _DI100Y = _days_before_year(101)    #    "    "   "   " 100   " | 
					
						
							|  |  |  | _DI4Y   = _days_before_year(5)      #    "    "   "   "   4   " | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # A 4-year cycle has an extra leap day over what we'd get from pasting | 
					
						
							|  |  |  | # together 4 single years. | 
					
						
							|  |  |  | assert _DI4Y == 4 * 365 + 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Similarly, a 400-year cycle has an extra leap day over what we'd get from | 
					
						
							|  |  |  | # pasting together 4 100-year cycles. | 
					
						
							|  |  |  | assert _DI400Y == 4 * _DI100Y + 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # OTOH, a 100-year cycle has one fewer leap day than we'd get from | 
					
						
							|  |  |  | # pasting together 25 4-year cycles. | 
					
						
							|  |  |  | assert _DI100Y == 25 * _DI4Y - 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _ord2ymd(n): | 
					
						
							|  |  |  |     "ordinal -> (year, month, day), considering 01-Jan-0001 as day 1." | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # n is a 1-based index, starting at 1-Jan-1.  The pattern of leap years | 
					
						
							|  |  |  |     # repeats exactly every 400 years.  The basic strategy is to find the | 
					
						
							|  |  |  |     # closest 400-year boundary at or before n, then work with the offset | 
					
						
							|  |  |  |     # from that boundary to n.  Life is much clearer if we subtract 1 from | 
					
						
							|  |  |  |     # n first -- then the values of n at 400-year boundaries are exactly | 
					
						
							|  |  |  |     # those divisible by _DI400Y: | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     #     D  M   Y            n              n-1 | 
					
						
							|  |  |  |     #     -- --- ----        ----------     ---------------- | 
					
						
							|  |  |  |     #     31 Dec -400        -_DI400Y       -_DI400Y -1 | 
					
						
							|  |  |  |     #      1 Jan -399         -_DI400Y +1   -_DI400Y      400-year boundary | 
					
						
							|  |  |  |     #     ... | 
					
						
							|  |  |  |     #     30 Dec  000        -1             -2 | 
					
						
							|  |  |  |     #     31 Dec  000         0             -1 | 
					
						
							|  |  |  |     #      1 Jan  001         1              0            400-year boundary | 
					
						
							|  |  |  |     #      2 Jan  001         2              1 | 
					
						
							|  |  |  |     #      3 Jan  001         3              2 | 
					
						
							|  |  |  |     #     ... | 
					
						
							|  |  |  |     #     31 Dec  400         _DI400Y        _DI400Y -1 | 
					
						
							|  |  |  |     #      1 Jan  401         _DI400Y +1     _DI400Y      400-year boundary | 
					
						
							|  |  |  |     n -= 1 | 
					
						
							|  |  |  |     n400, n = divmod(n, _DI400Y) | 
					
						
							|  |  |  |     year = n400 * 400 + 1   # ..., -399, 1, 401, ... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Now n is the (non-negative) offset, in days, from January 1 of year, to | 
					
						
							|  |  |  |     # the desired date.  Now compute how many 100-year cycles precede n. | 
					
						
							|  |  |  |     # Note that it's possible for n100 to equal 4!  In that case 4 full | 
					
						
							|  |  |  |     # 100-year cycles precede the desired day, which implies the desired | 
					
						
							|  |  |  |     # day is December 31 at the end of a 400-year cycle. | 
					
						
							|  |  |  |     n100, n = divmod(n, _DI100Y) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Now compute how many 4-year cycles precede it. | 
					
						
							|  |  |  |     n4, n = divmod(n, _DI4Y) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # And now how many single years.  Again n1 can be 4, and again meaning | 
					
						
							|  |  |  |     # that the desired day is December 31 at the end of the 4-year cycle. | 
					
						
							|  |  |  |     n1, n = divmod(n, 365) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     year += n100 * 100 + n4 * 4 + n1 | 
					
						
							|  |  |  |     if n1 == 4 or n100 == 4: | 
					
						
							|  |  |  |         assert n == 0 | 
					
						
							|  |  |  |         return year-1, 12, 31 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Now the year is correct, and n is the offset from January 1.  We find | 
					
						
							|  |  |  |     # the month via an estimate that's either exact or one too large. | 
					
						
							|  |  |  |     leapyear = n1 == 3 and (n4 != 24 or n100 == 3) | 
					
						
							|  |  |  |     assert leapyear == _is_leap(year) | 
					
						
							|  |  |  |     month = (n + 50) >> 5 | 
					
						
							|  |  |  |     preceding = _DAYS_BEFORE_MONTH[month] + (month > 2 and leapyear) | 
					
						
							|  |  |  |     if preceding > n:  # estimate is too large | 
					
						
							|  |  |  |         month -= 1 | 
					
						
							|  |  |  |         preceding -= _DAYS_IN_MONTH[month] + (month == 2 and leapyear) | 
					
						
							|  |  |  |     n -= preceding | 
					
						
							|  |  |  |     assert 0 <= n < _days_in_month(year, month) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Now the year and month are correct, and n is the offset from the | 
					
						
							|  |  |  |     # start of that month:  we're done! | 
					
						
							|  |  |  |     return year, month, n+1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Month and day names.  For localized versions, see the calendar module. | 
					
						
							|  |  |  | _MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun", | 
					
						
							|  |  |  |                      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] | 
					
						
							|  |  |  | _DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _build_struct_time(y, m, d, hh, mm, ss, dstflag): | 
					
						
							|  |  |  |     wday = (_ymd2ord(y, m, d) + 6) % 7 | 
					
						
							|  |  |  |     dnum = _days_before_month(y, m) + d | 
					
						
							|  |  |  |     return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _format_time(hh, mm, ss, us): | 
					
						
							|  |  |  |     # Skip trailing microseconds when us==0. | 
					
						
							|  |  |  |     result = "%02d:%02d:%02d" % (hh, mm, ss) | 
					
						
							|  |  |  |     if us: | 
					
						
							|  |  |  |         result += ".%06d" % us | 
					
						
							|  |  |  |     return result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Correctly substitute for %z and %Z escapes in strftime formats. | 
					
						
							|  |  |  | def _wrap_strftime(object, format, timetuple): | 
					
						
							|  |  |  |     # Don't call utcoffset() or tzname() unless actually needed. | 
					
						
							|  |  |  |     freplace = None # the string to use for %f | 
					
						
							|  |  |  |     zreplace = None # the string to use for %z | 
					
						
							|  |  |  |     Zreplace = None # the string to use for %Z | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Scan format for %z and %Z escapes, replacing as needed. | 
					
						
							|  |  |  |     newformat = [] | 
					
						
							|  |  |  |     push = newformat.append | 
					
						
							|  |  |  |     i, n = 0, len(format) | 
					
						
							|  |  |  |     while i < n: | 
					
						
							|  |  |  |         ch = format[i] | 
					
						
							|  |  |  |         i += 1 | 
					
						
							|  |  |  |         if ch == '%': | 
					
						
							|  |  |  |             if i < n: | 
					
						
							|  |  |  |                 ch = format[i] | 
					
						
							|  |  |  |                 i += 1 | 
					
						
							|  |  |  |                 if ch == 'f': | 
					
						
							|  |  |  |                     if freplace is None: | 
					
						
							|  |  |  |                         freplace = '%06d' % getattr(object, | 
					
						
							|  |  |  |                                                     'microsecond', 0) | 
					
						
							|  |  |  |                     newformat.append(freplace) | 
					
						
							|  |  |  |                 elif ch == 'z': | 
					
						
							|  |  |  |                     if zreplace is None: | 
					
						
							|  |  |  |                         zreplace = "" | 
					
						
							|  |  |  |                         if hasattr(object, "utcoffset"): | 
					
						
							|  |  |  |                             offset = object.utcoffset() | 
					
						
							|  |  |  |                             if offset is not None: | 
					
						
							|  |  |  |                                 sign = '+' | 
					
						
							|  |  |  |                                 if offset.days < 0: | 
					
						
							|  |  |  |                                     offset = -offset | 
					
						
							|  |  |  |                                     sign = '-' | 
					
						
							|  |  |  |                                 h, m = divmod(offset, timedelta(hours=1)) | 
					
						
							|  |  |  |                                 assert not m % timedelta(minutes=1), "whole minute" | 
					
						
							|  |  |  |                                 m //= timedelta(minutes=1) | 
					
						
							|  |  |  |                                 zreplace = '%c%02d%02d' % (sign, h, m) | 
					
						
							|  |  |  |                     assert '%' not in zreplace | 
					
						
							|  |  |  |                     newformat.append(zreplace) | 
					
						
							|  |  |  |                 elif ch == 'Z': | 
					
						
							|  |  |  |                     if Zreplace is None: | 
					
						
							|  |  |  |                         Zreplace = "" | 
					
						
							|  |  |  |                         if hasattr(object, "tzname"): | 
					
						
							|  |  |  |                             s = object.tzname() | 
					
						
							|  |  |  |                             if s is not None: | 
					
						
							|  |  |  |                                 # strftime is going to have at this: escape % | 
					
						
							|  |  |  |                                 Zreplace = s.replace('%', '%%') | 
					
						
							|  |  |  |                     newformat.append(Zreplace) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     push('%') | 
					
						
							|  |  |  |                     push(ch) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 push('%') | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             push(ch) | 
					
						
							|  |  |  |     newformat = "".join(newformat) | 
					
						
							|  |  |  |     return _time.strftime(newformat, timetuple) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _call_tzinfo_method(tzinfo, methname, tzinfoarg): | 
					
						
							|  |  |  |     if tzinfo is None: | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  |     return getattr(tzinfo, methname)(tzinfoarg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Just raise TypeError if the arg isn't None or a string. | 
					
						
							|  |  |  | def _check_tzname(name): | 
					
						
							|  |  |  |     if name is not None and not isinstance(name, str): | 
					
						
							|  |  |  |         raise TypeError("tzinfo.tzname() must return None or string, " | 
					
						
							|  |  |  |                         "not '%s'" % type(name)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # name is the offset-producing method, "utcoffset" or "dst". | 
					
						
							|  |  |  | # offset is what it returned. | 
					
						
							|  |  |  | # If offset isn't None or timedelta, raises TypeError. | 
					
						
							|  |  |  | # If offset is None, returns None. | 
					
						
							|  |  |  | # Else offset is checked for being in range, and a whole # of minutes. | 
					
						
							|  |  |  | # If it is, its integer value is returned.  Else ValueError is raised. | 
					
						
							|  |  |  | def _check_utc_offset(name, offset): | 
					
						
							|  |  |  |     assert name in ("utcoffset", "dst") | 
					
						
							|  |  |  |     if offset is None: | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not isinstance(offset, timedelta): | 
					
						
							|  |  |  |         raise TypeError("tzinfo.%s() must return None " | 
					
						
							|  |  |  |                         "or timedelta, not '%s'" % (name, type(offset))) | 
					
						
							|  |  |  |     if offset % timedelta(minutes=1) or offset.microseconds: | 
					
						
							|  |  |  |         raise ValueError("tzinfo.%s() must return a whole number " | 
					
						
							|  |  |  |                          "of minutes, got %s" % (name, offset)) | 
					
						
							|  |  |  |     if not -timedelta(1) < offset < timedelta(1): | 
					
						
							|  |  |  |         raise ValueError("%s()=%s, must be must be strictly between" | 
					
						
							|  |  |  |                          " -timedelta(hours=24) and timedelta(hours=24)" | 
					
						
							|  |  |  |                          % (name, offset)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _check_date_fields(year, month, day): | 
					
						
							|  |  |  |     if not isinstance(year, int): | 
					
						
							|  |  |  |         raise TypeError('int expected') | 
					
						
							|  |  |  |     if not MINYEAR <= year <= MAXYEAR: | 
					
						
							|  |  |  |         raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year) | 
					
						
							|  |  |  |     if not 1 <= month <= 12: | 
					
						
							|  |  |  |         raise ValueError('month must be in 1..12', month) | 
					
						
							|  |  |  |     dim = _days_in_month(year, month) | 
					
						
							|  |  |  |     if not 1 <= day <= dim: | 
					
						
							|  |  |  |         raise ValueError('day must be in 1..%d' % dim, day) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _check_time_fields(hour, minute, second, microsecond): | 
					
						
							|  |  |  |     if not isinstance(hour, int): | 
					
						
							|  |  |  |         raise TypeError('int expected') | 
					
						
							|  |  |  |     if not 0 <= hour <= 23: | 
					
						
							|  |  |  |         raise ValueError('hour must be in 0..23', hour) | 
					
						
							|  |  |  |     if not 0 <= minute <= 59: | 
					
						
							|  |  |  |         raise ValueError('minute must be in 0..59', minute) | 
					
						
							|  |  |  |     if not 0 <= second <= 59: | 
					
						
							|  |  |  |         raise ValueError('second must be in 0..59', second) | 
					
						
							|  |  |  |     if not 0 <= microsecond <= 999999: | 
					
						
							|  |  |  |         raise ValueError('microsecond must be in 0..999999', microsecond) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _check_tzinfo_arg(tz): | 
					
						
							|  |  |  |     if tz is not None and not isinstance(tz, tzinfo): | 
					
						
							|  |  |  |         raise TypeError("tzinfo argument must be None or of a tzinfo subclass") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _cmperror(x, y): | 
					
						
							|  |  |  |     raise TypeError("can't compare '%s' to '%s'" % ( | 
					
						
							|  |  |  |                     type(x).__name__, type(y).__name__)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class timedelta: | 
					
						
							|  |  |  |     """Represent the difference between two datetime objects.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Supported operators: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     - add, subtract timedelta | 
					
						
							|  |  |  |     - unary plus, minus, abs | 
					
						
							|  |  |  |     - compare to timedelta | 
					
						
							|  |  |  |     - multiply, divide by int/long | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     In addition, datetime supports subtraction of two datetime objects | 
					
						
							|  |  |  |     returning a timedelta, and addition or subtraction of a datetime | 
					
						
							|  |  |  |     and a timedelta giving a datetime. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Representation: (days, seconds, microseconds).  Why?  Because I | 
					
						
							|  |  |  |     felt like it. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     __slots__ = '_days', '_seconds', '_microseconds' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __new__(cls, days=0, seconds=0, microseconds=0, | 
					
						
							|  |  |  |                 milliseconds=0, minutes=0, hours=0, weeks=0): | 
					
						
							|  |  |  |         # Doing this efficiently and accurately in C is going to be difficult | 
					
						
							|  |  |  |         # and error-prone, due to ubiquitous overflow possibilities, and that | 
					
						
							|  |  |  |         # C double doesn't have enough bits of precision to represent | 
					
						
							|  |  |  |         # microseconds over 10K years faithfully.  The code here tries to make | 
					
						
							|  |  |  |         # explicit where go-fast assumptions can be relied on, in order to | 
					
						
							|  |  |  |         # guide the C implementation; it's way more convoluted than speed- | 
					
						
							|  |  |  |         # ignoring auto-overflow-to-long idiomatic Python could be. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # XXX Check that all inputs are ints or floats. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Final values, all integer. | 
					
						
							|  |  |  |         # s and us fit in 32-bit signed ints; d isn't bounded. | 
					
						
							|  |  |  |         d = s = us = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Normalize everything to days, seconds, microseconds. | 
					
						
							|  |  |  |         days += weeks*7 | 
					
						
							|  |  |  |         seconds += minutes*60 + hours*3600 | 
					
						
							|  |  |  |         microseconds += milliseconds*1000 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Get rid of all fractions, and normalize s and us. | 
					
						
							|  |  |  |         # Take a deep breath <wink>. | 
					
						
							|  |  |  |         if isinstance(days, float): | 
					
						
							|  |  |  |             dayfrac, days = _math.modf(days) | 
					
						
							|  |  |  |             daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.)) | 
					
						
							|  |  |  |             assert daysecondswhole == int(daysecondswhole)  # can't overflow | 
					
						
							|  |  |  |             s = int(daysecondswhole) | 
					
						
							|  |  |  |             assert days == int(days) | 
					
						
							|  |  |  |             d = int(days) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             daysecondsfrac = 0.0 | 
					
						
							|  |  |  |             d = days | 
					
						
							|  |  |  |         assert isinstance(daysecondsfrac, float) | 
					
						
							|  |  |  |         assert abs(daysecondsfrac) <= 1.0 | 
					
						
							|  |  |  |         assert isinstance(d, int) | 
					
						
							|  |  |  |         assert abs(s) <= 24 * 3600 | 
					
						
							|  |  |  |         # days isn't referenced again before redefinition | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if isinstance(seconds, float): | 
					
						
							|  |  |  |             secondsfrac, seconds = _math.modf(seconds) | 
					
						
							|  |  |  |             assert seconds == int(seconds) | 
					
						
							|  |  |  |             seconds = int(seconds) | 
					
						
							|  |  |  |             secondsfrac += daysecondsfrac | 
					
						
							|  |  |  |             assert abs(secondsfrac) <= 2.0 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             secondsfrac = daysecondsfrac | 
					
						
							|  |  |  |         # daysecondsfrac isn't referenced again | 
					
						
							|  |  |  |         assert isinstance(secondsfrac, float) | 
					
						
							|  |  |  |         assert abs(secondsfrac) <= 2.0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         assert isinstance(seconds, int) | 
					
						
							|  |  |  |         days, seconds = divmod(seconds, 24*3600) | 
					
						
							|  |  |  |         d += days | 
					
						
							|  |  |  |         s += int(seconds)    # can't overflow | 
					
						
							|  |  |  |         assert isinstance(s, int) | 
					
						
							|  |  |  |         assert abs(s) <= 2 * 24 * 3600 | 
					
						
							|  |  |  |         # seconds isn't referenced again before redefinition | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         usdouble = secondsfrac * 1e6 | 
					
						
							|  |  |  |         assert abs(usdouble) < 2.1e6    # exact value not critical | 
					
						
							|  |  |  |         # secondsfrac isn't referenced again | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if isinstance(microseconds, float): | 
					
						
							|  |  |  |             microseconds += usdouble | 
					
						
							|  |  |  |             microseconds = round(microseconds, 0) | 
					
						
							|  |  |  |             seconds, microseconds = divmod(microseconds, 1e6) | 
					
						
							|  |  |  |             assert microseconds == int(microseconds) | 
					
						
							|  |  |  |             assert seconds == int(seconds) | 
					
						
							|  |  |  |             days, seconds = divmod(seconds, 24.*3600.) | 
					
						
							|  |  |  |             assert days == int(days) | 
					
						
							|  |  |  |             assert seconds == int(seconds) | 
					
						
							|  |  |  |             d += int(days) | 
					
						
							|  |  |  |             s += int(seconds)   # can't overflow | 
					
						
							|  |  |  |             assert isinstance(s, int) | 
					
						
							|  |  |  |             assert abs(s) <= 3 * 24 * 3600 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             seconds, microseconds = divmod(microseconds, 1000000) | 
					
						
							|  |  |  |             days, seconds = divmod(seconds, 24*3600) | 
					
						
							|  |  |  |             d += days | 
					
						
							|  |  |  |             s += int(seconds)    # can't overflow | 
					
						
							|  |  |  |             assert isinstance(s, int) | 
					
						
							|  |  |  |             assert abs(s) <= 3 * 24 * 3600 | 
					
						
							|  |  |  |             microseconds = float(microseconds) | 
					
						
							|  |  |  |             microseconds += usdouble | 
					
						
							|  |  |  |             microseconds = round(microseconds, 0) | 
					
						
							|  |  |  |         assert abs(s) <= 3 * 24 * 3600 | 
					
						
							|  |  |  |         assert abs(microseconds) < 3.1e6 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Just a little bit of carrying possible for microseconds and seconds. | 
					
						
							|  |  |  |         assert isinstance(microseconds, float) | 
					
						
							|  |  |  |         assert int(microseconds) == microseconds | 
					
						
							|  |  |  |         us = int(microseconds) | 
					
						
							|  |  |  |         seconds, us = divmod(us, 1000000) | 
					
						
							|  |  |  |         s += seconds    # cant't overflow | 
					
						
							|  |  |  |         assert isinstance(s, int) | 
					
						
							|  |  |  |         days, s = divmod(s, 24*3600) | 
					
						
							|  |  |  |         d += days | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         assert isinstance(d, int) | 
					
						
							|  |  |  |         assert isinstance(s, int) and 0 <= s < 24*3600 | 
					
						
							|  |  |  |         assert isinstance(us, int) and 0 <= us < 1000000 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self = object.__new__(cls) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self._days = d | 
					
						
							|  |  |  |         self._seconds = s | 
					
						
							|  |  |  |         self._microseconds = us | 
					
						
							|  |  |  |         if abs(d) > 999999999: | 
					
						
							|  |  |  |             raise OverflowError("timedelta # of days is too large: %d" % d) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         if self._microseconds: | 
					
						
							|  |  |  |             return "%s(%d, %d, %d)" % ('datetime.' + self.__class__.__name__, | 
					
						
							|  |  |  |                                        self._days, | 
					
						
							|  |  |  |                                        self._seconds, | 
					
						
							|  |  |  |                                        self._microseconds) | 
					
						
							|  |  |  |         if self._seconds: | 
					
						
							|  |  |  |             return "%s(%d, %d)" % ('datetime.' + self.__class__.__name__, | 
					
						
							|  |  |  |                                    self._days, | 
					
						
							|  |  |  |                                    self._seconds) | 
					
						
							|  |  |  |         return "%s(%d)" % ('datetime.' + self.__class__.__name__, self._days) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         mm, ss = divmod(self._seconds, 60) | 
					
						
							|  |  |  |         hh, mm = divmod(mm, 60) | 
					
						
							|  |  |  |         s = "%d:%02d:%02d" % (hh, mm, ss) | 
					
						
							|  |  |  |         if self._days: | 
					
						
							|  |  |  |             def plural(n): | 
					
						
							|  |  |  |                 return n, abs(n) != 1 and "s" or "" | 
					
						
							|  |  |  |             s = ("%d day%s, " % plural(self._days)) + s | 
					
						
							|  |  |  |         if self._microseconds: | 
					
						
							|  |  |  |             s = s + ".%06d" % self._microseconds | 
					
						
							|  |  |  |         return s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def total_seconds(self): | 
					
						
							|  |  |  |         """Total seconds in the duration.""" | 
					
						
							|  |  |  |         return ((self.days * 86400 + self.seconds)*10**6 + | 
					
						
							|  |  |  |                 self.microseconds) / 10**6 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Read-only field accessors | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def days(self): | 
					
						
							|  |  |  |         """days""" | 
					
						
							|  |  |  |         return self._days | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def seconds(self): | 
					
						
							|  |  |  |         """seconds""" | 
					
						
							|  |  |  |         return self._seconds | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def microseconds(self): | 
					
						
							|  |  |  |         """microseconds""" | 
					
						
							|  |  |  |         return self._microseconds | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __add__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, timedelta): | 
					
						
							|  |  |  |             # for CPython compatibility, we cannot use | 
					
						
							|  |  |  |             # our __class__ here, but need a real timedelta | 
					
						
							|  |  |  |             return timedelta(self._days + other._days, | 
					
						
							|  |  |  |                              self._seconds + other._seconds, | 
					
						
							|  |  |  |                              self._microseconds + other._microseconds) | 
					
						
							|  |  |  |         return NotImplemented | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __radd__ = __add__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __sub__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, timedelta): | 
					
						
							| 
									
										
										
										
											2011-04-05 20:07:38 -04:00
										 |  |  |             # for CPython compatibility, we cannot use | 
					
						
							|  |  |  |             # our __class__ here, but need a real timedelta | 
					
						
							|  |  |  |             return timedelta(self._days - other._days, | 
					
						
							|  |  |  |                              self._seconds - other._seconds, | 
					
						
							|  |  |  |                              self._microseconds - other._microseconds) | 
					
						
							| 
									
										
										
										
											2010-07-23 19:25:47 +00:00
										 |  |  |         return NotImplemented | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __rsub__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, timedelta): | 
					
						
							|  |  |  |             return -self + other | 
					
						
							|  |  |  |         return NotImplemented | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __neg__(self): | 
					
						
							|  |  |  |         # for CPython compatibility, we cannot use | 
					
						
							|  |  |  |         # our __class__ here, but need a real timedelta | 
					
						
							|  |  |  |         return timedelta(-self._days, | 
					
						
							|  |  |  |                          -self._seconds, | 
					
						
							|  |  |  |                          -self._microseconds) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __pos__(self): | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __abs__(self): | 
					
						
							|  |  |  |         if self._days < 0: | 
					
						
							|  |  |  |             return -self | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __mul__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, int): | 
					
						
							|  |  |  |             # for CPython compatibility, we cannot use | 
					
						
							|  |  |  |             # our __class__ here, but need a real timedelta | 
					
						
							|  |  |  |             return timedelta(self._days * other, | 
					
						
							|  |  |  |                              self._seconds * other, | 
					
						
							|  |  |  |                              self._microseconds * other) | 
					
						
							|  |  |  |         if isinstance(other, float): | 
					
						
							|  |  |  |             a, b = other.as_integer_ratio() | 
					
						
							|  |  |  |             return self * a / b | 
					
						
							|  |  |  |         return NotImplemented | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __rmul__ = __mul__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _to_microseconds(self): | 
					
						
							|  |  |  |         return ((self._days * (24*3600) + self._seconds) * 1000000 + | 
					
						
							|  |  |  |                 self._microseconds) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __floordiv__(self, other): | 
					
						
							|  |  |  |         if not isinstance(other, (int, timedelta)): | 
					
						
							|  |  |  |             return NotImplemented | 
					
						
							|  |  |  |         usec = self._to_microseconds() | 
					
						
							|  |  |  |         if isinstance(other, timedelta): | 
					
						
							|  |  |  |             return usec // other._to_microseconds() | 
					
						
							|  |  |  |         if isinstance(other, int): | 
					
						
							|  |  |  |             return timedelta(0, 0, usec // other) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __truediv__(self, other): | 
					
						
							|  |  |  |         if not isinstance(other, (int, float, timedelta)): | 
					
						
							|  |  |  |             return NotImplemented | 
					
						
							|  |  |  |         usec = self._to_microseconds() | 
					
						
							|  |  |  |         if isinstance(other, timedelta): | 
					
						
							|  |  |  |             return usec / other._to_microseconds() | 
					
						
							|  |  |  |         if isinstance(other, int): | 
					
						
							|  |  |  |             return timedelta(0, 0, usec / other) | 
					
						
							|  |  |  |         if isinstance(other, float): | 
					
						
							|  |  |  |             a, b = other.as_integer_ratio() | 
					
						
							|  |  |  |             return timedelta(0, 0, b * usec / a) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __mod__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, timedelta): | 
					
						
							|  |  |  |             r = self._to_microseconds() % other._to_microseconds() | 
					
						
							|  |  |  |             return timedelta(0, 0, r) | 
					
						
							|  |  |  |         return NotImplemented | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __divmod__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, timedelta): | 
					
						
							|  |  |  |             q, r = divmod(self._to_microseconds(), | 
					
						
							|  |  |  |                           other._to_microseconds()) | 
					
						
							|  |  |  |             return q, timedelta(0, 0, r) | 
					
						
							|  |  |  |         return NotImplemented | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Comparisons of timedelta objects with other. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __eq__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, timedelta): | 
					
						
							|  |  |  |             return self._cmp(other) == 0 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ne__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, timedelta): | 
					
						
							|  |  |  |             return self._cmp(other) != 0 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __le__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, timedelta): | 
					
						
							|  |  |  |             return self._cmp(other) <= 0 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             _cmperror(self, other) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __lt__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, timedelta): | 
					
						
							|  |  |  |             return self._cmp(other) < 0 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             _cmperror(self, other) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ge__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, timedelta): | 
					
						
							|  |  |  |             return self._cmp(other) >= 0 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             _cmperror(self, other) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __gt__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, timedelta): | 
					
						
							|  |  |  |             return self._cmp(other) > 0 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             _cmperror(self, other) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _cmp(self, other): | 
					
						
							|  |  |  |         assert isinstance(other, timedelta) | 
					
						
							|  |  |  |         return _cmp(self._getstate(), other._getstate()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __hash__(self): | 
					
						
							|  |  |  |         return hash(self._getstate()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __bool__(self): | 
					
						
							|  |  |  |         return (self._days != 0 or | 
					
						
							|  |  |  |                 self._seconds != 0 or | 
					
						
							|  |  |  |                 self._microseconds != 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Pickle support. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _getstate(self): | 
					
						
							|  |  |  |         return (self._days, self._seconds, self._microseconds) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __reduce__(self): | 
					
						
							|  |  |  |         return (self.__class__, self._getstate()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | timedelta.min = timedelta(-999999999) | 
					
						
							|  |  |  | timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59, | 
					
						
							|  |  |  |                           microseconds=999999) | 
					
						
							|  |  |  | timedelta.resolution = timedelta(microseconds=1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class date: | 
					
						
							|  |  |  |     """Concrete date type.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Constructors: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __new__() | 
					
						
							|  |  |  |     fromtimestamp() | 
					
						
							|  |  |  |     today() | 
					
						
							|  |  |  |     fromordinal() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Operators: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __repr__, __str__ | 
					
						
							|  |  |  |     __cmp__, __hash__ | 
					
						
							|  |  |  |     __add__, __radd__, __sub__ (add/radd only with timedelta arg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Methods: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     timetuple() | 
					
						
							|  |  |  |     toordinal() | 
					
						
							|  |  |  |     weekday() | 
					
						
							|  |  |  |     isoweekday(), isocalendar(), isoformat() | 
					
						
							|  |  |  |     ctime() | 
					
						
							|  |  |  |     strftime() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Properties (readonly): | 
					
						
							|  |  |  |     year, month, day | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     __slots__ = '_year', '_month', '_day' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __new__(cls, year, month=None, day=None): | 
					
						
							|  |  |  |         """Constructor.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Arguments: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         year, month, day (required, base 1) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if (isinstance(year, bytes) and len(year) == 4 and | 
					
						
							|  |  |  |             1 <= year[2] <= 12 and month is None):  # Month is sane | 
					
						
							|  |  |  |             # Pickle support | 
					
						
							|  |  |  |             self = object.__new__(cls) | 
					
						
							|  |  |  |             self.__setstate(year) | 
					
						
							|  |  |  |             return self | 
					
						
							|  |  |  |         _check_date_fields(year, month, day) | 
					
						
							|  |  |  |         self = object.__new__(cls) | 
					
						
							|  |  |  |         self._year = year | 
					
						
							|  |  |  |         self._month = month | 
					
						
							|  |  |  |         self._day = day | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Additional constructors | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def fromtimestamp(cls, t): | 
					
						
							|  |  |  |         "Construct a date from a POSIX timestamp (like time.time())." | 
					
						
							|  |  |  |         y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t) | 
					
						
							|  |  |  |         return cls(y, m, d) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def today(cls): | 
					
						
							|  |  |  |         "Construct a date from time.time()." | 
					
						
							|  |  |  |         t = _time.time() | 
					
						
							|  |  |  |         return cls.fromtimestamp(t) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def fromordinal(cls, n): | 
					
						
							|  |  |  |         """Contruct a date from a proleptic Gregorian ordinal.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         January 1 of year 1 is day 1.  Only the year, month and day are | 
					
						
							|  |  |  |         non-zero in the result. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         y, m, d = _ord2ymd(n) | 
					
						
							|  |  |  |         return cls(y, m, d) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Conversions to string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         """Convert to formal string, for repr().
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         >>> dt = datetime(2010, 1, 1) | 
					
						
							|  |  |  |         >>> repr(dt) | 
					
						
							|  |  |  |         'datetime.datetime(2010, 1, 1, 0, 0)' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc) | 
					
						
							|  |  |  |         >>> repr(dt) | 
					
						
							|  |  |  |         'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)' | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return "%s(%d, %d, %d)" % ('datetime.' + self.__class__.__name__, | 
					
						
							|  |  |  |                                    self._year, | 
					
						
							|  |  |  |                                    self._month, | 
					
						
							|  |  |  |                                    self._day) | 
					
						
							|  |  |  |     # XXX These shouldn't depend on time.localtime(), because that | 
					
						
							|  |  |  |     # clips the usable dates to [1970 .. 2038).  At least ctime() is | 
					
						
							|  |  |  |     # easily done without using strftime() -- that's better too because | 
					
						
							|  |  |  |     # strftime("%c", ...) is locale specific. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def ctime(self): | 
					
						
							|  |  |  |         "Return ctime() style string." | 
					
						
							|  |  |  |         weekday = self.toordinal() % 7 or 7 | 
					
						
							|  |  |  |         return "%s %s %2d 00:00:00 %04d" % ( | 
					
						
							|  |  |  |             _DAYNAMES[weekday], | 
					
						
							|  |  |  |             _MONTHNAMES[self._month], | 
					
						
							|  |  |  |             self._day, self._year) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def strftime(self, fmt): | 
					
						
							|  |  |  |         "Format using strftime()." | 
					
						
							|  |  |  |         return _wrap_strftime(self, fmt, self.timetuple()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __format__(self, fmt): | 
					
						
							|  |  |  |         if len(fmt) != 0: | 
					
						
							|  |  |  |             return self.strftime(fmt) | 
					
						
							|  |  |  |         return str(self) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def isoformat(self): | 
					
						
							|  |  |  |         """Return the date formatted according to ISO.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This is 'YYYY-MM-DD'. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         References: | 
					
						
							|  |  |  |         - http://www.w3.org/TR/NOTE-datetime | 
					
						
							|  |  |  |         - http://www.cl.cam.ac.uk/~mgk25/iso-time.html | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return "%04d-%02d-%02d" % (self._year, self._month, self._day) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __str__ = isoformat | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Read-only field accessors | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def year(self): | 
					
						
							|  |  |  |         """year (1-9999)""" | 
					
						
							|  |  |  |         return self._year | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def month(self): | 
					
						
							|  |  |  |         """month (1-12)""" | 
					
						
							|  |  |  |         return self._month | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def day(self): | 
					
						
							|  |  |  |         """day (1-31)""" | 
					
						
							|  |  |  |         return self._day | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Standard conversions, __cmp__, __hash__ (and helpers) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def timetuple(self): | 
					
						
							|  |  |  |         "Return local time tuple compatible with time.localtime()." | 
					
						
							|  |  |  |         return _build_struct_time(self._year, self._month, self._day, | 
					
						
							|  |  |  |                                   0, 0, 0, -1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def toordinal(self): | 
					
						
							|  |  |  |         """Return proleptic Gregorian ordinal for the year, month and day.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         January 1 of year 1 is day 1.  Only the year, month and day values | 
					
						
							|  |  |  |         contribute to the result. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return _ymd2ord(self._year, self._month, self._day) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def replace(self, year=None, month=None, day=None): | 
					
						
							|  |  |  |         """Return a new date with new values for the specified fields.""" | 
					
						
							|  |  |  |         if year is None: | 
					
						
							|  |  |  |             year = self._year | 
					
						
							|  |  |  |         if month is None: | 
					
						
							|  |  |  |             month = self._month | 
					
						
							|  |  |  |         if day is None: | 
					
						
							|  |  |  |             day = self._day | 
					
						
							|  |  |  |         _check_date_fields(year, month, day) | 
					
						
							|  |  |  |         return date(year, month, day) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Comparisons of date objects with other. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __eq__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, date): | 
					
						
							|  |  |  |             return self._cmp(other) == 0 | 
					
						
							|  |  |  |         return NotImplemented | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ne__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, date): | 
					
						
							|  |  |  |             return self._cmp(other) != 0 | 
					
						
							|  |  |  |         return NotImplemented | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __le__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, date): | 
					
						
							|  |  |  |             return self._cmp(other) <= 0 | 
					
						
							|  |  |  |         return NotImplemented | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __lt__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, date): | 
					
						
							|  |  |  |             return self._cmp(other) < 0 | 
					
						
							|  |  |  |         return NotImplemented | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ge__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, date): | 
					
						
							|  |  |  |             return self._cmp(other) >= 0 | 
					
						
							|  |  |  |         return NotImplemented | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __gt__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, date): | 
					
						
							|  |  |  |             return self._cmp(other) > 0 | 
					
						
							|  |  |  |         return NotImplemented | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _cmp(self, other): | 
					
						
							|  |  |  |         assert isinstance(other, date) | 
					
						
							|  |  |  |         y, m, d = self._year, self._month, self._day | 
					
						
							|  |  |  |         y2, m2, d2 = other._year, other._month, other._day | 
					
						
							|  |  |  |         return _cmp((y, m, d), (y2, m2, d2)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __hash__(self): | 
					
						
							|  |  |  |         "Hash." | 
					
						
							|  |  |  |         return hash(self._getstate()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Computations | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __add__(self, other): | 
					
						
							|  |  |  |         "Add a date to a timedelta." | 
					
						
							|  |  |  |         if isinstance(other, timedelta): | 
					
						
							|  |  |  |             o = self.toordinal() + other.days | 
					
						
							|  |  |  |             if 0 < o <= _MAXORDINAL: | 
					
						
							|  |  |  |                 return date.fromordinal(o) | 
					
						
							|  |  |  |             raise OverflowError("result out of range") | 
					
						
							|  |  |  |         return NotImplemented | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __radd__ = __add__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __sub__(self, other): | 
					
						
							|  |  |  |         """Subtract two dates, or a date and a timedelta.""" | 
					
						
							|  |  |  |         if isinstance(other, timedelta): | 
					
						
							|  |  |  |             return self + timedelta(-other.days) | 
					
						
							|  |  |  |         if isinstance(other, date): | 
					
						
							|  |  |  |             days1 = self.toordinal() | 
					
						
							|  |  |  |             days2 = other.toordinal() | 
					
						
							|  |  |  |             return timedelta(days1 - days2) | 
					
						
							|  |  |  |         return NotImplemented | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def weekday(self): | 
					
						
							|  |  |  |         "Return day of the week, where Monday == 0 ... Sunday == 6." | 
					
						
							|  |  |  |         return (self.toordinal() + 6) % 7 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Day-of-the-week and week-of-the-year, according to ISO | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def isoweekday(self): | 
					
						
							|  |  |  |         "Return day of the week, where Monday == 1 ... Sunday == 7." | 
					
						
							|  |  |  |         # 1-Jan-0001 is a Monday | 
					
						
							|  |  |  |         return self.toordinal() % 7 or 7 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def isocalendar(self): | 
					
						
							|  |  |  |         """Return a 3-tuple containing ISO year, week number, and weekday.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         The first ISO week of the year is the (Mon-Sun) week | 
					
						
							|  |  |  |         containing the year's first Thursday; everything else derives | 
					
						
							|  |  |  |         from that. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         The first week is 1; Monday is 1 ... Sunday is 7. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ISO calendar algorithm taken from | 
					
						
							|  |  |  |         http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         year = self._year | 
					
						
							|  |  |  |         week1monday = _isoweek1monday(year) | 
					
						
							|  |  |  |         today = _ymd2ord(self._year, self._month, self._day) | 
					
						
							|  |  |  |         # Internally, week and day have origin 0 | 
					
						
							|  |  |  |         week, day = divmod(today - week1monday, 7) | 
					
						
							|  |  |  |         if week < 0: | 
					
						
							|  |  |  |             year -= 1 | 
					
						
							|  |  |  |             week1monday = _isoweek1monday(year) | 
					
						
							|  |  |  |             week, day = divmod(today - week1monday, 7) | 
					
						
							|  |  |  |         elif week >= 52: | 
					
						
							|  |  |  |             if today >= _isoweek1monday(year+1): | 
					
						
							|  |  |  |                 year += 1 | 
					
						
							|  |  |  |                 week = 0 | 
					
						
							|  |  |  |         return year, week+1, day+1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Pickle support. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _getstate(self): | 
					
						
							|  |  |  |         yhi, ylo = divmod(self._year, 256) | 
					
						
							|  |  |  |         return bytes([yhi, ylo, self._month, self._day]), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __setstate(self, string): | 
					
						
							|  |  |  |         if len(string) != 4 or not (1 <= string[2] <= 12): | 
					
						
							|  |  |  |             raise TypeError("not enough arguments") | 
					
						
							|  |  |  |         yhi, ylo, self._month, self._day = string | 
					
						
							|  |  |  |         self._year = yhi * 256 + ylo | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __reduce__(self): | 
					
						
							|  |  |  |         return (self.__class__, self._getstate()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _date_class = date  # so functions w/ args named "date" can get at the class | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | date.min = date(1, 1, 1) | 
					
						
							|  |  |  | date.max = date(9999, 12, 31) | 
					
						
							|  |  |  | date.resolution = timedelta(days=1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class tzinfo: | 
					
						
							|  |  |  |     """Abstract base class for time zone info classes.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Subclasses must override the name(), utcoffset() and dst() methods. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     __slots__ = () | 
					
						
							|  |  |  |     def tzname(self, dt): | 
					
						
							|  |  |  |         "datetime -> string name of time zone." | 
					
						
							|  |  |  |         raise NotImplementedError("tzinfo subclass must override tzname()") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def utcoffset(self, dt): | 
					
						
							|  |  |  |         "datetime -> minutes east of UTC (negative for west of UTC)" | 
					
						
							|  |  |  |         raise NotImplementedError("tzinfo subclass must override utcoffset()") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def dst(self, dt): | 
					
						
							|  |  |  |         """datetime -> DST offset in minutes east of UTC.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Return 0 if DST not in effect.  utcoffset() must include the DST | 
					
						
							|  |  |  |         offset. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         raise NotImplementedError("tzinfo subclass must override dst()") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def fromutc(self, dt): | 
					
						
							|  |  |  |         "datetime in UTC -> datetime in local time." | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if not isinstance(dt, datetime): | 
					
						
							|  |  |  |             raise TypeError("fromutc() requires a datetime argument") | 
					
						
							|  |  |  |         if dt.tzinfo is not self: | 
					
						
							|  |  |  |             raise ValueError("dt.tzinfo is not self") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dtoff = dt.utcoffset() | 
					
						
							|  |  |  |         if dtoff is None: | 
					
						
							|  |  |  |             raise ValueError("fromutc() requires a non-None utcoffset() " | 
					
						
							|  |  |  |                              "result") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # See the long comment block at the end of this file for an | 
					
						
							|  |  |  |         # explanation of this algorithm. | 
					
						
							|  |  |  |         dtdst = dt.dst() | 
					
						
							|  |  |  |         if dtdst is None: | 
					
						
							|  |  |  |             raise ValueError("fromutc() requires a non-None dst() result") | 
					
						
							|  |  |  |         delta = dtoff - dtdst | 
					
						
							|  |  |  |         if delta: | 
					
						
							|  |  |  |             dt += delta | 
					
						
							|  |  |  |             dtdst = dt.dst() | 
					
						
							|  |  |  |             if dtdst is None: | 
					
						
							|  |  |  |                 raise ValueError("fromutc(): dt.dst gave inconsistent " | 
					
						
							|  |  |  |                                  "results; cannot convert") | 
					
						
							|  |  |  |         return dt + dtdst | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Pickle support. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __reduce__(self): | 
					
						
							|  |  |  |         getinitargs = getattr(self, "__getinitargs__", None) | 
					
						
							|  |  |  |         if getinitargs: | 
					
						
							|  |  |  |             args = getinitargs() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             args = () | 
					
						
							|  |  |  |         getstate = getattr(self, "__getstate__", None) | 
					
						
							|  |  |  |         if getstate: | 
					
						
							|  |  |  |             state = getstate() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             state = getattr(self, "__dict__", None) or None | 
					
						
							|  |  |  |         if state is None: | 
					
						
							|  |  |  |             return (self.__class__, args) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return (self.__class__, args, state) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _tzinfo_class = tzinfo | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class time: | 
					
						
							|  |  |  |     """Time with time zone.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Constructors: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __new__() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Operators: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __repr__, __str__ | 
					
						
							|  |  |  |     __cmp__, __hash__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Methods: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     strftime() | 
					
						
							|  |  |  |     isoformat() | 
					
						
							|  |  |  |     utcoffset() | 
					
						
							|  |  |  |     tzname() | 
					
						
							|  |  |  |     dst() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Properties (readonly): | 
					
						
							|  |  |  |     hour, minute, second, microsecond, tzinfo | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None): | 
					
						
							|  |  |  |         """Constructor.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Arguments: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         hour, minute (required) | 
					
						
							|  |  |  |         second, microsecond (default to zero) | 
					
						
							|  |  |  |         tzinfo (default to None) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self = object.__new__(cls) | 
					
						
							|  |  |  |         if isinstance(hour, bytes) and len(hour) == 6: | 
					
						
							|  |  |  |             # Pickle support | 
					
						
							|  |  |  |             self.__setstate(hour, minute or None) | 
					
						
							|  |  |  |             return self | 
					
						
							|  |  |  |         _check_tzinfo_arg(tzinfo) | 
					
						
							|  |  |  |         _check_time_fields(hour, minute, second, microsecond) | 
					
						
							|  |  |  |         self._hour = hour | 
					
						
							|  |  |  |         self._minute = minute | 
					
						
							|  |  |  |         self._second = second | 
					
						
							|  |  |  |         self._microsecond = microsecond | 
					
						
							|  |  |  |         self._tzinfo = tzinfo | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Read-only field accessors | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def hour(self): | 
					
						
							|  |  |  |         """hour (0-23)""" | 
					
						
							|  |  |  |         return self._hour | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def minute(self): | 
					
						
							|  |  |  |         """minute (0-59)""" | 
					
						
							|  |  |  |         return self._minute | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def second(self): | 
					
						
							|  |  |  |         """second (0-59)""" | 
					
						
							|  |  |  |         return self._second | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def microsecond(self): | 
					
						
							|  |  |  |         """microsecond (0-999999)""" | 
					
						
							|  |  |  |         return self._microsecond | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def tzinfo(self): | 
					
						
							|  |  |  |         """timezone info object""" | 
					
						
							|  |  |  |         return self._tzinfo | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Standard conversions, __hash__ (and helpers) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Comparisons of time objects with other. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __eq__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, time): | 
					
						
							|  |  |  |             return self._cmp(other) == 0 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ne__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, time): | 
					
						
							|  |  |  |             return self._cmp(other) != 0 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __le__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, time): | 
					
						
							|  |  |  |             return self._cmp(other) <= 0 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             _cmperror(self, other) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __lt__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, time): | 
					
						
							|  |  |  |             return self._cmp(other) < 0 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             _cmperror(self, other) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ge__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, time): | 
					
						
							|  |  |  |             return self._cmp(other) >= 0 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             _cmperror(self, other) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __gt__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, time): | 
					
						
							|  |  |  |             return self._cmp(other) > 0 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             _cmperror(self, other) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _cmp(self, other): | 
					
						
							|  |  |  |         assert isinstance(other, time) | 
					
						
							|  |  |  |         mytz = self._tzinfo | 
					
						
							|  |  |  |         ottz = other._tzinfo | 
					
						
							|  |  |  |         myoff = otoff = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if mytz is ottz: | 
					
						
							|  |  |  |             base_compare = True | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             myoff = self.utcoffset() | 
					
						
							|  |  |  |             otoff = other.utcoffset() | 
					
						
							|  |  |  |             base_compare = myoff == otoff | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if base_compare: | 
					
						
							|  |  |  |             return _cmp((self._hour, self._minute, self._second, | 
					
						
							|  |  |  |                          self._microsecond), | 
					
						
							|  |  |  |                        (other._hour, other._minute, other._second, | 
					
						
							|  |  |  |                         other._microsecond)) | 
					
						
							|  |  |  |         if myoff is None or otoff is None: | 
					
						
							|  |  |  |             raise TypeError("cannot compare naive and aware times") | 
					
						
							|  |  |  |         myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1) | 
					
						
							|  |  |  |         othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1) | 
					
						
							|  |  |  |         return _cmp((myhhmm, self._second, self._microsecond), | 
					
						
							|  |  |  |                     (othhmm, other._second, other._microsecond)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __hash__(self): | 
					
						
							|  |  |  |         """Hash.""" | 
					
						
							|  |  |  |         tzoff = self.utcoffset() | 
					
						
							|  |  |  |         if not tzoff: # zero or None | 
					
						
							|  |  |  |             return hash(self._getstate()[0]) | 
					
						
							|  |  |  |         h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff, | 
					
						
							|  |  |  |                       timedelta(hours=1)) | 
					
						
							|  |  |  |         assert not m % timedelta(minutes=1), "whole minute" | 
					
						
							|  |  |  |         m //= timedelta(minutes=1) | 
					
						
							|  |  |  |         if 0 <= h < 24: | 
					
						
							|  |  |  |             return hash(time(h, m, self.second, self.microsecond)) | 
					
						
							|  |  |  |         return hash((h, m, self.second, self.microsecond)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Conversion to string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _tzstr(self, sep=":"): | 
					
						
							|  |  |  |         """Return formatted timezone offset (+xx:xx) or None.""" | 
					
						
							|  |  |  |         off = self.utcoffset() | 
					
						
							|  |  |  |         if off is not None: | 
					
						
							|  |  |  |             if off.days < 0: | 
					
						
							|  |  |  |                 sign = "-" | 
					
						
							|  |  |  |                 off = -off | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 sign = "+" | 
					
						
							|  |  |  |             hh, mm = divmod(off, timedelta(hours=1)) | 
					
						
							|  |  |  |             assert not mm % timedelta(minutes=1), "whole minute" | 
					
						
							|  |  |  |             mm //= timedelta(minutes=1) | 
					
						
							|  |  |  |             assert 0 <= hh < 24 | 
					
						
							|  |  |  |             off = "%s%02d%s%02d" % (sign, hh, sep, mm) | 
					
						
							|  |  |  |         return off | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         """Convert to formal string, for repr().""" | 
					
						
							|  |  |  |         if self._microsecond != 0: | 
					
						
							|  |  |  |             s = ", %d, %d" % (self._second, self._microsecond) | 
					
						
							|  |  |  |         elif self._second != 0: | 
					
						
							|  |  |  |             s = ", %d" % self._second | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             s = "" | 
					
						
							|  |  |  |         s= "%s(%d, %d%s)" % ('datetime.' + self.__class__.__name__, | 
					
						
							|  |  |  |                              self._hour, self._minute, s) | 
					
						
							|  |  |  |         if self._tzinfo is not None: | 
					
						
							|  |  |  |             assert s[-1:] == ")" | 
					
						
							|  |  |  |             s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")" | 
					
						
							|  |  |  |         return s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def isoformat(self): | 
					
						
							|  |  |  |         """Return the time formatted according to ISO.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This is 'HH:MM:SS.mmmmmm+zz:zz', or 'HH:MM:SS+zz:zz' if | 
					
						
							|  |  |  |         self.microsecond == 0. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         s = _format_time(self._hour, self._minute, self._second, | 
					
						
							|  |  |  |                          self._microsecond) | 
					
						
							|  |  |  |         tz = self._tzstr() | 
					
						
							|  |  |  |         if tz: | 
					
						
							|  |  |  |             s += tz | 
					
						
							|  |  |  |         return s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __str__ = isoformat | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def strftime(self, fmt): | 
					
						
							|  |  |  |         """Format using strftime().  The date part of the timestamp passed
 | 
					
						
							|  |  |  |         to underlying strftime should not be used. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2011-01-08 00:13:34 +00:00
										 |  |  |         # The year must be >= 1000 else Python's strftime implementation | 
					
						
							| 
									
										
										
										
											2010-07-23 19:25:47 +00:00
										 |  |  |         # can raise a bogus exception. | 
					
						
							|  |  |  |         timetuple = (1900, 1, 1, | 
					
						
							|  |  |  |                      self._hour, self._minute, self._second, | 
					
						
							|  |  |  |                      0, 1, -1) | 
					
						
							|  |  |  |         return _wrap_strftime(self, fmt, timetuple) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __format__(self, fmt): | 
					
						
							|  |  |  |         if len(fmt) != 0: | 
					
						
							|  |  |  |             return self.strftime(fmt) | 
					
						
							|  |  |  |         return str(self) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Timezone functions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def utcoffset(self): | 
					
						
							|  |  |  |         """Return the timezone offset in minutes east of UTC (negative west of
 | 
					
						
							|  |  |  |         UTC)."""
 | 
					
						
							|  |  |  |         if self._tzinfo is None: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         offset = self._tzinfo.utcoffset(None) | 
					
						
							|  |  |  |         _check_utc_offset("utcoffset", offset) | 
					
						
							|  |  |  |         return offset | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def tzname(self): | 
					
						
							|  |  |  |         """Return the timezone name.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Note that the name is 100% informational -- there's no requirement that | 
					
						
							|  |  |  |         it mean anything in particular. For example, "GMT", "UTC", "-500", | 
					
						
							|  |  |  |         "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self._tzinfo is None: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         name = self._tzinfo.tzname(None) | 
					
						
							|  |  |  |         _check_tzname(name) | 
					
						
							|  |  |  |         return name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def dst(self): | 
					
						
							|  |  |  |         """Return 0 if DST is not in effect, or the DST offset (in minutes
 | 
					
						
							|  |  |  |         eastward) if DST is in effect. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This is purely informational; the DST offset has already been added to | 
					
						
							|  |  |  |         the UTC offset returned by utcoffset() if applicable, so there's no | 
					
						
							|  |  |  |         need to consult dst() unless you're interested in displaying the DST | 
					
						
							|  |  |  |         info. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self._tzinfo is None: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         offset = self._tzinfo.dst(None) | 
					
						
							|  |  |  |         _check_utc_offset("dst", offset) | 
					
						
							|  |  |  |         return offset | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def replace(self, hour=None, minute=None, second=None, microsecond=None, | 
					
						
							|  |  |  |                 tzinfo=True): | 
					
						
							|  |  |  |         """Return a new time with new values for the specified fields.""" | 
					
						
							|  |  |  |         if hour is None: | 
					
						
							|  |  |  |             hour = self.hour | 
					
						
							|  |  |  |         if minute is None: | 
					
						
							|  |  |  |             minute = self.minute | 
					
						
							|  |  |  |         if second is None: | 
					
						
							|  |  |  |             second = self.second | 
					
						
							|  |  |  |         if microsecond is None: | 
					
						
							|  |  |  |             microsecond = self.microsecond | 
					
						
							|  |  |  |         if tzinfo is True: | 
					
						
							|  |  |  |             tzinfo = self.tzinfo | 
					
						
							|  |  |  |         _check_time_fields(hour, minute, second, microsecond) | 
					
						
							|  |  |  |         _check_tzinfo_arg(tzinfo) | 
					
						
							|  |  |  |         return time(hour, minute, second, microsecond, tzinfo) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __bool__(self): | 
					
						
							|  |  |  |         if self.second or self.microsecond: | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  |         offset = self.utcoffset() or timedelta(0) | 
					
						
							|  |  |  |         return timedelta(hours=self.hour, minutes=self.minute) != offset | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Pickle support. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _getstate(self): | 
					
						
							|  |  |  |         us2, us3 = divmod(self._microsecond, 256) | 
					
						
							|  |  |  |         us1, us2 = divmod(us2, 256) | 
					
						
							|  |  |  |         basestate = bytes([self._hour, self._minute, self._second, | 
					
						
							|  |  |  |                            us1, us2, us3]) | 
					
						
							|  |  |  |         if self._tzinfo is None: | 
					
						
							|  |  |  |             return (basestate,) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return (basestate, self._tzinfo) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __setstate(self, string, tzinfo): | 
					
						
							|  |  |  |         if len(string) != 6 or string[0] >= 24: | 
					
						
							|  |  |  |             raise TypeError("an integer is required") | 
					
						
							|  |  |  |         (self._hour, self._minute, self._second, | 
					
						
							|  |  |  |          us1, us2, us3) = string | 
					
						
							|  |  |  |         self._microsecond = (((us1 << 8) | us2) << 8) | us3 | 
					
						
							|  |  |  |         if tzinfo is None or isinstance(tzinfo, _tzinfo_class): | 
					
						
							|  |  |  |             self._tzinfo = tzinfo | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise TypeError("bad tzinfo state arg %r" % tzinfo) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __reduce__(self): | 
					
						
							|  |  |  |         return (time, self._getstate()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _time_class = time  # so functions w/ args named "time" can get at the class | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | time.min = time(0, 0, 0) | 
					
						
							|  |  |  | time.max = time(23, 59, 59, 999999) | 
					
						
							|  |  |  | time.resolution = timedelta(microseconds=1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class datetime(date): | 
					
						
							|  |  |  |     """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The year, month and day arguments are required. tzinfo may be None, or an | 
					
						
							|  |  |  |     instance of a tzinfo subclass. The remaining arguments may be ints or longs. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __slots__ = date.__slots__ + ( | 
					
						
							|  |  |  |         '_hour', '_minute', '_second', | 
					
						
							|  |  |  |         '_microsecond', '_tzinfo') | 
					
						
							|  |  |  |     def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0, | 
					
						
							|  |  |  |                 microsecond=0, tzinfo=None): | 
					
						
							|  |  |  |         if isinstance(year, bytes) and len(year) == 10: | 
					
						
							|  |  |  |             # Pickle support | 
					
						
							|  |  |  |             self = date.__new__(cls, year[:4]) | 
					
						
							|  |  |  |             self.__setstate(year, month) | 
					
						
							|  |  |  |             return self | 
					
						
							|  |  |  |         _check_tzinfo_arg(tzinfo) | 
					
						
							|  |  |  |         _check_time_fields(hour, minute, second, microsecond) | 
					
						
							|  |  |  |         self = date.__new__(cls, year, month, day) | 
					
						
							|  |  |  |         self._hour = hour | 
					
						
							|  |  |  |         self._minute = minute | 
					
						
							|  |  |  |         self._second = second | 
					
						
							|  |  |  |         self._microsecond = microsecond | 
					
						
							|  |  |  |         self._tzinfo = tzinfo | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Read-only field accessors | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def hour(self): | 
					
						
							|  |  |  |         """hour (0-23)""" | 
					
						
							|  |  |  |         return self._hour | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def minute(self): | 
					
						
							|  |  |  |         """minute (0-59)""" | 
					
						
							|  |  |  |         return self._minute | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def second(self): | 
					
						
							|  |  |  |         """second (0-59)""" | 
					
						
							|  |  |  |         return self._second | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def microsecond(self): | 
					
						
							|  |  |  |         """microsecond (0-999999)""" | 
					
						
							|  |  |  |         return self._microsecond | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def tzinfo(self): | 
					
						
							|  |  |  |         """timezone info object""" | 
					
						
							|  |  |  |         return self._tzinfo | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def fromtimestamp(cls, t, tz=None): | 
					
						
							|  |  |  |         """Construct a datetime from a POSIX timestamp (like time.time()).
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         A timezone info object may be passed in as well. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         _check_tzinfo_arg(tz) | 
					
						
							| 
									
										
										
										
											2010-07-26 02:36:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         converter = _time.localtime if tz is None else _time.gmtime | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         t, frac = divmod(t, 1.0) | 
					
						
							|  |  |  |         us = round(frac * 1e6) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # If timestamp is less than one microsecond smaller than a | 
					
						
							|  |  |  |         # full second, us can be rounded up to 1000000.  In this case, | 
					
						
							|  |  |  |         # roll over to seconds, otherwise, ValueError is raised | 
					
						
							|  |  |  |         # by the constructor. | 
					
						
							|  |  |  |         if us == 1000000: | 
					
						
							|  |  |  |             t += 1 | 
					
						
							|  |  |  |             us = 0 | 
					
						
							| 
									
										
										
										
											2010-07-23 19:25:47 +00:00
										 |  |  |         y, m, d, hh, mm, ss, weekday, jday, dst = converter(t) | 
					
						
							|  |  |  |         ss = min(ss, 59)    # clamp out leap seconds if the platform has them | 
					
						
							|  |  |  |         result = cls(y, m, d, hh, mm, ss, us, tz) | 
					
						
							|  |  |  |         if tz is not None: | 
					
						
							|  |  |  |             result = tz.fromutc(result) | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def utcfromtimestamp(cls, t): | 
					
						
							|  |  |  |         "Construct a UTC datetime from a POSIX timestamp (like time.time())." | 
					
						
							| 
									
										
										
										
											2010-09-21 16:30:56 +00:00
										 |  |  |         t, frac = divmod(t, 1.0) | 
					
						
							|  |  |  |         us = round(frac * 1e6) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # If timestamp is less than one microsecond smaller than a | 
					
						
							|  |  |  |         # full second, us can be rounded up to 1000000.  In this case, | 
					
						
							|  |  |  |         # roll over to seconds, otherwise, ValueError is raised | 
					
						
							|  |  |  |         # by the constructor. | 
					
						
							|  |  |  |         if us == 1000000: | 
					
						
							|  |  |  |             t += 1 | 
					
						
							|  |  |  |             us = 0 | 
					
						
							| 
									
										
										
										
											2010-07-23 19:25:47 +00:00
										 |  |  |         y, m, d, hh, mm, ss, weekday, jday, dst = _time.gmtime(t) | 
					
						
							|  |  |  |         ss = min(ss, 59)    # clamp out leap seconds if the platform has them | 
					
						
							|  |  |  |         return cls(y, m, d, hh, mm, ss, us) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # XXX This is supposed to do better than we *can* do by using time.time(), | 
					
						
							|  |  |  |     # XXX if the platform supports a more accurate way.  The C implementation | 
					
						
							|  |  |  |     # XXX uses gettimeofday on platforms that have it, but that isn't | 
					
						
							|  |  |  |     # XXX available from Python.  So now() may return different results | 
					
						
							|  |  |  |     # XXX across the implementations. | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def now(cls, tz=None): | 
					
						
							|  |  |  |         "Construct a datetime from time.time() and optional time zone info." | 
					
						
							|  |  |  |         t = _time.time() | 
					
						
							|  |  |  |         return cls.fromtimestamp(t, tz) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def utcnow(cls): | 
					
						
							|  |  |  |         "Construct a UTC datetime from time.time()." | 
					
						
							|  |  |  |         t = _time.time() | 
					
						
							|  |  |  |         return cls.utcfromtimestamp(t) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def combine(cls, date, time): | 
					
						
							|  |  |  |         "Construct a datetime from a given date and a given time." | 
					
						
							|  |  |  |         if not isinstance(date, _date_class): | 
					
						
							|  |  |  |             raise TypeError("date argument must be a date instance") | 
					
						
							|  |  |  |         if not isinstance(time, _time_class): | 
					
						
							|  |  |  |             raise TypeError("time argument must be a time instance") | 
					
						
							|  |  |  |         return cls(date.year, date.month, date.day, | 
					
						
							|  |  |  |                    time.hour, time.minute, time.second, time.microsecond, | 
					
						
							|  |  |  |                    time.tzinfo) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def timetuple(self): | 
					
						
							|  |  |  |         "Return local time tuple compatible with time.localtime()." | 
					
						
							|  |  |  |         dst = self.dst() | 
					
						
							|  |  |  |         if dst is None: | 
					
						
							|  |  |  |             dst = -1 | 
					
						
							|  |  |  |         elif dst: | 
					
						
							|  |  |  |             dst = 1 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             dst = 0 | 
					
						
							|  |  |  |         return _build_struct_time(self.year, self.month, self.day, | 
					
						
							|  |  |  |                                   self.hour, self.minute, self.second, | 
					
						
							|  |  |  |                                   dst) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def utctimetuple(self): | 
					
						
							|  |  |  |         "Return UTC time tuple compatible with time.gmtime()." | 
					
						
							|  |  |  |         offset = self.utcoffset() | 
					
						
							|  |  |  |         if offset: | 
					
						
							|  |  |  |             self -= offset | 
					
						
							|  |  |  |         y, m, d = self.year, self.month, self.day | 
					
						
							|  |  |  |         hh, mm, ss = self.hour, self.minute, self.second | 
					
						
							|  |  |  |         return _build_struct_time(y, m, d, hh, mm, ss, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def date(self): | 
					
						
							|  |  |  |         "Return the date part." | 
					
						
							|  |  |  |         return date(self._year, self._month, self._day) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def time(self): | 
					
						
							|  |  |  |         "Return the time part, with tzinfo None." | 
					
						
							|  |  |  |         return time(self.hour, self.minute, self.second, self.microsecond) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def timetz(self): | 
					
						
							|  |  |  |         "Return the time part, with same tzinfo." | 
					
						
							|  |  |  |         return time(self.hour, self.minute, self.second, self.microsecond, | 
					
						
							|  |  |  |                     self._tzinfo) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def replace(self, year=None, month=None, day=None, hour=None, | 
					
						
							|  |  |  |                 minute=None, second=None, microsecond=None, tzinfo=True): | 
					
						
							|  |  |  |         """Return a new datetime with new values for the specified fields.""" | 
					
						
							|  |  |  |         if year is None: | 
					
						
							|  |  |  |             year = self.year | 
					
						
							|  |  |  |         if month is None: | 
					
						
							|  |  |  |             month = self.month | 
					
						
							|  |  |  |         if day is None: | 
					
						
							|  |  |  |             day = self.day | 
					
						
							|  |  |  |         if hour is None: | 
					
						
							|  |  |  |             hour = self.hour | 
					
						
							|  |  |  |         if minute is None: | 
					
						
							|  |  |  |             minute = self.minute | 
					
						
							|  |  |  |         if second is None: | 
					
						
							|  |  |  |             second = self.second | 
					
						
							|  |  |  |         if microsecond is None: | 
					
						
							|  |  |  |             microsecond = self.microsecond | 
					
						
							|  |  |  |         if tzinfo is True: | 
					
						
							|  |  |  |             tzinfo = self.tzinfo | 
					
						
							|  |  |  |         _check_date_fields(year, month, day) | 
					
						
							|  |  |  |         _check_time_fields(hour, minute, second, microsecond) | 
					
						
							|  |  |  |         _check_tzinfo_arg(tzinfo) | 
					
						
							|  |  |  |         return datetime(year, month, day, hour, minute, second, | 
					
						
							|  |  |  |                           microsecond, tzinfo) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def astimezone(self, tz): | 
					
						
							|  |  |  |         if not isinstance(tz, tzinfo): | 
					
						
							|  |  |  |             raise TypeError("tz argument must be an instance of tzinfo") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         mytz = self.tzinfo | 
					
						
							|  |  |  |         if mytz is None: | 
					
						
							|  |  |  |             raise ValueError("astimezone() requires an aware datetime") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if tz is mytz: | 
					
						
							|  |  |  |             return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Convert self to UTC, and attach the new time zone object. | 
					
						
							|  |  |  |         myoffset = self.utcoffset() | 
					
						
							|  |  |  |         if myoffset is None: | 
					
						
							|  |  |  |             raise ValueError("astimezone() requires an aware datetime") | 
					
						
							|  |  |  |         utc = (self - myoffset).replace(tzinfo=tz) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Convert from UTC to tz's local time. | 
					
						
							|  |  |  |         return tz.fromutc(utc) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Ways to produce a string. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def ctime(self): | 
					
						
							|  |  |  |         "Return ctime() style string." | 
					
						
							|  |  |  |         weekday = self.toordinal() % 7 or 7 | 
					
						
							|  |  |  |         return "%s %s %2d %02d:%02d:%02d %04d" % ( | 
					
						
							|  |  |  |             _DAYNAMES[weekday], | 
					
						
							|  |  |  |             _MONTHNAMES[self._month], | 
					
						
							|  |  |  |             self._day, | 
					
						
							|  |  |  |             self._hour, self._minute, self._second, | 
					
						
							|  |  |  |             self._year) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def isoformat(self, sep='T'): | 
					
						
							|  |  |  |         """Return the time formatted according to ISO.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This is 'YYYY-MM-DD HH:MM:SS.mmmmmm', or 'YYYY-MM-DD HH:MM:SS' if | 
					
						
							|  |  |  |         self.microsecond == 0. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         If self.tzinfo is not None, the UTC offset is also attached, giving | 
					
						
							|  |  |  |         'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM' or 'YYYY-MM-DD HH:MM:SS+HH:MM'. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Optional argument sep specifies the separator between date and | 
					
						
							|  |  |  |         time, default 'T'. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, | 
					
						
							|  |  |  |                                   sep) + | 
					
						
							|  |  |  |                 _format_time(self._hour, self._minute, self._second, | 
					
						
							|  |  |  |                              self._microsecond)) | 
					
						
							|  |  |  |         off = self.utcoffset() | 
					
						
							|  |  |  |         if off is not None: | 
					
						
							|  |  |  |             if off.days < 0: | 
					
						
							|  |  |  |                 sign = "-" | 
					
						
							|  |  |  |                 off = -off | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 sign = "+" | 
					
						
							|  |  |  |             hh, mm = divmod(off, timedelta(hours=1)) | 
					
						
							|  |  |  |             assert not mm % timedelta(minutes=1), "whole minute" | 
					
						
							|  |  |  |             mm //= timedelta(minutes=1) | 
					
						
							|  |  |  |             s += "%s%02d:%02d" % (sign, hh, mm) | 
					
						
							|  |  |  |         return s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         """Convert to formal string, for repr().""" | 
					
						
							|  |  |  |         L = [self._year, self._month, self._day, # These are never zero | 
					
						
							|  |  |  |              self._hour, self._minute, self._second, self._microsecond] | 
					
						
							|  |  |  |         if L[-1] == 0: | 
					
						
							|  |  |  |             del L[-1] | 
					
						
							|  |  |  |         if L[-1] == 0: | 
					
						
							|  |  |  |             del L[-1] | 
					
						
							|  |  |  |         s = ", ".join(map(str, L)) | 
					
						
							|  |  |  |         s = "%s(%s)" % ('datetime.' + self.__class__.__name__, s) | 
					
						
							|  |  |  |         if self._tzinfo is not None: | 
					
						
							|  |  |  |             assert s[-1:] == ")" | 
					
						
							|  |  |  |             s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")" | 
					
						
							|  |  |  |         return s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         "Convert to string, for str()." | 
					
						
							|  |  |  |         return self.isoformat(sep=' ') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def strptime(cls, date_string, format): | 
					
						
							|  |  |  |         'string, format -> new datetime parsed from a string (like time.strptime()).' | 
					
						
							|  |  |  |         import _strptime | 
					
						
							|  |  |  |         return _strptime._strptime_datetime(cls, date_string, format) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def utcoffset(self): | 
					
						
							|  |  |  |         """Return the timezone offset in minutes east of UTC (negative west of
 | 
					
						
							|  |  |  |         UTC)."""
 | 
					
						
							|  |  |  |         if self._tzinfo is None: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         offset = self._tzinfo.utcoffset(self) | 
					
						
							|  |  |  |         _check_utc_offset("utcoffset", offset) | 
					
						
							|  |  |  |         return offset | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def tzname(self): | 
					
						
							|  |  |  |         """Return the timezone name.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Note that the name is 100% informational -- there's no requirement that | 
					
						
							|  |  |  |         it mean anything in particular. For example, "GMT", "UTC", "-500", | 
					
						
							|  |  |  |         "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         name = _call_tzinfo_method(self._tzinfo, "tzname", self) | 
					
						
							|  |  |  |         _check_tzname(name) | 
					
						
							|  |  |  |         return name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def dst(self): | 
					
						
							|  |  |  |         """Return 0 if DST is not in effect, or the DST offset (in minutes
 | 
					
						
							|  |  |  |         eastward) if DST is in effect. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This is purely informational; the DST offset has already been added to | 
					
						
							|  |  |  |         the UTC offset returned by utcoffset() if applicable, so there's no | 
					
						
							|  |  |  |         need to consult dst() unless you're interested in displaying the DST | 
					
						
							|  |  |  |         info. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self._tzinfo is None: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         offset = self._tzinfo.dst(self) | 
					
						
							|  |  |  |         _check_utc_offset("dst", offset) | 
					
						
							|  |  |  |         return offset | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Comparisons of datetime objects with other. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __eq__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, datetime): | 
					
						
							|  |  |  |             return self._cmp(other) == 0 | 
					
						
							|  |  |  |         elif not isinstance(other, date): | 
					
						
							|  |  |  |             return NotImplemented | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ne__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, datetime): | 
					
						
							|  |  |  |             return self._cmp(other) != 0 | 
					
						
							|  |  |  |         elif not isinstance(other, date): | 
					
						
							|  |  |  |             return NotImplemented | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __le__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, datetime): | 
					
						
							|  |  |  |             return self._cmp(other) <= 0 | 
					
						
							|  |  |  |         elif not isinstance(other, date): | 
					
						
							|  |  |  |             return NotImplemented | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             _cmperror(self, other) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __lt__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, datetime): | 
					
						
							|  |  |  |             return self._cmp(other) < 0 | 
					
						
							|  |  |  |         elif not isinstance(other, date): | 
					
						
							|  |  |  |             return NotImplemented | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             _cmperror(self, other) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ge__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, datetime): | 
					
						
							|  |  |  |             return self._cmp(other) >= 0 | 
					
						
							|  |  |  |         elif not isinstance(other, date): | 
					
						
							|  |  |  |             return NotImplemented | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             _cmperror(self, other) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __gt__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, datetime): | 
					
						
							|  |  |  |             return self._cmp(other) > 0 | 
					
						
							|  |  |  |         elif not isinstance(other, date): | 
					
						
							|  |  |  |             return NotImplemented | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             _cmperror(self, other) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _cmp(self, other): | 
					
						
							|  |  |  |         assert isinstance(other, datetime) | 
					
						
							|  |  |  |         mytz = self._tzinfo | 
					
						
							|  |  |  |         ottz = other._tzinfo | 
					
						
							|  |  |  |         myoff = otoff = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if mytz is ottz: | 
					
						
							|  |  |  |             base_compare = True | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             if mytz is not None: | 
					
						
							|  |  |  |                 myoff = self.utcoffset() | 
					
						
							|  |  |  |             if ottz is not None: | 
					
						
							|  |  |  |                 otoff = other.utcoffset() | 
					
						
							|  |  |  |             base_compare = myoff == otoff | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if base_compare: | 
					
						
							|  |  |  |             return _cmp((self._year, self._month, self._day, | 
					
						
							|  |  |  |                          self._hour, self._minute, self._second, | 
					
						
							|  |  |  |                          self._microsecond), | 
					
						
							|  |  |  |                        (other._year, other._month, other._day, | 
					
						
							|  |  |  |                         other._hour, other._minute, other._second, | 
					
						
							|  |  |  |                         other._microsecond)) | 
					
						
							|  |  |  |         if myoff is None or otoff is None: | 
					
						
							|  |  |  |             raise TypeError("cannot compare naive and aware datetimes") | 
					
						
							|  |  |  |         # XXX What follows could be done more efficiently... | 
					
						
							|  |  |  |         diff = self - other     # this will take offsets into account | 
					
						
							|  |  |  |         if diff.days < 0: | 
					
						
							|  |  |  |             return -1 | 
					
						
							|  |  |  |         return diff and 1 or 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __add__(self, other): | 
					
						
							|  |  |  |         "Add a datetime and a timedelta." | 
					
						
							|  |  |  |         if not isinstance(other, timedelta): | 
					
						
							|  |  |  |             return NotImplemented | 
					
						
							|  |  |  |         delta = timedelta(self.toordinal(), | 
					
						
							|  |  |  |                           hours=self._hour, | 
					
						
							|  |  |  |                           minutes=self._minute, | 
					
						
							|  |  |  |                           seconds=self._second, | 
					
						
							|  |  |  |                           microseconds=self._microsecond) | 
					
						
							|  |  |  |         delta += other | 
					
						
							|  |  |  |         hour, rem = divmod(delta.seconds, 3600) | 
					
						
							|  |  |  |         minute, second = divmod(rem, 60) | 
					
						
							|  |  |  |         if 0 < delta.days <= _MAXORDINAL: | 
					
						
							|  |  |  |             return datetime.combine(date.fromordinal(delta.days), | 
					
						
							|  |  |  |                                     time(hour, minute, second, | 
					
						
							|  |  |  |                                          delta.microseconds, | 
					
						
							|  |  |  |                                          tzinfo=self._tzinfo)) | 
					
						
							|  |  |  |         raise OverflowError("result out of range") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __radd__ = __add__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __sub__(self, other): | 
					
						
							|  |  |  |         "Subtract two datetimes, or a datetime and a timedelta." | 
					
						
							|  |  |  |         if not isinstance(other, datetime): | 
					
						
							|  |  |  |             if isinstance(other, timedelta): | 
					
						
							|  |  |  |                 return self + -other | 
					
						
							|  |  |  |             return NotImplemented | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         days1 = self.toordinal() | 
					
						
							|  |  |  |         days2 = other.toordinal() | 
					
						
							|  |  |  |         secs1 = self._second + self._minute * 60 + self._hour * 3600 | 
					
						
							|  |  |  |         secs2 = other._second + other._minute * 60 + other._hour * 3600 | 
					
						
							|  |  |  |         base = timedelta(days1 - days2, | 
					
						
							|  |  |  |                          secs1 - secs2, | 
					
						
							|  |  |  |                          self._microsecond - other._microsecond) | 
					
						
							|  |  |  |         if self._tzinfo is other._tzinfo: | 
					
						
							|  |  |  |             return base | 
					
						
							|  |  |  |         myoff = self.utcoffset() | 
					
						
							|  |  |  |         otoff = other.utcoffset() | 
					
						
							|  |  |  |         if myoff == otoff: | 
					
						
							|  |  |  |             return base | 
					
						
							|  |  |  |         if myoff is None or otoff is None: | 
					
						
							|  |  |  |             raise TypeError("cannot mix naive and timezone-aware time") | 
					
						
							|  |  |  |         return base + otoff - myoff | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __hash__(self): | 
					
						
							|  |  |  |         tzoff = self.utcoffset() | 
					
						
							|  |  |  |         if tzoff is None: | 
					
						
							|  |  |  |             return hash(self._getstate()[0]) | 
					
						
							|  |  |  |         days = _ymd2ord(self.year, self.month, self.day) | 
					
						
							|  |  |  |         seconds = self.hour * 3600 + self.minute * 60 + self.second | 
					
						
							|  |  |  |         return hash(timedelta(days, seconds, self.microsecond) - tzoff) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Pickle support. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _getstate(self): | 
					
						
							|  |  |  |         yhi, ylo = divmod(self._year, 256) | 
					
						
							|  |  |  |         us2, us3 = divmod(self._microsecond, 256) | 
					
						
							|  |  |  |         us1, us2 = divmod(us2, 256) | 
					
						
							|  |  |  |         basestate = bytes([yhi, ylo, self._month, self._day, | 
					
						
							|  |  |  |                            self._hour, self._minute, self._second, | 
					
						
							|  |  |  |                            us1, us2, us3]) | 
					
						
							|  |  |  |         if self._tzinfo is None: | 
					
						
							|  |  |  |             return (basestate,) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return (basestate, self._tzinfo) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __setstate(self, string, tzinfo): | 
					
						
							|  |  |  |         (yhi, ylo, self._month, self._day, self._hour, | 
					
						
							|  |  |  |          self._minute, self._second, us1, us2, us3) = string | 
					
						
							|  |  |  |         self._year = yhi * 256 + ylo | 
					
						
							|  |  |  |         self._microsecond = (((us1 << 8) | us2) << 8) | us3 | 
					
						
							|  |  |  |         if tzinfo is None or isinstance(tzinfo, _tzinfo_class): | 
					
						
							|  |  |  |             self._tzinfo = tzinfo | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise TypeError("bad tzinfo state arg %r" % tzinfo) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __reduce__(self): | 
					
						
							|  |  |  |         return (self.__class__, self._getstate()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | datetime.min = datetime(1, 1, 1) | 
					
						
							|  |  |  | datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999) | 
					
						
							|  |  |  | datetime.resolution = timedelta(microseconds=1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _isoweek1monday(year): | 
					
						
							|  |  |  |     # Helper to calculate the day number of the Monday starting week 1 | 
					
						
							|  |  |  |     # XXX This could be done more efficiently | 
					
						
							|  |  |  |     THURSDAY = 3 | 
					
						
							|  |  |  |     firstday = _ymd2ord(year, 1, 1) | 
					
						
							|  |  |  |     firstweekday = (firstday + 6) % 7 # See weekday() above | 
					
						
							|  |  |  |     week1monday = firstday - firstweekday | 
					
						
							|  |  |  |     if firstweekday > THURSDAY: | 
					
						
							|  |  |  |         week1monday += 7 | 
					
						
							|  |  |  |     return week1monday | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class timezone(tzinfo): | 
					
						
							|  |  |  |     __slots__ = '_offset', '_name' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Sentinel value to disallow None | 
					
						
							|  |  |  |     _Omitted = object() | 
					
						
							| 
									
										
										
										
											2010-10-14 17:03:51 +00:00
										 |  |  |     def __new__(cls, offset, name=_Omitted): | 
					
						
							|  |  |  |         if not isinstance(offset, timedelta): | 
					
						
							|  |  |  |             raise TypeError("offset must be a timedelta") | 
					
						
							|  |  |  |         if name is cls._Omitted: | 
					
						
							|  |  |  |             if not offset: | 
					
						
							|  |  |  |                 return cls.utc | 
					
						
							| 
									
										
										
										
											2010-07-23 19:25:47 +00:00
										 |  |  |             name = None | 
					
						
							|  |  |  |         elif not isinstance(name, str): | 
					
						
							|  |  |  |             raise TypeError("name must be a string") | 
					
						
							| 
									
										
										
										
											2010-10-14 17:03:51 +00:00
										 |  |  |         if not cls._minoffset <= offset <= cls._maxoffset: | 
					
						
							|  |  |  |             raise ValueError("offset must be a timedelta" | 
					
						
							|  |  |  |                              " strictly between -timedelta(hours=24) and" | 
					
						
							|  |  |  |                              " timedelta(hours=24).") | 
					
						
							|  |  |  |         if (offset.microseconds != 0 or | 
					
						
							|  |  |  |             offset.seconds % 60 != 0): | 
					
						
							|  |  |  |             raise ValueError("offset must be a timedelta" | 
					
						
							|  |  |  |                              " representing a whole number of minutes") | 
					
						
							|  |  |  |         return cls._create(offset, name) | 
					
						
							| 
									
										
										
										
											2010-07-23 19:25:47 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-14 17:03:51 +00:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def _create(cls, offset, name=None): | 
					
						
							|  |  |  |         self = tzinfo.__new__(cls) | 
					
						
							|  |  |  |         self._offset = offset | 
					
						
							| 
									
										
										
										
											2010-07-23 19:25:47 +00:00
										 |  |  |         self._name = name | 
					
						
							| 
									
										
										
										
											2010-10-14 17:03:51 +00:00
										 |  |  |         return self | 
					
						
							| 
									
										
										
										
											2010-07-23 19:25:47 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __getinitargs__(self): | 
					
						
							|  |  |  |         """pickle support""" | 
					
						
							|  |  |  |         if self._name is None: | 
					
						
							|  |  |  |             return (self._offset,) | 
					
						
							|  |  |  |         return (self._offset, self._name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __eq__(self, other): | 
					
						
							|  |  |  |         return self._offset == other._offset | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __hash__(self): | 
					
						
							|  |  |  |         return hash(self._offset) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         """Convert to formal string, for repr().
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         >>> tz = timezone.utc | 
					
						
							|  |  |  |         >>> repr(tz) | 
					
						
							|  |  |  |         'datetime.timezone.utc' | 
					
						
							|  |  |  |         >>> tz = timezone(timedelta(hours=-5), 'EST') | 
					
						
							|  |  |  |         >>> repr(tz) | 
					
						
							|  |  |  |         "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')" | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self is self.utc: | 
					
						
							|  |  |  |             return 'datetime.timezone.utc' | 
					
						
							|  |  |  |         if self._name is None: | 
					
						
							|  |  |  |             return "%s(%r)" % ('datetime.' + self.__class__.__name__, | 
					
						
							|  |  |  |                                self._offset) | 
					
						
							|  |  |  |         return "%s(%r, %r)" % ('datetime.' + self.__class__.__name__, | 
					
						
							|  |  |  |                                self._offset, self._name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return self.tzname(None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def utcoffset(self, dt): | 
					
						
							|  |  |  |         if isinstance(dt, datetime) or dt is None: | 
					
						
							|  |  |  |             return self._offset | 
					
						
							|  |  |  |         raise TypeError("utcoffset() argument must be a datetime instance" | 
					
						
							|  |  |  |                         " or None") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def tzname(self, dt): | 
					
						
							|  |  |  |         if isinstance(dt, datetime) or dt is None: | 
					
						
							|  |  |  |             if self._name is None: | 
					
						
							|  |  |  |                 return self._name_from_offset(self._offset) | 
					
						
							|  |  |  |             return self._name | 
					
						
							|  |  |  |         raise TypeError("tzname() argument must be a datetime instance" | 
					
						
							|  |  |  |                         " or None") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def dst(self, dt): | 
					
						
							|  |  |  |         if isinstance(dt, datetime) or dt is None: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         raise TypeError("dst() argument must be a datetime instance" | 
					
						
							|  |  |  |                         " or None") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def fromutc(self, dt): | 
					
						
							|  |  |  |         if isinstance(dt, datetime): | 
					
						
							|  |  |  |             if dt.tzinfo is not self: | 
					
						
							|  |  |  |                 raise ValueError("fromutc: dt.tzinfo " | 
					
						
							|  |  |  |                                  "is not self") | 
					
						
							|  |  |  |             return dt + self._offset | 
					
						
							|  |  |  |         raise TypeError("fromutc() argument must be a datetime instance" | 
					
						
							|  |  |  |                         " or None") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _maxoffset = timedelta(hours=23, minutes=59) | 
					
						
							|  |  |  |     _minoffset = -_maxoffset | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def _name_from_offset(delta): | 
					
						
							|  |  |  |         if delta < timedelta(0): | 
					
						
							|  |  |  |             sign = '-' | 
					
						
							|  |  |  |             delta = -delta | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             sign = '+' | 
					
						
							|  |  |  |         hours, rest = divmod(delta, timedelta(hours=1)) | 
					
						
							|  |  |  |         minutes = rest // timedelta(minutes=1) | 
					
						
							|  |  |  |         return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-14 17:03:51 +00:00
										 |  |  | timezone.utc = timezone._create(timedelta(0)) | 
					
						
							|  |  |  | timezone.min = timezone._create(timezone._minoffset) | 
					
						
							|  |  |  | timezone.max = timezone._create(timezone._maxoffset) | 
					
						
							| 
									
										
										
										
											2010-07-23 19:25:47 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | Some time zone algebra.  For a datetime x, let | 
					
						
							|  |  |  |     x.n = x stripped of its timezone -- its naive time. | 
					
						
							|  |  |  |     x.o = x.utcoffset(), and assuming that doesn't raise an exception or | 
					
						
							|  |  |  |           return None | 
					
						
							|  |  |  |     x.d = x.dst(), and assuming that doesn't raise an exception or | 
					
						
							|  |  |  |           return None | 
					
						
							|  |  |  |     x.s = x's standard offset, x.o - x.d | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Now some derived rules, where k is a duration (timedelta). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 1. x.o = x.s + x.d | 
					
						
							|  |  |  |    This follows from the definition of x.s. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 2. If x and y have the same tzinfo member, x.s = y.s. | 
					
						
							|  |  |  |    This is actually a requirement, an assumption we need to make about | 
					
						
							|  |  |  |    sane tzinfo classes. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 3. The naive UTC time corresponding to x is x.n - x.o. | 
					
						
							|  |  |  |    This is again a requirement for a sane tzinfo class. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 4. (x+k).s = x.s | 
					
						
							|  |  |  |    This follows from #2, and that datimetimetz+timedelta preserves tzinfo. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 5. (x+k).n = x.n + k | 
					
						
							|  |  |  |    Again follows from how arithmetic is defined. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Now we can explain tz.fromutc(x).  Let's assume it's an interesting case | 
					
						
							|  |  |  | (meaning that the various tzinfo methods exist, and don't blow up or return | 
					
						
							|  |  |  | None when called). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The function wants to return a datetime y with timezone tz, equivalent to x. | 
					
						
							|  |  |  | x is already in UTC. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | By #3, we want | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     y.n - y.o = x.n                             [1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The algorithm starts by attaching tz to x.n, and calling that y.  So | 
					
						
							|  |  |  | x.n = y.n at the start.  Then it wants to add a duration k to y, so that [1] | 
					
						
							|  |  |  | becomes true; in effect, we want to solve [2] for k: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    (y+k).n - (y+k).o = x.n                      [2] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | By #1, this is the same as | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    (y+k).n - ((y+k).s + (y+k).d) = x.n          [3] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start. | 
					
						
							|  |  |  | Substituting that into [3], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving | 
					
						
							|  |  |  |    k - (y+k).s - (y+k).d = 0; rearranging, | 
					
						
							|  |  |  |    k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so | 
					
						
							|  |  |  |    k = y.s - (y+k).d | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | On the RHS, (y+k).d can't be computed directly, but y.s can be, and we | 
					
						
							|  |  |  | approximate k by ignoring the (y+k).d term at first.  Note that k can't be | 
					
						
							|  |  |  | very large, since all offset-returning methods return a duration of magnitude | 
					
						
							|  |  |  | less than 24 hours.  For that reason, if y is firmly in std time, (y+k).d must | 
					
						
							|  |  |  | be 0, so ignoring it has no consequence then. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In any case, the new value is | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     z = y + y.s                                 [4] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | It's helpful to step back at look at [4] from a higher level:  it's simply | 
					
						
							|  |  |  | mapping from UTC to tz's standard time. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | At this point, if | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     z.n - z.o = x.n                             [5] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | we have an equivalent time, and are almost done.  The insecurity here is | 
					
						
							|  |  |  | at the start of daylight time.  Picture US Eastern for concreteness.  The wall | 
					
						
							|  |  |  | time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good | 
					
						
							|  |  |  | sense then.  The docs ask that an Eastern tzinfo class consider such a time to | 
					
						
							|  |  |  | be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST | 
					
						
							|  |  |  | on the day DST starts.  We want to return the 1:MM EST spelling because that's | 
					
						
							|  |  |  | the only spelling that makes sense on the local wall clock. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In fact, if [5] holds at this point, we do have the standard-time spelling, | 
					
						
							|  |  |  | but that takes a bit of proof.  We first prove a stronger result.  What's the | 
					
						
							|  |  |  | difference between the LHS and RHS of [5]?  Let | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     diff = x.n - (z.n - z.o)                    [6] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Now | 
					
						
							|  |  |  |     z.n =                       by [4] | 
					
						
							|  |  |  |     (y + y.s).n =               by #5 | 
					
						
							|  |  |  |     y.n + y.s =                 since y.n = x.n | 
					
						
							|  |  |  |     x.n + y.s =                 since z and y are have the same tzinfo member, | 
					
						
							|  |  |  |                                     y.s = z.s by #2 | 
					
						
							|  |  |  |     x.n + z.s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Plugging that back into [6] gives | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     diff = | 
					
						
							|  |  |  |     x.n - ((x.n + z.s) - z.o) =     expanding | 
					
						
							|  |  |  |     x.n - x.n - z.s + z.o =         cancelling | 
					
						
							|  |  |  |     - z.s + z.o =                   by #2 | 
					
						
							|  |  |  |     z.d | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | So diff = z.d. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time | 
					
						
							|  |  |  | spelling we wanted in the endcase described above.  We're done.  Contrarily, | 
					
						
							|  |  |  | if z.d = 0, then we have a UTC equivalent, and are also done. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to | 
					
						
							|  |  |  | add to z (in effect, z is in tz's standard time, and we need to shift the | 
					
						
							|  |  |  | local clock into tz's daylight time). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Let | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     z' = z + z.d = z + diff                     [7] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | and we can again ask whether | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     z'.n - z'.o = x.n                           [8] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If so, we're done.  If not, the tzinfo class is insane, according to the | 
					
						
							|  |  |  | assumptions we've made.  This also requires a bit of proof.  As before, let's | 
					
						
							|  |  |  | compute the difference between the LHS and RHS of [8] (and skipping some of | 
					
						
							|  |  |  | the justifications for the kinds of substitutions we've done several times | 
					
						
							|  |  |  | already): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     diff' = x.n - (z'.n - z'.o) =           replacing z'.n via [7] | 
					
						
							|  |  |  |             x.n  - (z.n + diff - z'.o) =    replacing diff via [6] | 
					
						
							|  |  |  |             x.n - (z.n + x.n - (z.n - z.o) - z'.o) = | 
					
						
							|  |  |  |             x.n - z.n - x.n + z.n - z.o + z'.o =    cancel x.n | 
					
						
							|  |  |  |             - z.n + z.n - z.o + z'.o =              cancel z.n | 
					
						
							|  |  |  |             - z.o + z'.o =                      #1 twice | 
					
						
							|  |  |  |             -z.s - z.d + z'.s + z'.d =          z and z' have same tzinfo | 
					
						
							|  |  |  |             z'.d - z.d | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | So z' is UTC-equivalent to x iff z'.d = z.d at this point.  If they are equal, | 
					
						
							|  |  |  | we've found the UTC-equivalent so are done.  In fact, we stop with [7] and | 
					
						
							|  |  |  | return z', not bothering to compute z'.d. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | How could z.d and z'd differ?  z' = z + z.d [7], so merely moving z' by | 
					
						
							|  |  |  | a dst() offset, and starting *from* a time already in DST (we know z.d != 0), | 
					
						
							|  |  |  | would have to change the result dst() returns:  we start in DST, and moving | 
					
						
							|  |  |  | a little further into it takes us out of DST. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | There isn't a sane case where this can happen.  The closest it gets is at | 
					
						
							|  |  |  | the end of DST, where there's an hour in UTC with no spelling in a hybrid | 
					
						
							|  |  |  | tzinfo class.  In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT.  During | 
					
						
							|  |  |  | that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM | 
					
						
							|  |  |  | UTC) because the docs insist on that, but 0:MM is taken as being in daylight | 
					
						
							|  |  |  | time (4:MM UTC).  There is no local time mapping to 5:MM UTC.  The local | 
					
						
							|  |  |  | clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in | 
					
						
							|  |  |  | standard time.  Since that's what the local clock *does*, we want to map both | 
					
						
							|  |  |  | UTC hours 5:MM and 6:MM to 1:MM Eastern.  The result is ambiguous | 
					
						
							|  |  |  | in local time, but so it goes -- it's the way the local clock works. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0, | 
					
						
							|  |  |  | so z=0:MM.  z.d=60 (minutes) then, so [5] doesn't hold and we keep going. | 
					
						
							|  |  |  | z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8] | 
					
						
							|  |  |  | (correctly) concludes that z' is not UTC-equivalent to x. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Because we know z.d said z was in daylight time (else [5] would have held and | 
					
						
							|  |  |  | we would have stopped then), and we know z.d != z'.d (else [8] would have held | 
					
						
							| 
									
										
										
										
											2011-10-19 10:58:56 +03:00
										 |  |  | and we have stopped then), and there are only 2 possible values dst() can | 
					
						
							| 
									
										
										
										
											2010-07-23 19:25:47 +00:00
										 |  |  | return in Eastern, it follows that z'.d must be 0 (which it is in the example, | 
					
						
							|  |  |  | but the reasoning doesn't depend on the example -- it depends on there being | 
					
						
							|  |  |  | two possible dst() outcomes, one zero and the other non-zero).  Therefore | 
					
						
							|  |  |  | z' must be in standard time, and is the spelling we want in this case. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is | 
					
						
							|  |  |  | concerned (because it takes z' as being in standard time rather than the | 
					
						
							|  |  |  | daylight time we intend here), but returning it gives the real-life "local | 
					
						
							|  |  |  | clock repeats an hour" behavior when mapping the "unspellable" UTC hour into | 
					
						
							|  |  |  | tz. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with | 
					
						
							|  |  |  | the 1:MM standard time spelling we want. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | So how can this break?  One of the assumptions must be violated.  Two | 
					
						
							|  |  |  | possibilities: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 1) [2] effectively says that y.s is invariant across all y belong to a given | 
					
						
							|  |  |  |    time zone.  This isn't true if, for political reasons or continental drift, | 
					
						
							|  |  |  |    a region decides to change its base offset from UTC. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 2) There may be versions of "double daylight" time where the tail end of | 
					
						
							|  |  |  |    the analysis gives up a step too early.  I haven't thought about that | 
					
						
							|  |  |  |    enough to say. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In any case, it's clear that the default fromutc() is strong enough to handle | 
					
						
							|  |  |  | "almost all" time zones:  so long as the standard offset is invariant, it | 
					
						
							|  |  |  | doesn't matter if daylight time transition points change from year to year, or | 
					
						
							|  |  |  | if daylight time is skipped in some years; it doesn't matter how large or | 
					
						
							|  |  |  | small dst() may get within its bounds; and it doesn't even matter if some | 
					
						
							|  |  |  | perverse time zone returns a negative dst()).  So a breaking case must be | 
					
						
							|  |  |  | pretty bizarre, and a tzinfo subclass can override fromutc() if it is. | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | try: | 
					
						
							|  |  |  |     from _datetime import * | 
					
						
							|  |  |  | except ImportError: | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | else: | 
					
						
							|  |  |  |     # Clean up unused names | 
					
						
							|  |  |  |     del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, | 
					
						
							|  |  |  |          _DI100Y, _DI400Y, _DI4Y, _MAXORDINAL, _MONTHNAMES, | 
					
						
							|  |  |  |          _build_struct_time, _call_tzinfo_method, _check_date_fields, | 
					
						
							|  |  |  |          _check_time_fields, _check_tzinfo_arg, _check_tzname, | 
					
						
							|  |  |  |          _check_utc_offset, _cmp, _cmperror, _date_class, _days_before_month, | 
					
						
							|  |  |  |          _days_before_year, _days_in_month, _format_time, _is_leap, | 
					
						
							|  |  |  |          _isoweek1monday, _math, _ord2ymd, _time, _time_class, _tzinfo_class, | 
					
						
							|  |  |  |          _wrap_strftime, _ymd2ord) | 
					
						
							| 
									
										
										
										
											2010-07-23 20:03:53 +00:00
										 |  |  |     # XXX Since import * above excludes names that start with _, | 
					
						
							|  |  |  |     # docstring does not get overwritten. In the future, it may be | 
					
						
							|  |  |  |     # appropriate to maintain a single module level docstring and | 
					
						
							|  |  |  |     # remove the following line. | 
					
						
							|  |  |  |     from _datetime import __doc__ |