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