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