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