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