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