blob: b896b94b0fe0e4e861422832440d02c9a8b0708b [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
Serhiy Storchaka578c3952020-05-26 18:43:38 +030014from operator import index as _index
Alexander Belopolskycf86e362010-07-23 19:25:47 +000015
16def _cmp(x, y):
17 return 0 if x == y else 1 if x > y else -1
18
19MINYEAR = 1
20MAXYEAR = 9999
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -040021_MAXORDINAL = 3652059 # date.max.toordinal()
Alexander Belopolskycf86e362010-07-23 19:25:47 +000022
23# Utility functions, adapted from Python's Demo/classes/Dates.py, which
24# also assumes the current Gregorian calendar indefinitely extended in
25# both directions. Difference: Dates.py calls January 1 of year 0 day
26# number 1. The code here calls January 1 of year 1 day number 1. This is
27# to match the definition of the "proleptic Gregorian" calendar in Dershowitz
28# and Reingold's "Calendrical Calculations", where it's the base calendar
29# for all computations. See the book for algorithms for converting between
30# proleptic Gregorian ordinals and many other calendar systems.
31
Benjamin Petersonda0bea22013-08-29 17:29:30 -040032# -1 is a placeholder for indexing purposes.
Benjamin Petersonf908efb2013-08-29 17:27:57 -040033_DAYS_IN_MONTH = [-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
Alexander Belopolskycf86e362010-07-23 19:25:47 +000034
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -040035_DAYS_BEFORE_MONTH = [-1] # -1 is a placeholder for indexing purposes.
Alexander Belopolskycf86e362010-07-23 19:25:47 +000036dbm = 0
37for dim in _DAYS_IN_MONTH[1:]:
38 _DAYS_BEFORE_MONTH.append(dbm)
39 dbm += dim
40del dbm, dim
41
42def _is_leap(year):
43 "year -> 1 if leap year, else 0."
44 return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
45
46def _days_before_year(year):
47 "year -> number of days before January 1st of year."
48 y = year - 1
49 return y*365 + y//4 - y//100 + y//400
50
51def _days_in_month(year, month):
52 "year, month -> number of days in that month in that year."
53 assert 1 <= month <= 12, month
54 if month == 2 and _is_leap(year):
55 return 29
56 return _DAYS_IN_MONTH[month]
57
58def _days_before_month(year, month):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +030059 "year, month -> number of days in year preceding first day of month."
Alexander Belopolskycf86e362010-07-23 19:25:47 +000060 assert 1 <= month <= 12, 'month must be in 1..12'
61 return _DAYS_BEFORE_MONTH[month] + (month > 2 and _is_leap(year))
62
63def _ymd2ord(year, month, day):
64 "year, month, day -> ordinal, considering 01-Jan-0001 as day 1."
65 assert 1 <= month <= 12, 'month must be in 1..12'
66 dim = _days_in_month(year, month)
67 assert 1 <= day <= dim, ('day must be in 1..%d' % dim)
68 return (_days_before_year(year) +
69 _days_before_month(year, month) +
70 day)
71
72_DI400Y = _days_before_year(401) # number of days in 400 years
73_DI100Y = _days_before_year(101) # " " " " 100 "
74_DI4Y = _days_before_year(5) # " " " " 4 "
75
76# A 4-year cycle has an extra leap day over what we'd get from pasting
77# together 4 single years.
78assert _DI4Y == 4 * 365 + 1
79
80# Similarly, a 400-year cycle has an extra leap day over what we'd get from
81# pasting together 4 100-year cycles.
82assert _DI400Y == 4 * _DI100Y + 1
83
84# OTOH, a 100-year cycle has one fewer leap day than we'd get from
85# pasting together 25 4-year cycles.
86assert _DI100Y == 25 * _DI4Y - 1
87
88def _ord2ymd(n):
89 "ordinal -> (year, month, day), considering 01-Jan-0001 as day 1."
90
91 # n is a 1-based index, starting at 1-Jan-1. The pattern of leap years
92 # repeats exactly every 400 years. The basic strategy is to find the
93 # closest 400-year boundary at or before n, then work with the offset
94 # from that boundary to n. Life is much clearer if we subtract 1 from
95 # n first -- then the values of n at 400-year boundaries are exactly
96 # those divisible by _DI400Y:
97 #
98 # D M Y n n-1
99 # -- --- ---- ---------- ----------------
100 # 31 Dec -400 -_DI400Y -_DI400Y -1
101 # 1 Jan -399 -_DI400Y +1 -_DI400Y 400-year boundary
102 # ...
103 # 30 Dec 000 -1 -2
104 # 31 Dec 000 0 -1
105 # 1 Jan 001 1 0 400-year boundary
106 # 2 Jan 001 2 1
107 # 3 Jan 001 3 2
108 # ...
109 # 31 Dec 400 _DI400Y _DI400Y -1
110 # 1 Jan 401 _DI400Y +1 _DI400Y 400-year boundary
111 n -= 1
112 n400, n = divmod(n, _DI400Y)
113 year = n400 * 400 + 1 # ..., -399, 1, 401, ...
114
115 # Now n is the (non-negative) offset, in days, from January 1 of year, to
116 # the desired date. Now compute how many 100-year cycles precede n.
117 # Note that it's possible for n100 to equal 4! In that case 4 full
118 # 100-year cycles precede the desired day, which implies the desired
119 # day is December 31 at the end of a 400-year cycle.
120 n100, n = divmod(n, _DI100Y)
121
122 # Now compute how many 4-year cycles precede it.
123 n4, n = divmod(n, _DI4Y)
124
125 # And now how many single years. Again n1 can be 4, and again meaning
126 # that the desired day is December 31 at the end of the 4-year cycle.
127 n1, n = divmod(n, 365)
128
129 year += n100 * 100 + n4 * 4 + n1
130 if n1 == 4 or n100 == 4:
131 assert n == 0
132 return year-1, 12, 31
133
134 # Now the year is correct, and n is the offset from January 1. We find
135 # the month via an estimate that's either exact or one too large.
136 leapyear = n1 == 3 and (n4 != 24 or n100 == 3)
137 assert leapyear == _is_leap(year)
138 month = (n + 50) >> 5
139 preceding = _DAYS_BEFORE_MONTH[month] + (month > 2 and leapyear)
140 if preceding > n: # estimate is too large
141 month -= 1
142 preceding -= _DAYS_IN_MONTH[month] + (month == 2 and leapyear)
143 n -= preceding
144 assert 0 <= n < _days_in_month(year, month)
145
146 # Now the year and month are correct, and n is the offset from the
147 # start of that month: we're done!
148 return year, month, n+1
149
150# Month and day names. For localized versions, see the calendar module.
151_MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
152 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
153_DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
154
155
156def _build_struct_time(y, m, d, hh, mm, ss, dstflag):
157 wday = (_ymd2ord(y, m, d) + 6) % 7
158 dnum = _days_before_month(y, m) + d
159 return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag))
160
Alexander Belopolskya2998a62016-03-06 14:58:43 -0500161def _format_time(hh, mm, ss, us, timespec='auto'):
162 specs = {
163 'hours': '{:02d}',
164 'minutes': '{:02d}:{:02d}',
165 'seconds': '{:02d}:{:02d}:{:02d}',
166 'milliseconds': '{:02d}:{:02d}:{:02d}.{:03d}',
167 'microseconds': '{:02d}:{:02d}:{:02d}.{:06d}'
168 }
169
170 if timespec == 'auto':
171 # Skip trailing microseconds when us==0.
172 timespec = 'microseconds' if us else 'seconds'
173 elif timespec == 'milliseconds':
174 us //= 1000
175 try:
176 fmt = specs[timespec]
177 except KeyError:
178 raise ValueError('Unknown timespec value')
179 else:
180 return fmt.format(hh, mm, ss, us)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000181
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500182def _format_offset(off):
183 s = ''
184 if off is not None:
185 if off.days < 0:
186 sign = "-"
187 off = -off
188 else:
189 sign = "+"
190 hh, mm = divmod(off, timedelta(hours=1))
191 mm, ss = divmod(mm, timedelta(minutes=1))
192 s += "%s%02d:%02d" % (sign, hh, mm)
193 if ss or ss.microseconds:
194 s += ":%02d" % ss.seconds
195
196 if ss.microseconds:
197 s += '.%06d' % ss.microseconds
198 return s
199
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000200# Correctly substitute for %z and %Z escapes in strftime formats.
201def _wrap_strftime(object, format, timetuple):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000202 # Don't call utcoffset() or tzname() unless actually needed.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400203 freplace = None # the string to use for %f
204 zreplace = None # the string to use for %z
205 Zreplace = None # the string to use for %Z
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000206
207 # Scan format for %z and %Z escapes, replacing as needed.
208 newformat = []
209 push = newformat.append
210 i, n = 0, len(format)
211 while i < n:
212 ch = format[i]
213 i += 1
214 if ch == '%':
215 if i < n:
216 ch = format[i]
217 i += 1
218 if ch == 'f':
219 if freplace is None:
220 freplace = '%06d' % getattr(object,
221 'microsecond', 0)
222 newformat.append(freplace)
223 elif ch == 'z':
224 if zreplace is None:
225 zreplace = ""
226 if hasattr(object, "utcoffset"):
227 offset = object.utcoffset()
228 if offset is not None:
229 sign = '+'
230 if offset.days < 0:
231 offset = -offset
232 sign = '-'
Alexander Belopolsky018d3532017-07-31 10:26:50 -0400233 h, rest = divmod(offset, timedelta(hours=1))
234 m, rest = divmod(rest, timedelta(minutes=1))
235 s = rest.seconds
236 u = offset.microseconds
237 if u:
238 zreplace = '%c%02d%02d%02d.%06d' % (sign, h, m, s, u)
239 elif s:
240 zreplace = '%c%02d%02d%02d' % (sign, h, m, s)
241 else:
242 zreplace = '%c%02d%02d' % (sign, h, m)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000243 assert '%' not in zreplace
244 newformat.append(zreplace)
245 elif ch == 'Z':
246 if Zreplace is None:
247 Zreplace = ""
248 if hasattr(object, "tzname"):
249 s = object.tzname()
250 if s is not None:
251 # strftime is going to have at this: escape %
252 Zreplace = s.replace('%', '%%')
253 newformat.append(Zreplace)
254 else:
255 push('%')
256 push(ch)
257 else:
258 push('%')
259 else:
260 push(ch)
261 newformat = "".join(newformat)
262 return _time.strftime(newformat, timetuple)
263
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500264# Helpers for parsing the result of isoformat()
265def _parse_isoformat_date(dtstr):
266 # It is assumed that this function will only be called with a
267 # string of length exactly 10, and (though this is not used) ASCII-only
268 year = int(dtstr[0:4])
269 if dtstr[4] != '-':
270 raise ValueError('Invalid date separator: %s' % dtstr[4])
271
272 month = int(dtstr[5:7])
273
274 if dtstr[7] != '-':
275 raise ValueError('Invalid date separator')
276
277 day = int(dtstr[8:10])
278
279 return [year, month, day]
280
281def _parse_hh_mm_ss_ff(tstr):
282 # Parses things of the form HH[:MM[:SS[.fff[fff]]]]
283 len_str = len(tstr)
284
285 time_comps = [0, 0, 0, 0]
286 pos = 0
287 for comp in range(0, 3):
288 if (len_str - pos) < 2:
289 raise ValueError('Incomplete time component')
290
291 time_comps[comp] = int(tstr[pos:pos+2])
292
293 pos += 2
294 next_char = tstr[pos:pos+1]
295
296 if not next_char or comp >= 2:
297 break
298
299 if next_char != ':':
300 raise ValueError('Invalid time separator: %c' % next_char)
301
302 pos += 1
303
304 if pos < len_str:
305 if tstr[pos] != '.':
306 raise ValueError('Invalid microsecond component')
307 else:
308 pos += 1
309
310 len_remainder = len_str - pos
311 if len_remainder not in (3, 6):
312 raise ValueError('Invalid microsecond component')
313
314 time_comps[3] = int(tstr[pos:])
315 if len_remainder == 3:
316 time_comps[3] *= 1000
317
318 return time_comps
319
320def _parse_isoformat_time(tstr):
321 # Format supported is HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]
322 len_str = len(tstr)
323 if len_str < 2:
324 raise ValueError('Isoformat time too short')
325
326 # This is equivalent to re.search('[+-]', tstr), but faster
327 tz_pos = (tstr.find('-') + 1 or tstr.find('+') + 1)
328 timestr = tstr[:tz_pos-1] if tz_pos > 0 else tstr
329
330 time_comps = _parse_hh_mm_ss_ff(timestr)
331
332 tzi = None
333 if tz_pos > 0:
334 tzstr = tstr[tz_pos:]
335
336 # Valid time zone strings are:
337 # HH:MM len: 5
338 # HH:MM:SS len: 8
339 # HH:MM:SS.ffffff len: 15
340
341 if len(tzstr) not in (5, 8, 15):
342 raise ValueError('Malformed time zone string')
343
344 tz_comps = _parse_hh_mm_ss_ff(tzstr)
345 if all(x == 0 for x in tz_comps):
346 tzi = timezone.utc
347 else:
348 tzsign = -1 if tstr[tz_pos - 1] == '-' else 1
349
350 td = timedelta(hours=tz_comps[0], minutes=tz_comps[1],
351 seconds=tz_comps[2], microseconds=tz_comps[3])
352
353 tzi = timezone(tzsign * td)
354
355 time_comps.append(tzi)
356
357 return time_comps
358
359
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000360# Just raise TypeError if the arg isn't None or a string.
361def _check_tzname(name):
362 if name is not None and not isinstance(name, str):
363 raise TypeError("tzinfo.tzname() must return None or string, "
364 "not '%s'" % type(name))
365
366# name is the offset-producing method, "utcoffset" or "dst".
367# offset is what it returned.
368# If offset isn't None or timedelta, raises TypeError.
369# If offset is None, returns None.
Alexander Belopolsky018d3532017-07-31 10:26:50 -0400370# Else offset is checked for being in range.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000371# If it is, its integer value is returned. Else ValueError is raised.
372def _check_utc_offset(name, offset):
373 assert name in ("utcoffset", "dst")
374 if offset is None:
375 return
376 if not isinstance(offset, timedelta):
377 raise TypeError("tzinfo.%s() must return None "
378 "or timedelta, not '%s'" % (name, type(offset)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000379 if not -timedelta(1) < offset < timedelta(1):
Martin Panterdd780e42016-05-30 04:08:23 +0000380 raise ValueError("%s()=%s, must be strictly between "
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400381 "-timedelta(hours=24) and timedelta(hours=24)" %
382 (name, offset))
383
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000384def _check_date_fields(year, month, day):
Serhiy Storchaka578c3952020-05-26 18:43:38 +0300385 year = _index(year)
386 month = _index(month)
387 day = _index(day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000388 if not MINYEAR <= year <= MAXYEAR:
389 raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year)
390 if not 1 <= month <= 12:
391 raise ValueError('month must be in 1..12', month)
392 dim = _days_in_month(year, month)
393 if not 1 <= day <= dim:
394 raise ValueError('day must be in 1..%d' % dim, day)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400395 return year, month, day
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000396
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400397def _check_time_fields(hour, minute, second, microsecond, fold):
Serhiy Storchaka578c3952020-05-26 18:43:38 +0300398 hour = _index(hour)
399 minute = _index(minute)
400 second = _index(second)
401 microsecond = _index(microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000402 if not 0 <= hour <= 23:
403 raise ValueError('hour must be in 0..23', hour)
404 if not 0 <= minute <= 59:
405 raise ValueError('minute must be in 0..59', minute)
406 if not 0 <= second <= 59:
407 raise ValueError('second must be in 0..59', second)
408 if not 0 <= microsecond <= 999999:
409 raise ValueError('microsecond must be in 0..999999', microsecond)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400410 if fold not in (0, 1):
411 raise ValueError('fold must be either 0 or 1', fold)
412 return hour, minute, second, microsecond, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000413
414def _check_tzinfo_arg(tz):
415 if tz is not None and not isinstance(tz, tzinfo):
416 raise TypeError("tzinfo argument must be None or of a tzinfo subclass")
417
418def _cmperror(x, y):
419 raise TypeError("can't compare '%s' to '%s'" % (
420 type(x).__name__, type(y).__name__))
421
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500422def _divide_and_round(a, b):
423 """divide a by b and round result to the nearest integer
424
425 When the ratio is exactly half-way between two integers,
426 the even integer is returned.
427 """
428 # Based on the reference implementation for divmod_near
429 # in Objects/longobject.c.
430 q, r = divmod(a, b)
431 # round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
432 # The expression r / b > 0.5 is equivalent to 2 * r > b if b is
433 # positive, 2 * r < b if b negative.
434 r *= 2
435 greater_than_half = r > b if b > 0 else r < b
436 if greater_than_half or r == b and q % 2 == 1:
437 q += 1
438
439 return q
440
Victor Stinner2ec55872015-09-02 19:16:07 +0200441
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000442class timedelta:
443 """Represent the difference between two datetime objects.
444
445 Supported operators:
446
447 - add, subtract timedelta
448 - unary plus, minus, abs
449 - compare to timedelta
Serhiy Storchaka95949422013-08-27 19:40:23 +0300450 - multiply, divide by int
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000451
452 In addition, datetime supports subtraction of two datetime objects
453 returning a timedelta, and addition or subtraction of a datetime
454 and a timedelta giving a datetime.
455
456 Representation: (days, seconds, microseconds). Why? Because I
457 felt like it.
458 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400459 __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000460
461 def __new__(cls, days=0, seconds=0, microseconds=0,
462 milliseconds=0, minutes=0, hours=0, weeks=0):
463 # Doing this efficiently and accurately in C is going to be difficult
464 # and error-prone, due to ubiquitous overflow possibilities, and that
465 # C double doesn't have enough bits of precision to represent
466 # microseconds over 10K years faithfully. The code here tries to make
467 # explicit where go-fast assumptions can be relied on, in order to
468 # guide the C implementation; it's way more convoluted than speed-
469 # ignoring auto-overflow-to-long idiomatic Python could be.
470
471 # XXX Check that all inputs are ints or floats.
472
473 # Final values, all integer.
474 # s and us fit in 32-bit signed ints; d isn't bounded.
475 d = s = us = 0
476
477 # Normalize everything to days, seconds, microseconds.
478 days += weeks*7
479 seconds += minutes*60 + hours*3600
480 microseconds += milliseconds*1000
481
482 # Get rid of all fractions, and normalize s and us.
483 # Take a deep breath <wink>.
484 if isinstance(days, float):
485 dayfrac, days = _math.modf(days)
486 daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
487 assert daysecondswhole == int(daysecondswhole) # can't overflow
488 s = int(daysecondswhole)
489 assert days == int(days)
490 d = int(days)
491 else:
492 daysecondsfrac = 0.0
493 d = days
494 assert isinstance(daysecondsfrac, float)
495 assert abs(daysecondsfrac) <= 1.0
496 assert isinstance(d, int)
497 assert abs(s) <= 24 * 3600
498 # days isn't referenced again before redefinition
499
500 if isinstance(seconds, float):
501 secondsfrac, seconds = _math.modf(seconds)
502 assert seconds == int(seconds)
503 seconds = int(seconds)
504 secondsfrac += daysecondsfrac
505 assert abs(secondsfrac) <= 2.0
506 else:
507 secondsfrac = daysecondsfrac
508 # daysecondsfrac isn't referenced again
509 assert isinstance(secondsfrac, float)
510 assert abs(secondsfrac) <= 2.0
511
512 assert isinstance(seconds, int)
513 days, seconds = divmod(seconds, 24*3600)
514 d += days
515 s += int(seconds) # can't overflow
516 assert isinstance(s, int)
517 assert abs(s) <= 2 * 24 * 3600
518 # seconds isn't referenced again before redefinition
519
520 usdouble = secondsfrac * 1e6
521 assert abs(usdouble) < 2.1e6 # exact value not critical
522 # secondsfrac isn't referenced again
523
524 if isinstance(microseconds, float):
Victor Stinner69cc4872015-09-08 23:58:54 +0200525 microseconds = round(microseconds + usdouble)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000526 seconds, microseconds = divmod(microseconds, 1000000)
527 days, seconds = divmod(seconds, 24*3600)
528 d += days
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400529 s += seconds
530 else:
531 microseconds = int(microseconds)
532 seconds, microseconds = divmod(microseconds, 1000000)
533 days, seconds = divmod(seconds, 24*3600)
534 d += days
535 s += seconds
Victor Stinner69cc4872015-09-08 23:58:54 +0200536 microseconds = round(microseconds + usdouble)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400537 assert isinstance(s, int)
538 assert isinstance(microseconds, int)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000539 assert abs(s) <= 3 * 24 * 3600
540 assert abs(microseconds) < 3.1e6
541
542 # Just a little bit of carrying possible for microseconds and seconds.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400543 seconds, us = divmod(microseconds, 1000000)
544 s += seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000545 days, s = divmod(s, 24*3600)
546 d += days
547
548 assert isinstance(d, int)
549 assert isinstance(s, int) and 0 <= s < 24*3600
550 assert isinstance(us, int) and 0 <= us < 1000000
551
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000552 if abs(d) > 999999999:
553 raise OverflowError("timedelta # of days is too large: %d" % d)
554
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400555 self = object.__new__(cls)
556 self._days = d
557 self._seconds = s
558 self._microseconds = us
559 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000560 return self
561
562 def __repr__(self):
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200563 args = []
564 if self._days:
565 args.append("days=%d" % self._days)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000566 if self._seconds:
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200567 args.append("seconds=%d" % self._seconds)
568 if self._microseconds:
569 args.append("microseconds=%d" % self._microseconds)
570 if not args:
571 args.append('0')
572 return "%s.%s(%s)" % (self.__class__.__module__,
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300573 self.__class__.__qualname__,
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200574 ', '.join(args))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000575
576 def __str__(self):
577 mm, ss = divmod(self._seconds, 60)
578 hh, mm = divmod(mm, 60)
579 s = "%d:%02d:%02d" % (hh, mm, ss)
580 if self._days:
581 def plural(n):
582 return n, abs(n) != 1 and "s" or ""
583 s = ("%d day%s, " % plural(self._days)) + s
584 if self._microseconds:
585 s = s + ".%06d" % self._microseconds
586 return s
587
588 def total_seconds(self):
589 """Total seconds in the duration."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400590 return ((self.days * 86400 + self.seconds) * 10**6 +
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000591 self.microseconds) / 10**6
592
593 # Read-only field accessors
594 @property
595 def days(self):
596 """days"""
597 return self._days
598
599 @property
600 def seconds(self):
601 """seconds"""
602 return self._seconds
603
604 @property
605 def microseconds(self):
606 """microseconds"""
607 return self._microseconds
608
609 def __add__(self, other):
610 if isinstance(other, timedelta):
611 # for CPython compatibility, we cannot use
612 # our __class__ here, but need a real timedelta
613 return timedelta(self._days + other._days,
614 self._seconds + other._seconds,
615 self._microseconds + other._microseconds)
616 return NotImplemented
617
618 __radd__ = __add__
619
620 def __sub__(self, other):
621 if isinstance(other, timedelta):
Alexander Belopolskyb6f5ec72011-04-05 20:07:38 -0400622 # for CPython compatibility, we cannot use
623 # our __class__ here, but need a real timedelta
624 return timedelta(self._days - other._days,
625 self._seconds - other._seconds,
626 self._microseconds - other._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000627 return NotImplemented
628
629 def __rsub__(self, other):
630 if isinstance(other, timedelta):
631 return -self + other
632 return NotImplemented
633
634 def __neg__(self):
635 # for CPython compatibility, we cannot use
636 # our __class__ here, but need a real timedelta
637 return timedelta(-self._days,
638 -self._seconds,
639 -self._microseconds)
640
641 def __pos__(self):
642 return self
643
644 def __abs__(self):
645 if self._days < 0:
646 return -self
647 else:
648 return self
649
650 def __mul__(self, other):
651 if isinstance(other, int):
652 # for CPython compatibility, we cannot use
653 # our __class__ here, but need a real timedelta
654 return timedelta(self._days * other,
655 self._seconds * other,
656 self._microseconds * other)
657 if isinstance(other, float):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500658 usec = self._to_microseconds()
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000659 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500660 return timedelta(0, 0, _divide_and_round(usec * a, b))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000661 return NotImplemented
662
663 __rmul__ = __mul__
664
665 def _to_microseconds(self):
666 return ((self._days * (24*3600) + self._seconds) * 1000000 +
667 self._microseconds)
668
669 def __floordiv__(self, other):
670 if not isinstance(other, (int, timedelta)):
671 return NotImplemented
672 usec = self._to_microseconds()
673 if isinstance(other, timedelta):
674 return usec // other._to_microseconds()
675 if isinstance(other, int):
676 return timedelta(0, 0, usec // other)
677
678 def __truediv__(self, other):
679 if not isinstance(other, (int, float, timedelta)):
680 return NotImplemented
681 usec = self._to_microseconds()
682 if isinstance(other, timedelta):
683 return usec / other._to_microseconds()
684 if isinstance(other, int):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500685 return timedelta(0, 0, _divide_and_round(usec, other))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000686 if isinstance(other, float):
687 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500688 return timedelta(0, 0, _divide_and_round(b * usec, a))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000689
690 def __mod__(self, other):
691 if isinstance(other, timedelta):
692 r = self._to_microseconds() % other._to_microseconds()
693 return timedelta(0, 0, r)
694 return NotImplemented
695
696 def __divmod__(self, other):
697 if isinstance(other, timedelta):
698 q, r = divmod(self._to_microseconds(),
699 other._to_microseconds())
700 return q, timedelta(0, 0, r)
701 return NotImplemented
702
703 # Comparisons of timedelta objects with other.
704
705 def __eq__(self, other):
706 if isinstance(other, timedelta):
707 return self._cmp(other) == 0
708 else:
Xtreake6b46aa2019-07-13 18:52:21 +0530709 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000710
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000711 def __le__(self, other):
712 if isinstance(other, timedelta):
713 return self._cmp(other) <= 0
714 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +0300715 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000716
717 def __lt__(self, other):
718 if isinstance(other, timedelta):
719 return self._cmp(other) < 0
720 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +0300721 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000722
723 def __ge__(self, other):
724 if isinstance(other, timedelta):
725 return self._cmp(other) >= 0
726 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +0300727 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000728
729 def __gt__(self, other):
730 if isinstance(other, timedelta):
731 return self._cmp(other) > 0
732 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +0300733 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000734
735 def _cmp(self, other):
736 assert isinstance(other, timedelta)
737 return _cmp(self._getstate(), other._getstate())
738
739 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400740 if self._hashcode == -1:
741 self._hashcode = hash(self._getstate())
742 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000743
744 def __bool__(self):
745 return (self._days != 0 or
746 self._seconds != 0 or
747 self._microseconds != 0)
748
749 # Pickle support.
750
751 def _getstate(self):
752 return (self._days, self._seconds, self._microseconds)
753
754 def __reduce__(self):
755 return (self.__class__, self._getstate())
756
757timedelta.min = timedelta(-999999999)
758timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
759 microseconds=999999)
760timedelta.resolution = timedelta(microseconds=1)
761
762class date:
763 """Concrete date type.
764
765 Constructors:
766
767 __new__()
768 fromtimestamp()
769 today()
770 fromordinal()
771
772 Operators:
773
774 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200775 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000776 __add__, __radd__, __sub__ (add/radd only with timedelta arg)
777
778 Methods:
779
780 timetuple()
781 toordinal()
782 weekday()
783 isoweekday(), isocalendar(), isoformat()
784 ctime()
785 strftime()
786
787 Properties (readonly):
788 year, month, day
789 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400790 __slots__ = '_year', '_month', '_day', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000791
792 def __new__(cls, year, month=None, day=None):
793 """Constructor.
794
795 Arguments:
796
797 year, month, day (required, base 1)
798 """
Serhiy Storchaka8452ca12018-12-07 13:42:10 +0200799 if (month is None and
800 isinstance(year, (bytes, str)) and len(year) == 4 and
801 1 <= ord(year[2:3]) <= 12):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000802 # Pickle support
Serhiy Storchaka8452ca12018-12-07 13:42:10 +0200803 if isinstance(year, str):
804 try:
805 year = year.encode('latin1')
806 except UnicodeEncodeError:
807 # More informative error message.
808 raise ValueError(
809 "Failed to encode latin1 string when unpickling "
810 "a date object. "
811 "pickle.load(data, encoding='latin1') is assumed.")
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000812 self = object.__new__(cls)
813 self.__setstate(year)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400814 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000815 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400816 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000817 self = object.__new__(cls)
818 self._year = year
819 self._month = month
820 self._day = day
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400821 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000822 return self
823
824 # Additional constructors
825
826 @classmethod
827 def fromtimestamp(cls, t):
828 "Construct a date from a POSIX timestamp (like time.time())."
829 y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
830 return cls(y, m, d)
831
832 @classmethod
833 def today(cls):
834 "Construct a date from time.time()."
835 t = _time.time()
836 return cls.fromtimestamp(t)
837
838 @classmethod
839 def fromordinal(cls, n):
Martin Pantereb995702016-07-28 01:11:04 +0000840 """Construct a date from a proleptic Gregorian ordinal.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000841
842 January 1 of year 1 is day 1. Only the year, month and day are
843 non-zero in the result.
844 """
845 y, m, d = _ord2ymd(n)
846 return cls(y, m, d)
847
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500848 @classmethod
849 def fromisoformat(cls, date_string):
850 """Construct a date from the output of date.isoformat()."""
851 if not isinstance(date_string, str):
852 raise TypeError('fromisoformat: argument must be str')
853
854 try:
855 assert len(date_string) == 10
856 return cls(*_parse_isoformat_date(date_string))
857 except Exception:
Paul Ganssle3df85402018-10-22 12:32:52 -0400858 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500859
Paul Ganssle88c09372019-04-29 09:22:03 -0400860 @classmethod
861 def fromisocalendar(cls, year, week, day):
862 """Construct a date from the ISO year, week number and weekday.
863
864 This is the inverse of the date.isocalendar() function"""
865 # Year is bounded this way because 9999-12-31 is (9999, 52, 5)
866 if not MINYEAR <= year <= MAXYEAR:
867 raise ValueError(f"Year is out of range: {year}")
868
869 if not 0 < week < 53:
870 out_of_range = True
871
872 if week == 53:
873 # ISO years have 53 weeks in them on years starting with a
874 # Thursday and leap years starting on a Wednesday
875 first_weekday = _ymd2ord(year, 1, 1) % 7
876 if (first_weekday == 4 or (first_weekday == 3 and
877 _is_leap(year))):
878 out_of_range = False
879
880 if out_of_range:
881 raise ValueError(f"Invalid week: {week}")
882
883 if not 0 < day < 8:
884 raise ValueError(f"Invalid weekday: {day} (range is [1, 7])")
885
886 # Now compute the offset from (Y, 1, 1) in days:
887 day_offset = (week - 1) * 7 + (day - 1)
888
889 # Calculate the ordinal day for monday, week 1
890 day_1 = _isoweek1monday(year)
891 ord_day = day_1 + day_offset
892
893 return cls(*_ord2ymd(ord_day))
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500894
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000895 # Conversions to string
896
897 def __repr__(self):
898 """Convert to formal string, for repr().
899
900 >>> dt = datetime(2010, 1, 1)
901 >>> repr(dt)
902 'datetime.datetime(2010, 1, 1, 0, 0)'
903
904 >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
905 >>> repr(dt)
906 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
907 """
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300908 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
909 self.__class__.__qualname__,
910 self._year,
911 self._month,
912 self._day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000913 # XXX These shouldn't depend on time.localtime(), because that
914 # clips the usable dates to [1970 .. 2038). At least ctime() is
915 # easily done without using strftime() -- that's better too because
916 # strftime("%c", ...) is locale specific.
917
918
919 def ctime(self):
920 "Return ctime() style string."
921 weekday = self.toordinal() % 7 or 7
922 return "%s %s %2d 00:00:00 %04d" % (
923 _DAYNAMES[weekday],
924 _MONTHNAMES[self._month],
925 self._day, self._year)
926
927 def strftime(self, fmt):
928 "Format using strftime()."
929 return _wrap_strftime(self, fmt, self.timetuple())
930
931 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400932 if not isinstance(fmt, str):
933 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000934 if len(fmt) != 0:
935 return self.strftime(fmt)
936 return str(self)
937
938 def isoformat(self):
939 """Return the date formatted according to ISO.
940
941 This is 'YYYY-MM-DD'.
942
943 References:
944 - http://www.w3.org/TR/NOTE-datetime
945 - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
946 """
947 return "%04d-%02d-%02d" % (self._year, self._month, self._day)
948
949 __str__ = isoformat
950
951 # Read-only field accessors
952 @property
953 def year(self):
954 """year (1-9999)"""
955 return self._year
956
957 @property
958 def month(self):
959 """month (1-12)"""
960 return self._month
961
962 @property
963 def day(self):
964 """day (1-31)"""
965 return self._day
966
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200967 # Standard conversions, __eq__, __le__, __lt__, __ge__, __gt__,
968 # __hash__ (and helpers)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000969
970 def timetuple(self):
971 "Return local time tuple compatible with time.localtime()."
972 return _build_struct_time(self._year, self._month, self._day,
973 0, 0, 0, -1)
974
975 def toordinal(self):
976 """Return proleptic Gregorian ordinal for the year, month and day.
977
978 January 1 of year 1 is day 1. Only the year, month and day values
979 contribute to the result.
980 """
981 return _ymd2ord(self._year, self._month, self._day)
982
983 def replace(self, year=None, month=None, day=None):
984 """Return a new date with new values for the specified fields."""
985 if year is None:
986 year = self._year
987 if month is None:
988 month = self._month
989 if day is None:
990 day = self._day
Paul Ganssle191e9932017-11-09 16:34:29 -0500991 return type(self)(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000992
993 # Comparisons of date objects with other.
994
995 def __eq__(self, other):
996 if isinstance(other, date):
997 return self._cmp(other) == 0
998 return NotImplemented
999
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001000 def __le__(self, other):
1001 if isinstance(other, date):
1002 return self._cmp(other) <= 0
1003 return NotImplemented
1004
1005 def __lt__(self, other):
1006 if isinstance(other, date):
1007 return self._cmp(other) < 0
1008 return NotImplemented
1009
1010 def __ge__(self, other):
1011 if isinstance(other, date):
1012 return self._cmp(other) >= 0
1013 return NotImplemented
1014
1015 def __gt__(self, other):
1016 if isinstance(other, date):
1017 return self._cmp(other) > 0
1018 return NotImplemented
1019
1020 def _cmp(self, other):
1021 assert isinstance(other, date)
1022 y, m, d = self._year, self._month, self._day
1023 y2, m2, d2 = other._year, other._month, other._day
1024 return _cmp((y, m, d), (y2, m2, d2))
1025
1026 def __hash__(self):
1027 "Hash."
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001028 if self._hashcode == -1:
1029 self._hashcode = hash(self._getstate())
1030 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001031
1032 # Computations
1033
1034 def __add__(self, other):
1035 "Add a date to a timedelta."
1036 if isinstance(other, timedelta):
1037 o = self.toordinal() + other.days
1038 if 0 < o <= _MAXORDINAL:
Paul Ganssle89427cd2019-02-04 14:42:04 -05001039 return type(self).fromordinal(o)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001040 raise OverflowError("result out of range")
1041 return NotImplemented
1042
1043 __radd__ = __add__
1044
1045 def __sub__(self, other):
1046 """Subtract two dates, or a date and a timedelta."""
1047 if isinstance(other, timedelta):
1048 return self + timedelta(-other.days)
1049 if isinstance(other, date):
1050 days1 = self.toordinal()
1051 days2 = other.toordinal()
1052 return timedelta(days1 - days2)
1053 return NotImplemented
1054
1055 def weekday(self):
1056 "Return day of the week, where Monday == 0 ... Sunday == 6."
1057 return (self.toordinal() + 6) % 7
1058
1059 # Day-of-the-week and week-of-the-year, according to ISO
1060
1061 def isoweekday(self):
1062 "Return day of the week, where Monday == 1 ... Sunday == 7."
1063 # 1-Jan-0001 is a Monday
1064 return self.toordinal() % 7 or 7
1065
1066 def isocalendar(self):
Paul Ganssle1b97b9b2020-05-16 10:02:59 -04001067 """Return a named tuple containing ISO year, week number, and weekday.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001068
1069 The first ISO week of the year is the (Mon-Sun) week
1070 containing the year's first Thursday; everything else derives
1071 from that.
1072
1073 The first week is 1; Monday is 1 ... Sunday is 7.
1074
1075 ISO calendar algorithm taken from
1076 http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
Brett Cannon07b954d2016-01-15 09:53:51 -08001077 (used with permission)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001078 """
1079 year = self._year
1080 week1monday = _isoweek1monday(year)
1081 today = _ymd2ord(self._year, self._month, self._day)
1082 # Internally, week and day have origin 0
1083 week, day = divmod(today - week1monday, 7)
1084 if week < 0:
1085 year -= 1
1086 week1monday = _isoweek1monday(year)
1087 week, day = divmod(today - week1monday, 7)
1088 elif week >= 52:
1089 if today >= _isoweek1monday(year+1):
1090 year += 1
1091 week = 0
Paul Ganssle1b97b9b2020-05-16 10:02:59 -04001092 return _IsoCalendarDate(year, week+1, day+1)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001093
1094 # Pickle support.
1095
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001096 def _getstate(self):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001097 yhi, ylo = divmod(self._year, 256)
1098 return bytes([yhi, ylo, self._month, self._day]),
1099
1100 def __setstate(self, string):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001101 yhi, ylo, self._month, self._day = string
1102 self._year = yhi * 256 + ylo
1103
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001104 def __reduce__(self):
1105 return (self.__class__, self._getstate())
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001106
1107_date_class = date # so functions w/ args named "date" can get at the class
1108
1109date.min = date(1, 1, 1)
1110date.max = date(9999, 12, 31)
1111date.resolution = timedelta(days=1)
1112
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001113
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001114class tzinfo:
1115 """Abstract base class for time zone info classes.
1116
1117 Subclasses must override the name(), utcoffset() and dst() methods.
1118 """
1119 __slots__ = ()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001120
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001121 def tzname(self, dt):
1122 "datetime -> string name of time zone."
1123 raise NotImplementedError("tzinfo subclass must override tzname()")
1124
1125 def utcoffset(self, dt):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001126 "datetime -> timedelta, positive for east of UTC, negative for west of UTC"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001127 raise NotImplementedError("tzinfo subclass must override utcoffset()")
1128
1129 def dst(self, dt):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001130 """datetime -> DST offset as timedelta, positive for east of UTC.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001131
1132 Return 0 if DST not in effect. utcoffset() must include the DST
1133 offset.
1134 """
1135 raise NotImplementedError("tzinfo subclass must override dst()")
1136
1137 def fromutc(self, dt):
1138 "datetime in UTC -> datetime in local time."
1139
1140 if not isinstance(dt, datetime):
1141 raise TypeError("fromutc() requires a datetime argument")
1142 if dt.tzinfo is not self:
1143 raise ValueError("dt.tzinfo is not self")
1144
1145 dtoff = dt.utcoffset()
1146 if dtoff is None:
1147 raise ValueError("fromutc() requires a non-None utcoffset() "
1148 "result")
1149
1150 # See the long comment block at the end of this file for an
1151 # explanation of this algorithm.
1152 dtdst = dt.dst()
1153 if dtdst is None:
1154 raise ValueError("fromutc() requires a non-None dst() result")
1155 delta = dtoff - dtdst
1156 if delta:
1157 dt += delta
1158 dtdst = dt.dst()
1159 if dtdst is None:
1160 raise ValueError("fromutc(): dt.dst gave inconsistent "
1161 "results; cannot convert")
1162 return dt + dtdst
1163
1164 # Pickle support.
1165
1166 def __reduce__(self):
1167 getinitargs = getattr(self, "__getinitargs__", None)
1168 if getinitargs:
1169 args = getinitargs()
1170 else:
1171 args = ()
1172 getstate = getattr(self, "__getstate__", None)
1173 if getstate:
1174 state = getstate()
1175 else:
1176 state = getattr(self, "__dict__", None) or None
1177 if state is None:
1178 return (self.__class__, args)
1179 else:
1180 return (self.__class__, args, state)
1181
Paul Ganssle1b97b9b2020-05-16 10:02:59 -04001182
1183class IsoCalendarDate(tuple):
1184
1185 def __new__(cls, year, week, weekday, /):
1186 return super().__new__(cls, (year, week, weekday))
1187
1188 @property
1189 def year(self):
1190 return self[0]
1191
1192 @property
1193 def week(self):
1194 return self[1]
1195
1196 @property
1197 def weekday(self):
1198 return self[2]
1199
1200 def __reduce__(self):
1201 # This code is intended to pickle the object without making the
1202 # class public. See https://bugs.python.org/msg352381
1203 return (tuple, (tuple(self),))
1204
1205 def __repr__(self):
1206 return (f'{self.__class__.__name__}'
1207 f'(year={self[0]}, week={self[1]}, weekday={self[2]})')
1208
1209
1210_IsoCalendarDate = IsoCalendarDate
1211del IsoCalendarDate
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001212_tzinfo_class = tzinfo
1213
1214class time:
1215 """Time with time zone.
1216
1217 Constructors:
1218
1219 __new__()
1220
1221 Operators:
1222
1223 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +02001224 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001225
1226 Methods:
1227
1228 strftime()
1229 isoformat()
1230 utcoffset()
1231 tzname()
1232 dst()
1233
1234 Properties (readonly):
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001235 hour, minute, second, microsecond, tzinfo, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001236 """
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001237 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode', '_fold'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001238
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001239 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001240 """Constructor.
1241
1242 Arguments:
1243
1244 hour, minute (required)
1245 second, microsecond (default to zero)
1246 tzinfo (default to None)
Victor Stinner51b90d22017-01-04 12:01:16 +01001247 fold (keyword only, default to zero)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001248 """
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001249 if (isinstance(hour, (bytes, str)) and len(hour) == 6 and
1250 ord(hour[0:1])&0x7F < 24):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001251 # Pickle support
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001252 if isinstance(hour, str):
1253 try:
1254 hour = hour.encode('latin1')
1255 except UnicodeEncodeError:
1256 # More informative error message.
1257 raise ValueError(
1258 "Failed to encode latin1 string when unpickling "
1259 "a time object. "
1260 "pickle.load(data, encoding='latin1') is assumed.")
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001261 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001262 self.__setstate(hour, minute or None)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001263 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001264 return self
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001265 hour, minute, second, microsecond, fold = _check_time_fields(
1266 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001267 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001268 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001269 self._hour = hour
1270 self._minute = minute
1271 self._second = second
1272 self._microsecond = microsecond
1273 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001274 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001275 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001276 return self
1277
1278 # Read-only field accessors
1279 @property
1280 def hour(self):
1281 """hour (0-23)"""
1282 return self._hour
1283
1284 @property
1285 def minute(self):
1286 """minute (0-59)"""
1287 return self._minute
1288
1289 @property
1290 def second(self):
1291 """second (0-59)"""
1292 return self._second
1293
1294 @property
1295 def microsecond(self):
1296 """microsecond (0-999999)"""
1297 return self._microsecond
1298
1299 @property
1300 def tzinfo(self):
1301 """timezone info object"""
1302 return self._tzinfo
1303
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001304 @property
1305 def fold(self):
1306 return self._fold
1307
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001308 # Standard conversions, __hash__ (and helpers)
1309
1310 # Comparisons of time objects with other.
1311
1312 def __eq__(self, other):
1313 if isinstance(other, time):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001314 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001315 else:
Xtreake6b46aa2019-07-13 18:52:21 +05301316 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001317
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001318 def __le__(self, other):
1319 if isinstance(other, time):
1320 return self._cmp(other) <= 0
1321 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +03001322 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001323
1324 def __lt__(self, other):
1325 if isinstance(other, time):
1326 return self._cmp(other) < 0
1327 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +03001328 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001329
1330 def __ge__(self, other):
1331 if isinstance(other, time):
1332 return self._cmp(other) >= 0
1333 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +03001334 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001335
1336 def __gt__(self, other):
1337 if isinstance(other, time):
1338 return self._cmp(other) > 0
1339 else:
Serhiy Storchaka17e52642019-08-04 12:38:46 +03001340 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001341
Alexander Belopolsky08313822012-06-15 20:19:47 -04001342 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001343 assert isinstance(other, time)
1344 mytz = self._tzinfo
1345 ottz = other._tzinfo
1346 myoff = otoff = None
1347
1348 if mytz is ottz:
1349 base_compare = True
1350 else:
1351 myoff = self.utcoffset()
1352 otoff = other.utcoffset()
1353 base_compare = myoff == otoff
1354
1355 if base_compare:
1356 return _cmp((self._hour, self._minute, self._second,
1357 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001358 (other._hour, other._minute, other._second,
1359 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001360 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001361 if allow_mixed:
1362 return 2 # arbitrary non-zero value
1363 else:
1364 raise TypeError("cannot compare naive and aware times")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001365 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1366 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1367 return _cmp((myhhmm, self._second, self._microsecond),
1368 (othhmm, other._second, other._microsecond))
1369
1370 def __hash__(self):
1371 """Hash."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001372 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001373 if self.fold:
1374 t = self.replace(fold=0)
1375 else:
1376 t = self
1377 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001378 if not tzoff: # zero or None
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001379 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001380 else:
1381 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1382 timedelta(hours=1))
1383 assert not m % timedelta(minutes=1), "whole minute"
1384 m //= timedelta(minutes=1)
1385 if 0 <= h < 24:
1386 self._hashcode = hash(time(h, m, self.second, self.microsecond))
1387 else:
1388 self._hashcode = hash((h, m, self.second, self.microsecond))
1389 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001390
1391 # Conversion to string
1392
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001393 def _tzstr(self):
1394 """Return formatted timezone offset (+xx:xx) or an empty string."""
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001395 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001396 return _format_offset(off)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001397
1398 def __repr__(self):
1399 """Convert to formal string, for repr()."""
1400 if self._microsecond != 0:
1401 s = ", %d, %d" % (self._second, self._microsecond)
1402 elif self._second != 0:
1403 s = ", %d" % self._second
1404 else:
1405 s = ""
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001406 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1407 self.__class__.__qualname__,
1408 self._hour, self._minute, s)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001409 if self._tzinfo is not None:
1410 assert s[-1:] == ")"
1411 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001412 if self._fold:
1413 assert s[-1:] == ")"
1414 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001415 return s
1416
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001417 def isoformat(self, timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001418 """Return the time formatted according to ISO.
1419
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001420 The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional
1421 part is omitted if self.microsecond == 0.
1422
1423 The optional argument timespec specifies the number of additional
Ram Rachum52301312020-10-03 13:43:47 +03001424 terms of the time to include. Valid options are 'auto', 'hours',
1425 'minutes', 'seconds', 'milliseconds' and 'microseconds'.
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):
scaramallionc304c9a2020-10-19 01:49:48 +11001551 return (self.__class__, 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
Paul Ganssle1b97b9b2020-05-16 10:02:59 -04001562
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001563class datetime(date):
1564 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1565
1566 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001567 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001568 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001569 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001570
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001571 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001572 microsecond=0, tzinfo=None, *, fold=0):
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001573 if (isinstance(year, (bytes, str)) and len(year) == 10 and
1574 1 <= ord(year[2:3])&0x7F <= 12):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001575 # Pickle support
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001576 if isinstance(year, str):
1577 try:
1578 year = bytes(year, 'latin1')
1579 except UnicodeEncodeError:
1580 # More informative error message.
1581 raise ValueError(
1582 "Failed to encode latin1 string when unpickling "
1583 "a datetime object. "
1584 "pickle.load(data, encoding='latin1') is assumed.")
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001585 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001586 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001587 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001588 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001589 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001590 hour, minute, second, microsecond, fold = _check_time_fields(
1591 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001592 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001593 self = object.__new__(cls)
1594 self._year = year
1595 self._month = month
1596 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001597 self._hour = hour
1598 self._minute = minute
1599 self._second = second
1600 self._microsecond = microsecond
1601 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001602 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001603 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001604 return self
1605
1606 # Read-only field accessors
1607 @property
1608 def hour(self):
1609 """hour (0-23)"""
1610 return self._hour
1611
1612 @property
1613 def minute(self):
1614 """minute (0-59)"""
1615 return self._minute
1616
1617 @property
1618 def second(self):
1619 """second (0-59)"""
1620 return self._second
1621
1622 @property
1623 def microsecond(self):
1624 """microsecond (0-999999)"""
1625 return self._microsecond
1626
1627 @property
1628 def tzinfo(self):
1629 """timezone info object"""
1630 return self._tzinfo
1631
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001632 @property
1633 def fold(self):
1634 return self._fold
1635
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001636 @classmethod
Victor Stinneradfefa52015-09-04 23:57:25 +02001637 def _fromtimestamp(cls, t, utc, tz):
1638 """Construct a datetime from a POSIX timestamp (like time.time()).
1639
1640 A timezone info object may be passed in as well.
1641 """
1642 frac, t = _math.modf(t)
Victor Stinner7667f582015-09-09 01:02:23 +02001643 us = round(frac * 1e6)
Victor Stinneradfefa52015-09-04 23:57:25 +02001644 if us >= 1000000:
1645 t += 1
1646 us -= 1000000
1647 elif us < 0:
1648 t -= 1
1649 us += 1000000
1650
1651 converter = _time.gmtime if utc else _time.localtime
1652 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1653 ss = min(ss, 59) # clamp out leap seconds if the platform has them
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001654 result = cls(y, m, d, hh, mm, ss, us, tz)
1655 if tz is None:
1656 # As of version 2015f max fold in IANA database is
1657 # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
1658 # Let's probe 24 hours in the past to detect a transition:
1659 max_fold_seconds = 24 * 3600
Ammar Askar96d1e692018-07-25 09:54:58 -07001660
1661 # On Windows localtime_s throws an OSError for negative values,
1662 # thus we can't perform fold detection for values of time less
1663 # than the max time fold. See comments in _datetimemodule's
1664 # version of this method for more details.
1665 if t < max_fold_seconds and sys.platform.startswith("win"):
1666 return result
1667
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001668 y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1669 probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1670 trans = result - probe1 - timedelta(0, max_fold_seconds)
1671 if trans.days < 0:
1672 y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
1673 probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1674 if probe2 == result:
1675 result._fold = 1
1676 else:
1677 result = tz.fromutc(result)
1678 return result
Victor Stinneradfefa52015-09-04 23:57:25 +02001679
1680 @classmethod
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001681 def fromtimestamp(cls, t, tz=None):
1682 """Construct a datetime from a POSIX timestamp (like time.time()).
1683
1684 A timezone info object may be passed in as well.
1685 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001686 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001687
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001688 return cls._fromtimestamp(t, tz is not None, tz)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001689
1690 @classmethod
1691 def utcfromtimestamp(cls, t):
Alexander Belopolskye2e178e2015-03-01 14:52:07 -05001692 """Construct a naive UTC datetime from a POSIX timestamp."""
Victor Stinneradfefa52015-09-04 23:57:25 +02001693 return cls._fromtimestamp(t, True, None)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001694
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001695 @classmethod
1696 def now(cls, tz=None):
1697 "Construct a datetime from time.time() and optional time zone info."
1698 t = _time.time()
1699 return cls.fromtimestamp(t, tz)
1700
1701 @classmethod
1702 def utcnow(cls):
1703 "Construct a UTC datetime from time.time()."
1704 t = _time.time()
1705 return cls.utcfromtimestamp(t)
1706
1707 @classmethod
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001708 def combine(cls, date, time, tzinfo=True):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001709 "Construct a datetime from a given date and a given time."
1710 if not isinstance(date, _date_class):
1711 raise TypeError("date argument must be a date instance")
1712 if not isinstance(time, _time_class):
1713 raise TypeError("time argument must be a time instance")
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001714 if tzinfo is True:
1715 tzinfo = time.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001716 return cls(date.year, date.month, date.day,
1717 time.hour, time.minute, time.second, time.microsecond,
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001718 tzinfo, fold=time.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001719
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001720 @classmethod
1721 def fromisoformat(cls, date_string):
1722 """Construct a datetime from the output of datetime.isoformat()."""
1723 if not isinstance(date_string, str):
1724 raise TypeError('fromisoformat: argument must be str')
1725
1726 # Split this at the separator
1727 dstr = date_string[0:10]
1728 tstr = date_string[11:]
1729
1730 try:
1731 date_components = _parse_isoformat_date(dstr)
1732 except ValueError:
Paul Ganssle3df85402018-10-22 12:32:52 -04001733 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001734
1735 if tstr:
1736 try:
1737 time_components = _parse_isoformat_time(tstr)
1738 except ValueError:
Paul Ganssle3df85402018-10-22 12:32:52 -04001739 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001740 else:
1741 time_components = [0, 0, 0, 0, None]
1742
1743 return cls(*(date_components + time_components))
1744
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001745 def timetuple(self):
1746 "Return local time tuple compatible with time.localtime()."
1747 dst = self.dst()
1748 if dst is None:
1749 dst = -1
1750 elif dst:
1751 dst = 1
1752 else:
1753 dst = 0
1754 return _build_struct_time(self.year, self.month, self.day,
1755 self.hour, self.minute, self.second,
1756 dst)
1757
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001758 def _mktime(self):
1759 """Return integer POSIX timestamp."""
1760 epoch = datetime(1970, 1, 1)
1761 max_fold_seconds = 24 * 3600
1762 t = (self - epoch) // timedelta(0, 1)
1763 def local(u):
1764 y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1765 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1766
1767 # Our goal is to solve t = local(u) for u.
1768 a = local(t) - t
1769 u1 = t - a
1770 t1 = local(u1)
1771 if t1 == t:
1772 # We found one solution, but it may not be the one we need.
1773 # Look for an earlier solution (if `fold` is 0), or a
1774 # later one (if `fold` is 1).
1775 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1776 b = local(u2) - u2
1777 if a == b:
1778 return u1
1779 else:
1780 b = t1 - u1
1781 assert a != b
1782 u2 = t - b
1783 t2 = local(u2)
1784 if t2 == t:
1785 return u2
1786 if t1 == t:
1787 return u1
1788 # We have found both offsets a and b, but neither t - a nor t - b is
1789 # a solution. This means t is in the gap.
1790 return (max, min)[self.fold](u1, u2)
1791
1792
Alexander Belopolskya4415142012-06-08 12:33:09 -04001793 def timestamp(self):
1794 "Return POSIX timestamp as float"
1795 if self._tzinfo is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001796 s = self._mktime()
1797 return s + self.microsecond / 1e6
Alexander Belopolskya4415142012-06-08 12:33:09 -04001798 else:
1799 return (self - _EPOCH).total_seconds()
1800
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001801 def utctimetuple(self):
1802 "Return UTC time tuple compatible with time.gmtime()."
1803 offset = self.utcoffset()
1804 if offset:
1805 self -= offset
1806 y, m, d = self.year, self.month, self.day
1807 hh, mm, ss = self.hour, self.minute, self.second
1808 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1809
1810 def date(self):
1811 "Return the date part."
1812 return date(self._year, self._month, self._day)
1813
1814 def time(self):
1815 "Return the time part, with tzinfo None."
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001816 return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001817
1818 def timetz(self):
1819 "Return the time part, with same tzinfo."
1820 return time(self.hour, self.minute, self.second, self.microsecond,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001821 self._tzinfo, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001822
1823 def replace(self, year=None, month=None, day=None, hour=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001824 minute=None, second=None, microsecond=None, tzinfo=True,
1825 *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001826 """Return a new datetime with new values for the specified fields."""
1827 if year is None:
1828 year = self.year
1829 if month is None:
1830 month = self.month
1831 if day is None:
1832 day = self.day
1833 if hour is None:
1834 hour = self.hour
1835 if minute is None:
1836 minute = self.minute
1837 if second is None:
1838 second = self.second
1839 if microsecond is None:
1840 microsecond = self.microsecond
1841 if tzinfo is True:
1842 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001843 if fold is None:
1844 fold = self.fold
Paul Ganssle191e9932017-11-09 16:34:29 -05001845 return type(self)(year, month, day, hour, minute, second,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001846 microsecond, tzinfo, fold=fold)
1847
1848 def _local_timezone(self):
1849 if self.tzinfo is None:
1850 ts = self._mktime()
1851 else:
1852 ts = (self - _EPOCH) // timedelta(seconds=1)
1853 localtm = _time.localtime(ts)
1854 local = datetime(*localtm[:6])
Alexander Belopolskybcb032e2018-06-08 19:22:33 -04001855 # Extract TZ data
1856 gmtoff = localtm.tm_gmtoff
1857 zone = localtm.tm_zone
1858 return timezone(timedelta(seconds=gmtoff), zone)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001859
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001860 def astimezone(self, tz=None):
1861 if tz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001862 tz = self._local_timezone()
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001863 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001864 raise TypeError("tz argument must be an instance of tzinfo")
1865
1866 mytz = self.tzinfo
1867 if mytz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001868 mytz = self._local_timezone()
Alexander Belopolsky877b2322018-06-10 17:02:58 -04001869 myoffset = mytz.utcoffset(self)
1870 else:
1871 myoffset = mytz.utcoffset(self)
1872 if myoffset is None:
1873 mytz = self.replace(tzinfo=None)._local_timezone()
1874 myoffset = mytz.utcoffset(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001875
1876 if tz is mytz:
1877 return self
1878
1879 # Convert self to UTC, and attach the new time zone object.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001880 utc = (self - myoffset).replace(tzinfo=tz)
1881
1882 # Convert from UTC to tz's local time.
1883 return tz.fromutc(utc)
1884
1885 # Ways to produce a string.
1886
1887 def ctime(self):
1888 "Return ctime() style string."
1889 weekday = self.toordinal() % 7 or 7
1890 return "%s %s %2d %02d:%02d:%02d %04d" % (
1891 _DAYNAMES[weekday],
1892 _MONTHNAMES[self._month],
1893 self._day,
1894 self._hour, self._minute, self._second,
1895 self._year)
1896
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001897 def isoformat(self, sep='T', timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001898 """Return the time formatted according to ISO.
1899
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001900 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1901 By default, the fractional part is omitted if self.microsecond == 0.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001902
1903 If self.tzinfo is not None, the UTC offset is also attached, giving
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001904 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001905
1906 Optional argument sep specifies the separator between date and
1907 time, default 'T'.
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001908
1909 The optional argument timespec specifies the number of additional
Ram Rachum52301312020-10-03 13:43:47 +03001910 terms of the time to include. Valid options are 'auto', 'hours',
1911 'minutes', 'seconds', 'milliseconds' and 'microseconds'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001912 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001913 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1914 _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001915 self._microsecond, timespec))
1916
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001917 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001918 tz = _format_offset(off)
1919 if tz:
1920 s += tz
1921
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001922 return s
1923
1924 def __repr__(self):
1925 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001926 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001927 self._hour, self._minute, self._second, self._microsecond]
1928 if L[-1] == 0:
1929 del L[-1]
1930 if L[-1] == 0:
1931 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001932 s = "%s.%s(%s)" % (self.__class__.__module__,
1933 self.__class__.__qualname__,
1934 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001935 if self._tzinfo is not None:
1936 assert s[-1:] == ")"
1937 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001938 if self._fold:
1939 assert s[-1:] == ")"
1940 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001941 return s
1942
1943 def __str__(self):
1944 "Convert to string, for str()."
1945 return self.isoformat(sep=' ')
1946
1947 @classmethod
1948 def strptime(cls, date_string, format):
1949 'string, format -> new datetime parsed from a string (like time.strptime()).'
1950 import _strptime
1951 return _strptime._strptime_datetime(cls, date_string, format)
1952
1953 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001954 """Return the timezone offset as timedelta positive east of UTC (negative west of
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001955 UTC)."""
1956 if self._tzinfo is None:
1957 return None
1958 offset = self._tzinfo.utcoffset(self)
1959 _check_utc_offset("utcoffset", offset)
1960 return offset
1961
1962 def tzname(self):
1963 """Return the timezone name.
1964
1965 Note that the name is 100% informational -- there's no requirement that
1966 it mean anything in particular. For example, "GMT", "UTC", "-500",
1967 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1968 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001969 if self._tzinfo is None:
1970 return None
1971 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001972 _check_tzname(name)
1973 return name
1974
1975 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001976 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1977 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001978
1979 This is purely informational; the DST offset has already been added to
1980 the UTC offset returned by utcoffset() if applicable, so there's no
1981 need to consult dst() unless you're interested in displaying the DST
1982 info.
1983 """
1984 if self._tzinfo is None:
1985 return None
1986 offset = self._tzinfo.dst(self)
1987 _check_utc_offset("dst", offset)
1988 return offset
1989
1990 # Comparisons of datetime objects with other.
1991
1992 def __eq__(self, other):
1993 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001994 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001995 elif not isinstance(other, date):
1996 return NotImplemented
1997 else:
1998 return False
1999
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002000 def __le__(self, other):
2001 if isinstance(other, datetime):
2002 return self._cmp(other) <= 0
2003 elif not isinstance(other, date):
2004 return NotImplemented
2005 else:
2006 _cmperror(self, other)
2007
2008 def __lt__(self, other):
2009 if isinstance(other, datetime):
2010 return self._cmp(other) < 0
2011 elif not isinstance(other, date):
2012 return NotImplemented
2013 else:
2014 _cmperror(self, other)
2015
2016 def __ge__(self, other):
2017 if isinstance(other, datetime):
2018 return self._cmp(other) >= 0
2019 elif not isinstance(other, date):
2020 return NotImplemented
2021 else:
2022 _cmperror(self, other)
2023
2024 def __gt__(self, other):
2025 if isinstance(other, datetime):
2026 return self._cmp(other) > 0
2027 elif not isinstance(other, date):
2028 return NotImplemented
2029 else:
2030 _cmperror(self, other)
2031
Alexander Belopolsky08313822012-06-15 20:19:47 -04002032 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002033 assert isinstance(other, datetime)
2034 mytz = self._tzinfo
2035 ottz = other._tzinfo
2036 myoff = otoff = None
2037
2038 if mytz is ottz:
2039 base_compare = True
2040 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04002041 myoff = self.utcoffset()
2042 otoff = other.utcoffset()
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002043 # Assume that allow_mixed means that we are called from __eq__
2044 if allow_mixed:
2045 if myoff != self.replace(fold=not self.fold).utcoffset():
2046 return 2
2047 if otoff != other.replace(fold=not other.fold).utcoffset():
2048 return 2
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002049 base_compare = myoff == otoff
2050
2051 if base_compare:
2052 return _cmp((self._year, self._month, self._day,
2053 self._hour, self._minute, self._second,
2054 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002055 (other._year, other._month, other._day,
2056 other._hour, other._minute, other._second,
2057 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002058 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04002059 if allow_mixed:
2060 return 2 # arbitrary non-zero value
2061 else:
2062 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002063 # XXX What follows could be done more efficiently...
2064 diff = self - other # this will take offsets into account
2065 if diff.days < 0:
2066 return -1
2067 return diff and 1 or 0
2068
2069 def __add__(self, other):
2070 "Add a datetime and a timedelta."
2071 if not isinstance(other, timedelta):
2072 return NotImplemented
2073 delta = timedelta(self.toordinal(),
2074 hours=self._hour,
2075 minutes=self._minute,
2076 seconds=self._second,
2077 microseconds=self._microsecond)
2078 delta += other
2079 hour, rem = divmod(delta.seconds, 3600)
2080 minute, second = divmod(rem, 60)
2081 if 0 < delta.days <= _MAXORDINAL:
Paul Ganssle89427cd2019-02-04 14:42:04 -05002082 return type(self).combine(date.fromordinal(delta.days),
2083 time(hour, minute, second,
2084 delta.microseconds,
2085 tzinfo=self._tzinfo))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002086 raise OverflowError("result out of range")
2087
2088 __radd__ = __add__
2089
2090 def __sub__(self, other):
2091 "Subtract two datetimes, or a datetime and a timedelta."
2092 if not isinstance(other, datetime):
2093 if isinstance(other, timedelta):
2094 return self + -other
2095 return NotImplemented
2096
2097 days1 = self.toordinal()
2098 days2 = other.toordinal()
2099 secs1 = self._second + self._minute * 60 + self._hour * 3600
2100 secs2 = other._second + other._minute * 60 + other._hour * 3600
2101 base = timedelta(days1 - days2,
2102 secs1 - secs2,
2103 self._microsecond - other._microsecond)
2104 if self._tzinfo is other._tzinfo:
2105 return base
2106 myoff = self.utcoffset()
2107 otoff = other.utcoffset()
2108 if myoff == otoff:
2109 return base
2110 if myoff is None or otoff is None:
2111 raise TypeError("cannot mix naive and timezone-aware time")
2112 return base + otoff - myoff
2113
2114 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002115 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002116 if self.fold:
2117 t = self.replace(fold=0)
2118 else:
2119 t = self
2120 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002121 if tzoff is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002122 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002123 else:
2124 days = _ymd2ord(self.year, self.month, self.day)
2125 seconds = self.hour * 3600 + self.minute * 60 + self.second
2126 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
2127 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002128
2129 # Pickle support.
2130
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002131 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002132 yhi, ylo = divmod(self._year, 256)
2133 us2, us3 = divmod(self._microsecond, 256)
2134 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002135 m = self._month
2136 if self._fold and protocol > 3:
2137 m += 128
2138 basestate = bytes([yhi, ylo, m, self._day,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002139 self._hour, self._minute, self._second,
2140 us1, us2, us3])
2141 if self._tzinfo is None:
2142 return (basestate,)
2143 else:
2144 return (basestate, self._tzinfo)
2145
2146 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002147 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
2148 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002149 (yhi, ylo, m, self._day, self._hour,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002150 self._minute, self._second, us1, us2, us3) = string
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002151 if m > 127:
2152 self._fold = 1
2153 self._month = m - 128
2154 else:
2155 self._fold = 0
2156 self._month = m
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002157 self._year = yhi * 256 + ylo
2158 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002159 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002160
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002161 def __reduce_ex__(self, protocol):
2162 return (self.__class__, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002163
Serhiy Storchaka546ce652016-11-22 00:29:42 +02002164 def __reduce__(self):
2165 return self.__reduce_ex__(2)
2166
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002167
2168datetime.min = datetime(1, 1, 1)
2169datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
2170datetime.resolution = timedelta(microseconds=1)
2171
2172
2173def _isoweek1monday(year):
2174 # Helper to calculate the day number of the Monday starting week 1
2175 # XXX This could be done more efficiently
2176 THURSDAY = 3
2177 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002178 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002179 week1monday = firstday - firstweekday
2180 if firstweekday > THURSDAY:
2181 week1monday += 7
2182 return week1monday
2183
Paul Ganssle88c09372019-04-29 09:22:03 -04002184
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002185class timezone(tzinfo):
2186 __slots__ = '_offset', '_name'
2187
2188 # Sentinel value to disallow None
2189 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002190 def __new__(cls, offset, name=_Omitted):
2191 if not isinstance(offset, timedelta):
2192 raise TypeError("offset must be a timedelta")
2193 if name is cls._Omitted:
2194 if not offset:
2195 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002196 name = None
2197 elif not isinstance(name, str):
2198 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002199 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002200 raise ValueError("offset must be a timedelta "
2201 "strictly between -timedelta(hours=24) and "
2202 "timedelta(hours=24).")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002203 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002204
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002205 @classmethod
2206 def _create(cls, offset, name=None):
2207 self = tzinfo.__new__(cls)
2208 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002209 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002210 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002211
2212 def __getinitargs__(self):
2213 """pickle support"""
2214 if self._name is None:
2215 return (self._offset,)
2216 return (self._offset, self._name)
2217
2218 def __eq__(self, other):
Serhiy Storchaka17e52642019-08-04 12:38:46 +03002219 if isinstance(other, timezone):
2220 return self._offset == other._offset
2221 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002222
2223 def __hash__(self):
2224 return hash(self._offset)
2225
2226 def __repr__(self):
2227 """Convert to formal string, for repr().
2228
2229 >>> tz = timezone.utc
2230 >>> repr(tz)
2231 'datetime.timezone.utc'
2232 >>> tz = timezone(timedelta(hours=-5), 'EST')
2233 >>> repr(tz)
2234 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
2235 """
2236 if self is self.utc:
2237 return 'datetime.timezone.utc'
2238 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03002239 return "%s.%s(%r)" % (self.__class__.__module__,
2240 self.__class__.__qualname__,
2241 self._offset)
2242 return "%s.%s(%r, %r)" % (self.__class__.__module__,
2243 self.__class__.__qualname__,
2244 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002245
2246 def __str__(self):
2247 return self.tzname(None)
2248
2249 def utcoffset(self, dt):
2250 if isinstance(dt, datetime) or dt is None:
2251 return self._offset
2252 raise TypeError("utcoffset() argument must be a datetime instance"
2253 " or None")
2254
2255 def tzname(self, dt):
2256 if isinstance(dt, datetime) or dt is None:
2257 if self._name is None:
2258 return self._name_from_offset(self._offset)
2259 return self._name
2260 raise TypeError("tzname() argument must be a datetime instance"
2261 " or None")
2262
2263 def dst(self, dt):
2264 if isinstance(dt, datetime) or dt is None:
2265 return None
2266 raise TypeError("dst() argument must be a datetime instance"
2267 " or None")
2268
2269 def fromutc(self, dt):
2270 if isinstance(dt, datetime):
2271 if dt.tzinfo is not self:
2272 raise ValueError("fromutc: dt.tzinfo "
2273 "is not self")
2274 return dt + self._offset
2275 raise TypeError("fromutc() argument must be a datetime instance"
2276 " or None")
2277
Ngalim Siregar92c7e302019-08-09 21:22:16 +07002278 _maxoffset = timedelta(hours=24, microseconds=-1)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002279 _minoffset = -_maxoffset
2280
2281 @staticmethod
2282 def _name_from_offset(delta):
Alexander Belopolsky7827a5b2015-09-06 13:07:21 -04002283 if not delta:
2284 return 'UTC'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002285 if delta < timedelta(0):
2286 sign = '-'
2287 delta = -delta
2288 else:
2289 sign = '+'
2290 hours, rest = divmod(delta, timedelta(hours=1))
Alexander Belopolsky018d3532017-07-31 10:26:50 -04002291 minutes, rest = divmod(rest, timedelta(minutes=1))
2292 seconds = rest.seconds
2293 microseconds = rest.microseconds
2294 if microseconds:
2295 return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2296 f'.{microseconds:06d}')
2297 if seconds:
2298 return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2299 return f'UTC{sign}{hours:02d}:{minutes:02d}'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002300
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002301timezone.utc = timezone._create(timedelta(0))
Ngalim Siregar92c7e302019-08-09 21:22:16 +07002302# bpo-37642: These attributes are rounded to the nearest minute for backwards
2303# compatibility, even though the constructor will accept a wider range of
2304# values. This may change in the future.
2305timezone.min = timezone._create(-timedelta(hours=23, minutes=59))
2306timezone.max = timezone._create(timedelta(hours=23, minutes=59))
Alexander Belopolskya4415142012-06-08 12:33:09 -04002307_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002308
Victor Stinner765531d2013-03-26 01:11:54 +01002309# Some time zone algebra. For a datetime x, let
2310# x.n = x stripped of its timezone -- its naive time.
2311# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2312# return None
2313# x.d = x.dst(), and assuming that doesn't raise an exception or
2314# return None
2315# x.s = x's standard offset, x.o - x.d
2316#
2317# Now some derived rules, where k is a duration (timedelta).
2318#
2319# 1. x.o = x.s + x.d
2320# This follows from the definition of x.s.
2321#
2322# 2. If x and y have the same tzinfo member, x.s = y.s.
2323# This is actually a requirement, an assumption we need to make about
2324# sane tzinfo classes.
2325#
2326# 3. The naive UTC time corresponding to x is x.n - x.o.
2327# This is again a requirement for a sane tzinfo class.
2328#
2329# 4. (x+k).s = x.s
2330# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
2331#
2332# 5. (x+k).n = x.n + k
2333# Again follows from how arithmetic is defined.
2334#
2335# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
2336# (meaning that the various tzinfo methods exist, and don't blow up or return
2337# None when called).
2338#
2339# The function wants to return a datetime y with timezone tz, equivalent to x.
2340# x is already in UTC.
2341#
2342# By #3, we want
2343#
2344# y.n - y.o = x.n [1]
2345#
2346# The algorithm starts by attaching tz to x.n, and calling that y. So
2347# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
2348# becomes true; in effect, we want to solve [2] for k:
2349#
2350# (y+k).n - (y+k).o = x.n [2]
2351#
2352# By #1, this is the same as
2353#
2354# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
2355#
2356# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2357# Substituting that into [3],
2358#
2359# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2360# k - (y+k).s - (y+k).d = 0; rearranging,
2361# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2362# k = y.s - (y+k).d
2363#
2364# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2365# approximate k by ignoring the (y+k).d term at first. Note that k can't be
2366# very large, since all offset-returning methods return a duration of magnitude
2367# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
2368# be 0, so ignoring it has no consequence then.
2369#
2370# In any case, the new value is
2371#
2372# z = y + y.s [4]
2373#
2374# It's helpful to step back at look at [4] from a higher level: it's simply
2375# mapping from UTC to tz's standard time.
2376#
2377# At this point, if
2378#
2379# z.n - z.o = x.n [5]
2380#
2381# we have an equivalent time, and are almost done. The insecurity here is
2382# at the start of daylight time. Picture US Eastern for concreteness. The wall
2383# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2384# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2385# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2386# on the day DST starts. We want to return the 1:MM EST spelling because that's
2387# the only spelling that makes sense on the local wall clock.
2388#
2389# In fact, if [5] holds at this point, we do have the standard-time spelling,
2390# but that takes a bit of proof. We first prove a stronger result. What's the
2391# difference between the LHS and RHS of [5]? Let
2392#
2393# diff = x.n - (z.n - z.o) [6]
2394#
2395# Now
2396# z.n = by [4]
2397# (y + y.s).n = by #5
2398# y.n + y.s = since y.n = x.n
2399# x.n + y.s = since z and y are have the same tzinfo member,
2400# y.s = z.s by #2
2401# x.n + z.s
2402#
2403# Plugging that back into [6] gives
2404#
2405# diff =
2406# x.n - ((x.n + z.s) - z.o) = expanding
2407# x.n - x.n - z.s + z.o = cancelling
2408# - z.s + z.o = by #2
2409# z.d
2410#
2411# So diff = z.d.
2412#
2413# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2414# spelling we wanted in the endcase described above. We're done. Contrarily,
2415# if z.d = 0, then we have a UTC equivalent, and are also done.
2416#
2417# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2418# add to z (in effect, z is in tz's standard time, and we need to shift the
2419# local clock into tz's daylight time).
2420#
2421# Let
2422#
2423# z' = z + z.d = z + diff [7]
2424#
2425# and we can again ask whether
2426#
2427# z'.n - z'.o = x.n [8]
2428#
2429# If so, we're done. If not, the tzinfo class is insane, according to the
2430# assumptions we've made. This also requires a bit of proof. As before, let's
2431# compute the difference between the LHS and RHS of [8] (and skipping some of
2432# the justifications for the kinds of substitutions we've done several times
2433# already):
2434#
2435# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2436# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2437# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2438# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2439# - z.n + z.n - z.o + z'.o = cancel z.n
2440# - z.o + z'.o = #1 twice
2441# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2442# z'.d - z.d
2443#
2444# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2445# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2446# return z', not bothering to compute z'.d.
2447#
2448# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2449# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2450# would have to change the result dst() returns: we start in DST, and moving
2451# a little further into it takes us out of DST.
2452#
2453# There isn't a sane case where this can happen. The closest it gets is at
2454# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2455# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2456# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2457# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2458# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2459# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2460# standard time. Since that's what the local clock *does*, we want to map both
2461# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2462# in local time, but so it goes -- it's the way the local clock works.
2463#
2464# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2465# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2466# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2467# (correctly) concludes that z' is not UTC-equivalent to x.
2468#
2469# Because we know z.d said z was in daylight time (else [5] would have held and
2470# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2471# and we have stopped then), and there are only 2 possible values dst() can
2472# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2473# but the reasoning doesn't depend on the example -- it depends on there being
2474# two possible dst() outcomes, one zero and the other non-zero). Therefore
2475# z' must be in standard time, and is the spelling we want in this case.
2476#
2477# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2478# concerned (because it takes z' as being in standard time rather than the
2479# daylight time we intend here), but returning it gives the real-life "local
2480# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2481# tz.
2482#
2483# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2484# the 1:MM standard time spelling we want.
2485#
2486# So how can this break? One of the assumptions must be violated. Two
2487# possibilities:
2488#
2489# 1) [2] effectively says that y.s is invariant across all y belong to a given
2490# time zone. This isn't true if, for political reasons or continental drift,
2491# a region decides to change its base offset from UTC.
2492#
2493# 2) There may be versions of "double daylight" time where the tail end of
2494# the analysis gives up a step too early. I haven't thought about that
2495# enough to say.
2496#
2497# In any case, it's clear that the default fromutc() is strong enough to handle
2498# "almost all" time zones: so long as the standard offset is invariant, it
2499# doesn't matter if daylight time transition points change from year to year, or
2500# if daylight time is skipped in some years; it doesn't matter how large or
2501# small dst() may get within its bounds; and it doesn't even matter if some
2502# perverse time zone returns a negative dst()). So a breaking case must be
2503# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002504
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002505try:
2506 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002507except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002508 pass
2509else:
2510 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002511 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2512 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
Serhiy Storchaka578c3952020-05-26 18:43:38 +03002513 _check_date_fields, _check_time_fields,
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002514 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2515 _date_class, _days_before_month, _days_before_year, _days_in_month,
Serhiy Storchaka578c3952020-05-26 18:43:38 +03002516 _format_time, _format_offset, _index, _is_leap, _isoweek1monday, _math,
Paul Ganssle09dc2f52017-12-21 00:33:49 -05002517 _ord2ymd, _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord,
2518 _divide_and_round, _parse_isoformat_date, _parse_isoformat_time,
Paul Ganssle1b97b9b2020-05-16 10:02:59 -04002519 _parse_hh_mm_ss_ff, _IsoCalendarDate)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002520 # XXX Since import * above excludes names that start with _,
2521 # docstring does not get overwritten. In the future, it may be
2522 # appropriate to maintain a single module level docstring and
2523 # remove the following line.
2524 from _datetime import __doc__