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