blob: 3090978508c92112faacad2b04b39fc77defed8f [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
1424 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001425 """
1426 s = _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001427 self._microsecond, timespec)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001428 tz = self._tzstr()
1429 if tz:
1430 s += tz
1431 return s
1432
1433 __str__ = isoformat
1434
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001435 @classmethod
1436 def fromisoformat(cls, time_string):
1437 """Construct a time from the output of isoformat()."""
1438 if not isinstance(time_string, str):
1439 raise TypeError('fromisoformat: argument must be str')
1440
1441 try:
1442 return cls(*_parse_isoformat_time(time_string))
1443 except Exception:
Paul Ganssle3df85402018-10-22 12:32:52 -04001444 raise ValueError(f'Invalid isoformat string: {time_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001445
1446
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001447 def strftime(self, fmt):
1448 """Format using strftime(). The date part of the timestamp passed
1449 to underlying strftime should not be used.
1450 """
Alexander Belopolskyb8bb4662011-01-08 00:13:34 +00001451 # The year must be >= 1000 else Python's strftime implementation
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001452 # can raise a bogus exception.
1453 timetuple = (1900, 1, 1,
1454 self._hour, self._minute, self._second,
1455 0, 1, -1)
1456 return _wrap_strftime(self, fmt, timetuple)
1457
1458 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001459 if not isinstance(fmt, str):
1460 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001461 if len(fmt) != 0:
1462 return self.strftime(fmt)
1463 return str(self)
1464
1465 # Timezone functions
1466
1467 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001468 """Return the timezone offset as timedelta, positive east of UTC
1469 (negative west of UTC)."""
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001470 if self._tzinfo is None:
1471 return None
1472 offset = self._tzinfo.utcoffset(None)
1473 _check_utc_offset("utcoffset", offset)
1474 return offset
1475
1476 def tzname(self):
1477 """Return the timezone name.
1478
1479 Note that the name is 100% informational -- there's no requirement that
1480 it mean anything in particular. For example, "GMT", "UTC", "-500",
1481 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1482 """
1483 if self._tzinfo is None:
1484 return None
1485 name = self._tzinfo.tzname(None)
1486 _check_tzname(name)
1487 return name
1488
1489 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001490 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1491 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001492
1493 This is purely informational; the DST offset has already been added to
1494 the UTC offset returned by utcoffset() if applicable, so there's no
1495 need to consult dst() unless you're interested in displaying the DST
1496 info.
1497 """
1498 if self._tzinfo is None:
1499 return None
1500 offset = self._tzinfo.dst(None)
1501 _check_utc_offset("dst", offset)
1502 return offset
1503
1504 def replace(self, hour=None, minute=None, second=None, microsecond=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001505 tzinfo=True, *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001506 """Return a new time with new values for the specified fields."""
1507 if hour is None:
1508 hour = self.hour
1509 if minute is None:
1510 minute = self.minute
1511 if second is None:
1512 second = self.second
1513 if microsecond is None:
1514 microsecond = self.microsecond
1515 if tzinfo is True:
1516 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001517 if fold is None:
1518 fold = self._fold
Paul Ganssle191e9932017-11-09 16:34:29 -05001519 return type(self)(hour, minute, second, microsecond, tzinfo, fold=fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001520
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001521 # Pickle support.
1522
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001523 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001524 us2, us3 = divmod(self._microsecond, 256)
1525 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001526 h = self._hour
1527 if self._fold and protocol > 3:
1528 h += 128
1529 basestate = bytes([h, self._minute, self._second,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001530 us1, us2, us3])
1531 if self._tzinfo is None:
1532 return (basestate,)
1533 else:
1534 return (basestate, self._tzinfo)
1535
1536 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001537 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1538 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001539 h, self._minute, self._second, us1, us2, us3 = string
1540 if h > 127:
1541 self._fold = 1
1542 self._hour = h - 128
1543 else:
1544 self._fold = 0
1545 self._hour = h
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001546 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001547 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001548
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001549 def __reduce_ex__(self, protocol):
1550 return (time, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001551
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001552 def __reduce__(self):
1553 return self.__reduce_ex__(2)
1554
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001555_time_class = time # so functions w/ args named "time" can get at the class
1556
1557time.min = time(0, 0, 0)
1558time.max = time(23, 59, 59, 999999)
1559time.resolution = timedelta(microseconds=1)
1560
Paul Ganssle1b97b9b2020-05-16 10:02:59 -04001561
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001562class datetime(date):
1563 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1564
1565 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001566 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001567 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001568 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001569
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001570 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001571 microsecond=0, tzinfo=None, *, fold=0):
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001572 if (isinstance(year, (bytes, str)) and len(year) == 10 and
1573 1 <= ord(year[2:3])&0x7F <= 12):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001574 # Pickle support
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001575 if isinstance(year, str):
1576 try:
1577 year = bytes(year, 'latin1')
1578 except UnicodeEncodeError:
1579 # More informative error message.
1580 raise ValueError(
1581 "Failed to encode latin1 string when unpickling "
1582 "a datetime object. "
1583 "pickle.load(data, encoding='latin1') is assumed.")
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001584 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001585 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001586 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001587 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001588 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001589 hour, minute, second, microsecond, fold = _check_time_fields(
1590 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001591 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001592 self = object.__new__(cls)
1593 self._year = year
1594 self._month = month
1595 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001596 self._hour = hour
1597 self._minute = minute
1598 self._second = second
1599 self._microsecond = microsecond
1600 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001601 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001602 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001603 return self
1604
1605 # Read-only field accessors
1606 @property
1607 def hour(self):
1608 """hour (0-23)"""
1609 return self._hour
1610
1611 @property
1612 def minute(self):
1613 """minute (0-59)"""
1614 return self._minute
1615
1616 @property
1617 def second(self):
1618 """second (0-59)"""
1619 return self._second
1620
1621 @property
1622 def microsecond(self):
1623 """microsecond (0-999999)"""
1624 return self._microsecond
1625
1626 @property
1627 def tzinfo(self):
1628 """timezone info object"""
1629 return self._tzinfo
1630
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001631 @property
1632 def fold(self):
1633 return self._fold
1634
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001635 @classmethod
Victor Stinneradfefa52015-09-04 23:57:25 +02001636 def _fromtimestamp(cls, t, utc, tz):
1637 """Construct a datetime from a POSIX timestamp (like time.time()).
1638
1639 A timezone info object may be passed in as well.
1640 """
1641 frac, t = _math.modf(t)
Victor Stinner7667f582015-09-09 01:02:23 +02001642 us = round(frac * 1e6)
Victor Stinneradfefa52015-09-04 23:57:25 +02001643 if us >= 1000000:
1644 t += 1
1645 us -= 1000000
1646 elif us < 0:
1647 t -= 1
1648 us += 1000000
1649
1650 converter = _time.gmtime if utc else _time.localtime
1651 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1652 ss = min(ss, 59) # clamp out leap seconds if the platform has them
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001653 result = cls(y, m, d, hh, mm, ss, us, tz)
1654 if tz is None:
1655 # As of version 2015f max fold in IANA database is
1656 # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
1657 # Let's probe 24 hours in the past to detect a transition:
1658 max_fold_seconds = 24 * 3600
Ammar Askar96d1e692018-07-25 09:54:58 -07001659
1660 # On Windows localtime_s throws an OSError for negative values,
1661 # thus we can't perform fold detection for values of time less
1662 # than the max time fold. See comments in _datetimemodule's
1663 # version of this method for more details.
1664 if t < max_fold_seconds and sys.platform.startswith("win"):
1665 return result
1666
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001667 y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1668 probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1669 trans = result - probe1 - timedelta(0, max_fold_seconds)
1670 if trans.days < 0:
1671 y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
1672 probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1673 if probe2 == result:
1674 result._fold = 1
1675 else:
1676 result = tz.fromutc(result)
1677 return result
Victor Stinneradfefa52015-09-04 23:57:25 +02001678
1679 @classmethod
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001680 def fromtimestamp(cls, t, tz=None):
1681 """Construct a datetime from a POSIX timestamp (like time.time()).
1682
1683 A timezone info object may be passed in as well.
1684 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001685 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001686
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001687 return cls._fromtimestamp(t, tz is not None, tz)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001688
1689 @classmethod
1690 def utcfromtimestamp(cls, t):
Alexander Belopolskye2e178e2015-03-01 14:52:07 -05001691 """Construct a naive UTC datetime from a POSIX timestamp."""
Victor Stinneradfefa52015-09-04 23:57:25 +02001692 return cls._fromtimestamp(t, True, None)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001693
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001694 @classmethod
1695 def now(cls, tz=None):
1696 "Construct a datetime from time.time() and optional time zone info."
1697 t = _time.time()
1698 return cls.fromtimestamp(t, tz)
1699
1700 @classmethod
1701 def utcnow(cls):
1702 "Construct a UTC datetime from time.time()."
1703 t = _time.time()
1704 return cls.utcfromtimestamp(t)
1705
1706 @classmethod
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001707 def combine(cls, date, time, tzinfo=True):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001708 "Construct a datetime from a given date and a given time."
1709 if not isinstance(date, _date_class):
1710 raise TypeError("date argument must be a date instance")
1711 if not isinstance(time, _time_class):
1712 raise TypeError("time argument must be a time instance")
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001713 if tzinfo is True:
1714 tzinfo = time.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001715 return cls(date.year, date.month, date.day,
1716 time.hour, time.minute, time.second, time.microsecond,
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001717 tzinfo, fold=time.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001718
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001719 @classmethod
1720 def fromisoformat(cls, date_string):
1721 """Construct a datetime from the output of datetime.isoformat()."""
1722 if not isinstance(date_string, str):
1723 raise TypeError('fromisoformat: argument must be str')
1724
1725 # Split this at the separator
1726 dstr = date_string[0:10]
1727 tstr = date_string[11:]
1728
1729 try:
1730 date_components = _parse_isoformat_date(dstr)
1731 except ValueError:
Paul Ganssle3df85402018-10-22 12:32:52 -04001732 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001733
1734 if tstr:
1735 try:
1736 time_components = _parse_isoformat_time(tstr)
1737 except ValueError:
Paul Ganssle3df85402018-10-22 12:32:52 -04001738 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001739 else:
1740 time_components = [0, 0, 0, 0, None]
1741
1742 return cls(*(date_components + time_components))
1743
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001744 def timetuple(self):
1745 "Return local time tuple compatible with time.localtime()."
1746 dst = self.dst()
1747 if dst is None:
1748 dst = -1
1749 elif dst:
1750 dst = 1
1751 else:
1752 dst = 0
1753 return _build_struct_time(self.year, self.month, self.day,
1754 self.hour, self.minute, self.second,
1755 dst)
1756
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001757 def _mktime(self):
1758 """Return integer POSIX timestamp."""
1759 epoch = datetime(1970, 1, 1)
1760 max_fold_seconds = 24 * 3600
1761 t = (self - epoch) // timedelta(0, 1)
1762 def local(u):
1763 y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1764 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1765
1766 # Our goal is to solve t = local(u) for u.
1767 a = local(t) - t
1768 u1 = t - a
1769 t1 = local(u1)
1770 if t1 == t:
1771 # We found one solution, but it may not be the one we need.
1772 # Look for an earlier solution (if `fold` is 0), or a
1773 # later one (if `fold` is 1).
1774 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1775 b = local(u2) - u2
1776 if a == b:
1777 return u1
1778 else:
1779 b = t1 - u1
1780 assert a != b
1781 u2 = t - b
1782 t2 = local(u2)
1783 if t2 == t:
1784 return u2
1785 if t1 == t:
1786 return u1
1787 # We have found both offsets a and b, but neither t - a nor t - b is
1788 # a solution. This means t is in the gap.
1789 return (max, min)[self.fold](u1, u2)
1790
1791
Alexander Belopolskya4415142012-06-08 12:33:09 -04001792 def timestamp(self):
1793 "Return POSIX timestamp as float"
1794 if self._tzinfo is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001795 s = self._mktime()
1796 return s + self.microsecond / 1e6
Alexander Belopolskya4415142012-06-08 12:33:09 -04001797 else:
1798 return (self - _EPOCH).total_seconds()
1799
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001800 def utctimetuple(self):
1801 "Return UTC time tuple compatible with time.gmtime()."
1802 offset = self.utcoffset()
1803 if offset:
1804 self -= offset
1805 y, m, d = self.year, self.month, self.day
1806 hh, mm, ss = self.hour, self.minute, self.second
1807 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1808
1809 def date(self):
1810 "Return the date part."
1811 return date(self._year, self._month, self._day)
1812
1813 def time(self):
1814 "Return the time part, with tzinfo None."
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001815 return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001816
1817 def timetz(self):
1818 "Return the time part, with same tzinfo."
1819 return time(self.hour, self.minute, self.second, self.microsecond,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001820 self._tzinfo, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001821
1822 def replace(self, year=None, month=None, day=None, hour=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001823 minute=None, second=None, microsecond=None, tzinfo=True,
1824 *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001825 """Return a new datetime with new values for the specified fields."""
1826 if year is None:
1827 year = self.year
1828 if month is None:
1829 month = self.month
1830 if day is None:
1831 day = self.day
1832 if hour is None:
1833 hour = self.hour
1834 if minute is None:
1835 minute = self.minute
1836 if second is None:
1837 second = self.second
1838 if microsecond is None:
1839 microsecond = self.microsecond
1840 if tzinfo is True:
1841 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001842 if fold is None:
1843 fold = self.fold
Paul Ganssle191e9932017-11-09 16:34:29 -05001844 return type(self)(year, month, day, hour, minute, second,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001845 microsecond, tzinfo, fold=fold)
1846
1847 def _local_timezone(self):
1848 if self.tzinfo is None:
1849 ts = self._mktime()
1850 else:
1851 ts = (self - _EPOCH) // timedelta(seconds=1)
1852 localtm = _time.localtime(ts)
1853 local = datetime(*localtm[:6])
Alexander Belopolskybcb032e2018-06-08 19:22:33 -04001854 # Extract TZ data
1855 gmtoff = localtm.tm_gmtoff
1856 zone = localtm.tm_zone
1857 return timezone(timedelta(seconds=gmtoff), zone)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001858
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001859 def astimezone(self, tz=None):
1860 if tz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001861 tz = self._local_timezone()
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001862 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001863 raise TypeError("tz argument must be an instance of tzinfo")
1864
1865 mytz = self.tzinfo
1866 if mytz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001867 mytz = self._local_timezone()
Alexander Belopolsky877b2322018-06-10 17:02:58 -04001868 myoffset = mytz.utcoffset(self)
1869 else:
1870 myoffset = mytz.utcoffset(self)
1871 if myoffset is None:
1872 mytz = self.replace(tzinfo=None)._local_timezone()
1873 myoffset = mytz.utcoffset(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001874
1875 if tz is mytz:
1876 return self
1877
1878 # Convert self to UTC, and attach the new time zone object.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001879 utc = (self - myoffset).replace(tzinfo=tz)
1880
1881 # Convert from UTC to tz's local time.
1882 return tz.fromutc(utc)
1883
1884 # Ways to produce a string.
1885
1886 def ctime(self):
1887 "Return ctime() style string."
1888 weekday = self.toordinal() % 7 or 7
1889 return "%s %s %2d %02d:%02d:%02d %04d" % (
1890 _DAYNAMES[weekday],
1891 _MONTHNAMES[self._month],
1892 self._day,
1893 self._hour, self._minute, self._second,
1894 self._year)
1895
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001896 def isoformat(self, sep='T', timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001897 """Return the time formatted according to ISO.
1898
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001899 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1900 By default, the fractional part is omitted if self.microsecond == 0.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001901
1902 If self.tzinfo is not None, the UTC offset is also attached, giving
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001903 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001904
1905 Optional argument sep specifies the separator between date and
1906 time, default 'T'.
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001907
1908 The optional argument timespec specifies the number of additional
1909 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001910 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001911 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1912 _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001913 self._microsecond, timespec))
1914
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001915 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001916 tz = _format_offset(off)
1917 if tz:
1918 s += tz
1919
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001920 return s
1921
1922 def __repr__(self):
1923 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001924 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001925 self._hour, self._minute, self._second, self._microsecond]
1926 if L[-1] == 0:
1927 del L[-1]
1928 if L[-1] == 0:
1929 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001930 s = "%s.%s(%s)" % (self.__class__.__module__,
1931 self.__class__.__qualname__,
1932 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001933 if self._tzinfo is not None:
1934 assert s[-1:] == ")"
1935 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001936 if self._fold:
1937 assert s[-1:] == ")"
1938 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001939 return s
1940
1941 def __str__(self):
1942 "Convert to string, for str()."
1943 return self.isoformat(sep=' ')
1944
1945 @classmethod
1946 def strptime(cls, date_string, format):
1947 'string, format -> new datetime parsed from a string (like time.strptime()).'
1948 import _strptime
1949 return _strptime._strptime_datetime(cls, date_string, format)
1950
1951 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001952 """Return the timezone offset as timedelta positive east of UTC (negative west of
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001953 UTC)."""
1954 if self._tzinfo is None:
1955 return None
1956 offset = self._tzinfo.utcoffset(self)
1957 _check_utc_offset("utcoffset", offset)
1958 return offset
1959
1960 def tzname(self):
1961 """Return the timezone name.
1962
1963 Note that the name is 100% informational -- there's no requirement that
1964 it mean anything in particular. For example, "GMT", "UTC", "-500",
1965 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1966 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001967 if self._tzinfo is None:
1968 return None
1969 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001970 _check_tzname(name)
1971 return name
1972
1973 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001974 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1975 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001976
1977 This is purely informational; the DST offset has already been added to
1978 the UTC offset returned by utcoffset() if applicable, so there's no
1979 need to consult dst() unless you're interested in displaying the DST
1980 info.
1981 """
1982 if self._tzinfo is None:
1983 return None
1984 offset = self._tzinfo.dst(self)
1985 _check_utc_offset("dst", offset)
1986 return offset
1987
1988 # Comparisons of datetime objects with other.
1989
1990 def __eq__(self, other):
1991 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001992 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001993 elif not isinstance(other, date):
1994 return NotImplemented
1995 else:
1996 return False
1997
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001998 def __le__(self, other):
1999 if isinstance(other, datetime):
2000 return self._cmp(other) <= 0
2001 elif not isinstance(other, date):
2002 return NotImplemented
2003 else:
2004 _cmperror(self, other)
2005
2006 def __lt__(self, other):
2007 if isinstance(other, datetime):
2008 return self._cmp(other) < 0
2009 elif not isinstance(other, date):
2010 return NotImplemented
2011 else:
2012 _cmperror(self, other)
2013
2014 def __ge__(self, other):
2015 if isinstance(other, datetime):
2016 return self._cmp(other) >= 0
2017 elif not isinstance(other, date):
2018 return NotImplemented
2019 else:
2020 _cmperror(self, other)
2021
2022 def __gt__(self, other):
2023 if isinstance(other, datetime):
2024 return self._cmp(other) > 0
2025 elif not isinstance(other, date):
2026 return NotImplemented
2027 else:
2028 _cmperror(self, other)
2029
Alexander Belopolsky08313822012-06-15 20:19:47 -04002030 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002031 assert isinstance(other, datetime)
2032 mytz = self._tzinfo
2033 ottz = other._tzinfo
2034 myoff = otoff = None
2035
2036 if mytz is ottz:
2037 base_compare = True
2038 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04002039 myoff = self.utcoffset()
2040 otoff = other.utcoffset()
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002041 # Assume that allow_mixed means that we are called from __eq__
2042 if allow_mixed:
2043 if myoff != self.replace(fold=not self.fold).utcoffset():
2044 return 2
2045 if otoff != other.replace(fold=not other.fold).utcoffset():
2046 return 2
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002047 base_compare = myoff == otoff
2048
2049 if base_compare:
2050 return _cmp((self._year, self._month, self._day,
2051 self._hour, self._minute, self._second,
2052 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002053 (other._year, other._month, other._day,
2054 other._hour, other._minute, other._second,
2055 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002056 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04002057 if allow_mixed:
2058 return 2 # arbitrary non-zero value
2059 else:
2060 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002061 # XXX What follows could be done more efficiently...
2062 diff = self - other # this will take offsets into account
2063 if diff.days < 0:
2064 return -1
2065 return diff and 1 or 0
2066
2067 def __add__(self, other):
2068 "Add a datetime and a timedelta."
2069 if not isinstance(other, timedelta):
2070 return NotImplemented
2071 delta = timedelta(self.toordinal(),
2072 hours=self._hour,
2073 minutes=self._minute,
2074 seconds=self._second,
2075 microseconds=self._microsecond)
2076 delta += other
2077 hour, rem = divmod(delta.seconds, 3600)
2078 minute, second = divmod(rem, 60)
2079 if 0 < delta.days <= _MAXORDINAL:
Paul Ganssle89427cd2019-02-04 14:42:04 -05002080 return type(self).combine(date.fromordinal(delta.days),
2081 time(hour, minute, second,
2082 delta.microseconds,
2083 tzinfo=self._tzinfo))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002084 raise OverflowError("result out of range")
2085
2086 __radd__ = __add__
2087
2088 def __sub__(self, other):
2089 "Subtract two datetimes, or a datetime and a timedelta."
2090 if not isinstance(other, datetime):
2091 if isinstance(other, timedelta):
2092 return self + -other
2093 return NotImplemented
2094
2095 days1 = self.toordinal()
2096 days2 = other.toordinal()
2097 secs1 = self._second + self._minute * 60 + self._hour * 3600
2098 secs2 = other._second + other._minute * 60 + other._hour * 3600
2099 base = timedelta(days1 - days2,
2100 secs1 - secs2,
2101 self._microsecond - other._microsecond)
2102 if self._tzinfo is other._tzinfo:
2103 return base
2104 myoff = self.utcoffset()
2105 otoff = other.utcoffset()
2106 if myoff == otoff:
2107 return base
2108 if myoff is None or otoff is None:
2109 raise TypeError("cannot mix naive and timezone-aware time")
2110 return base + otoff - myoff
2111
2112 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002113 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002114 if self.fold:
2115 t = self.replace(fold=0)
2116 else:
2117 t = self
2118 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002119 if tzoff is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002120 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002121 else:
2122 days = _ymd2ord(self.year, self.month, self.day)
2123 seconds = self.hour * 3600 + self.minute * 60 + self.second
2124 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
2125 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002126
2127 # Pickle support.
2128
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002129 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002130 yhi, ylo = divmod(self._year, 256)
2131 us2, us3 = divmod(self._microsecond, 256)
2132 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002133 m = self._month
2134 if self._fold and protocol > 3:
2135 m += 128
2136 basestate = bytes([yhi, ylo, m, self._day,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002137 self._hour, self._minute, self._second,
2138 us1, us2, us3])
2139 if self._tzinfo is None:
2140 return (basestate,)
2141 else:
2142 return (basestate, self._tzinfo)
2143
2144 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002145 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
2146 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002147 (yhi, ylo, m, self._day, self._hour,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002148 self._minute, self._second, us1, us2, us3) = string
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002149 if m > 127:
2150 self._fold = 1
2151 self._month = m - 128
2152 else:
2153 self._fold = 0
2154 self._month = m
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002155 self._year = yhi * 256 + ylo
2156 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002157 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002158
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002159 def __reduce_ex__(self, protocol):
2160 return (self.__class__, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002161
Serhiy Storchaka546ce652016-11-22 00:29:42 +02002162 def __reduce__(self):
2163 return self.__reduce_ex__(2)
2164
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002165
2166datetime.min = datetime(1, 1, 1)
2167datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
2168datetime.resolution = timedelta(microseconds=1)
2169
2170
2171def _isoweek1monday(year):
2172 # Helper to calculate the day number of the Monday starting week 1
2173 # XXX This could be done more efficiently
2174 THURSDAY = 3
2175 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002176 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002177 week1monday = firstday - firstweekday
2178 if firstweekday > THURSDAY:
2179 week1monday += 7
2180 return week1monday
2181
Paul Ganssle88c09372019-04-29 09:22:03 -04002182
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002183class timezone(tzinfo):
2184 __slots__ = '_offset', '_name'
2185
2186 # Sentinel value to disallow None
2187 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002188 def __new__(cls, offset, name=_Omitted):
2189 if not isinstance(offset, timedelta):
2190 raise TypeError("offset must be a timedelta")
2191 if name is cls._Omitted:
2192 if not offset:
2193 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002194 name = None
2195 elif not isinstance(name, str):
2196 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002197 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002198 raise ValueError("offset must be a timedelta "
2199 "strictly between -timedelta(hours=24) and "
2200 "timedelta(hours=24).")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002201 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002202
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002203 @classmethod
2204 def _create(cls, offset, name=None):
2205 self = tzinfo.__new__(cls)
2206 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002207 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002208 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002209
2210 def __getinitargs__(self):
2211 """pickle support"""
2212 if self._name is None:
2213 return (self._offset,)
2214 return (self._offset, self._name)
2215
2216 def __eq__(self, other):
Serhiy Storchaka17e52642019-08-04 12:38:46 +03002217 if isinstance(other, timezone):
2218 return self._offset == other._offset
2219 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002220
2221 def __hash__(self):
2222 return hash(self._offset)
2223
2224 def __repr__(self):
2225 """Convert to formal string, for repr().
2226
2227 >>> tz = timezone.utc
2228 >>> repr(tz)
2229 'datetime.timezone.utc'
2230 >>> tz = timezone(timedelta(hours=-5), 'EST')
2231 >>> repr(tz)
2232 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
2233 """
2234 if self is self.utc:
2235 return 'datetime.timezone.utc'
2236 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03002237 return "%s.%s(%r)" % (self.__class__.__module__,
2238 self.__class__.__qualname__,
2239 self._offset)
2240 return "%s.%s(%r, %r)" % (self.__class__.__module__,
2241 self.__class__.__qualname__,
2242 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002243
2244 def __str__(self):
2245 return self.tzname(None)
2246
2247 def utcoffset(self, dt):
2248 if isinstance(dt, datetime) or dt is None:
2249 return self._offset
2250 raise TypeError("utcoffset() argument must be a datetime instance"
2251 " or None")
2252
2253 def tzname(self, dt):
2254 if isinstance(dt, datetime) or dt is None:
2255 if self._name is None:
2256 return self._name_from_offset(self._offset)
2257 return self._name
2258 raise TypeError("tzname() argument must be a datetime instance"
2259 " or None")
2260
2261 def dst(self, dt):
2262 if isinstance(dt, datetime) or dt is None:
2263 return None
2264 raise TypeError("dst() argument must be a datetime instance"
2265 " or None")
2266
2267 def fromutc(self, dt):
2268 if isinstance(dt, datetime):
2269 if dt.tzinfo is not self:
2270 raise ValueError("fromutc: dt.tzinfo "
2271 "is not self")
2272 return dt + self._offset
2273 raise TypeError("fromutc() argument must be a datetime instance"
2274 " or None")
2275
Ngalim Siregar92c7e302019-08-09 21:22:16 +07002276 _maxoffset = timedelta(hours=24, microseconds=-1)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002277 _minoffset = -_maxoffset
2278
2279 @staticmethod
2280 def _name_from_offset(delta):
Alexander Belopolsky7827a5b2015-09-06 13:07:21 -04002281 if not delta:
2282 return 'UTC'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002283 if delta < timedelta(0):
2284 sign = '-'
2285 delta = -delta
2286 else:
2287 sign = '+'
2288 hours, rest = divmod(delta, timedelta(hours=1))
Alexander Belopolsky018d3532017-07-31 10:26:50 -04002289 minutes, rest = divmod(rest, timedelta(minutes=1))
2290 seconds = rest.seconds
2291 microseconds = rest.microseconds
2292 if microseconds:
2293 return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2294 f'.{microseconds:06d}')
2295 if seconds:
2296 return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2297 return f'UTC{sign}{hours:02d}:{minutes:02d}'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002298
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002299timezone.utc = timezone._create(timedelta(0))
Ngalim Siregar92c7e302019-08-09 21:22:16 +07002300# bpo-37642: These attributes are rounded to the nearest minute for backwards
2301# compatibility, even though the constructor will accept a wider range of
2302# values. This may change in the future.
2303timezone.min = timezone._create(-timedelta(hours=23, minutes=59))
2304timezone.max = timezone._create(timedelta(hours=23, minutes=59))
Alexander Belopolskya4415142012-06-08 12:33:09 -04002305_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002306
Victor Stinner765531d2013-03-26 01:11:54 +01002307# Some time zone algebra. For a datetime x, let
2308# x.n = x stripped of its timezone -- its naive time.
2309# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2310# return None
2311# x.d = x.dst(), and assuming that doesn't raise an exception or
2312# return None
2313# x.s = x's standard offset, x.o - x.d
2314#
2315# Now some derived rules, where k is a duration (timedelta).
2316#
2317# 1. x.o = x.s + x.d
2318# This follows from the definition of x.s.
2319#
2320# 2. If x and y have the same tzinfo member, x.s = y.s.
2321# This is actually a requirement, an assumption we need to make about
2322# sane tzinfo classes.
2323#
2324# 3. The naive UTC time corresponding to x is x.n - x.o.
2325# This is again a requirement for a sane tzinfo class.
2326#
2327# 4. (x+k).s = x.s
2328# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
2329#
2330# 5. (x+k).n = x.n + k
2331# Again follows from how arithmetic is defined.
2332#
2333# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
2334# (meaning that the various tzinfo methods exist, and don't blow up or return
2335# None when called).
2336#
2337# The function wants to return a datetime y with timezone tz, equivalent to x.
2338# x is already in UTC.
2339#
2340# By #3, we want
2341#
2342# y.n - y.o = x.n [1]
2343#
2344# The algorithm starts by attaching tz to x.n, and calling that y. So
2345# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
2346# becomes true; in effect, we want to solve [2] for k:
2347#
2348# (y+k).n - (y+k).o = x.n [2]
2349#
2350# By #1, this is the same as
2351#
2352# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
2353#
2354# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2355# Substituting that into [3],
2356#
2357# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2358# k - (y+k).s - (y+k).d = 0; rearranging,
2359# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2360# k = y.s - (y+k).d
2361#
2362# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2363# approximate k by ignoring the (y+k).d term at first. Note that k can't be
2364# very large, since all offset-returning methods return a duration of magnitude
2365# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
2366# be 0, so ignoring it has no consequence then.
2367#
2368# In any case, the new value is
2369#
2370# z = y + y.s [4]
2371#
2372# It's helpful to step back at look at [4] from a higher level: it's simply
2373# mapping from UTC to tz's standard time.
2374#
2375# At this point, if
2376#
2377# z.n - z.o = x.n [5]
2378#
2379# we have an equivalent time, and are almost done. The insecurity here is
2380# at the start of daylight time. Picture US Eastern for concreteness. The wall
2381# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2382# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2383# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2384# on the day DST starts. We want to return the 1:MM EST spelling because that's
2385# the only spelling that makes sense on the local wall clock.
2386#
2387# In fact, if [5] holds at this point, we do have the standard-time spelling,
2388# but that takes a bit of proof. We first prove a stronger result. What's the
2389# difference between the LHS and RHS of [5]? Let
2390#
2391# diff = x.n - (z.n - z.o) [6]
2392#
2393# Now
2394# z.n = by [4]
2395# (y + y.s).n = by #5
2396# y.n + y.s = since y.n = x.n
2397# x.n + y.s = since z and y are have the same tzinfo member,
2398# y.s = z.s by #2
2399# x.n + z.s
2400#
2401# Plugging that back into [6] gives
2402#
2403# diff =
2404# x.n - ((x.n + z.s) - z.o) = expanding
2405# x.n - x.n - z.s + z.o = cancelling
2406# - z.s + z.o = by #2
2407# z.d
2408#
2409# So diff = z.d.
2410#
2411# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2412# spelling we wanted in the endcase described above. We're done. Contrarily,
2413# if z.d = 0, then we have a UTC equivalent, and are also done.
2414#
2415# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2416# add to z (in effect, z is in tz's standard time, and we need to shift the
2417# local clock into tz's daylight time).
2418#
2419# Let
2420#
2421# z' = z + z.d = z + diff [7]
2422#
2423# and we can again ask whether
2424#
2425# z'.n - z'.o = x.n [8]
2426#
2427# If so, we're done. If not, the tzinfo class is insane, according to the
2428# assumptions we've made. This also requires a bit of proof. As before, let's
2429# compute the difference between the LHS and RHS of [8] (and skipping some of
2430# the justifications for the kinds of substitutions we've done several times
2431# already):
2432#
2433# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2434# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2435# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2436# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2437# - z.n + z.n - z.o + z'.o = cancel z.n
2438# - z.o + z'.o = #1 twice
2439# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2440# z'.d - z.d
2441#
2442# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2443# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2444# return z', not bothering to compute z'.d.
2445#
2446# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2447# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2448# would have to change the result dst() returns: we start in DST, and moving
2449# a little further into it takes us out of DST.
2450#
2451# There isn't a sane case where this can happen. The closest it gets is at
2452# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2453# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2454# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2455# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2456# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2457# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2458# standard time. Since that's what the local clock *does*, we want to map both
2459# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2460# in local time, but so it goes -- it's the way the local clock works.
2461#
2462# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2463# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2464# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2465# (correctly) concludes that z' is not UTC-equivalent to x.
2466#
2467# Because we know z.d said z was in daylight time (else [5] would have held and
2468# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2469# and we have stopped then), and there are only 2 possible values dst() can
2470# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2471# but the reasoning doesn't depend on the example -- it depends on there being
2472# two possible dst() outcomes, one zero and the other non-zero). Therefore
2473# z' must be in standard time, and is the spelling we want in this case.
2474#
2475# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2476# concerned (because it takes z' as being in standard time rather than the
2477# daylight time we intend here), but returning it gives the real-life "local
2478# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2479# tz.
2480#
2481# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2482# the 1:MM standard time spelling we want.
2483#
2484# So how can this break? One of the assumptions must be violated. Two
2485# possibilities:
2486#
2487# 1) [2] effectively says that y.s is invariant across all y belong to a given
2488# time zone. This isn't true if, for political reasons or continental drift,
2489# a region decides to change its base offset from UTC.
2490#
2491# 2) There may be versions of "double daylight" time where the tail end of
2492# the analysis gives up a step too early. I haven't thought about that
2493# enough to say.
2494#
2495# In any case, it's clear that the default fromutc() is strong enough to handle
2496# "almost all" time zones: so long as the standard offset is invariant, it
2497# doesn't matter if daylight time transition points change from year to year, or
2498# if daylight time is skipped in some years; it doesn't matter how large or
2499# small dst() may get within its bounds; and it doesn't even matter if some
2500# perverse time zone returns a negative dst()). So a breaking case must be
2501# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002502
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002503try:
2504 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002505except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002506 pass
2507else:
2508 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002509 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2510 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
Serhiy Storchaka578c3952020-05-26 18:43:38 +03002511 _check_date_fields, _check_time_fields,
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002512 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2513 _date_class, _days_before_month, _days_before_year, _days_in_month,
Serhiy Storchaka578c3952020-05-26 18:43:38 +03002514 _format_time, _format_offset, _index, _is_leap, _isoweek1monday, _math,
Paul Ganssle09dc2f52017-12-21 00:33:49 -05002515 _ord2ymd, _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord,
2516 _divide_and_round, _parse_isoformat_date, _parse_isoformat_time,
Paul Ganssle1b97b9b2020-05-16 10:02:59 -04002517 _parse_hh_mm_ss_ff, _IsoCalendarDate)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002518 # XXX Since import * above excludes names that start with _,
2519 # docstring does not get overwritten. In the future, it may be
2520 # appropriate to maintain a single module level docstring and
2521 # remove the following line.
2522 from _datetime import __doc__