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. Valid options are 'auto', 'hours', 1422 'minutes', 'seconds', 'milliseconds' and 'microseconds'. 1423 """ 1424 s = _format_time(self._hour, self._minute, self._second, 1425 self._microsecond, timespec) 1426 tz = self._tzstr() 1427 if tz: 1428 s += tz 1429 return s 1430 1431 __str__ = isoformat 1432 1433 @classmethod 1434 def fromisoformat(cls, time_string): 1435 """Construct a time from the output of isoformat().""" 1436 if not isinstance(time_string, str): 1437 raise TypeError('fromisoformat: argument must be str') 1438 1439 try: 1440 return cls(*_parse_isoformat_time(time_string)) 1441 except Exception: 1442 raise ValueError(f'Invalid isoformat string: {time_string!r}') 1443 1444 1445 def strftime(self, fmt): 1446 """Format using strftime(). The date part of the timestamp passed 1447 to underlying strftime should not be used. 1448 """ 1449 # The year must be >= 1000 else Python's strftime implementation 1450 # can raise a bogus exception. 1451 timetuple = (1900, 1, 1, 1452 self._hour, self._minute, self._second, 1453 0, 1, -1) 1454 return _wrap_strftime(self, fmt, timetuple) 1455 1456 def __format__(self, fmt): 1457 if not isinstance(fmt, str): 1458 raise TypeError("must be str, not %s" % type(fmt).__name__) 1459 if len(fmt) != 0: 1460 return self.strftime(fmt) 1461 return str(self) 1462 1463 # Timezone functions 1464 1465 def utcoffset(self): 1466 """Return the timezone offset as timedelta, positive east of UTC 1467 (negative west of UTC).""" 1468 if self._tzinfo is None: 1469 return None 1470 offset = self._tzinfo.utcoffset(None) 1471 _check_utc_offset("utcoffset", offset) 1472 return offset 1473 1474 def tzname(self): 1475 """Return the timezone name. 1476 1477 Note that the name is 100% informational -- there's no requirement that 1478 it mean anything in particular. For example, "GMT", "UTC", "-500", 1479 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies. 1480 """ 1481 if self._tzinfo is None: 1482 return None 1483 name = self._tzinfo.tzname(None) 1484 _check_tzname(name) 1485 return name 1486 1487 def dst(self): 1488 """Return 0 if DST is not in effect, or the DST offset (as timedelta 1489 positive eastward) if DST is in effect. 1490 1491 This is purely informational; the DST offset has already been added to 1492 the UTC offset returned by utcoffset() if applicable, so there's no 1493 need to consult dst() unless you're interested in displaying the DST 1494 info. 1495 """ 1496 if self._tzinfo is None: 1497 return None 1498 offset = self._tzinfo.dst(None) 1499 _check_utc_offset("dst", offset) 1500 return offset 1501 1502 def replace(self, hour=None, minute=None, second=None, microsecond=None, 1503 tzinfo=True, *, fold=None): 1504 """Return a new time with new values for the specified fields.""" 1505 if hour is None: 1506 hour = self.hour 1507 if minute is None: 1508 minute = self.minute 1509 if second is None: 1510 second = self.second 1511 if microsecond is None: 1512 microsecond = self.microsecond 1513 if tzinfo is True: 1514 tzinfo = self.tzinfo 1515 if fold is None: 1516 fold = self._fold 1517 return type(self)(hour, minute, second, microsecond, tzinfo, fold=fold) 1518 1519 # Pickle support. 1520 1521 def _getstate(self, protocol=3): 1522 us2, us3 = divmod(self._microsecond, 256) 1523 us1, us2 = divmod(us2, 256) 1524 h = self._hour 1525 if self._fold and protocol > 3: 1526 h += 128 1527 basestate = bytes([h, self._minute, self._second, 1528 us1, us2, us3]) 1529 if self._tzinfo is None: 1530 return (basestate,) 1531 else: 1532 return (basestate, self._tzinfo) 1533 1534 def __setstate(self, string, tzinfo): 1535 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class): 1536 raise TypeError("bad tzinfo state arg") 1537 h, self._minute, self._second, us1, us2, us3 = string 1538 if h > 127: 1539 self._fold = 1 1540 self._hour = h - 128 1541 else: 1542 self._fold = 0 1543 self._hour = h 1544 self._microsecond = (((us1 << 8) | us2) << 8) | us3 1545 self._tzinfo = tzinfo 1546 1547 def __reduce_ex__(self, protocol): 1548 return (self.__class__, self._getstate(protocol)) 1549 1550 def __reduce__(self): 1551 return self.__reduce_ex__(2) 1552 1553_time_class = time # so functions w/ args named "time" can get at the class 1554 1555time.min = time(0, 0, 0) 1556time.max = time(23, 59, 59, 999999) 1557time.resolution = timedelta(microseconds=1) 1558 1559class datetime(date): 1560 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]]) 1561 1562 The year, month and day arguments are required. tzinfo may be None, or an 1563 instance of a tzinfo subclass. The remaining arguments may be ints. 1564 """ 1565 __slots__ = date.__slots__ + time.__slots__ 1566 1567 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0, 1568 microsecond=0, tzinfo=None, *, fold=0): 1569 if (isinstance(year, (bytes, str)) and len(year) == 10 and 1570 1 <= ord(year[2:3])&0x7F <= 12): 1571 # Pickle support 1572 if isinstance(year, str): 1573 try: 1574 year = bytes(year, 'latin1') 1575 except UnicodeEncodeError: 1576 # More informative error message. 1577 raise ValueError( 1578 "Failed to encode latin1 string when unpickling " 1579 "a datetime object. " 1580 "pickle.load(data, encoding='latin1') is assumed.") 1581 self = object.__new__(cls) 1582 self.__setstate(year, month) 1583 self._hashcode = -1 1584 return self 1585 year, month, day = _check_date_fields(year, month, day) 1586 hour, minute, second, microsecond, fold = _check_time_fields( 1587 hour, minute, second, microsecond, fold) 1588 _check_tzinfo_arg(tzinfo) 1589 self = object.__new__(cls) 1590 self._year = year 1591 self._month = month 1592 self._day = day 1593 self._hour = hour 1594 self._minute = minute 1595 self._second = second 1596 self._microsecond = microsecond 1597 self._tzinfo = tzinfo 1598 self._hashcode = -1 1599 self._fold = fold 1600 return self 1601 1602 # Read-only field accessors 1603 @property 1604 def hour(self): 1605 """hour (0-23)""" 1606 return self._hour 1607 1608 @property 1609 def minute(self): 1610 """minute (0-59)""" 1611 return self._minute 1612 1613 @property 1614 def second(self): 1615 """second (0-59)""" 1616 return self._second 1617 1618 @property 1619 def microsecond(self): 1620 """microsecond (0-999999)""" 1621 return self._microsecond 1622 1623 @property 1624 def tzinfo(self): 1625 """timezone info object""" 1626 return self._tzinfo 1627 1628 @property 1629 def fold(self): 1630 return self._fold 1631 1632 @classmethod 1633 def _fromtimestamp(cls, t, utc, tz): 1634 """Construct a datetime from a POSIX timestamp (like time.time()). 1635 1636 A timezone info object may be passed in as well. 1637 """ 1638 frac, t = _math.modf(t) 1639 us = round(frac * 1e6) 1640 if us >= 1000000: 1641 t += 1 1642 us -= 1000000 1643 elif us < 0: 1644 t -= 1 1645 us += 1000000 1646 1647 converter = _time.gmtime if utc else _time.localtime 1648 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t) 1649 ss = min(ss, 59) # clamp out leap seconds if the platform has them 1650 result = cls(y, m, d, hh, mm, ss, us, tz) 1651 if tz is None: 1652 # As of version 2015f max fold in IANA database is 1653 # 23 hours at 1969-09-30 13:00:00 in Kwajalein. 1654 # Let's probe 24 hours in the past to detect a transition: 1655 max_fold_seconds = 24 * 3600 1656 1657 # On Windows localtime_s throws an OSError for negative values, 1658 # thus we can't perform fold detection for values of time less 1659 # than the max time fold. See comments in _datetimemodule's 1660 # version of this method for more details. 1661 if t < max_fold_seconds and sys.platform.startswith("win"): 1662 return result 1663 1664 y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6] 1665 probe1 = cls(y, m, d, hh, mm, ss, us, tz) 1666 trans = result - probe1 - timedelta(0, max_fold_seconds) 1667 if trans.days < 0: 1668 y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6] 1669 probe2 = cls(y, m, d, hh, mm, ss, us, tz) 1670 if probe2 == result: 1671 result._fold = 1 1672 else: 1673 result = tz.fromutc(result) 1674 return result 1675 1676 @classmethod 1677 def fromtimestamp(cls, t, tz=None): 1678 """Construct a datetime from a POSIX timestamp (like time.time()). 1679 1680 A timezone info object may be passed in as well. 1681 """ 1682 _check_tzinfo_arg(tz) 1683 1684 return cls._fromtimestamp(t, tz is not None, tz) 1685 1686 @classmethod 1687 def utcfromtimestamp(cls, t): 1688 """Construct a naive UTC datetime from a POSIX timestamp.""" 1689 return cls._fromtimestamp(t, True, None) 1690 1691 @classmethod 1692 def now(cls, tz=None): 1693 "Construct a datetime from time.time() and optional time zone info." 1694 t = _time.time() 1695 return cls.fromtimestamp(t, tz) 1696 1697 @classmethod 1698 def utcnow(cls): 1699 "Construct a UTC datetime from time.time()." 1700 t = _time.time() 1701 return cls.utcfromtimestamp(t) 1702 1703 @classmethod 1704 def combine(cls, date, time, tzinfo=True): 1705 "Construct a datetime from a given date and a given time." 1706 if not isinstance(date, _date_class): 1707 raise TypeError("date argument must be a date instance") 1708 if not isinstance(time, _time_class): 1709 raise TypeError("time argument must be a time instance") 1710 if tzinfo is True: 1711 tzinfo = time.tzinfo 1712 return cls(date.year, date.month, date.day, 1713 time.hour, time.minute, time.second, time.microsecond, 1714 tzinfo, fold=time.fold) 1715 1716 @classmethod 1717 def fromisoformat(cls, date_string): 1718 """Construct a datetime from the output of datetime.isoformat().""" 1719 if not isinstance(date_string, str): 1720 raise TypeError('fromisoformat: argument must be str') 1721 1722 # Split this at the separator 1723 dstr = date_string[0:10] 1724 tstr = date_string[11:] 1725 1726 try: 1727 date_components = _parse_isoformat_date(dstr) 1728 except ValueError: 1729 raise ValueError(f'Invalid isoformat string: {date_string!r}') 1730 1731 if tstr: 1732 try: 1733 time_components = _parse_isoformat_time(tstr) 1734 except ValueError: 1735 raise ValueError(f'Invalid isoformat string: {date_string!r}') 1736 else: 1737 time_components = [0, 0, 0, 0, None] 1738 1739 return cls(*(date_components + time_components)) 1740 1741 def timetuple(self): 1742 "Return local time tuple compatible with time.localtime()." 1743 dst = self.dst() 1744 if dst is None: 1745 dst = -1 1746 elif dst: 1747 dst = 1 1748 else: 1749 dst = 0 1750 return _build_struct_time(self.year, self.month, self.day, 1751 self.hour, self.minute, self.second, 1752 dst) 1753 1754 def _mktime(self): 1755 """Return integer POSIX timestamp.""" 1756 epoch = datetime(1970, 1, 1) 1757 max_fold_seconds = 24 * 3600 1758 t = (self - epoch) // timedelta(0, 1) 1759 def local(u): 1760 y, m, d, hh, mm, ss = _time.localtime(u)[:6] 1761 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1) 1762 1763 # Our goal is to solve t = local(u) for u. 1764 a = local(t) - t 1765 u1 = t - a 1766 t1 = local(u1) 1767 if t1 == t: 1768 # We found one solution, but it may not be the one we need. 1769 # Look for an earlier solution (if `fold` is 0), or a 1770 # later one (if `fold` is 1). 1771 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold] 1772 b = local(u2) - u2 1773 if a == b: 1774 return u1 1775 else: 1776 b = t1 - u1 1777 assert a != b 1778 u2 = t - b 1779 t2 = local(u2) 1780 if t2 == t: 1781 return u2 1782 if t1 == t: 1783 return u1 1784 # We have found both offsets a and b, but neither t - a nor t - b is 1785 # a solution. This means t is in the gap. 1786 return (max, min)[self.fold](u1, u2) 1787 1788 1789 def timestamp(self): 1790 "Return POSIX timestamp as float" 1791 if self._tzinfo is None: 1792 s = self._mktime() 1793 return s + self.microsecond / 1e6 1794 else: 1795 return (self - _EPOCH).total_seconds() 1796 1797 def utctimetuple(self): 1798 "Return UTC time tuple compatible with time.gmtime()." 1799 offset = self.utcoffset() 1800 if offset: 1801 self -= offset 1802 y, m, d = self.year, self.month, self.day 1803 hh, mm, ss = self.hour, self.minute, self.second 1804 return _build_struct_time(y, m, d, hh, mm, ss, 0) 1805 1806 def date(self): 1807 "Return the date part." 1808 return date(self._year, self._month, self._day) 1809 1810 def time(self): 1811 "Return the time part, with tzinfo None." 1812 return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold) 1813 1814 def timetz(self): 1815 "Return the time part, with same tzinfo." 1816 return time(self.hour, self.minute, self.second, self.microsecond, 1817 self._tzinfo, fold=self.fold) 1818 1819 def replace(self, year=None, month=None, day=None, hour=None, 1820 minute=None, second=None, microsecond=None, tzinfo=True, 1821 *, fold=None): 1822 """Return a new datetime with new values for the specified fields.""" 1823 if year is None: 1824 year = self.year 1825 if month is None: 1826 month = self.month 1827 if day is None: 1828 day = self.day 1829 if hour is None: 1830 hour = self.hour 1831 if minute is None: 1832 minute = self.minute 1833 if second is None: 1834 second = self.second 1835 if microsecond is None: 1836 microsecond = self.microsecond 1837 if tzinfo is True: 1838 tzinfo = self.tzinfo 1839 if fold is None: 1840 fold = self.fold 1841 return type(self)(year, month, day, hour, minute, second, 1842 microsecond, tzinfo, fold=fold) 1843 1844 def _local_timezone(self): 1845 if self.tzinfo is None: 1846 ts = self._mktime() 1847 else: 1848 ts = (self - _EPOCH) // timedelta(seconds=1) 1849 localtm = _time.localtime(ts) 1850 local = datetime(*localtm[:6]) 1851 # Extract TZ data 1852 gmtoff = localtm.tm_gmtoff 1853 zone = localtm.tm_zone 1854 return timezone(timedelta(seconds=gmtoff), zone) 1855 1856 def astimezone(self, tz=None): 1857 if tz is None: 1858 tz = self._local_timezone() 1859 elif not isinstance(tz, tzinfo): 1860 raise TypeError("tz argument must be an instance of tzinfo") 1861 1862 mytz = self.tzinfo 1863 if mytz is None: 1864 mytz = self._local_timezone() 1865 myoffset = mytz.utcoffset(self) 1866 else: 1867 myoffset = mytz.utcoffset(self) 1868 if myoffset is None: 1869 mytz = self.replace(tzinfo=None)._local_timezone() 1870 myoffset = mytz.utcoffset(self) 1871 1872 if tz is mytz: 1873 return self 1874 1875 # Convert self to UTC, and attach the new time zone object. 1876 utc = (self - myoffset).replace(tzinfo=tz) 1877 1878 # Convert from UTC to tz's local time. 1879 return tz.fromutc(utc) 1880 1881 # Ways to produce a string. 1882 1883 def ctime(self): 1884 "Return ctime() style string." 1885 weekday = self.toordinal() % 7 or 7 1886 return "%s %s %2d %02d:%02d:%02d %04d" % ( 1887 _DAYNAMES[weekday], 1888 _MONTHNAMES[self._month], 1889 self._day, 1890 self._hour, self._minute, self._second, 1891 self._year) 1892 1893 def isoformat(self, sep='T', timespec='auto'): 1894 """Return the time formatted according to ISO. 1895 1896 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'. 1897 By default, the fractional part is omitted if self.microsecond == 0. 1898 1899 If self.tzinfo is not None, the UTC offset is also attached, giving 1900 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'. 1901 1902 Optional argument sep specifies the separator between date and 1903 time, default 'T'. 1904 1905 The optional argument timespec specifies the number of additional 1906 terms of the time to include. Valid options are 'auto', 'hours', 1907 'minutes', 'seconds', 'milliseconds' and 'microseconds'. 1908 """ 1909 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) + 1910 _format_time(self._hour, self._minute, self._second, 1911 self._microsecond, timespec)) 1912 1913 off = self.utcoffset() 1914 tz = _format_offset(off) 1915 if tz: 1916 s += tz 1917 1918 return s 1919 1920 def __repr__(self): 1921 """Convert to formal string, for repr().""" 1922 L = [self._year, self._month, self._day, # These are never zero 1923 self._hour, self._minute, self._second, self._microsecond] 1924 if L[-1] == 0: 1925 del L[-1] 1926 if L[-1] == 0: 1927 del L[-1] 1928 s = "%s.%s(%s)" % (self.__class__.__module__, 1929 self.__class__.__qualname__, 1930 ", ".join(map(str, L))) 1931 if self._tzinfo is not None: 1932 assert s[-1:] == ")" 1933 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")" 1934 if self._fold: 1935 assert s[-1:] == ")" 1936 s = s[:-1] + ", fold=1)" 1937 return s 1938 1939 def __str__(self): 1940 "Convert to string, for str()." 1941 return self.isoformat(sep=' ') 1942 1943 @classmethod 1944 def strptime(cls, date_string, format): 1945 'string, format -> new datetime parsed from a string (like time.strptime()).' 1946 import _strptime 1947 return _strptime._strptime_datetime(cls, date_string, format) 1948 1949 def utcoffset(self): 1950 """Return the timezone offset as timedelta positive east of UTC (negative west of 1951 UTC).""" 1952 if self._tzinfo is None: 1953 return None 1954 offset = self._tzinfo.utcoffset(self) 1955 _check_utc_offset("utcoffset", offset) 1956 return offset 1957 1958 def tzname(self): 1959 """Return the timezone name. 1960 1961 Note that the name is 100% informational -- there's no requirement that 1962 it mean anything in particular. For example, "GMT", "UTC", "-500", 1963 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies. 1964 """ 1965 if self._tzinfo is None: 1966 return None 1967 name = self._tzinfo.tzname(self) 1968 _check_tzname(name) 1969 return name 1970 1971 def dst(self): 1972 """Return 0 if DST is not in effect, or the DST offset (as timedelta 1973 positive eastward) if DST is in effect. 1974 1975 This is purely informational; the DST offset has already been added to 1976 the UTC offset returned by utcoffset() if applicable, so there's no 1977 need to consult dst() unless you're interested in displaying the DST 1978 info. 1979 """ 1980 if self._tzinfo is None: 1981 return None 1982 offset = self._tzinfo.dst(self) 1983 _check_utc_offset("dst", offset) 1984 return offset 1985 1986 # Comparisons of datetime objects with other. 1987 1988 def __eq__(self, other): 1989 if isinstance(other, datetime): 1990 return self._cmp(other, allow_mixed=True) == 0 1991 elif not isinstance(other, date): 1992 return NotImplemented 1993 else: 1994 return False 1995 1996 def __le__(self, other): 1997 if isinstance(other, datetime): 1998 return self._cmp(other) <= 0 1999 elif not isinstance(other, date): 2000 return NotImplemented 2001 else: 2002 _cmperror(self, other) 2003 2004 def __lt__(self, other): 2005 if isinstance(other, datetime): 2006 return self._cmp(other) < 0 2007 elif not isinstance(other, date): 2008 return NotImplemented 2009 else: 2010 _cmperror(self, other) 2011 2012 def __ge__(self, other): 2013 if isinstance(other, datetime): 2014 return self._cmp(other) >= 0 2015 elif not isinstance(other, date): 2016 return NotImplemented 2017 else: 2018 _cmperror(self, other) 2019 2020 def __gt__(self, other): 2021 if isinstance(other, datetime): 2022 return self._cmp(other) > 0 2023 elif not isinstance(other, date): 2024 return NotImplemented 2025 else: 2026 _cmperror(self, other) 2027 2028 def _cmp(self, other, allow_mixed=False): 2029 assert isinstance(other, datetime) 2030 mytz = self._tzinfo 2031 ottz = other._tzinfo 2032 myoff = otoff = None 2033 2034 if mytz is ottz: 2035 base_compare = True 2036 else: 2037 myoff = self.utcoffset() 2038 otoff = other.utcoffset() 2039 # Assume that allow_mixed means that we are called from __eq__ 2040 if allow_mixed: 2041 if myoff != self.replace(fold=not self.fold).utcoffset(): 2042 return 2 2043 if otoff != other.replace(fold=not other.fold).utcoffset(): 2044 return 2 2045 base_compare = myoff == otoff 2046 2047 if base_compare: 2048 return _cmp((self._year, self._month, self._day, 2049 self._hour, self._minute, self._second, 2050 self._microsecond), 2051 (other._year, other._month, other._day, 2052 other._hour, other._minute, other._second, 2053 other._microsecond)) 2054 if myoff is None or otoff is None: 2055 if allow_mixed: 2056 return 2 # arbitrary non-zero value 2057 else: 2058 raise TypeError("cannot compare naive and aware datetimes") 2059 # XXX What follows could be done more efficiently... 2060 diff = self - other # this will take offsets into account 2061 if diff.days < 0: 2062 return -1 2063 return diff and 1 or 0 2064 2065 def __add__(self, other): 2066 "Add a datetime and a timedelta." 2067 if not isinstance(other, timedelta): 2068 return NotImplemented 2069 delta = timedelta(self.toordinal(), 2070 hours=self._hour, 2071 minutes=self._minute, 2072 seconds=self._second, 2073 microseconds=self._microsecond) 2074 delta += other 2075 hour, rem = divmod(delta.seconds, 3600) 2076 minute, second = divmod(rem, 60) 2077 if 0 < delta.days <= _MAXORDINAL: 2078 return type(self).combine(date.fromordinal(delta.days), 2079 time(hour, minute, second, 2080 delta.microseconds, 2081 tzinfo=self._tzinfo)) 2082 raise OverflowError("result out of range") 2083 2084 __radd__ = __add__ 2085 2086 def __sub__(self, other): 2087 "Subtract two datetimes, or a datetime and a timedelta." 2088 if not isinstance(other, datetime): 2089 if isinstance(other, timedelta): 2090 return self + -other 2091 return NotImplemented 2092 2093 days1 = self.toordinal() 2094 days2 = other.toordinal() 2095 secs1 = self._second + self._minute * 60 + self._hour * 3600 2096 secs2 = other._second + other._minute * 60 + other._hour * 3600 2097 base = timedelta(days1 - days2, 2098 secs1 - secs2, 2099 self._microsecond - other._microsecond) 2100 if self._tzinfo is other._tzinfo: 2101 return base 2102 myoff = self.utcoffset() 2103 otoff = other.utcoffset() 2104 if myoff == otoff: 2105 return base 2106 if myoff is None or otoff is None: 2107 raise TypeError("cannot mix naive and timezone-aware time") 2108 return base + otoff - myoff 2109 2110 def __hash__(self): 2111 if self._hashcode == -1: 2112 if self.fold: 2113 t = self.replace(fold=0) 2114 else: 2115 t = self 2116 tzoff = t.utcoffset() 2117 if tzoff is None: 2118 self._hashcode = hash(t._getstate()[0]) 2119 else: 2120 days = _ymd2ord(self.year, self.month, self.day) 2121 seconds = self.hour * 3600 + self.minute * 60 + self.second 2122 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff) 2123 return self._hashcode 2124 2125 # Pickle support. 2126 2127 def _getstate(self, protocol=3): 2128 yhi, ylo = divmod(self._year, 256) 2129 us2, us3 = divmod(self._microsecond, 256) 2130 us1, us2 = divmod(us2, 256) 2131 m = self._month 2132 if self._fold and protocol > 3: 2133 m += 128 2134 basestate = bytes([yhi, ylo, m, self._day, 2135 self._hour, self._minute, self._second, 2136 us1, us2, us3]) 2137 if self._tzinfo is None: 2138 return (basestate,) 2139 else: 2140 return (basestate, self._tzinfo) 2141 2142 def __setstate(self, string, tzinfo): 2143 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class): 2144 raise TypeError("bad tzinfo state arg") 2145 (yhi, ylo, m, self._day, self._hour, 2146 self._minute, self._second, us1, us2, us3) = string 2147 if m > 127: 2148 self._fold = 1 2149 self._month = m - 128 2150 else: 2151 self._fold = 0 2152 self._month = m 2153 self._year = yhi * 256 + ylo 2154 self._microsecond = (((us1 << 8) | us2) << 8) | us3 2155 self._tzinfo = tzinfo 2156 2157 def __reduce_ex__(self, protocol): 2158 return (self.__class__, self._getstate(protocol)) 2159 2160 def __reduce__(self): 2161 return self.__reduce_ex__(2) 2162 2163 2164datetime.min = datetime(1, 1, 1) 2165datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999) 2166datetime.resolution = timedelta(microseconds=1) 2167 2168 2169def _isoweek1monday(year): 2170 # Helper to calculate the day number of the Monday starting week 1 2171 # XXX This could be done more efficiently 2172 THURSDAY = 3 2173 firstday = _ymd2ord(year, 1, 1) 2174 firstweekday = (firstday + 6) % 7 # See weekday() above 2175 week1monday = firstday - firstweekday 2176 if firstweekday > THURSDAY: 2177 week1monday += 7 2178 return week1monday 2179 2180 2181class timezone(tzinfo): 2182 __slots__ = '_offset', '_name' 2183 2184 # Sentinel value to disallow None 2185 _Omitted = object() 2186 def __new__(cls, offset, name=_Omitted): 2187 if not isinstance(offset, timedelta): 2188 raise TypeError("offset must be a timedelta") 2189 if name is cls._Omitted: 2190 if not offset: 2191 return cls.utc 2192 name = None 2193 elif not isinstance(name, str): 2194 raise TypeError("name must be a string") 2195 if not cls._minoffset <= offset <= cls._maxoffset: 2196 raise ValueError("offset must be a timedelta " 2197 "strictly between -timedelta(hours=24) and " 2198 "timedelta(hours=24).") 2199 return cls._create(offset, name) 2200 2201 @classmethod 2202 def _create(cls, offset, name=None): 2203 self = tzinfo.__new__(cls) 2204 self._offset = offset 2205 self._name = name 2206 return self 2207 2208 def __getinitargs__(self): 2209 """pickle support""" 2210 if self._name is None: 2211 return (self._offset,) 2212 return (self._offset, self._name) 2213 2214 def __eq__(self, other): 2215 if isinstance(other, timezone): 2216 return self._offset == other._offset 2217 return NotImplemented 2218 2219 def __hash__(self): 2220 return hash(self._offset) 2221 2222 def __repr__(self): 2223 """Convert to formal string, for repr(). 2224 2225 >>> tz = timezone.utc 2226 >>> repr(tz) 2227 'datetime.timezone.utc' 2228 >>> tz = timezone(timedelta(hours=-5), 'EST') 2229 >>> repr(tz) 2230 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')" 2231 """ 2232 if self is self.utc: 2233 return 'datetime.timezone.utc' 2234 if self._name is None: 2235 return "%s.%s(%r)" % (self.__class__.__module__, 2236 self.__class__.__qualname__, 2237 self._offset) 2238 return "%s.%s(%r, %r)" % (self.__class__.__module__, 2239 self.__class__.__qualname__, 2240 self._offset, self._name) 2241 2242 def __str__(self): 2243 return self.tzname(None) 2244 2245 def utcoffset(self, dt): 2246 if isinstance(dt, datetime) or dt is None: 2247 return self._offset 2248 raise TypeError("utcoffset() argument must be a datetime instance" 2249 " or None") 2250 2251 def tzname(self, dt): 2252 if isinstance(dt, datetime) or dt is None: 2253 if self._name is None: 2254 return self._name_from_offset(self._offset) 2255 return self._name 2256 raise TypeError("tzname() argument must be a datetime instance" 2257 " or None") 2258 2259 def dst(self, dt): 2260 if isinstance(dt, datetime) or dt is None: 2261 return None 2262 raise TypeError("dst() argument must be a datetime instance" 2263 " or None") 2264 2265 def fromutc(self, dt): 2266 if isinstance(dt, datetime): 2267 if dt.tzinfo is not self: 2268 raise ValueError("fromutc: dt.tzinfo " 2269 "is not self") 2270 return dt + self._offset 2271 raise TypeError("fromutc() argument must be a datetime instance" 2272 " or None") 2273 2274 _maxoffset = timedelta(hours=24, microseconds=-1) 2275 _minoffset = -_maxoffset 2276 2277 @staticmethod 2278 def _name_from_offset(delta): 2279 if not delta: 2280 return 'UTC' 2281 if delta < timedelta(0): 2282 sign = '-' 2283 delta = -delta 2284 else: 2285 sign = '+' 2286 hours, rest = divmod(delta, timedelta(hours=1)) 2287 minutes, rest = divmod(rest, timedelta(minutes=1)) 2288 seconds = rest.seconds 2289 microseconds = rest.microseconds 2290 if microseconds: 2291 return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}' 2292 f'.{microseconds:06d}') 2293 if seconds: 2294 return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}' 2295 return f'UTC{sign}{hours:02d}:{minutes:02d}' 2296 2297timezone.utc = timezone._create(timedelta(0)) 2298# bpo-37642: These attributes are rounded to the nearest minute for backwards 2299# compatibility, even though the constructor will accept a wider range of 2300# values. This may change in the future. 2301timezone.min = timezone._create(-timedelta(hours=23, minutes=59)) 2302timezone.max = timezone._create(timedelta(hours=23, minutes=59)) 2303_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc) 2304 2305# Some time zone algebra. For a datetime x, let 2306# x.n = x stripped of its timezone -- its naive time. 2307# x.o = x.utcoffset(), and assuming that doesn't raise an exception or 2308# return None 2309# x.d = x.dst(), and assuming that doesn't raise an exception or 2310# return None 2311# x.s = x's standard offset, x.o - x.d 2312# 2313# Now some derived rules, where k is a duration (timedelta). 2314# 2315# 1. x.o = x.s + x.d 2316# This follows from the definition of x.s. 2317# 2318# 2. If x and y have the same tzinfo member, x.s = y.s. 2319# This is actually a requirement, an assumption we need to make about 2320# sane tzinfo classes. 2321# 2322# 3. The naive UTC time corresponding to x is x.n - x.o. 2323# This is again a requirement for a sane tzinfo class. 2324# 2325# 4. (x+k).s = x.s 2326# This follows from #2, and that datetime.timetz+timedelta preserves tzinfo. 2327# 2328# 5. (x+k).n = x.n + k 2329# Again follows from how arithmetic is defined. 2330# 2331# Now we can explain tz.fromutc(x). Let's assume it's an interesting case 2332# (meaning that the various tzinfo methods exist, and don't blow up or return 2333# None when called). 2334# 2335# The function wants to return a datetime y with timezone tz, equivalent to x. 2336# x is already in UTC. 2337# 2338# By #3, we want 2339# 2340# y.n - y.o = x.n [1] 2341# 2342# The algorithm starts by attaching tz to x.n, and calling that y. So 2343# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1] 2344# becomes true; in effect, we want to solve [2] for k: 2345# 2346# (y+k).n - (y+k).o = x.n [2] 2347# 2348# By #1, this is the same as 2349# 2350# (y+k).n - ((y+k).s + (y+k).d) = x.n [3] 2351# 2352# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start. 2353# Substituting that into [3], 2354# 2355# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving 2356# k - (y+k).s - (y+k).d = 0; rearranging, 2357# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so 2358# k = y.s - (y+k).d 2359# 2360# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we 2361# approximate k by ignoring the (y+k).d term at first. Note that k can't be 2362# very large, since all offset-returning methods return a duration of magnitude 2363# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must 2364# be 0, so ignoring it has no consequence then. 2365# 2366# In any case, the new value is 2367# 2368# z = y + y.s [4] 2369# 2370# It's helpful to step back at look at [4] from a higher level: it's simply 2371# mapping from UTC to tz's standard time. 2372# 2373# At this point, if 2374# 2375# z.n - z.o = x.n [5] 2376# 2377# we have an equivalent time, and are almost done. The insecurity here is 2378# at the start of daylight time. Picture US Eastern for concreteness. The wall 2379# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good 2380# sense then. The docs ask that an Eastern tzinfo class consider such a time to 2381# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST 2382# on the day DST starts. We want to return the 1:MM EST spelling because that's 2383# the only spelling that makes sense on the local wall clock. 2384# 2385# In fact, if [5] holds at this point, we do have the standard-time spelling, 2386# but that takes a bit of proof. We first prove a stronger result. What's the 2387# difference between the LHS and RHS of [5]? Let 2388# 2389# diff = x.n - (z.n - z.o) [6] 2390# 2391# Now 2392# z.n = by [4] 2393# (y + y.s).n = by #5 2394# y.n + y.s = since y.n = x.n 2395# x.n + y.s = since z and y are have the same tzinfo member, 2396# y.s = z.s by #2 2397# x.n + z.s 2398# 2399# Plugging that back into [6] gives 2400# 2401# diff = 2402# x.n - ((x.n + z.s) - z.o) = expanding 2403# x.n - x.n - z.s + z.o = cancelling 2404# - z.s + z.o = by #2 2405# z.d 2406# 2407# So diff = z.d. 2408# 2409# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time 2410# spelling we wanted in the endcase described above. We're done. Contrarily, 2411# if z.d = 0, then we have a UTC equivalent, and are also done. 2412# 2413# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to 2414# add to z (in effect, z is in tz's standard time, and we need to shift the 2415# local clock into tz's daylight time). 2416# 2417# Let 2418# 2419# z' = z + z.d = z + diff [7] 2420# 2421# and we can again ask whether 2422# 2423# z'.n - z'.o = x.n [8] 2424# 2425# If so, we're done. If not, the tzinfo class is insane, according to the 2426# assumptions we've made. This also requires a bit of proof. As before, let's 2427# compute the difference between the LHS and RHS of [8] (and skipping some of 2428# the justifications for the kinds of substitutions we've done several times 2429# already): 2430# 2431# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7] 2432# x.n - (z.n + diff - z'.o) = replacing diff via [6] 2433# x.n - (z.n + x.n - (z.n - z.o) - z'.o) = 2434# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n 2435# - z.n + z.n - z.o + z'.o = cancel z.n 2436# - z.o + z'.o = #1 twice 2437# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo 2438# z'.d - z.d 2439# 2440# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal, 2441# we've found the UTC-equivalent so are done. In fact, we stop with [7] and 2442# return z', not bothering to compute z'.d. 2443# 2444# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by 2445# a dst() offset, and starting *from* a time already in DST (we know z.d != 0), 2446# would have to change the result dst() returns: we start in DST, and moving 2447# a little further into it takes us out of DST. 2448# 2449# There isn't a sane case where this can happen. The closest it gets is at 2450# the end of DST, where there's an hour in UTC with no spelling in a hybrid 2451# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During 2452# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM 2453# UTC) because the docs insist on that, but 0:MM is taken as being in daylight 2454# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local 2455# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in 2456# standard time. Since that's what the local clock *does*, we want to map both 2457# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous 2458# in local time, but so it goes -- it's the way the local clock works. 2459# 2460# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0, 2461# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going. 2462# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8] 2463# (correctly) concludes that z' is not UTC-equivalent to x. 2464# 2465# Because we know z.d said z was in daylight time (else [5] would have held and 2466# we would have stopped then), and we know z.d != z'.d (else [8] would have held 2467# and we have stopped then), and there are only 2 possible values dst() can 2468# return in Eastern, it follows that z'.d must be 0 (which it is in the example, 2469# but the reasoning doesn't depend on the example -- it depends on there being 2470# two possible dst() outcomes, one zero and the other non-zero). Therefore 2471# z' must be in standard time, and is the spelling we want in this case. 2472# 2473# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is 2474# concerned (because it takes z' as being in standard time rather than the 2475# daylight time we intend here), but returning it gives the real-life "local 2476# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into 2477# tz. 2478# 2479# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with 2480# the 1:MM standard time spelling we want. 2481# 2482# So how can this break? One of the assumptions must be violated. Two 2483# possibilities: 2484# 2485# 1) [2] effectively says that y.s is invariant across all y belong to a given 2486# time zone. This isn't true if, for political reasons or continental drift, 2487# a region decides to change its base offset from UTC. 2488# 2489# 2) There may be versions of "double daylight" time where the tail end of 2490# the analysis gives up a step too early. I haven't thought about that 2491# enough to say. 2492# 2493# In any case, it's clear that the default fromutc() is strong enough to handle 2494# "almost all" time zones: so long as the standard offset is invariant, it 2495# doesn't matter if daylight time transition points change from year to year, or 2496# if daylight time is skipped in some years; it doesn't matter how large or 2497# small dst() may get within its bounds; and it doesn't even matter if some 2498# perverse time zone returns a negative dst()). So a breaking case must be 2499# pretty bizarre, and a tzinfo subclass can override fromutc() if it is. 2500 2501try: 2502 from _datetime import * 2503except ImportError: 2504 pass 2505else: 2506 # Clean up unused names 2507 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y, 2508 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time, 2509 _check_date_fields, _check_int_field, _check_time_fields, 2510 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror, 2511 _date_class, _days_before_month, _days_before_year, _days_in_month, 2512 _format_time, _format_offset, _is_leap, _isoweek1monday, _math, 2513 _ord2ymd, _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord, 2514 _divide_and_round, _parse_isoformat_date, _parse_isoformat_time, 2515 _parse_hh_mm_ss_ff) 2516 # XXX Since import * above excludes names that start with _, 2517 # docstring does not get overwritten. In the future, it may be 2518 # appropriate to maintain a single module level docstring and 2519 # remove the following line. 2520 from _datetime import __doc__ 2521