blob: 67555191d02c187587148d9c88d49d610574e91f [file] [log] [blame]
Ezio Melottif756f942013-04-13 20:12:38 +03001"""Concrete date/time and related types.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002
Ezio Melottif756f942013-04-13 20:12:38 +03003See http://www.iana.org/time-zones/repository/tz-link.html for
4time zone and DST data sources.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00005"""
6
t k96b1c592019-09-19 09:34:41 -04007__all__ = ("date", "datetime", "time", "timedelta", "timezone", "tzinfo",
8 "MINYEAR", "MAXYEAR")
9
10
Alexander Belopolskycf86e362010-07-23 19:25:47 +000011import time as _time
12import math as _math
Ammar Askar96d1e692018-07-25 09:54:58 -070013import sys
Alexander Belopolskycf86e362010-07-23 19:25:47 +000014
15def _cmp(x, y):
16 return 0 if x == y else 1 if x > y else -1
17
18MINYEAR = 1
19MAXYEAR = 9999
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -040020_MAXORDINAL = 3652059 # date.max.toordinal()
Alexander Belopolskycf86e362010-07-23 19:25:47 +000021
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
Benjamin Petersonda0bea22013-08-29 17:29:30 -040031# -1 is a placeholder for indexing purposes.
Benjamin Petersonf908efb2013-08-29 17:27:57 -040032_DAYS_IN_MONTH = [-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
Alexander Belopolskycf86e362010-07-23 19:25:47 +000033
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -040034_DAYS_BEFORE_MONTH = [-1] # -1 is a placeholder for indexing purposes.
Alexander Belopolskycf86e362010-07-23 19:25:47 +000035dbm = 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):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +030058 "year, month -> number of days in year preceding first day of month."
Alexander Belopolskycf86e362010-07-23 19:25:47 +000059 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
Alexander Belopolskya2998a62016-03-06 14:58:43 -0500160def _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)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000180
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500181def _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
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000199# Correctly substitute for %z and %Z escapes in strftime formats.
200def _wrap_strftime(object, format, timetuple):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000201 # Don't call utcoffset() or tzname() unless actually needed.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400202 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
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000205
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 = '-'
Alexander Belopolsky018d3532017-07-31 10:26:50 -0400232 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)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000242 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
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500263# 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
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000359# 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.
Alexander Belopolsky018d3532017-07-31 10:26:50 -0400369# Else offset is checked for being in range.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000370# 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)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000378 if not -timedelta(1) < offset < timedelta(1):
Martin Panterdd780e42016-05-30 04:08:23 +0000379 raise ValueError("%s()=%s, must be strictly between "
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400380 "-timedelta(hours=24) and timedelta(hours=24)" %
381 (name, offset))
382
383def _check_int_field(value):
384 if isinstance(value, int):
385 return value
Serhiy Storchaka6a44f6e2019-02-25 17:57:58 +0200386 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):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400404 raise TypeError('__int__ returned non-int (type %s)' %
405 type(value).__name__)
Serhiy Storchaka6a44f6e2019-02-25 17:57:58 +0200406 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__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000414
415def _check_date_fields(year, month, day):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400416 year = _check_int_field(year)
417 month = _check_int_field(month)
418 day = _check_int_field(day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000419 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)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400426 return year, month, day
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000427
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400428def _check_time_fields(hour, minute, second, microsecond, fold):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400429 hour = _check_int_field(hour)
430 minute = _check_int_field(minute)
431 second = _check_int_field(second)
432 microsecond = _check_int_field(microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000433 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)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400441 if fold not in (0, 1):
442 raise ValueError('fold must be either 0 or 1', fold)
443 return hour, minute, second, microsecond, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000444
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
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500453def _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
Victor Stinner2ec55872015-09-02 19:16:07 +0200472
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000473class 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
Serhiy Storchaka95949422013-08-27 19:40:23 +0300481 - multiply, divide by int
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000482
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 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400490 __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000491
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):
Victor Stinner69cc4872015-09-08 23:58:54 +0200556 microseconds = round(microseconds + usdouble)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000557 seconds, microseconds = divmod(microseconds, 1000000)
558 days, seconds = divmod(seconds, 24*3600)
559 d += days
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400560 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
Victor Stinner69cc4872015-09-08 23:58:54 +0200567 microseconds = round(microseconds + usdouble)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400568 assert isinstance(s, int)
569 assert isinstance(microseconds, int)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000570 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.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400574 seconds, us = divmod(microseconds, 1000000)
575 s += seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000576 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
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000583 if abs(d) > 999999999:
584 raise OverflowError("timedelta # of days is too large: %d" % d)
585
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400586 self = object.__new__(cls)
587 self._days = d
588 self._seconds = s
589 self._microseconds = us
590 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000591 return self
592
593 def __repr__(self):
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200594 args = []
595 if self._days:
596 args.append("days=%d" % self._days)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000597 if self._seconds:
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200598 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__,
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300604 self.__class__.__qualname__,
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200605 ', '.join(args))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000606
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."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400621 return ((self.days * 86400 + self.seconds) * 10**6 +
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000622 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):
Alexander Belopolskyb6f5ec72011-04-05 20:07:38 -0400653 # 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)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000658 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):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500689 usec = self._to_microseconds()
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000690 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500691 return timedelta(0, 0, _divide_and_round(usec * a, b))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000692 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):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500716 return timedelta(0, 0, _divide_and_round(usec, other))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000717 if isinstance(other, float):
718 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500719 return timedelta(0, 0, _divide_and_round(b * usec, a))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000720
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:
Xtreake6b46aa2019-07-13 18:52:21 +0530740 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000741
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000742 def __le__(self, other):
743 if isinstance(other, timedelta):
744 return self._cmp(other) <= 0
745 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +0300746 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000747
748 def __lt__(self, other):
749 if isinstance(other, timedelta):
750 return self._cmp(other) < 0
751 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +0300752 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000753
754 def __ge__(self, other):
755 if isinstance(other, timedelta):
756 return self._cmp(other) >= 0
757 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +0300758 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000759
760 def __gt__(self, other):
761 if isinstance(other, timedelta):
762 return self._cmp(other) > 0
763 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +0300764 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000765
766 def _cmp(self, other):
767 assert isinstance(other, timedelta)
768 return _cmp(self._getstate(), other._getstate())
769
770 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400771 if self._hashcode == -1:
772 self._hashcode = hash(self._getstate())
773 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000774
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__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200806 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000807 __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 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400821 __slots__ = '_year', '_month', '_day', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000822
823 def __new__(cls, year, month=None, day=None):
824 """Constructor.
825
826 Arguments:
827
828 year, month, day (required, base 1)
829 """
Serhiy Storchaka8452ca12018-12-07 13:42:10 +0200830 if (month is None and
831 isinstance(year, (bytes, str)) and len(year) == 4 and
832 1 <= ord(year[2:3]) <= 12):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000833 # Pickle support
Serhiy Storchaka8452ca12018-12-07 13:42:10 +0200834 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.")
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000843 self = object.__new__(cls)
844 self.__setstate(year)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400845 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000846 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400847 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000848 self = object.__new__(cls)
849 self._year = year
850 self._month = month
851 self._day = day
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400852 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000853 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):
Martin Pantereb995702016-07-28 01:11:04 +0000871 """Construct a date from a proleptic Gregorian ordinal.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000872
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
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500879 @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:
Paul Ganssle3df85402018-10-22 12:32:52 -0400889 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500890
Paul Ganssle88c09372019-04-29 09:22:03 -0400891 @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))
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500925
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000926 # 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 """
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300939 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
940 self.__class__.__qualname__,
941 self._year,
942 self._month,
943 self._day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000944 # 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):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400963 if not isinstance(fmt, str):
964 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000965 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
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200998 # Standard conversions, __eq__, __le__, __lt__, __ge__, __gt__,
999 # __hash__ (and helpers)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001000
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
Paul Ganssle191e9932017-11-09 16:34:29 -05001022 return type(self)(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001023
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
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001031 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."
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001059 if self._hashcode == -1:
1060 self._hashcode = hash(self._getstate())
1061 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001062
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:
Paul Ganssle89427cd2019-02-04 14:42:04 -05001070 return type(self).fromordinal(o)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001071 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 3-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
Brett Cannon07b954d2016-01-15 09:53:51 -08001108 (used with permission)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001109 """
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 year, week+1, day+1
1124
1125 # Pickle support.
1126
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001127 def _getstate(self):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001128 yhi, ylo = divmod(self._year, 256)
1129 return bytes([yhi, ylo, self._month, self._day]),
1130
1131 def __setstate(self, string):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001132 yhi, ylo, self._month, self._day = string
1133 self._year = yhi * 256 + ylo
1134
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001135 def __reduce__(self):
1136 return (self.__class__, self._getstate())
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001137
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
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001144
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001145class tzinfo:
1146 """Abstract base class for time zone info classes.
1147
1148 Subclasses must override the name(), utcoffset() and dst() methods.
1149 """
1150 __slots__ = ()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001151
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001152 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):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001157 "datetime -> timedelta, positive for east of UTC, negative for west of UTC"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001158 raise NotImplementedError("tzinfo subclass must override utcoffset()")
1159
1160 def dst(self, dt):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001161 """datetime -> DST offset as timedelta, positive for east of UTC.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001162
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_tzinfo_class = tzinfo
1214
1215class time:
1216 """Time with time zone.
1217
1218 Constructors:
1219
1220 __new__()
1221
1222 Operators:
1223
1224 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +02001225 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001226
1227 Methods:
1228
1229 strftime()
1230 isoformat()
1231 utcoffset()
1232 tzname()
1233 dst()
1234
1235 Properties (readonly):
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001236 hour, minute, second, microsecond, tzinfo, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001237 """
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001238 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode', '_fold'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001239
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001240 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001241 """Constructor.
1242
1243 Arguments:
1244
1245 hour, minute (required)
1246 second, microsecond (default to zero)
1247 tzinfo (default to None)
Victor Stinner51b90d22017-01-04 12:01:16 +01001248 fold (keyword only, default to zero)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001249 """
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001250 if (isinstance(hour, (bytes, str)) and len(hour) == 6 and
1251 ord(hour[0:1])&0x7F < 24):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001252 # Pickle support
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001253 if isinstance(hour, str):
1254 try:
1255 hour = hour.encode('latin1')
1256 except UnicodeEncodeError:
1257 # More informative error message.
1258 raise ValueError(
1259 "Failed to encode latin1 string when unpickling "
1260 "a time object. "
1261 "pickle.load(data, encoding='latin1') is assumed.")
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001262 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001263 self.__setstate(hour, minute or None)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001264 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001265 return self
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001266 hour, minute, second, microsecond, fold = _check_time_fields(
1267 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001268 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001269 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001270 self._hour = hour
1271 self._minute = minute
1272 self._second = second
1273 self._microsecond = microsecond
1274 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001275 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001276 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001277 return self
1278
1279 # Read-only field accessors
1280 @property
1281 def hour(self):
1282 """hour (0-23)"""
1283 return self._hour
1284
1285 @property
1286 def minute(self):
1287 """minute (0-59)"""
1288 return self._minute
1289
1290 @property
1291 def second(self):
1292 """second (0-59)"""
1293 return self._second
1294
1295 @property
1296 def microsecond(self):
1297 """microsecond (0-999999)"""
1298 return self._microsecond
1299
1300 @property
1301 def tzinfo(self):
1302 """timezone info object"""
1303 return self._tzinfo
1304
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001305 @property
1306 def fold(self):
1307 return self._fold
1308
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001309 # Standard conversions, __hash__ (and helpers)
1310
1311 # Comparisons of time objects with other.
1312
1313 def __eq__(self, other):
1314 if isinstance(other, time):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001315 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001316 else:
Xtreake6b46aa2019-07-13 18:52:21 +05301317 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001318
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001319 def __le__(self, other):
1320 if isinstance(other, time):
1321 return self._cmp(other) <= 0
1322 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +03001323 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001324
1325 def __lt__(self, other):
1326 if isinstance(other, time):
1327 return self._cmp(other) < 0
1328 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +03001329 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001330
1331 def __ge__(self, other):
1332 if isinstance(other, time):
1333 return self._cmp(other) >= 0
1334 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +03001335 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001336
1337 def __gt__(self, other):
1338 if isinstance(other, time):
1339 return self._cmp(other) > 0
1340 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +03001341 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001342
Alexander Belopolsky08313822012-06-15 20:19:47 -04001343 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001344 assert isinstance(other, time)
1345 mytz = self._tzinfo
1346 ottz = other._tzinfo
1347 myoff = otoff = None
1348
1349 if mytz is ottz:
1350 base_compare = True
1351 else:
1352 myoff = self.utcoffset()
1353 otoff = other.utcoffset()
1354 base_compare = myoff == otoff
1355
1356 if base_compare:
1357 return _cmp((self._hour, self._minute, self._second,
1358 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001359 (other._hour, other._minute, other._second,
1360 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001361 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001362 if allow_mixed:
1363 return 2 # arbitrary non-zero value
1364 else:
1365 raise TypeError("cannot compare naive and aware times")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001366 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1367 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1368 return _cmp((myhhmm, self._second, self._microsecond),
1369 (othhmm, other._second, other._microsecond))
1370
1371 def __hash__(self):
1372 """Hash."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001373 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001374 if self.fold:
1375 t = self.replace(fold=0)
1376 else:
1377 t = self
1378 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001379 if not tzoff: # zero or None
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001380 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001381 else:
1382 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1383 timedelta(hours=1))
1384 assert not m % timedelta(minutes=1), "whole minute"
1385 m //= timedelta(minutes=1)
1386 if 0 <= h < 24:
1387 self._hashcode = hash(time(h, m, self.second, self.microsecond))
1388 else:
1389 self._hashcode = hash((h, m, self.second, self.microsecond))
1390 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001391
1392 # Conversion to string
1393
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001394 def _tzstr(self):
1395 """Return formatted timezone offset (+xx:xx) or an empty string."""
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001396 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001397 return _format_offset(off)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001398
1399 def __repr__(self):
1400 """Convert to formal string, for repr()."""
1401 if self._microsecond != 0:
1402 s = ", %d, %d" % (self._second, self._microsecond)
1403 elif self._second != 0:
1404 s = ", %d" % self._second
1405 else:
1406 s = ""
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001407 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1408 self.__class__.__qualname__,
1409 self._hour, self._minute, s)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001410 if self._tzinfo is not None:
1411 assert s[-1:] == ")"
1412 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001413 if self._fold:
1414 assert s[-1:] == ")"
1415 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001416 return s
1417
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001418 def isoformat(self, timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001419 """Return the time formatted according to ISO.
1420
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001421 The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional
1422 part is omitted if self.microsecond == 0.
1423
1424 The optional argument timespec specifies the number of additional
1425 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001426 """
1427 s = _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001428 self._microsecond, timespec)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001429 tz = self._tzstr()
1430 if tz:
1431 s += tz
1432 return s
1433
1434 __str__ = isoformat
1435
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001436 @classmethod
1437 def fromisoformat(cls, time_string):
1438 """Construct a time from the output of isoformat()."""
1439 if not isinstance(time_string, str):
1440 raise TypeError('fromisoformat: argument must be str')
1441
1442 try:
1443 return cls(*_parse_isoformat_time(time_string))
1444 except Exception:
Paul Ganssle3df85402018-10-22 12:32:52 -04001445 raise ValueError(f'Invalid isoformat string: {time_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001446
1447
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001448 def strftime(self, fmt):
1449 """Format using strftime(). The date part of the timestamp passed
1450 to underlying strftime should not be used.
1451 """
Alexander Belopolskyb8bb4662011-01-08 00:13:34 +00001452 # The year must be >= 1000 else Python's strftime implementation
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001453 # can raise a bogus exception.
1454 timetuple = (1900, 1, 1,
1455 self._hour, self._minute, self._second,
1456 0, 1, -1)
1457 return _wrap_strftime(self, fmt, timetuple)
1458
1459 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001460 if not isinstance(fmt, str):
1461 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001462 if len(fmt) != 0:
1463 return self.strftime(fmt)
1464 return str(self)
1465
1466 # Timezone functions
1467
1468 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001469 """Return the timezone offset as timedelta, positive east of UTC
1470 (negative west of UTC)."""
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001471 if self._tzinfo is None:
1472 return None
1473 offset = self._tzinfo.utcoffset(None)
1474 _check_utc_offset("utcoffset", offset)
1475 return offset
1476
1477 def tzname(self):
1478 """Return the timezone name.
1479
1480 Note that the name is 100% informational -- there's no requirement that
1481 it mean anything in particular. For example, "GMT", "UTC", "-500",
1482 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1483 """
1484 if self._tzinfo is None:
1485 return None
1486 name = self._tzinfo.tzname(None)
1487 _check_tzname(name)
1488 return name
1489
1490 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001491 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1492 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001493
1494 This is purely informational; the DST offset has already been added to
1495 the UTC offset returned by utcoffset() if applicable, so there's no
1496 need to consult dst() unless you're interested in displaying the DST
1497 info.
1498 """
1499 if self._tzinfo is None:
1500 return None
1501 offset = self._tzinfo.dst(None)
1502 _check_utc_offset("dst", offset)
1503 return offset
1504
1505 def replace(self, hour=None, minute=None, second=None, microsecond=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001506 tzinfo=True, *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001507 """Return a new time with new values for the specified fields."""
1508 if hour is None:
1509 hour = self.hour
1510 if minute is None:
1511 minute = self.minute
1512 if second is None:
1513 second = self.second
1514 if microsecond is None:
1515 microsecond = self.microsecond
1516 if tzinfo is True:
1517 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001518 if fold is None:
1519 fold = self._fold
Paul Ganssle191e9932017-11-09 16:34:29 -05001520 return type(self)(hour, minute, second, microsecond, tzinfo, fold=fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001521
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001522 # Pickle support.
1523
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001524 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001525 us2, us3 = divmod(self._microsecond, 256)
1526 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001527 h = self._hour
1528 if self._fold and protocol > 3:
1529 h += 128
1530 basestate = bytes([h, self._minute, self._second,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001531 us1, us2, us3])
1532 if self._tzinfo is None:
1533 return (basestate,)
1534 else:
1535 return (basestate, self._tzinfo)
1536
1537 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001538 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1539 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001540 h, self._minute, self._second, us1, us2, us3 = string
1541 if h > 127:
1542 self._fold = 1
1543 self._hour = h - 128
1544 else:
1545 self._fold = 0
1546 self._hour = h
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001547 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001548 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001549
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001550 def __reduce_ex__(self, protocol):
1551 return (time, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001552
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001553 def __reduce__(self):
1554 return self.__reduce_ex__(2)
1555
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001556_time_class = time # so functions w/ args named "time" can get at the class
1557
1558time.min = time(0, 0, 0)
1559time.max = time(23, 59, 59, 999999)
1560time.resolution = timedelta(microseconds=1)
1561
1562class datetime(date):
1563 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1564
1565 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001566 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001567 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001568 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001569
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001570 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001571 microsecond=0, tzinfo=None, *, fold=0):
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001572 if (isinstance(year, (bytes, str)) and len(year) == 10 and
1573 1 <= ord(year[2:3])&0x7F <= 12):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001574 # Pickle support
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001575 if isinstance(year, str):
1576 try:
1577 year = bytes(year, 'latin1')
1578 except UnicodeEncodeError:
1579 # More informative error message.
1580 raise ValueError(
1581 "Failed to encode latin1 string when unpickling "
1582 "a datetime object. "
1583 "pickle.load(data, encoding='latin1') is assumed.")
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001584 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001585 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001586 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001587 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001588 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001589 hour, minute, second, microsecond, fold = _check_time_fields(
1590 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001591 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001592 self = object.__new__(cls)
1593 self._year = year
1594 self._month = month
1595 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001596 self._hour = hour
1597 self._minute = minute
1598 self._second = second
1599 self._microsecond = microsecond
1600 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001601 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001602 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001603 return self
1604
1605 # Read-only field accessors
1606 @property
1607 def hour(self):
1608 """hour (0-23)"""
1609 return self._hour
1610
1611 @property
1612 def minute(self):
1613 """minute (0-59)"""
1614 return self._minute
1615
1616 @property
1617 def second(self):
1618 """second (0-59)"""
1619 return self._second
1620
1621 @property
1622 def microsecond(self):
1623 """microsecond (0-999999)"""
1624 return self._microsecond
1625
1626 @property
1627 def tzinfo(self):
1628 """timezone info object"""
1629 return self._tzinfo
1630
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001631 @property
1632 def fold(self):
1633 return self._fold
1634
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001635 @classmethod
Victor Stinneradfefa52015-09-04 23:57:25 +02001636 def _fromtimestamp(cls, t, utc, tz):
1637 """Construct a datetime from a POSIX timestamp (like time.time()).
1638
1639 A timezone info object may be passed in as well.
1640 """
1641 frac, t = _math.modf(t)
Victor Stinner7667f582015-09-09 01:02:23 +02001642 us = round(frac * 1e6)
Victor Stinneradfefa52015-09-04 23:57:25 +02001643 if us >= 1000000:
1644 t += 1
1645 us -= 1000000
1646 elif us < 0:
1647 t -= 1
1648 us += 1000000
1649
1650 converter = _time.gmtime if utc else _time.localtime
1651 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1652 ss = min(ss, 59) # clamp out leap seconds if the platform has them
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001653 result = cls(y, m, d, hh, mm, ss, us, tz)
1654 if tz is None:
1655 # As of version 2015f max fold in IANA database is
1656 # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
1657 # Let's probe 24 hours in the past to detect a transition:
1658 max_fold_seconds = 24 * 3600
Ammar Askar96d1e692018-07-25 09:54:58 -07001659
1660 # On Windows localtime_s throws an OSError for negative values,
1661 # thus we can't perform fold detection for values of time less
1662 # than the max time fold. See comments in _datetimemodule's
1663 # version of this method for more details.
1664 if t < max_fold_seconds and sys.platform.startswith("win"):
1665 return result
1666
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001667 y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1668 probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1669 trans = result - probe1 - timedelta(0, max_fold_seconds)
1670 if trans.days < 0:
1671 y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
1672 probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1673 if probe2 == result:
1674 result._fold = 1
1675 else:
1676 result = tz.fromutc(result)
1677 return result
Victor Stinneradfefa52015-09-04 23:57:25 +02001678
1679 @classmethod
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001680 def fromtimestamp(cls, t, tz=None):
1681 """Construct a datetime from a POSIX timestamp (like time.time()).
1682
1683 A timezone info object may be passed in as well.
1684 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001685 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001686
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001687 return cls._fromtimestamp(t, tz is not None, tz)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001688
1689 @classmethod
1690 def utcfromtimestamp(cls, t):
Alexander Belopolskye2e178e2015-03-01 14:52:07 -05001691 """Construct a naive UTC datetime from a POSIX timestamp."""
Victor Stinneradfefa52015-09-04 23:57:25 +02001692 return cls._fromtimestamp(t, True, None)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001693
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001694 @classmethod
1695 def now(cls, tz=None):
1696 "Construct a datetime from time.time() and optional time zone info."
1697 t = _time.time()
1698 return cls.fromtimestamp(t, tz)
1699
1700 @classmethod
1701 def utcnow(cls):
1702 "Construct a UTC datetime from time.time()."
1703 t = _time.time()
1704 return cls.utcfromtimestamp(t)
1705
1706 @classmethod
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001707 def combine(cls, date, time, tzinfo=True):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001708 "Construct a datetime from a given date and a given time."
1709 if not isinstance(date, _date_class):
1710 raise TypeError("date argument must be a date instance")
1711 if not isinstance(time, _time_class):
1712 raise TypeError("time argument must be a time instance")
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001713 if tzinfo is True:
1714 tzinfo = time.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001715 return cls(date.year, date.month, date.day,
1716 time.hour, time.minute, time.second, time.microsecond,
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001717 tzinfo, fold=time.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001718
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001719 @classmethod
1720 def fromisoformat(cls, date_string):
1721 """Construct a datetime from the output of datetime.isoformat()."""
1722 if not isinstance(date_string, str):
1723 raise TypeError('fromisoformat: argument must be str')
1724
1725 # Split this at the separator
1726 dstr = date_string[0:10]
1727 tstr = date_string[11:]
1728
1729 try:
1730 date_components = _parse_isoformat_date(dstr)
1731 except ValueError:
Paul Ganssle3df85402018-10-22 12:32:52 -04001732 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001733
1734 if tstr:
1735 try:
1736 time_components = _parse_isoformat_time(tstr)
1737 except ValueError:
Paul Ganssle3df85402018-10-22 12:32:52 -04001738 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001739 else:
1740 time_components = [0, 0, 0, 0, None]
1741
1742 return cls(*(date_components + time_components))
1743
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001744 def timetuple(self):
1745 "Return local time tuple compatible with time.localtime()."
1746 dst = self.dst()
1747 if dst is None:
1748 dst = -1
1749 elif dst:
1750 dst = 1
1751 else:
1752 dst = 0
1753 return _build_struct_time(self.year, self.month, self.day,
1754 self.hour, self.minute, self.second,
1755 dst)
1756
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001757 def _mktime(self):
1758 """Return integer POSIX timestamp."""
1759 epoch = datetime(1970, 1, 1)
1760 max_fold_seconds = 24 * 3600
1761 t = (self - epoch) // timedelta(0, 1)
1762 def local(u):
1763 y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1764 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1765
1766 # Our goal is to solve t = local(u) for u.
1767 a = local(t) - t
1768 u1 = t - a
1769 t1 = local(u1)
1770 if t1 == t:
1771 # We found one solution, but it may not be the one we need.
1772 # Look for an earlier solution (if `fold` is 0), or a
1773 # later one (if `fold` is 1).
1774 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1775 b = local(u2) - u2
1776 if a == b:
1777 return u1
1778 else:
1779 b = t1 - u1
1780 assert a != b
1781 u2 = t - b
1782 t2 = local(u2)
1783 if t2 == t:
1784 return u2
1785 if t1 == t:
1786 return u1
1787 # We have found both offsets a and b, but neither t - a nor t - b is
1788 # a solution. This means t is in the gap.
1789 return (max, min)[self.fold](u1, u2)
1790
1791
Alexander Belopolskya4415142012-06-08 12:33:09 -04001792 def timestamp(self):
1793 "Return POSIX timestamp as float"
1794 if self._tzinfo is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001795 s = self._mktime()
1796 return s + self.microsecond / 1e6
Alexander Belopolskya4415142012-06-08 12:33:09 -04001797 else:
1798 return (self - _EPOCH).total_seconds()
1799
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001800 def utctimetuple(self):
1801 "Return UTC time tuple compatible with time.gmtime()."
1802 offset = self.utcoffset()
1803 if offset:
1804 self -= offset
1805 y, m, d = self.year, self.month, self.day
1806 hh, mm, ss = self.hour, self.minute, self.second
1807 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1808
1809 def date(self):
1810 "Return the date part."
1811 return date(self._year, self._month, self._day)
1812
1813 def time(self):
1814 "Return the time part, with tzinfo None."
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001815 return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001816
1817 def timetz(self):
1818 "Return the time part, with same tzinfo."
1819 return time(self.hour, self.minute, self.second, self.microsecond,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001820 self._tzinfo, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001821
1822 def replace(self, year=None, month=None, day=None, hour=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001823 minute=None, second=None, microsecond=None, tzinfo=True,
1824 *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001825 """Return a new datetime with new values for the specified fields."""
1826 if year is None:
1827 year = self.year
1828 if month is None:
1829 month = self.month
1830 if day is None:
1831 day = self.day
1832 if hour is None:
1833 hour = self.hour
1834 if minute is None:
1835 minute = self.minute
1836 if second is None:
1837 second = self.second
1838 if microsecond is None:
1839 microsecond = self.microsecond
1840 if tzinfo is True:
1841 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001842 if fold is None:
1843 fold = self.fold
Paul Ganssle191e9932017-11-09 16:34:29 -05001844 return type(self)(year, month, day, hour, minute, second,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001845 microsecond, tzinfo, fold=fold)
1846
1847 def _local_timezone(self):
1848 if self.tzinfo is None:
1849 ts = self._mktime()
1850 else:
1851 ts = (self - _EPOCH) // timedelta(seconds=1)
1852 localtm = _time.localtime(ts)
1853 local = datetime(*localtm[:6])
Alexander Belopolskybcb032e2018-06-08 19:22:33 -04001854 # Extract TZ data
1855 gmtoff = localtm.tm_gmtoff
1856 zone = localtm.tm_zone
1857 return timezone(timedelta(seconds=gmtoff), zone)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001858
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001859 def astimezone(self, tz=None):
1860 if tz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001861 tz = self._local_timezone()
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001862 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001863 raise TypeError("tz argument must be an instance of tzinfo")
1864
1865 mytz = self.tzinfo
1866 if mytz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001867 mytz = self._local_timezone()
Alexander Belopolsky877b2322018-06-10 17:02:58 -04001868 myoffset = mytz.utcoffset(self)
1869 else:
1870 myoffset = mytz.utcoffset(self)
1871 if myoffset is None:
1872 mytz = self.replace(tzinfo=None)._local_timezone()
1873 myoffset = mytz.utcoffset(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001874
1875 if tz is mytz:
1876 return self
1877
1878 # Convert self to UTC, and attach the new time zone object.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001879 utc = (self - myoffset).replace(tzinfo=tz)
1880
1881 # Convert from UTC to tz's local time.
1882 return tz.fromutc(utc)
1883
1884 # Ways to produce a string.
1885
1886 def ctime(self):
1887 "Return ctime() style string."
1888 weekday = self.toordinal() % 7 or 7
1889 return "%s %s %2d %02d:%02d:%02d %04d" % (
1890 _DAYNAMES[weekday],
1891 _MONTHNAMES[self._month],
1892 self._day,
1893 self._hour, self._minute, self._second,
1894 self._year)
1895
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001896 def isoformat(self, sep='T', timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001897 """Return the time formatted according to ISO.
1898
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001899 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1900 By default, the fractional part is omitted if self.microsecond == 0.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001901
1902 If self.tzinfo is not None, the UTC offset is also attached, giving
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001903 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001904
1905 Optional argument sep specifies the separator between date and
1906 time, default 'T'.
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001907
1908 The optional argument timespec specifies the number of additional
1909 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001910 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001911 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1912 _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001913 self._microsecond, timespec))
1914
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001915 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001916 tz = _format_offset(off)
1917 if tz:
1918 s += tz
1919
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001920 return s
1921
1922 def __repr__(self):
1923 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001924 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001925 self._hour, self._minute, self._second, self._microsecond]
1926 if L[-1] == 0:
1927 del L[-1]
1928 if L[-1] == 0:
1929 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001930 s = "%s.%s(%s)" % (self.__class__.__module__,
1931 self.__class__.__qualname__,
1932 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001933 if self._tzinfo is not None:
1934 assert s[-1:] == ")"
1935 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001936 if self._fold:
1937 assert s[-1:] == ")"
1938 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001939 return s
1940
1941 def __str__(self):
1942 "Convert to string, for str()."
1943 return self.isoformat(sep=' ')
1944
1945 @classmethod
1946 def strptime(cls, date_string, format):
1947 'string, format -> new datetime parsed from a string (like time.strptime()).'
1948 import _strptime
1949 return _strptime._strptime_datetime(cls, date_string, format)
1950
1951 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001952 """Return the timezone offset as timedelta positive east of UTC (negative west of
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001953 UTC)."""
1954 if self._tzinfo is None:
1955 return None
1956 offset = self._tzinfo.utcoffset(self)
1957 _check_utc_offset("utcoffset", offset)
1958 return offset
1959
1960 def tzname(self):
1961 """Return the timezone name.
1962
1963 Note that the name is 100% informational -- there's no requirement that
1964 it mean anything in particular. For example, "GMT", "UTC", "-500",
1965 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1966 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001967 if self._tzinfo is None:
1968 return None
1969 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001970 _check_tzname(name)
1971 return name
1972
1973 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001974 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1975 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001976
1977 This is purely informational; the DST offset has already been added to
1978 the UTC offset returned by utcoffset() if applicable, so there's no
1979 need to consult dst() unless you're interested in displaying the DST
1980 info.
1981 """
1982 if self._tzinfo is None:
1983 return None
1984 offset = self._tzinfo.dst(self)
1985 _check_utc_offset("dst", offset)
1986 return offset
1987
1988 # Comparisons of datetime objects with other.
1989
1990 def __eq__(self, other):
1991 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001992 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001993 elif not isinstance(other, date):
1994 return NotImplemented
1995 else:
1996 return False
1997
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001998 def __le__(self, other):
1999 if isinstance(other, datetime):
2000 return self._cmp(other) <= 0
2001 elif not isinstance(other, date):
2002 return NotImplemented
2003 else:
2004 _cmperror(self, other)
2005
2006 def __lt__(self, other):
2007 if isinstance(other, datetime):
2008 return self._cmp(other) < 0
2009 elif not isinstance(other, date):
2010 return NotImplemented
2011 else:
2012 _cmperror(self, other)
2013
2014 def __ge__(self, other):
2015 if isinstance(other, datetime):
2016 return self._cmp(other) >= 0
2017 elif not isinstance(other, date):
2018 return NotImplemented
2019 else:
2020 _cmperror(self, other)
2021
2022 def __gt__(self, other):
2023 if isinstance(other, datetime):
2024 return self._cmp(other) > 0
2025 elif not isinstance(other, date):
2026 return NotImplemented
2027 else:
2028 _cmperror(self, other)
2029
Alexander Belopolsky08313822012-06-15 20:19:47 -04002030 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002031 assert isinstance(other, datetime)
2032 mytz = self._tzinfo
2033 ottz = other._tzinfo
2034 myoff = otoff = None
2035
2036 if mytz is ottz:
2037 base_compare = True
2038 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04002039 myoff = self.utcoffset()
2040 otoff = other.utcoffset()
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002041 # Assume that allow_mixed means that we are called from __eq__
2042 if allow_mixed:
2043 if myoff != self.replace(fold=not self.fold).utcoffset():
2044 return 2
2045 if otoff != other.replace(fold=not other.fold).utcoffset():
2046 return 2
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002047 base_compare = myoff == otoff
2048
2049 if base_compare:
2050 return _cmp((self._year, self._month, self._day,
2051 self._hour, self._minute, self._second,
2052 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002053 (other._year, other._month, other._day,
2054 other._hour, other._minute, other._second,
2055 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002056 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04002057 if allow_mixed:
2058 return 2 # arbitrary non-zero value
2059 else:
2060 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002061 # XXX What follows could be done more efficiently...
2062 diff = self - other # this will take offsets into account
2063 if diff.days < 0:
2064 return -1
2065 return diff and 1 or 0
2066
2067 def __add__(self, other):
2068 "Add a datetime and a timedelta."
2069 if not isinstance(other, timedelta):
2070 return NotImplemented
2071 delta = timedelta(self.toordinal(),
2072 hours=self._hour,
2073 minutes=self._minute,
2074 seconds=self._second,
2075 microseconds=self._microsecond)
2076 delta += other
2077 hour, rem = divmod(delta.seconds, 3600)
2078 minute, second = divmod(rem, 60)
2079 if 0 < delta.days <= _MAXORDINAL:
Paul Ganssle89427cd2019-02-04 14:42:04 -05002080 return type(self).combine(date.fromordinal(delta.days),
2081 time(hour, minute, second,
2082 delta.microseconds,
2083 tzinfo=self._tzinfo))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002084 raise OverflowError("result out of range")
2085
2086 __radd__ = __add__
2087
2088 def __sub__(self, other):
2089 "Subtract two datetimes, or a datetime and a timedelta."
2090 if not isinstance(other, datetime):
2091 if isinstance(other, timedelta):
2092 return self + -other
2093 return NotImplemented
2094
2095 days1 = self.toordinal()
2096 days2 = other.toordinal()
2097 secs1 = self._second + self._minute * 60 + self._hour * 3600
2098 secs2 = other._second + other._minute * 60 + other._hour * 3600
2099 base = timedelta(days1 - days2,
2100 secs1 - secs2,
2101 self._microsecond - other._microsecond)
2102 if self._tzinfo is other._tzinfo:
2103 return base
2104 myoff = self.utcoffset()
2105 otoff = other.utcoffset()
2106 if myoff == otoff:
2107 return base
2108 if myoff is None or otoff is None:
2109 raise TypeError("cannot mix naive and timezone-aware time")
2110 return base + otoff - myoff
2111
2112 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002113 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002114 if self.fold:
2115 t = self.replace(fold=0)
2116 else:
2117 t = self
2118 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002119 if tzoff is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002120 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002121 else:
2122 days = _ymd2ord(self.year, self.month, self.day)
2123 seconds = self.hour * 3600 + self.minute * 60 + self.second
2124 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
2125 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002126
2127 # Pickle support.
2128
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002129 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002130 yhi, ylo = divmod(self._year, 256)
2131 us2, us3 = divmod(self._microsecond, 256)
2132 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002133 m = self._month
2134 if self._fold and protocol > 3:
2135 m += 128
2136 basestate = bytes([yhi, ylo, m, self._day,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002137 self._hour, self._minute, self._second,
2138 us1, us2, us3])
2139 if self._tzinfo is None:
2140 return (basestate,)
2141 else:
2142 return (basestate, self._tzinfo)
2143
2144 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002145 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
2146 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002147 (yhi, ylo, m, self._day, self._hour,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002148 self._minute, self._second, us1, us2, us3) = string
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002149 if m > 127:
2150 self._fold = 1
2151 self._month = m - 128
2152 else:
2153 self._fold = 0
2154 self._month = m
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002155 self._year = yhi * 256 + ylo
2156 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002157 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002158
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002159 def __reduce_ex__(self, protocol):
2160 return (self.__class__, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002161
Serhiy Storchaka546ce652016-11-22 00:29:42 +02002162 def __reduce__(self):
2163 return self.__reduce_ex__(2)
2164
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002165
2166datetime.min = datetime(1, 1, 1)
2167datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
2168datetime.resolution = timedelta(microseconds=1)
2169
2170
2171def _isoweek1monday(year):
2172 # Helper to calculate the day number of the Monday starting week 1
2173 # XXX This could be done more efficiently
2174 THURSDAY = 3
2175 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002176 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002177 week1monday = firstday - firstweekday
2178 if firstweekday > THURSDAY:
2179 week1monday += 7
2180 return week1monday
2181
Paul Ganssle88c09372019-04-29 09:22:03 -04002182
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002183class timezone(tzinfo):
2184 __slots__ = '_offset', '_name'
2185
2186 # Sentinel value to disallow None
2187 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002188 def __new__(cls, offset, name=_Omitted):
2189 if not isinstance(offset, timedelta):
2190 raise TypeError("offset must be a timedelta")
2191 if name is cls._Omitted:
2192 if not offset:
2193 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002194 name = None
2195 elif not isinstance(name, str):
2196 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002197 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002198 raise ValueError("offset must be a timedelta "
2199 "strictly between -timedelta(hours=24) and "
2200 "timedelta(hours=24).")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002201 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002202
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002203 @classmethod
2204 def _create(cls, offset, name=None):
2205 self = tzinfo.__new__(cls)
2206 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002207 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002208 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002209
2210 def __getinitargs__(self):
2211 """pickle support"""
2212 if self._name is None:
2213 return (self._offset,)
2214 return (self._offset, self._name)
2215
2216 def __eq__(self, other):
Serhiy Storchaka17e52642019-08-04 12:38:46 +03002217 if isinstance(other, timezone):
2218 return self._offset == other._offset
2219 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002220
2221 def __hash__(self):
2222 return hash(self._offset)
2223
2224 def __repr__(self):
2225 """Convert to formal string, for repr().
2226
2227 >>> tz = timezone.utc
2228 >>> repr(tz)
2229 'datetime.timezone.utc'
2230 >>> tz = timezone(timedelta(hours=-5), 'EST')
2231 >>> repr(tz)
2232 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
2233 """
2234 if self is self.utc:
2235 return 'datetime.timezone.utc'
2236 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03002237 return "%s.%s(%r)" % (self.__class__.__module__,
2238 self.__class__.__qualname__,
2239 self._offset)
2240 return "%s.%s(%r, %r)" % (self.__class__.__module__,
2241 self.__class__.__qualname__,
2242 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002243
2244 def __str__(self):
2245 return self.tzname(None)
2246
2247 def utcoffset(self, dt):
2248 if isinstance(dt, datetime) or dt is None:
2249 return self._offset
2250 raise TypeError("utcoffset() argument must be a datetime instance"
2251 " or None")
2252
2253 def tzname(self, dt):
2254 if isinstance(dt, datetime) or dt is None:
2255 if self._name is None:
2256 return self._name_from_offset(self._offset)
2257 return self._name
2258 raise TypeError("tzname() argument must be a datetime instance"
2259 " or None")
2260
2261 def dst(self, dt):
2262 if isinstance(dt, datetime) or dt is None:
2263 return None
2264 raise TypeError("dst() argument must be a datetime instance"
2265 " or None")
2266
2267 def fromutc(self, dt):
2268 if isinstance(dt, datetime):
2269 if dt.tzinfo is not self:
2270 raise ValueError("fromutc: dt.tzinfo "
2271 "is not self")
2272 return dt + self._offset
2273 raise TypeError("fromutc() argument must be a datetime instance"
2274 " or None")
2275
Ngalim Siregar92c7e302019-08-09 21:22:16 +07002276 _maxoffset = timedelta(hours=24, microseconds=-1)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002277 _minoffset = -_maxoffset
2278
2279 @staticmethod
2280 def _name_from_offset(delta):
Alexander Belopolsky7827a5b2015-09-06 13:07:21 -04002281 if not delta:
2282 return 'UTC'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002283 if delta < timedelta(0):
2284 sign = '-'
2285 delta = -delta
2286 else:
2287 sign = '+'
2288 hours, rest = divmod(delta, timedelta(hours=1))
Alexander Belopolsky018d3532017-07-31 10:26:50 -04002289 minutes, rest = divmod(rest, timedelta(minutes=1))
2290 seconds = rest.seconds
2291 microseconds = rest.microseconds
2292 if microseconds:
2293 return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2294 f'.{microseconds:06d}')
2295 if seconds:
2296 return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2297 return f'UTC{sign}{hours:02d}:{minutes:02d}'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002298
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002299timezone.utc = timezone._create(timedelta(0))
Ngalim Siregar92c7e302019-08-09 21:22:16 +07002300# bpo-37642: These attributes are rounded to the nearest minute for backwards
2301# compatibility, even though the constructor will accept a wider range of
2302# values. This may change in the future.
2303timezone.min = timezone._create(-timedelta(hours=23, minutes=59))
2304timezone.max = timezone._create(timedelta(hours=23, minutes=59))
Alexander Belopolskya4415142012-06-08 12:33:09 -04002305_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002306
Victor Stinner765531d2013-03-26 01:11:54 +01002307# Some time zone algebra. For a datetime x, let
2308# x.n = x stripped of its timezone -- its naive time.
2309# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2310# return None
2311# x.d = x.dst(), and assuming that doesn't raise an exception or
2312# return None
2313# x.s = x's standard offset, x.o - x.d
2314#
2315# Now some derived rules, where k is a duration (timedelta).
2316#
2317# 1. x.o = x.s + x.d
2318# This follows from the definition of x.s.
2319#
2320# 2. If x and y have the same tzinfo member, x.s = y.s.
2321# This is actually a requirement, an assumption we need to make about
2322# sane tzinfo classes.
2323#
2324# 3. The naive UTC time corresponding to x is x.n - x.o.
2325# This is again a requirement for a sane tzinfo class.
2326#
2327# 4. (x+k).s = x.s
2328# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
2329#
2330# 5. (x+k).n = x.n + k
2331# Again follows from how arithmetic is defined.
2332#
2333# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
2334# (meaning that the various tzinfo methods exist, and don't blow up or return
2335# None when called).
2336#
2337# The function wants to return a datetime y with timezone tz, equivalent to x.
2338# x is already in UTC.
2339#
2340# By #3, we want
2341#
2342# y.n - y.o = x.n [1]
2343#
2344# The algorithm starts by attaching tz to x.n, and calling that y. So
2345# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
2346# becomes true; in effect, we want to solve [2] for k:
2347#
2348# (y+k).n - (y+k).o = x.n [2]
2349#
2350# By #1, this is the same as
2351#
2352# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
2353#
2354# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2355# Substituting that into [3],
2356#
2357# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2358# k - (y+k).s - (y+k).d = 0; rearranging,
2359# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2360# k = y.s - (y+k).d
2361#
2362# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2363# approximate k by ignoring the (y+k).d term at first. Note that k can't be
2364# very large, since all offset-returning methods return a duration of magnitude
2365# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
2366# be 0, so ignoring it has no consequence then.
2367#
2368# In any case, the new value is
2369#
2370# z = y + y.s [4]
2371#
2372# It's helpful to step back at look at [4] from a higher level: it's simply
2373# mapping from UTC to tz's standard time.
2374#
2375# At this point, if
2376#
2377# z.n - z.o = x.n [5]
2378#
2379# we have an equivalent time, and are almost done. The insecurity here is
2380# at the start of daylight time. Picture US Eastern for concreteness. The wall
2381# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2382# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2383# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2384# on the day DST starts. We want to return the 1:MM EST spelling because that's
2385# the only spelling that makes sense on the local wall clock.
2386#
2387# In fact, if [5] holds at this point, we do have the standard-time spelling,
2388# but that takes a bit of proof. We first prove a stronger result. What's the
2389# difference between the LHS and RHS of [5]? Let
2390#
2391# diff = x.n - (z.n - z.o) [6]
2392#
2393# Now
2394# z.n = by [4]
2395# (y + y.s).n = by #5
2396# y.n + y.s = since y.n = x.n
2397# x.n + y.s = since z and y are have the same tzinfo member,
2398# y.s = z.s by #2
2399# x.n + z.s
2400#
2401# Plugging that back into [6] gives
2402#
2403# diff =
2404# x.n - ((x.n + z.s) - z.o) = expanding
2405# x.n - x.n - z.s + z.o = cancelling
2406# - z.s + z.o = by #2
2407# z.d
2408#
2409# So diff = z.d.
2410#
2411# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2412# spelling we wanted in the endcase described above. We're done. Contrarily,
2413# if z.d = 0, then we have a UTC equivalent, and are also done.
2414#
2415# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2416# add to z (in effect, z is in tz's standard time, and we need to shift the
2417# local clock into tz's daylight time).
2418#
2419# Let
2420#
2421# z' = z + z.d = z + diff [7]
2422#
2423# and we can again ask whether
2424#
2425# z'.n - z'.o = x.n [8]
2426#
2427# If so, we're done. If not, the tzinfo class is insane, according to the
2428# assumptions we've made. This also requires a bit of proof. As before, let's
2429# compute the difference between the LHS and RHS of [8] (and skipping some of
2430# the justifications for the kinds of substitutions we've done several times
2431# already):
2432#
2433# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2434# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2435# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2436# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2437# - z.n + z.n - z.o + z'.o = cancel z.n
2438# - z.o + z'.o = #1 twice
2439# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2440# z'.d - z.d
2441#
2442# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2443# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2444# return z', not bothering to compute z'.d.
2445#
2446# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2447# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2448# would have to change the result dst() returns: we start in DST, and moving
2449# a little further into it takes us out of DST.
2450#
2451# There isn't a sane case where this can happen. The closest it gets is at
2452# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2453# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2454# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2455# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2456# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2457# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2458# standard time. Since that's what the local clock *does*, we want to map both
2459# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2460# in local time, but so it goes -- it's the way the local clock works.
2461#
2462# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2463# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2464# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2465# (correctly) concludes that z' is not UTC-equivalent to x.
2466#
2467# Because we know z.d said z was in daylight time (else [5] would have held and
2468# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2469# and we have stopped then), and there are only 2 possible values dst() can
2470# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2471# but the reasoning doesn't depend on the example -- it depends on there being
2472# two possible dst() outcomes, one zero and the other non-zero). Therefore
2473# z' must be in standard time, and is the spelling we want in this case.
2474#
2475# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2476# concerned (because it takes z' as being in standard time rather than the
2477# daylight time we intend here), but returning it gives the real-life "local
2478# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2479# tz.
2480#
2481# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2482# the 1:MM standard time spelling we want.
2483#
2484# So how can this break? One of the assumptions must be violated. Two
2485# possibilities:
2486#
2487# 1) [2] effectively says that y.s is invariant across all y belong to a given
2488# time zone. This isn't true if, for political reasons or continental drift,
2489# a region decides to change its base offset from UTC.
2490#
2491# 2) There may be versions of "double daylight" time where the tail end of
2492# the analysis gives up a step too early. I haven't thought about that
2493# enough to say.
2494#
2495# In any case, it's clear that the default fromutc() is strong enough to handle
2496# "almost all" time zones: so long as the standard offset is invariant, it
2497# doesn't matter if daylight time transition points change from year to year, or
2498# if daylight time is skipped in some years; it doesn't matter how large or
2499# small dst() may get within its bounds; and it doesn't even matter if some
2500# perverse time zone returns a negative dst()). So a breaking case must be
2501# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002502
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002503try:
2504 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002505except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002506 pass
2507else:
2508 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002509 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2510 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2511 _check_date_fields, _check_int_field, _check_time_fields,
2512 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2513 _date_class, _days_before_month, _days_before_year, _days_in_month,
Paul Ganssle09dc2f52017-12-21 00:33:49 -05002514 _format_time, _format_offset, _is_leap, _isoweek1monday, _math,
2515 _ord2ymd, _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord,
2516 _divide_and_round, _parse_isoformat_date, _parse_isoformat_time,
2517 _parse_hh_mm_ss_ff)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002518 # XXX Since import * above excludes names that start with _,
2519 # docstring does not get overwritten. In the future, it may be
2520 # appropriate to maintain a single module level docstring and
2521 # remove the following line.
2522 from _datetime import __doc__