blob: e35ee0554c1ffcf16315d24bf54aad4adcaa54dd [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
7import time as _time
8import math as _math
Ammar Askar96d1e692018-07-25 09:54:58 -07009import sys
Alexander Belopolskycf86e362010-07-23 19:25:47 +000010
11def _cmp(x, y):
12 return 0 if x == y else 1 if x > y else -1
13
14MINYEAR = 1
15MAXYEAR = 9999
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -040016_MAXORDINAL = 3652059 # date.max.toordinal()
Alexander Belopolskycf86e362010-07-23 19:25:47 +000017
18# Utility functions, adapted from Python's Demo/classes/Dates.py, which
19# also assumes the current Gregorian calendar indefinitely extended in
20# both directions. Difference: Dates.py calls January 1 of year 0 day
21# number 1. The code here calls January 1 of year 1 day number 1. This is
22# to match the definition of the "proleptic Gregorian" calendar in Dershowitz
23# and Reingold's "Calendrical Calculations", where it's the base calendar
24# for all computations. See the book for algorithms for converting between
25# proleptic Gregorian ordinals and many other calendar systems.
26
Benjamin Petersonda0bea22013-08-29 17:29:30 -040027# -1 is a placeholder for indexing purposes.
Benjamin Petersonf908efb2013-08-29 17:27:57 -040028_DAYS_IN_MONTH = [-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
Alexander Belopolskycf86e362010-07-23 19:25:47 +000029
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -040030_DAYS_BEFORE_MONTH = [-1] # -1 is a placeholder for indexing purposes.
Alexander Belopolskycf86e362010-07-23 19:25:47 +000031dbm = 0
32for dim in _DAYS_IN_MONTH[1:]:
33 _DAYS_BEFORE_MONTH.append(dbm)
34 dbm += dim
35del dbm, dim
36
37def _is_leap(year):
38 "year -> 1 if leap year, else 0."
39 return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
40
41def _days_before_year(year):
42 "year -> number of days before January 1st of year."
43 y = year - 1
44 return y*365 + y//4 - y//100 + y//400
45
46def _days_in_month(year, month):
47 "year, month -> number of days in that month in that year."
48 assert 1 <= month <= 12, month
49 if month == 2 and _is_leap(year):
50 return 29
51 return _DAYS_IN_MONTH[month]
52
53def _days_before_month(year, month):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +030054 "year, month -> number of days in year preceding first day of month."
Alexander Belopolskycf86e362010-07-23 19:25:47 +000055 assert 1 <= month <= 12, 'month must be in 1..12'
56 return _DAYS_BEFORE_MONTH[month] + (month > 2 and _is_leap(year))
57
58def _ymd2ord(year, month, day):
59 "year, month, day -> ordinal, considering 01-Jan-0001 as day 1."
60 assert 1 <= month <= 12, 'month must be in 1..12'
61 dim = _days_in_month(year, month)
62 assert 1 <= day <= dim, ('day must be in 1..%d' % dim)
63 return (_days_before_year(year) +
64 _days_before_month(year, month) +
65 day)
66
67_DI400Y = _days_before_year(401) # number of days in 400 years
68_DI100Y = _days_before_year(101) # " " " " 100 "
69_DI4Y = _days_before_year(5) # " " " " 4 "
70
71# A 4-year cycle has an extra leap day over what we'd get from pasting
72# together 4 single years.
73assert _DI4Y == 4 * 365 + 1
74
75# Similarly, a 400-year cycle has an extra leap day over what we'd get from
76# pasting together 4 100-year cycles.
77assert _DI400Y == 4 * _DI100Y + 1
78
79# OTOH, a 100-year cycle has one fewer leap day than we'd get from
80# pasting together 25 4-year cycles.
81assert _DI100Y == 25 * _DI4Y - 1
82
83def _ord2ymd(n):
84 "ordinal -> (year, month, day), considering 01-Jan-0001 as day 1."
85
86 # n is a 1-based index, starting at 1-Jan-1. The pattern of leap years
87 # repeats exactly every 400 years. The basic strategy is to find the
88 # closest 400-year boundary at or before n, then work with the offset
89 # from that boundary to n. Life is much clearer if we subtract 1 from
90 # n first -- then the values of n at 400-year boundaries are exactly
91 # those divisible by _DI400Y:
92 #
93 # D M Y n n-1
94 # -- --- ---- ---------- ----------------
95 # 31 Dec -400 -_DI400Y -_DI400Y -1
96 # 1 Jan -399 -_DI400Y +1 -_DI400Y 400-year boundary
97 # ...
98 # 30 Dec 000 -1 -2
99 # 31 Dec 000 0 -1
100 # 1 Jan 001 1 0 400-year boundary
101 # 2 Jan 001 2 1
102 # 3 Jan 001 3 2
103 # ...
104 # 31 Dec 400 _DI400Y _DI400Y -1
105 # 1 Jan 401 _DI400Y +1 _DI400Y 400-year boundary
106 n -= 1
107 n400, n = divmod(n, _DI400Y)
108 year = n400 * 400 + 1 # ..., -399, 1, 401, ...
109
110 # Now n is the (non-negative) offset, in days, from January 1 of year, to
111 # the desired date. Now compute how many 100-year cycles precede n.
112 # Note that it's possible for n100 to equal 4! In that case 4 full
113 # 100-year cycles precede the desired day, which implies the desired
114 # day is December 31 at the end of a 400-year cycle.
115 n100, n = divmod(n, _DI100Y)
116
117 # Now compute how many 4-year cycles precede it.
118 n4, n = divmod(n, _DI4Y)
119
120 # And now how many single years. Again n1 can be 4, and again meaning
121 # that the desired day is December 31 at the end of the 4-year cycle.
122 n1, n = divmod(n, 365)
123
124 year += n100 * 100 + n4 * 4 + n1
125 if n1 == 4 or n100 == 4:
126 assert n == 0
127 return year-1, 12, 31
128
129 # Now the year is correct, and n is the offset from January 1. We find
130 # the month via an estimate that's either exact or one too large.
131 leapyear = n1 == 3 and (n4 != 24 or n100 == 3)
132 assert leapyear == _is_leap(year)
133 month = (n + 50) >> 5
134 preceding = _DAYS_BEFORE_MONTH[month] + (month > 2 and leapyear)
135 if preceding > n: # estimate is too large
136 month -= 1
137 preceding -= _DAYS_IN_MONTH[month] + (month == 2 and leapyear)
138 n -= preceding
139 assert 0 <= n < _days_in_month(year, month)
140
141 # Now the year and month are correct, and n is the offset from the
142 # start of that month: we're done!
143 return year, month, n+1
144
145# Month and day names. For localized versions, see the calendar module.
146_MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
147 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
148_DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
149
150
151def _build_struct_time(y, m, d, hh, mm, ss, dstflag):
152 wday = (_ymd2ord(y, m, d) + 6) % 7
153 dnum = _days_before_month(y, m) + d
154 return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag))
155
Alexander Belopolskya2998a62016-03-06 14:58:43 -0500156def _format_time(hh, mm, ss, us, timespec='auto'):
157 specs = {
158 'hours': '{:02d}',
159 'minutes': '{:02d}:{:02d}',
160 'seconds': '{:02d}:{:02d}:{:02d}',
161 'milliseconds': '{:02d}:{:02d}:{:02d}.{:03d}',
162 'microseconds': '{:02d}:{:02d}:{:02d}.{:06d}'
163 }
164
165 if timespec == 'auto':
166 # Skip trailing microseconds when us==0.
167 timespec = 'microseconds' if us else 'seconds'
168 elif timespec == 'milliseconds':
169 us //= 1000
170 try:
171 fmt = specs[timespec]
172 except KeyError:
173 raise ValueError('Unknown timespec value')
174 else:
175 return fmt.format(hh, mm, ss, us)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000176
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500177def _format_offset(off):
178 s = ''
179 if off is not None:
180 if off.days < 0:
181 sign = "-"
182 off = -off
183 else:
184 sign = "+"
185 hh, mm = divmod(off, timedelta(hours=1))
186 mm, ss = divmod(mm, timedelta(minutes=1))
187 s += "%s%02d:%02d" % (sign, hh, mm)
188 if ss or ss.microseconds:
189 s += ":%02d" % ss.seconds
190
191 if ss.microseconds:
192 s += '.%06d' % ss.microseconds
193 return s
194
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000195# Correctly substitute for %z and %Z escapes in strftime formats.
196def _wrap_strftime(object, format, timetuple):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000197 # Don't call utcoffset() or tzname() unless actually needed.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400198 freplace = None # the string to use for %f
199 zreplace = None # the string to use for %z
200 Zreplace = None # the string to use for %Z
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000201
202 # Scan format for %z and %Z escapes, replacing as needed.
203 newformat = []
204 push = newformat.append
205 i, n = 0, len(format)
206 while i < n:
207 ch = format[i]
208 i += 1
209 if ch == '%':
210 if i < n:
211 ch = format[i]
212 i += 1
213 if ch == 'f':
214 if freplace is None:
215 freplace = '%06d' % getattr(object,
216 'microsecond', 0)
217 newformat.append(freplace)
218 elif ch == 'z':
219 if zreplace is None:
220 zreplace = ""
221 if hasattr(object, "utcoffset"):
222 offset = object.utcoffset()
223 if offset is not None:
224 sign = '+'
225 if offset.days < 0:
226 offset = -offset
227 sign = '-'
Alexander Belopolsky018d3532017-07-31 10:26:50 -0400228 h, rest = divmod(offset, timedelta(hours=1))
229 m, rest = divmod(rest, timedelta(minutes=1))
230 s = rest.seconds
231 u = offset.microseconds
232 if u:
233 zreplace = '%c%02d%02d%02d.%06d' % (sign, h, m, s, u)
234 elif s:
235 zreplace = '%c%02d%02d%02d' % (sign, h, m, s)
236 else:
237 zreplace = '%c%02d%02d' % (sign, h, m)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000238 assert '%' not in zreplace
239 newformat.append(zreplace)
240 elif ch == 'Z':
241 if Zreplace is None:
242 Zreplace = ""
243 if hasattr(object, "tzname"):
244 s = object.tzname()
245 if s is not None:
246 # strftime is going to have at this: escape %
247 Zreplace = s.replace('%', '%%')
248 newformat.append(Zreplace)
249 else:
250 push('%')
251 push(ch)
252 else:
253 push('%')
254 else:
255 push(ch)
256 newformat = "".join(newformat)
257 return _time.strftime(newformat, timetuple)
258
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500259# Helpers for parsing the result of isoformat()
260def _parse_isoformat_date(dtstr):
261 # It is assumed that this function will only be called with a
262 # string of length exactly 10, and (though this is not used) ASCII-only
263 year = int(dtstr[0:4])
264 if dtstr[4] != '-':
265 raise ValueError('Invalid date separator: %s' % dtstr[4])
266
267 month = int(dtstr[5:7])
268
269 if dtstr[7] != '-':
270 raise ValueError('Invalid date separator')
271
272 day = int(dtstr[8:10])
273
274 return [year, month, day]
275
276def _parse_hh_mm_ss_ff(tstr):
277 # Parses things of the form HH[:MM[:SS[.fff[fff]]]]
278 len_str = len(tstr)
279
280 time_comps = [0, 0, 0, 0]
281 pos = 0
282 for comp in range(0, 3):
283 if (len_str - pos) < 2:
284 raise ValueError('Incomplete time component')
285
286 time_comps[comp] = int(tstr[pos:pos+2])
287
288 pos += 2
289 next_char = tstr[pos:pos+1]
290
291 if not next_char or comp >= 2:
292 break
293
294 if next_char != ':':
295 raise ValueError('Invalid time separator: %c' % next_char)
296
297 pos += 1
298
299 if pos < len_str:
300 if tstr[pos] != '.':
301 raise ValueError('Invalid microsecond component')
302 else:
303 pos += 1
304
305 len_remainder = len_str - pos
306 if len_remainder not in (3, 6):
307 raise ValueError('Invalid microsecond component')
308
309 time_comps[3] = int(tstr[pos:])
310 if len_remainder == 3:
311 time_comps[3] *= 1000
312
313 return time_comps
314
315def _parse_isoformat_time(tstr):
316 # Format supported is HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]
317 len_str = len(tstr)
318 if len_str < 2:
319 raise ValueError('Isoformat time too short')
320
321 # This is equivalent to re.search('[+-]', tstr), but faster
322 tz_pos = (tstr.find('-') + 1 or tstr.find('+') + 1)
323 timestr = tstr[:tz_pos-1] if tz_pos > 0 else tstr
324
325 time_comps = _parse_hh_mm_ss_ff(timestr)
326
327 tzi = None
328 if tz_pos > 0:
329 tzstr = tstr[tz_pos:]
330
331 # Valid time zone strings are:
332 # HH:MM len: 5
333 # HH:MM:SS len: 8
334 # HH:MM:SS.ffffff len: 15
335
336 if len(tzstr) not in (5, 8, 15):
337 raise ValueError('Malformed time zone string')
338
339 tz_comps = _parse_hh_mm_ss_ff(tzstr)
340 if all(x == 0 for x in tz_comps):
341 tzi = timezone.utc
342 else:
343 tzsign = -1 if tstr[tz_pos - 1] == '-' else 1
344
345 td = timedelta(hours=tz_comps[0], minutes=tz_comps[1],
346 seconds=tz_comps[2], microseconds=tz_comps[3])
347
348 tzi = timezone(tzsign * td)
349
350 time_comps.append(tzi)
351
352 return time_comps
353
354
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000355# Just raise TypeError if the arg isn't None or a string.
356def _check_tzname(name):
357 if name is not None and not isinstance(name, str):
358 raise TypeError("tzinfo.tzname() must return None or string, "
359 "not '%s'" % type(name))
360
361# name is the offset-producing method, "utcoffset" or "dst".
362# offset is what it returned.
363# If offset isn't None or timedelta, raises TypeError.
364# If offset is None, returns None.
Alexander Belopolsky018d3532017-07-31 10:26:50 -0400365# Else offset is checked for being in range.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000366# If it is, its integer value is returned. Else ValueError is raised.
367def _check_utc_offset(name, offset):
368 assert name in ("utcoffset", "dst")
369 if offset is None:
370 return
371 if not isinstance(offset, timedelta):
372 raise TypeError("tzinfo.%s() must return None "
373 "or timedelta, not '%s'" % (name, type(offset)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000374 if not -timedelta(1) < offset < timedelta(1):
Martin Panterdd780e42016-05-30 04:08:23 +0000375 raise ValueError("%s()=%s, must be strictly between "
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400376 "-timedelta(hours=24) and timedelta(hours=24)" %
377 (name, offset))
378
379def _check_int_field(value):
380 if isinstance(value, int):
381 return value
Serhiy Storchaka6a44f6e2019-02-25 17:57:58 +0200382 if isinstance(value, float):
383 raise TypeError('integer argument expected, got float')
384 try:
385 value = value.__index__()
386 except AttributeError:
387 pass
388 else:
389 if not isinstance(value, int):
390 raise TypeError('__index__ returned non-int (type %s)' %
391 type(value).__name__)
392 return value
393 orig = value
394 try:
395 value = value.__int__()
396 except AttributeError:
397 pass
398 else:
399 if not isinstance(value, int):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400400 raise TypeError('__int__ returned non-int (type %s)' %
401 type(value).__name__)
Serhiy Storchaka6a44f6e2019-02-25 17:57:58 +0200402 import warnings
403 warnings.warn("an integer is required (got type %s)" %
404 type(orig).__name__,
405 DeprecationWarning,
406 stacklevel=2)
407 return value
408 raise TypeError('an integer is required (got type %s)' %
409 type(value).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000410
411def _check_date_fields(year, month, day):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400412 year = _check_int_field(year)
413 month = _check_int_field(month)
414 day = _check_int_field(day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000415 if not MINYEAR <= year <= MAXYEAR:
416 raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year)
417 if not 1 <= month <= 12:
418 raise ValueError('month must be in 1..12', month)
419 dim = _days_in_month(year, month)
420 if not 1 <= day <= dim:
421 raise ValueError('day must be in 1..%d' % dim, day)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400422 return year, month, day
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000423
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400424def _check_time_fields(hour, minute, second, microsecond, fold):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400425 hour = _check_int_field(hour)
426 minute = _check_int_field(minute)
427 second = _check_int_field(second)
428 microsecond = _check_int_field(microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000429 if not 0 <= hour <= 23:
430 raise ValueError('hour must be in 0..23', hour)
431 if not 0 <= minute <= 59:
432 raise ValueError('minute must be in 0..59', minute)
433 if not 0 <= second <= 59:
434 raise ValueError('second must be in 0..59', second)
435 if not 0 <= microsecond <= 999999:
436 raise ValueError('microsecond must be in 0..999999', microsecond)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400437 if fold not in (0, 1):
438 raise ValueError('fold must be either 0 or 1', fold)
439 return hour, minute, second, microsecond, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000440
441def _check_tzinfo_arg(tz):
442 if tz is not None and not isinstance(tz, tzinfo):
443 raise TypeError("tzinfo argument must be None or of a tzinfo subclass")
444
445def _cmperror(x, y):
446 raise TypeError("can't compare '%s' to '%s'" % (
447 type(x).__name__, type(y).__name__))
448
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500449def _divide_and_round(a, b):
450 """divide a by b and round result to the nearest integer
451
452 When the ratio is exactly half-way between two integers,
453 the even integer is returned.
454 """
455 # Based on the reference implementation for divmod_near
456 # in Objects/longobject.c.
457 q, r = divmod(a, b)
458 # round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
459 # The expression r / b > 0.5 is equivalent to 2 * r > b if b is
460 # positive, 2 * r < b if b negative.
461 r *= 2
462 greater_than_half = r > b if b > 0 else r < b
463 if greater_than_half or r == b and q % 2 == 1:
464 q += 1
465
466 return q
467
Victor Stinner2ec55872015-09-02 19:16:07 +0200468
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000469class timedelta:
470 """Represent the difference between two datetime objects.
471
472 Supported operators:
473
474 - add, subtract timedelta
475 - unary plus, minus, abs
476 - compare to timedelta
Serhiy Storchaka95949422013-08-27 19:40:23 +0300477 - multiply, divide by int
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000478
479 In addition, datetime supports subtraction of two datetime objects
480 returning a timedelta, and addition or subtraction of a datetime
481 and a timedelta giving a datetime.
482
483 Representation: (days, seconds, microseconds). Why? Because I
484 felt like it.
485 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400486 __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000487
488 def __new__(cls, days=0, seconds=0, microseconds=0,
489 milliseconds=0, minutes=0, hours=0, weeks=0):
490 # Doing this efficiently and accurately in C is going to be difficult
491 # and error-prone, due to ubiquitous overflow possibilities, and that
492 # C double doesn't have enough bits of precision to represent
493 # microseconds over 10K years faithfully. The code here tries to make
494 # explicit where go-fast assumptions can be relied on, in order to
495 # guide the C implementation; it's way more convoluted than speed-
496 # ignoring auto-overflow-to-long idiomatic Python could be.
497
498 # XXX Check that all inputs are ints or floats.
499
500 # Final values, all integer.
501 # s and us fit in 32-bit signed ints; d isn't bounded.
502 d = s = us = 0
503
504 # Normalize everything to days, seconds, microseconds.
505 days += weeks*7
506 seconds += minutes*60 + hours*3600
507 microseconds += milliseconds*1000
508
509 # Get rid of all fractions, and normalize s and us.
510 # Take a deep breath <wink>.
511 if isinstance(days, float):
512 dayfrac, days = _math.modf(days)
513 daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
514 assert daysecondswhole == int(daysecondswhole) # can't overflow
515 s = int(daysecondswhole)
516 assert days == int(days)
517 d = int(days)
518 else:
519 daysecondsfrac = 0.0
520 d = days
521 assert isinstance(daysecondsfrac, float)
522 assert abs(daysecondsfrac) <= 1.0
523 assert isinstance(d, int)
524 assert abs(s) <= 24 * 3600
525 # days isn't referenced again before redefinition
526
527 if isinstance(seconds, float):
528 secondsfrac, seconds = _math.modf(seconds)
529 assert seconds == int(seconds)
530 seconds = int(seconds)
531 secondsfrac += daysecondsfrac
532 assert abs(secondsfrac) <= 2.0
533 else:
534 secondsfrac = daysecondsfrac
535 # daysecondsfrac isn't referenced again
536 assert isinstance(secondsfrac, float)
537 assert abs(secondsfrac) <= 2.0
538
539 assert isinstance(seconds, int)
540 days, seconds = divmod(seconds, 24*3600)
541 d += days
542 s += int(seconds) # can't overflow
543 assert isinstance(s, int)
544 assert abs(s) <= 2 * 24 * 3600
545 # seconds isn't referenced again before redefinition
546
547 usdouble = secondsfrac * 1e6
548 assert abs(usdouble) < 2.1e6 # exact value not critical
549 # secondsfrac isn't referenced again
550
551 if isinstance(microseconds, float):
Victor Stinner69cc4872015-09-08 23:58:54 +0200552 microseconds = round(microseconds + usdouble)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000553 seconds, microseconds = divmod(microseconds, 1000000)
554 days, seconds = divmod(seconds, 24*3600)
555 d += days
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400556 s += seconds
557 else:
558 microseconds = int(microseconds)
559 seconds, microseconds = divmod(microseconds, 1000000)
560 days, seconds = divmod(seconds, 24*3600)
561 d += days
562 s += seconds
Victor Stinner69cc4872015-09-08 23:58:54 +0200563 microseconds = round(microseconds + usdouble)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400564 assert isinstance(s, int)
565 assert isinstance(microseconds, int)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000566 assert abs(s) <= 3 * 24 * 3600
567 assert abs(microseconds) < 3.1e6
568
569 # Just a little bit of carrying possible for microseconds and seconds.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400570 seconds, us = divmod(microseconds, 1000000)
571 s += seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000572 days, s = divmod(s, 24*3600)
573 d += days
574
575 assert isinstance(d, int)
576 assert isinstance(s, int) and 0 <= s < 24*3600
577 assert isinstance(us, int) and 0 <= us < 1000000
578
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000579 if abs(d) > 999999999:
580 raise OverflowError("timedelta # of days is too large: %d" % d)
581
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400582 self = object.__new__(cls)
583 self._days = d
584 self._seconds = s
585 self._microseconds = us
586 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000587 return self
588
589 def __repr__(self):
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200590 args = []
591 if self._days:
592 args.append("days=%d" % self._days)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000593 if self._seconds:
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200594 args.append("seconds=%d" % self._seconds)
595 if self._microseconds:
596 args.append("microseconds=%d" % self._microseconds)
597 if not args:
598 args.append('0')
599 return "%s.%s(%s)" % (self.__class__.__module__,
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300600 self.__class__.__qualname__,
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200601 ', '.join(args))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000602
603 def __str__(self):
604 mm, ss = divmod(self._seconds, 60)
605 hh, mm = divmod(mm, 60)
606 s = "%d:%02d:%02d" % (hh, mm, ss)
607 if self._days:
608 def plural(n):
609 return n, abs(n) != 1 and "s" or ""
610 s = ("%d day%s, " % plural(self._days)) + s
611 if self._microseconds:
612 s = s + ".%06d" % self._microseconds
613 return s
614
615 def total_seconds(self):
616 """Total seconds in the duration."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400617 return ((self.days * 86400 + self.seconds) * 10**6 +
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000618 self.microseconds) / 10**6
619
620 # Read-only field accessors
621 @property
622 def days(self):
623 """days"""
624 return self._days
625
626 @property
627 def seconds(self):
628 """seconds"""
629 return self._seconds
630
631 @property
632 def microseconds(self):
633 """microseconds"""
634 return self._microseconds
635
636 def __add__(self, other):
637 if isinstance(other, timedelta):
638 # for CPython compatibility, we cannot use
639 # our __class__ here, but need a real timedelta
640 return timedelta(self._days + other._days,
641 self._seconds + other._seconds,
642 self._microseconds + other._microseconds)
643 return NotImplemented
644
645 __radd__ = __add__
646
647 def __sub__(self, other):
648 if isinstance(other, timedelta):
Alexander Belopolskyb6f5ec72011-04-05 20:07:38 -0400649 # for CPython compatibility, we cannot use
650 # our __class__ here, but need a real timedelta
651 return timedelta(self._days - other._days,
652 self._seconds - other._seconds,
653 self._microseconds - other._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000654 return NotImplemented
655
656 def __rsub__(self, other):
657 if isinstance(other, timedelta):
658 return -self + other
659 return NotImplemented
660
661 def __neg__(self):
662 # for CPython compatibility, we cannot use
663 # our __class__ here, but need a real timedelta
664 return timedelta(-self._days,
665 -self._seconds,
666 -self._microseconds)
667
668 def __pos__(self):
669 return self
670
671 def __abs__(self):
672 if self._days < 0:
673 return -self
674 else:
675 return self
676
677 def __mul__(self, other):
678 if isinstance(other, int):
679 # for CPython compatibility, we cannot use
680 # our __class__ here, but need a real timedelta
681 return timedelta(self._days * other,
682 self._seconds * other,
683 self._microseconds * other)
684 if isinstance(other, float):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500685 usec = self._to_microseconds()
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000686 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500687 return timedelta(0, 0, _divide_and_round(usec * a, b))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000688 return NotImplemented
689
690 __rmul__ = __mul__
691
692 def _to_microseconds(self):
693 return ((self._days * (24*3600) + self._seconds) * 1000000 +
694 self._microseconds)
695
696 def __floordiv__(self, other):
697 if not isinstance(other, (int, timedelta)):
698 return NotImplemented
699 usec = self._to_microseconds()
700 if isinstance(other, timedelta):
701 return usec // other._to_microseconds()
702 if isinstance(other, int):
703 return timedelta(0, 0, usec // other)
704
705 def __truediv__(self, other):
706 if not isinstance(other, (int, float, timedelta)):
707 return NotImplemented
708 usec = self._to_microseconds()
709 if isinstance(other, timedelta):
710 return usec / other._to_microseconds()
711 if isinstance(other, int):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500712 return timedelta(0, 0, _divide_and_round(usec, other))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000713 if isinstance(other, float):
714 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500715 return timedelta(0, 0, _divide_and_round(b * usec, a))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000716
717 def __mod__(self, other):
718 if isinstance(other, timedelta):
719 r = self._to_microseconds() % other._to_microseconds()
720 return timedelta(0, 0, r)
721 return NotImplemented
722
723 def __divmod__(self, other):
724 if isinstance(other, timedelta):
725 q, r = divmod(self._to_microseconds(),
726 other._to_microseconds())
727 return q, timedelta(0, 0, r)
728 return NotImplemented
729
730 # Comparisons of timedelta objects with other.
731
732 def __eq__(self, other):
733 if isinstance(other, timedelta):
734 return self._cmp(other) == 0
735 else:
Miss Islington (bot)143672c2019-07-13 06:59:37 -0700736 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000737
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000738 def __le__(self, other):
739 if isinstance(other, timedelta):
740 return self._cmp(other) <= 0
741 else:
742 _cmperror(self, other)
743
744 def __lt__(self, other):
745 if isinstance(other, timedelta):
746 return self._cmp(other) < 0
747 else:
748 _cmperror(self, other)
749
750 def __ge__(self, other):
751 if isinstance(other, timedelta):
752 return self._cmp(other) >= 0
753 else:
754 _cmperror(self, other)
755
756 def __gt__(self, other):
757 if isinstance(other, timedelta):
758 return self._cmp(other) > 0
759 else:
760 _cmperror(self, other)
761
762 def _cmp(self, other):
763 assert isinstance(other, timedelta)
764 return _cmp(self._getstate(), other._getstate())
765
766 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400767 if self._hashcode == -1:
768 self._hashcode = hash(self._getstate())
769 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000770
771 def __bool__(self):
772 return (self._days != 0 or
773 self._seconds != 0 or
774 self._microseconds != 0)
775
776 # Pickle support.
777
778 def _getstate(self):
779 return (self._days, self._seconds, self._microseconds)
780
781 def __reduce__(self):
782 return (self.__class__, self._getstate())
783
784timedelta.min = timedelta(-999999999)
785timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
786 microseconds=999999)
787timedelta.resolution = timedelta(microseconds=1)
788
789class date:
790 """Concrete date type.
791
792 Constructors:
793
794 __new__()
795 fromtimestamp()
796 today()
797 fromordinal()
798
799 Operators:
800
801 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200802 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000803 __add__, __radd__, __sub__ (add/radd only with timedelta arg)
804
805 Methods:
806
807 timetuple()
808 toordinal()
809 weekday()
810 isoweekday(), isocalendar(), isoformat()
811 ctime()
812 strftime()
813
814 Properties (readonly):
815 year, month, day
816 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400817 __slots__ = '_year', '_month', '_day', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000818
819 def __new__(cls, year, month=None, day=None):
820 """Constructor.
821
822 Arguments:
823
824 year, month, day (required, base 1)
825 """
Serhiy Storchaka8452ca12018-12-07 13:42:10 +0200826 if (month is None and
827 isinstance(year, (bytes, str)) and len(year) == 4 and
828 1 <= ord(year[2:3]) <= 12):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000829 # Pickle support
Serhiy Storchaka8452ca12018-12-07 13:42:10 +0200830 if isinstance(year, str):
831 try:
832 year = year.encode('latin1')
833 except UnicodeEncodeError:
834 # More informative error message.
835 raise ValueError(
836 "Failed to encode latin1 string when unpickling "
837 "a date object. "
838 "pickle.load(data, encoding='latin1') is assumed.")
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000839 self = object.__new__(cls)
840 self.__setstate(year)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400841 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000842 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400843 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000844 self = object.__new__(cls)
845 self._year = year
846 self._month = month
847 self._day = day
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400848 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000849 return self
850
851 # Additional constructors
852
853 @classmethod
854 def fromtimestamp(cls, t):
855 "Construct a date from a POSIX timestamp (like time.time())."
856 y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
857 return cls(y, m, d)
858
859 @classmethod
860 def today(cls):
861 "Construct a date from time.time()."
862 t = _time.time()
863 return cls.fromtimestamp(t)
864
865 @classmethod
866 def fromordinal(cls, n):
Martin Pantereb995702016-07-28 01:11:04 +0000867 """Construct a date from a proleptic Gregorian ordinal.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000868
869 January 1 of year 1 is day 1. Only the year, month and day are
870 non-zero in the result.
871 """
872 y, m, d = _ord2ymd(n)
873 return cls(y, m, d)
874
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500875 @classmethod
876 def fromisoformat(cls, date_string):
877 """Construct a date from the output of date.isoformat()."""
878 if not isinstance(date_string, str):
879 raise TypeError('fromisoformat: argument must be str')
880
881 try:
882 assert len(date_string) == 10
883 return cls(*_parse_isoformat_date(date_string))
884 except Exception:
Paul Ganssle3df85402018-10-22 12:32:52 -0400885 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500886
Paul Ganssle88c09372019-04-29 09:22:03 -0400887 @classmethod
888 def fromisocalendar(cls, year, week, day):
889 """Construct a date from the ISO year, week number and weekday.
890
891 This is the inverse of the date.isocalendar() function"""
892 # Year is bounded this way because 9999-12-31 is (9999, 52, 5)
893 if not MINYEAR <= year <= MAXYEAR:
894 raise ValueError(f"Year is out of range: {year}")
895
896 if not 0 < week < 53:
897 out_of_range = True
898
899 if week == 53:
900 # ISO years have 53 weeks in them on years starting with a
901 # Thursday and leap years starting on a Wednesday
902 first_weekday = _ymd2ord(year, 1, 1) % 7
903 if (first_weekday == 4 or (first_weekday == 3 and
904 _is_leap(year))):
905 out_of_range = False
906
907 if out_of_range:
908 raise ValueError(f"Invalid week: {week}")
909
910 if not 0 < day < 8:
911 raise ValueError(f"Invalid weekday: {day} (range is [1, 7])")
912
913 # Now compute the offset from (Y, 1, 1) in days:
914 day_offset = (week - 1) * 7 + (day - 1)
915
916 # Calculate the ordinal day for monday, week 1
917 day_1 = _isoweek1monday(year)
918 ord_day = day_1 + day_offset
919
920 return cls(*_ord2ymd(ord_day))
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500921
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000922 # Conversions to string
923
924 def __repr__(self):
925 """Convert to formal string, for repr().
926
927 >>> dt = datetime(2010, 1, 1)
928 >>> repr(dt)
929 'datetime.datetime(2010, 1, 1, 0, 0)'
930
931 >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
932 >>> repr(dt)
933 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
934 """
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300935 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
936 self.__class__.__qualname__,
937 self._year,
938 self._month,
939 self._day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000940 # XXX These shouldn't depend on time.localtime(), because that
941 # clips the usable dates to [1970 .. 2038). At least ctime() is
942 # easily done without using strftime() -- that's better too because
943 # strftime("%c", ...) is locale specific.
944
945
946 def ctime(self):
947 "Return ctime() style string."
948 weekday = self.toordinal() % 7 or 7
949 return "%s %s %2d 00:00:00 %04d" % (
950 _DAYNAMES[weekday],
951 _MONTHNAMES[self._month],
952 self._day, self._year)
953
954 def strftime(self, fmt):
955 "Format using strftime()."
956 return _wrap_strftime(self, fmt, self.timetuple())
957
958 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400959 if not isinstance(fmt, str):
960 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000961 if len(fmt) != 0:
962 return self.strftime(fmt)
963 return str(self)
964
965 def isoformat(self):
966 """Return the date formatted according to ISO.
967
968 This is 'YYYY-MM-DD'.
969
970 References:
971 - http://www.w3.org/TR/NOTE-datetime
972 - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
973 """
974 return "%04d-%02d-%02d" % (self._year, self._month, self._day)
975
976 __str__ = isoformat
977
978 # Read-only field accessors
979 @property
980 def year(self):
981 """year (1-9999)"""
982 return self._year
983
984 @property
985 def month(self):
986 """month (1-12)"""
987 return self._month
988
989 @property
990 def day(self):
991 """day (1-31)"""
992 return self._day
993
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200994 # Standard conversions, __eq__, __le__, __lt__, __ge__, __gt__,
995 # __hash__ (and helpers)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000996
997 def timetuple(self):
998 "Return local time tuple compatible with time.localtime()."
999 return _build_struct_time(self._year, self._month, self._day,
1000 0, 0, 0, -1)
1001
1002 def toordinal(self):
1003 """Return proleptic Gregorian ordinal for the year, month and day.
1004
1005 January 1 of year 1 is day 1. Only the year, month and day values
1006 contribute to the result.
1007 """
1008 return _ymd2ord(self._year, self._month, self._day)
1009
1010 def replace(self, year=None, month=None, day=None):
1011 """Return a new date with new values for the specified fields."""
1012 if year is None:
1013 year = self._year
1014 if month is None:
1015 month = self._month
1016 if day is None:
1017 day = self._day
Paul Ganssle191e9932017-11-09 16:34:29 -05001018 return type(self)(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001019
1020 # Comparisons of date objects with other.
1021
1022 def __eq__(self, other):
1023 if isinstance(other, date):
1024 return self._cmp(other) == 0
1025 return NotImplemented
1026
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001027 def __le__(self, other):
1028 if isinstance(other, date):
1029 return self._cmp(other) <= 0
1030 return NotImplemented
1031
1032 def __lt__(self, other):
1033 if isinstance(other, date):
1034 return self._cmp(other) < 0
1035 return NotImplemented
1036
1037 def __ge__(self, other):
1038 if isinstance(other, date):
1039 return self._cmp(other) >= 0
1040 return NotImplemented
1041
1042 def __gt__(self, other):
1043 if isinstance(other, date):
1044 return self._cmp(other) > 0
1045 return NotImplemented
1046
1047 def _cmp(self, other):
1048 assert isinstance(other, date)
1049 y, m, d = self._year, self._month, self._day
1050 y2, m2, d2 = other._year, other._month, other._day
1051 return _cmp((y, m, d), (y2, m2, d2))
1052
1053 def __hash__(self):
1054 "Hash."
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001055 if self._hashcode == -1:
1056 self._hashcode = hash(self._getstate())
1057 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001058
1059 # Computations
1060
1061 def __add__(self, other):
1062 "Add a date to a timedelta."
1063 if isinstance(other, timedelta):
1064 o = self.toordinal() + other.days
1065 if 0 < o <= _MAXORDINAL:
Paul Ganssle89427cd2019-02-04 14:42:04 -05001066 return type(self).fromordinal(o)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001067 raise OverflowError("result out of range")
1068 return NotImplemented
1069
1070 __radd__ = __add__
1071
1072 def __sub__(self, other):
1073 """Subtract two dates, or a date and a timedelta."""
1074 if isinstance(other, timedelta):
1075 return self + timedelta(-other.days)
1076 if isinstance(other, date):
1077 days1 = self.toordinal()
1078 days2 = other.toordinal()
1079 return timedelta(days1 - days2)
1080 return NotImplemented
1081
1082 def weekday(self):
1083 "Return day of the week, where Monday == 0 ... Sunday == 6."
1084 return (self.toordinal() + 6) % 7
1085
1086 # Day-of-the-week and week-of-the-year, according to ISO
1087
1088 def isoweekday(self):
1089 "Return day of the week, where Monday == 1 ... Sunday == 7."
1090 # 1-Jan-0001 is a Monday
1091 return self.toordinal() % 7 or 7
1092
1093 def isocalendar(self):
1094 """Return a 3-tuple containing ISO year, week number, and weekday.
1095
1096 The first ISO week of the year is the (Mon-Sun) week
1097 containing the year's first Thursday; everything else derives
1098 from that.
1099
1100 The first week is 1; Monday is 1 ... Sunday is 7.
1101
1102 ISO calendar algorithm taken from
1103 http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
Brett Cannon07b954d2016-01-15 09:53:51 -08001104 (used with permission)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001105 """
1106 year = self._year
1107 week1monday = _isoweek1monday(year)
1108 today = _ymd2ord(self._year, self._month, self._day)
1109 # Internally, week and day have origin 0
1110 week, day = divmod(today - week1monday, 7)
1111 if week < 0:
1112 year -= 1
1113 week1monday = _isoweek1monday(year)
1114 week, day = divmod(today - week1monday, 7)
1115 elif week >= 52:
1116 if today >= _isoweek1monday(year+1):
1117 year += 1
1118 week = 0
1119 return year, week+1, day+1
1120
1121 # Pickle support.
1122
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001123 def _getstate(self):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001124 yhi, ylo = divmod(self._year, 256)
1125 return bytes([yhi, ylo, self._month, self._day]),
1126
1127 def __setstate(self, string):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001128 yhi, ylo, self._month, self._day = string
1129 self._year = yhi * 256 + ylo
1130
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001131 def __reduce__(self):
1132 return (self.__class__, self._getstate())
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001133
1134_date_class = date # so functions w/ args named "date" can get at the class
1135
1136date.min = date(1, 1, 1)
1137date.max = date(9999, 12, 31)
1138date.resolution = timedelta(days=1)
1139
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001140
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001141class tzinfo:
1142 """Abstract base class for time zone info classes.
1143
1144 Subclasses must override the name(), utcoffset() and dst() methods.
1145 """
1146 __slots__ = ()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001147
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001148 def tzname(self, dt):
1149 "datetime -> string name of time zone."
1150 raise NotImplementedError("tzinfo subclass must override tzname()")
1151
1152 def utcoffset(self, dt):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001153 "datetime -> timedelta, positive for east of UTC, negative for west of UTC"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001154 raise NotImplementedError("tzinfo subclass must override utcoffset()")
1155
1156 def dst(self, dt):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001157 """datetime -> DST offset as timedelta, positive for east of UTC.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001158
1159 Return 0 if DST not in effect. utcoffset() must include the DST
1160 offset.
1161 """
1162 raise NotImplementedError("tzinfo subclass must override dst()")
1163
1164 def fromutc(self, dt):
1165 "datetime in UTC -> datetime in local time."
1166
1167 if not isinstance(dt, datetime):
1168 raise TypeError("fromutc() requires a datetime argument")
1169 if dt.tzinfo is not self:
1170 raise ValueError("dt.tzinfo is not self")
1171
1172 dtoff = dt.utcoffset()
1173 if dtoff is None:
1174 raise ValueError("fromutc() requires a non-None utcoffset() "
1175 "result")
1176
1177 # See the long comment block at the end of this file for an
1178 # explanation of this algorithm.
1179 dtdst = dt.dst()
1180 if dtdst is None:
1181 raise ValueError("fromutc() requires a non-None dst() result")
1182 delta = dtoff - dtdst
1183 if delta:
1184 dt += delta
1185 dtdst = dt.dst()
1186 if dtdst is None:
1187 raise ValueError("fromutc(): dt.dst gave inconsistent "
1188 "results; cannot convert")
1189 return dt + dtdst
1190
1191 # Pickle support.
1192
1193 def __reduce__(self):
1194 getinitargs = getattr(self, "__getinitargs__", None)
1195 if getinitargs:
1196 args = getinitargs()
1197 else:
1198 args = ()
1199 getstate = getattr(self, "__getstate__", None)
1200 if getstate:
1201 state = getstate()
1202 else:
1203 state = getattr(self, "__dict__", None) or None
1204 if state is None:
1205 return (self.__class__, args)
1206 else:
1207 return (self.__class__, args, state)
1208
1209_tzinfo_class = tzinfo
1210
1211class time:
1212 """Time with time zone.
1213
1214 Constructors:
1215
1216 __new__()
1217
1218 Operators:
1219
1220 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +02001221 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001222
1223 Methods:
1224
1225 strftime()
1226 isoformat()
1227 utcoffset()
1228 tzname()
1229 dst()
1230
1231 Properties (readonly):
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001232 hour, minute, second, microsecond, tzinfo, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001233 """
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001234 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode', '_fold'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001235
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001236 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001237 """Constructor.
1238
1239 Arguments:
1240
1241 hour, minute (required)
1242 second, microsecond (default to zero)
1243 tzinfo (default to None)
Victor Stinner51b90d22017-01-04 12:01:16 +01001244 fold (keyword only, default to zero)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001245 """
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001246 if (isinstance(hour, (bytes, str)) and len(hour) == 6 and
1247 ord(hour[0:1])&0x7F < 24):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001248 # Pickle support
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001249 if isinstance(hour, str):
1250 try:
1251 hour = hour.encode('latin1')
1252 except UnicodeEncodeError:
1253 # More informative error message.
1254 raise ValueError(
1255 "Failed to encode latin1 string when unpickling "
1256 "a time object. "
1257 "pickle.load(data, encoding='latin1') is assumed.")
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001258 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001259 self.__setstate(hour, minute or None)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001260 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001261 return self
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001262 hour, minute, second, microsecond, fold = _check_time_fields(
1263 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001264 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001265 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001266 self._hour = hour
1267 self._minute = minute
1268 self._second = second
1269 self._microsecond = microsecond
1270 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001271 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001272 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001273 return self
1274
1275 # Read-only field accessors
1276 @property
1277 def hour(self):
1278 """hour (0-23)"""
1279 return self._hour
1280
1281 @property
1282 def minute(self):
1283 """minute (0-59)"""
1284 return self._minute
1285
1286 @property
1287 def second(self):
1288 """second (0-59)"""
1289 return self._second
1290
1291 @property
1292 def microsecond(self):
1293 """microsecond (0-999999)"""
1294 return self._microsecond
1295
1296 @property
1297 def tzinfo(self):
1298 """timezone info object"""
1299 return self._tzinfo
1300
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001301 @property
1302 def fold(self):
1303 return self._fold
1304
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001305 # Standard conversions, __hash__ (and helpers)
1306
1307 # Comparisons of time objects with other.
1308
1309 def __eq__(self, other):
1310 if isinstance(other, time):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001311 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001312 else:
Miss Islington (bot)143672c2019-07-13 06:59:37 -07001313 return NotImplemented
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001314
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001315 def __le__(self, other):
1316 if isinstance(other, time):
1317 return self._cmp(other) <= 0
1318 else:
1319 _cmperror(self, other)
1320
1321 def __lt__(self, other):
1322 if isinstance(other, time):
1323 return self._cmp(other) < 0
1324 else:
1325 _cmperror(self, other)
1326
1327 def __ge__(self, other):
1328 if isinstance(other, time):
1329 return self._cmp(other) >= 0
1330 else:
1331 _cmperror(self, other)
1332
1333 def __gt__(self, other):
1334 if isinstance(other, time):
1335 return self._cmp(other) > 0
1336 else:
1337 _cmperror(self, other)
1338
Alexander Belopolsky08313822012-06-15 20:19:47 -04001339 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001340 assert isinstance(other, time)
1341 mytz = self._tzinfo
1342 ottz = other._tzinfo
1343 myoff = otoff = None
1344
1345 if mytz is ottz:
1346 base_compare = True
1347 else:
1348 myoff = self.utcoffset()
1349 otoff = other.utcoffset()
1350 base_compare = myoff == otoff
1351
1352 if base_compare:
1353 return _cmp((self._hour, self._minute, self._second,
1354 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001355 (other._hour, other._minute, other._second,
1356 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001357 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001358 if allow_mixed:
1359 return 2 # arbitrary non-zero value
1360 else:
1361 raise TypeError("cannot compare naive and aware times")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001362 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1363 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1364 return _cmp((myhhmm, self._second, self._microsecond),
1365 (othhmm, other._second, other._microsecond))
1366
1367 def __hash__(self):
1368 """Hash."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001369 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001370 if self.fold:
1371 t = self.replace(fold=0)
1372 else:
1373 t = self
1374 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001375 if not tzoff: # zero or None
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001376 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001377 else:
1378 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1379 timedelta(hours=1))
1380 assert not m % timedelta(minutes=1), "whole minute"
1381 m //= timedelta(minutes=1)
1382 if 0 <= h < 24:
1383 self._hashcode = hash(time(h, m, self.second, self.microsecond))
1384 else:
1385 self._hashcode = hash((h, m, self.second, self.microsecond))
1386 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001387
1388 # Conversion to string
1389
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001390 def _tzstr(self):
1391 """Return formatted timezone offset (+xx:xx) or an empty string."""
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001392 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001393 return _format_offset(off)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001394
1395 def __repr__(self):
1396 """Convert to formal string, for repr()."""
1397 if self._microsecond != 0:
1398 s = ", %d, %d" % (self._second, self._microsecond)
1399 elif self._second != 0:
1400 s = ", %d" % self._second
1401 else:
1402 s = ""
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001403 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1404 self.__class__.__qualname__,
1405 self._hour, self._minute, s)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001406 if self._tzinfo is not None:
1407 assert s[-1:] == ")"
1408 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001409 if self._fold:
1410 assert s[-1:] == ")"
1411 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001412 return s
1413
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001414 def isoformat(self, timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001415 """Return the time formatted according to ISO.
1416
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001417 The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional
1418 part is omitted if self.microsecond == 0.
1419
1420 The optional argument timespec specifies the number of additional
1421 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001422 """
1423 s = _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001424 self._microsecond, timespec)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001425 tz = self._tzstr()
1426 if tz:
1427 s += tz
1428 return s
1429
1430 __str__ = isoformat
1431
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001432 @classmethod
1433 def fromisoformat(cls, time_string):
1434 """Construct a time from the output of isoformat()."""
1435 if not isinstance(time_string, str):
1436 raise TypeError('fromisoformat: argument must be str')
1437
1438 try:
1439 return cls(*_parse_isoformat_time(time_string))
1440 except Exception:
Paul Ganssle3df85402018-10-22 12:32:52 -04001441 raise ValueError(f'Invalid isoformat string: {time_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001442
1443
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001444 def strftime(self, fmt):
1445 """Format using strftime(). The date part of the timestamp passed
1446 to underlying strftime should not be used.
1447 """
Alexander Belopolskyb8bb4662011-01-08 00:13:34 +00001448 # The year must be >= 1000 else Python's strftime implementation
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001449 # can raise a bogus exception.
1450 timetuple = (1900, 1, 1,
1451 self._hour, self._minute, self._second,
1452 0, 1, -1)
1453 return _wrap_strftime(self, fmt, timetuple)
1454
1455 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001456 if not isinstance(fmt, str):
1457 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001458 if len(fmt) != 0:
1459 return self.strftime(fmt)
1460 return str(self)
1461
1462 # Timezone functions
1463
1464 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001465 """Return the timezone offset as timedelta, positive east of UTC
1466 (negative west of UTC)."""
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001467 if self._tzinfo is None:
1468 return None
1469 offset = self._tzinfo.utcoffset(None)
1470 _check_utc_offset("utcoffset", offset)
1471 return offset
1472
1473 def tzname(self):
1474 """Return the timezone name.
1475
1476 Note that the name is 100% informational -- there's no requirement that
1477 it mean anything in particular. For example, "GMT", "UTC", "-500",
1478 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1479 """
1480 if self._tzinfo is None:
1481 return None
1482 name = self._tzinfo.tzname(None)
1483 _check_tzname(name)
1484 return name
1485
1486 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001487 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1488 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001489
1490 This is purely informational; the DST offset has already been added to
1491 the UTC offset returned by utcoffset() if applicable, so there's no
1492 need to consult dst() unless you're interested in displaying the DST
1493 info.
1494 """
1495 if self._tzinfo is None:
1496 return None
1497 offset = self._tzinfo.dst(None)
1498 _check_utc_offset("dst", offset)
1499 return offset
1500
1501 def replace(self, hour=None, minute=None, second=None, microsecond=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001502 tzinfo=True, *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001503 """Return a new time with new values for the specified fields."""
1504 if hour is None:
1505 hour = self.hour
1506 if minute is None:
1507 minute = self.minute
1508 if second is None:
1509 second = self.second
1510 if microsecond is None:
1511 microsecond = self.microsecond
1512 if tzinfo is True:
1513 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001514 if fold is None:
1515 fold = self._fold
Paul Ganssle191e9932017-11-09 16:34:29 -05001516 return type(self)(hour, minute, second, microsecond, tzinfo, fold=fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001517
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001518 # Pickle support.
1519
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001520 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001521 us2, us3 = divmod(self._microsecond, 256)
1522 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001523 h = self._hour
1524 if self._fold and protocol > 3:
1525 h += 128
1526 basestate = bytes([h, self._minute, self._second,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001527 us1, us2, us3])
1528 if self._tzinfo is None:
1529 return (basestate,)
1530 else:
1531 return (basestate, self._tzinfo)
1532
1533 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001534 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1535 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001536 h, self._minute, self._second, us1, us2, us3 = string
1537 if h > 127:
1538 self._fold = 1
1539 self._hour = h - 128
1540 else:
1541 self._fold = 0
1542 self._hour = h
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001543 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001544 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001545
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001546 def __reduce_ex__(self, protocol):
1547 return (time, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001548
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001549 def __reduce__(self):
1550 return self.__reduce_ex__(2)
1551
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001552_time_class = time # so functions w/ args named "time" can get at the class
1553
1554time.min = time(0, 0, 0)
1555time.max = time(23, 59, 59, 999999)
1556time.resolution = timedelta(microseconds=1)
1557
1558class datetime(date):
1559 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1560
1561 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001562 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001563 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001564 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001565
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001566 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001567 microsecond=0, tzinfo=None, *, fold=0):
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001568 if (isinstance(year, (bytes, str)) and len(year) == 10 and
1569 1 <= ord(year[2:3])&0x7F <= 12):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001570 # Pickle support
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001571 if isinstance(year, str):
1572 try:
1573 year = bytes(year, 'latin1')
1574 except UnicodeEncodeError:
1575 # More informative error message.
1576 raise ValueError(
1577 "Failed to encode latin1 string when unpickling "
1578 "a datetime object. "
1579 "pickle.load(data, encoding='latin1') is assumed.")
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001580 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001581 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001582 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001583 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001584 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001585 hour, minute, second, microsecond, fold = _check_time_fields(
1586 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001587 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001588 self = object.__new__(cls)
1589 self._year = year
1590 self._month = month
1591 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001592 self._hour = hour
1593 self._minute = minute
1594 self._second = second
1595 self._microsecond = microsecond
1596 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001597 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001598 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001599 return self
1600
1601 # Read-only field accessors
1602 @property
1603 def hour(self):
1604 """hour (0-23)"""
1605 return self._hour
1606
1607 @property
1608 def minute(self):
1609 """minute (0-59)"""
1610 return self._minute
1611
1612 @property
1613 def second(self):
1614 """second (0-59)"""
1615 return self._second
1616
1617 @property
1618 def microsecond(self):
1619 """microsecond (0-999999)"""
1620 return self._microsecond
1621
1622 @property
1623 def tzinfo(self):
1624 """timezone info object"""
1625 return self._tzinfo
1626
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001627 @property
1628 def fold(self):
1629 return self._fold
1630
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001631 @classmethod
Victor Stinneradfefa52015-09-04 23:57:25 +02001632 def _fromtimestamp(cls, t, utc, tz):
1633 """Construct a datetime from a POSIX timestamp (like time.time()).
1634
1635 A timezone info object may be passed in as well.
1636 """
1637 frac, t = _math.modf(t)
Victor Stinner7667f582015-09-09 01:02:23 +02001638 us = round(frac * 1e6)
Victor Stinneradfefa52015-09-04 23:57:25 +02001639 if us >= 1000000:
1640 t += 1
1641 us -= 1000000
1642 elif us < 0:
1643 t -= 1
1644 us += 1000000
1645
1646 converter = _time.gmtime if utc else _time.localtime
1647 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1648 ss = min(ss, 59) # clamp out leap seconds if the platform has them
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001649 result = cls(y, m, d, hh, mm, ss, us, tz)
1650 if tz is None:
1651 # As of version 2015f max fold in IANA database is
1652 # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
1653 # Let's probe 24 hours in the past to detect a transition:
1654 max_fold_seconds = 24 * 3600
Ammar Askar96d1e692018-07-25 09:54:58 -07001655
1656 # On Windows localtime_s throws an OSError for negative values,
1657 # thus we can't perform fold detection for values of time less
1658 # than the max time fold. See comments in _datetimemodule's
1659 # version of this method for more details.
1660 if t < max_fold_seconds and sys.platform.startswith("win"):
1661 return result
1662
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001663 y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1664 probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1665 trans = result - probe1 - timedelta(0, max_fold_seconds)
1666 if trans.days < 0:
1667 y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
1668 probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1669 if probe2 == result:
1670 result._fold = 1
1671 else:
1672 result = tz.fromutc(result)
1673 return result
Victor Stinneradfefa52015-09-04 23:57:25 +02001674
1675 @classmethod
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001676 def fromtimestamp(cls, t, tz=None):
1677 """Construct a datetime from a POSIX timestamp (like time.time()).
1678
1679 A timezone info object may be passed in as well.
1680 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001681 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001682
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001683 return cls._fromtimestamp(t, tz is not None, tz)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001684
1685 @classmethod
1686 def utcfromtimestamp(cls, t):
Alexander Belopolskye2e178e2015-03-01 14:52:07 -05001687 """Construct a naive UTC datetime from a POSIX timestamp."""
Victor Stinneradfefa52015-09-04 23:57:25 +02001688 return cls._fromtimestamp(t, True, None)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001689
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001690 @classmethod
1691 def now(cls, tz=None):
1692 "Construct a datetime from time.time() and optional time zone info."
1693 t = _time.time()
1694 return cls.fromtimestamp(t, tz)
1695
1696 @classmethod
1697 def utcnow(cls):
1698 "Construct a UTC datetime from time.time()."
1699 t = _time.time()
1700 return cls.utcfromtimestamp(t)
1701
1702 @classmethod
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001703 def combine(cls, date, time, tzinfo=True):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001704 "Construct a datetime from a given date and a given time."
1705 if not isinstance(date, _date_class):
1706 raise TypeError("date argument must be a date instance")
1707 if not isinstance(time, _time_class):
1708 raise TypeError("time argument must be a time instance")
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001709 if tzinfo is True:
1710 tzinfo = time.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001711 return cls(date.year, date.month, date.day,
1712 time.hour, time.minute, time.second, time.microsecond,
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001713 tzinfo, fold=time.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001714
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001715 @classmethod
1716 def fromisoformat(cls, date_string):
1717 """Construct a datetime from the output of datetime.isoformat()."""
1718 if not isinstance(date_string, str):
1719 raise TypeError('fromisoformat: argument must be str')
1720
1721 # Split this at the separator
1722 dstr = date_string[0:10]
1723 tstr = date_string[11:]
1724
1725 try:
1726 date_components = _parse_isoformat_date(dstr)
1727 except ValueError:
Paul Ganssle3df85402018-10-22 12:32:52 -04001728 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001729
1730 if tstr:
1731 try:
1732 time_components = _parse_isoformat_time(tstr)
1733 except ValueError:
Paul Ganssle3df85402018-10-22 12:32:52 -04001734 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001735 else:
1736 time_components = [0, 0, 0, 0, None]
1737
1738 return cls(*(date_components + time_components))
1739
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001740 def timetuple(self):
1741 "Return local time tuple compatible with time.localtime()."
1742 dst = self.dst()
1743 if dst is None:
1744 dst = -1
1745 elif dst:
1746 dst = 1
1747 else:
1748 dst = 0
1749 return _build_struct_time(self.year, self.month, self.day,
1750 self.hour, self.minute, self.second,
1751 dst)
1752
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001753 def _mktime(self):
1754 """Return integer POSIX timestamp."""
1755 epoch = datetime(1970, 1, 1)
1756 max_fold_seconds = 24 * 3600
1757 t = (self - epoch) // timedelta(0, 1)
1758 def local(u):
1759 y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1760 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1761
1762 # Our goal is to solve t = local(u) for u.
1763 a = local(t) - t
1764 u1 = t - a
1765 t1 = local(u1)
1766 if t1 == t:
1767 # We found one solution, but it may not be the one we need.
1768 # Look for an earlier solution (if `fold` is 0), or a
1769 # later one (if `fold` is 1).
1770 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1771 b = local(u2) - u2
1772 if a == b:
1773 return u1
1774 else:
1775 b = t1 - u1
1776 assert a != b
1777 u2 = t - b
1778 t2 = local(u2)
1779 if t2 == t:
1780 return u2
1781 if t1 == t:
1782 return u1
1783 # We have found both offsets a and b, but neither t - a nor t - b is
1784 # a solution. This means t is in the gap.
1785 return (max, min)[self.fold](u1, u2)
1786
1787
Alexander Belopolskya4415142012-06-08 12:33:09 -04001788 def timestamp(self):
1789 "Return POSIX timestamp as float"
1790 if self._tzinfo is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001791 s = self._mktime()
1792 return s + self.microsecond / 1e6
Alexander Belopolskya4415142012-06-08 12:33:09 -04001793 else:
1794 return (self - _EPOCH).total_seconds()
1795
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001796 def utctimetuple(self):
1797 "Return UTC time tuple compatible with time.gmtime()."
1798 offset = self.utcoffset()
1799 if offset:
1800 self -= offset
1801 y, m, d = self.year, self.month, self.day
1802 hh, mm, ss = self.hour, self.minute, self.second
1803 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1804
1805 def date(self):
1806 "Return the date part."
1807 return date(self._year, self._month, self._day)
1808
1809 def time(self):
1810 "Return the time part, with tzinfo None."
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001811 return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001812
1813 def timetz(self):
1814 "Return the time part, with same tzinfo."
1815 return time(self.hour, self.minute, self.second, self.microsecond,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001816 self._tzinfo, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001817
1818 def replace(self, year=None, month=None, day=None, hour=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001819 minute=None, second=None, microsecond=None, tzinfo=True,
1820 *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001821 """Return a new datetime with new values for the specified fields."""
1822 if year is None:
1823 year = self.year
1824 if month is None:
1825 month = self.month
1826 if day is None:
1827 day = self.day
1828 if hour is None:
1829 hour = self.hour
1830 if minute is None:
1831 minute = self.minute
1832 if second is None:
1833 second = self.second
1834 if microsecond is None:
1835 microsecond = self.microsecond
1836 if tzinfo is True:
1837 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001838 if fold is None:
1839 fold = self.fold
Paul Ganssle191e9932017-11-09 16:34:29 -05001840 return type(self)(year, month, day, hour, minute, second,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001841 microsecond, tzinfo, fold=fold)
1842
1843 def _local_timezone(self):
1844 if self.tzinfo is None:
1845 ts = self._mktime()
1846 else:
1847 ts = (self - _EPOCH) // timedelta(seconds=1)
1848 localtm = _time.localtime(ts)
1849 local = datetime(*localtm[:6])
Alexander Belopolskybcb032e2018-06-08 19:22:33 -04001850 # Extract TZ data
1851 gmtoff = localtm.tm_gmtoff
1852 zone = localtm.tm_zone
1853 return timezone(timedelta(seconds=gmtoff), zone)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001854
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001855 def astimezone(self, tz=None):
1856 if tz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001857 tz = self._local_timezone()
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001858 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001859 raise TypeError("tz argument must be an instance of tzinfo")
1860
1861 mytz = self.tzinfo
1862 if mytz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001863 mytz = self._local_timezone()
Alexander Belopolsky877b2322018-06-10 17:02:58 -04001864 myoffset = mytz.utcoffset(self)
1865 else:
1866 myoffset = mytz.utcoffset(self)
1867 if myoffset is None:
1868 mytz = self.replace(tzinfo=None)._local_timezone()
1869 myoffset = mytz.utcoffset(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001870
1871 if tz is mytz:
1872 return self
1873
1874 # Convert self to UTC, and attach the new time zone object.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001875 utc = (self - myoffset).replace(tzinfo=tz)
1876
1877 # Convert from UTC to tz's local time.
1878 return tz.fromutc(utc)
1879
1880 # Ways to produce a string.
1881
1882 def ctime(self):
1883 "Return ctime() style string."
1884 weekday = self.toordinal() % 7 or 7
1885 return "%s %s %2d %02d:%02d:%02d %04d" % (
1886 _DAYNAMES[weekday],
1887 _MONTHNAMES[self._month],
1888 self._day,
1889 self._hour, self._minute, self._second,
1890 self._year)
1891
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001892 def isoformat(self, sep='T', timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001893 """Return the time formatted according to ISO.
1894
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001895 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1896 By default, the fractional part is omitted if self.microsecond == 0.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001897
1898 If self.tzinfo is not None, the UTC offset is also attached, giving
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001899 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001900
1901 Optional argument sep specifies the separator between date and
1902 time, default 'T'.
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001903
1904 The optional argument timespec specifies the number of additional
1905 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001906 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001907 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1908 _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001909 self._microsecond, timespec))
1910
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001911 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001912 tz = _format_offset(off)
1913 if tz:
1914 s += tz
1915
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001916 return s
1917
1918 def __repr__(self):
1919 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001920 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001921 self._hour, self._minute, self._second, self._microsecond]
1922 if L[-1] == 0:
1923 del L[-1]
1924 if L[-1] == 0:
1925 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001926 s = "%s.%s(%s)" % (self.__class__.__module__,
1927 self.__class__.__qualname__,
1928 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001929 if self._tzinfo is not None:
1930 assert s[-1:] == ")"
1931 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001932 if self._fold:
1933 assert s[-1:] == ")"
1934 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001935 return s
1936
1937 def __str__(self):
1938 "Convert to string, for str()."
1939 return self.isoformat(sep=' ')
1940
1941 @classmethod
1942 def strptime(cls, date_string, format):
1943 'string, format -> new datetime parsed from a string (like time.strptime()).'
1944 import _strptime
1945 return _strptime._strptime_datetime(cls, date_string, format)
1946
1947 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001948 """Return the timezone offset as timedelta positive east of UTC (negative west of
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001949 UTC)."""
1950 if self._tzinfo is None:
1951 return None
1952 offset = self._tzinfo.utcoffset(self)
1953 _check_utc_offset("utcoffset", offset)
1954 return offset
1955
1956 def tzname(self):
1957 """Return the timezone name.
1958
1959 Note that the name is 100% informational -- there's no requirement that
1960 it mean anything in particular. For example, "GMT", "UTC", "-500",
1961 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1962 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001963 if self._tzinfo is None:
1964 return None
1965 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001966 _check_tzname(name)
1967 return name
1968
1969 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001970 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1971 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001972
1973 This is purely informational; the DST offset has already been added to
1974 the UTC offset returned by utcoffset() if applicable, so there's no
1975 need to consult dst() unless you're interested in displaying the DST
1976 info.
1977 """
1978 if self._tzinfo is None:
1979 return None
1980 offset = self._tzinfo.dst(self)
1981 _check_utc_offset("dst", offset)
1982 return offset
1983
1984 # Comparisons of datetime objects with other.
1985
1986 def __eq__(self, other):
1987 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001988 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001989 elif not isinstance(other, date):
1990 return NotImplemented
1991 else:
1992 return False
1993
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001994 def __le__(self, other):
1995 if isinstance(other, datetime):
1996 return self._cmp(other) <= 0
1997 elif not isinstance(other, date):
1998 return NotImplemented
1999 else:
2000 _cmperror(self, other)
2001
2002 def __lt__(self, other):
2003 if isinstance(other, datetime):
2004 return self._cmp(other) < 0
2005 elif not isinstance(other, date):
2006 return NotImplemented
2007 else:
2008 _cmperror(self, other)
2009
2010 def __ge__(self, other):
2011 if isinstance(other, datetime):
2012 return self._cmp(other) >= 0
2013 elif not isinstance(other, date):
2014 return NotImplemented
2015 else:
2016 _cmperror(self, other)
2017
2018 def __gt__(self, other):
2019 if isinstance(other, datetime):
2020 return self._cmp(other) > 0
2021 elif not isinstance(other, date):
2022 return NotImplemented
2023 else:
2024 _cmperror(self, other)
2025
Alexander Belopolsky08313822012-06-15 20:19:47 -04002026 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002027 assert isinstance(other, datetime)
2028 mytz = self._tzinfo
2029 ottz = other._tzinfo
2030 myoff = otoff = None
2031
2032 if mytz is ottz:
2033 base_compare = True
2034 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04002035 myoff = self.utcoffset()
2036 otoff = other.utcoffset()
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002037 # Assume that allow_mixed means that we are called from __eq__
2038 if allow_mixed:
2039 if myoff != self.replace(fold=not self.fold).utcoffset():
2040 return 2
2041 if otoff != other.replace(fold=not other.fold).utcoffset():
2042 return 2
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002043 base_compare = myoff == otoff
2044
2045 if base_compare:
2046 return _cmp((self._year, self._month, self._day,
2047 self._hour, self._minute, self._second,
2048 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002049 (other._year, other._month, other._day,
2050 other._hour, other._minute, other._second,
2051 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002052 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04002053 if allow_mixed:
2054 return 2 # arbitrary non-zero value
2055 else:
2056 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002057 # XXX What follows could be done more efficiently...
2058 diff = self - other # this will take offsets into account
2059 if diff.days < 0:
2060 return -1
2061 return diff and 1 or 0
2062
2063 def __add__(self, other):
2064 "Add a datetime and a timedelta."
2065 if not isinstance(other, timedelta):
2066 return NotImplemented
2067 delta = timedelta(self.toordinal(),
2068 hours=self._hour,
2069 minutes=self._minute,
2070 seconds=self._second,
2071 microseconds=self._microsecond)
2072 delta += other
2073 hour, rem = divmod(delta.seconds, 3600)
2074 minute, second = divmod(rem, 60)
2075 if 0 < delta.days <= _MAXORDINAL:
Paul Ganssle89427cd2019-02-04 14:42:04 -05002076 return type(self).combine(date.fromordinal(delta.days),
2077 time(hour, minute, second,
2078 delta.microseconds,
2079 tzinfo=self._tzinfo))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002080 raise OverflowError("result out of range")
2081
2082 __radd__ = __add__
2083
2084 def __sub__(self, other):
2085 "Subtract two datetimes, or a datetime and a timedelta."
2086 if not isinstance(other, datetime):
2087 if isinstance(other, timedelta):
2088 return self + -other
2089 return NotImplemented
2090
2091 days1 = self.toordinal()
2092 days2 = other.toordinal()
2093 secs1 = self._second + self._minute * 60 + self._hour * 3600
2094 secs2 = other._second + other._minute * 60 + other._hour * 3600
2095 base = timedelta(days1 - days2,
2096 secs1 - secs2,
2097 self._microsecond - other._microsecond)
2098 if self._tzinfo is other._tzinfo:
2099 return base
2100 myoff = self.utcoffset()
2101 otoff = other.utcoffset()
2102 if myoff == otoff:
2103 return base
2104 if myoff is None or otoff is None:
2105 raise TypeError("cannot mix naive and timezone-aware time")
2106 return base + otoff - myoff
2107
2108 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002109 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002110 if self.fold:
2111 t = self.replace(fold=0)
2112 else:
2113 t = self
2114 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002115 if tzoff is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002116 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002117 else:
2118 days = _ymd2ord(self.year, self.month, self.day)
2119 seconds = self.hour * 3600 + self.minute * 60 + self.second
2120 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
2121 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002122
2123 # Pickle support.
2124
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002125 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002126 yhi, ylo = divmod(self._year, 256)
2127 us2, us3 = divmod(self._microsecond, 256)
2128 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002129 m = self._month
2130 if self._fold and protocol > 3:
2131 m += 128
2132 basestate = bytes([yhi, ylo, m, self._day,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002133 self._hour, self._minute, self._second,
2134 us1, us2, us3])
2135 if self._tzinfo is None:
2136 return (basestate,)
2137 else:
2138 return (basestate, self._tzinfo)
2139
2140 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002141 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
2142 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002143 (yhi, ylo, m, self._day, self._hour,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002144 self._minute, self._second, us1, us2, us3) = string
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002145 if m > 127:
2146 self._fold = 1
2147 self._month = m - 128
2148 else:
2149 self._fold = 0
2150 self._month = m
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002151 self._year = yhi * 256 + ylo
2152 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002153 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002154
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002155 def __reduce_ex__(self, protocol):
2156 return (self.__class__, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002157
Serhiy Storchaka546ce652016-11-22 00:29:42 +02002158 def __reduce__(self):
2159 return self.__reduce_ex__(2)
2160
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002161
2162datetime.min = datetime(1, 1, 1)
2163datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
2164datetime.resolution = timedelta(microseconds=1)
2165
2166
2167def _isoweek1monday(year):
2168 # Helper to calculate the day number of the Monday starting week 1
2169 # XXX This could be done more efficiently
2170 THURSDAY = 3
2171 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002172 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002173 week1monday = firstday - firstweekday
2174 if firstweekday > THURSDAY:
2175 week1monday += 7
2176 return week1monday
2177
Paul Ganssle88c09372019-04-29 09:22:03 -04002178
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002179class timezone(tzinfo):
2180 __slots__ = '_offset', '_name'
2181
2182 # Sentinel value to disallow None
2183 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002184 def __new__(cls, offset, name=_Omitted):
2185 if not isinstance(offset, timedelta):
2186 raise TypeError("offset must be a timedelta")
2187 if name is cls._Omitted:
2188 if not offset:
2189 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002190 name = None
2191 elif not isinstance(name, str):
2192 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002193 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002194 raise ValueError("offset must be a timedelta "
2195 "strictly between -timedelta(hours=24) and "
2196 "timedelta(hours=24).")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002197 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002198
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002199 @classmethod
2200 def _create(cls, offset, name=None):
2201 self = tzinfo.__new__(cls)
2202 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002203 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002204 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002205
2206 def __getinitargs__(self):
2207 """pickle support"""
2208 if self._name is None:
2209 return (self._offset,)
2210 return (self._offset, self._name)
2211
2212 def __eq__(self, other):
Georg Brandl0085a242012-09-22 09:23:12 +02002213 if type(other) != timezone:
2214 return False
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002215 return self._offset == other._offset
2216
2217 def __hash__(self):
2218 return hash(self._offset)
2219
2220 def __repr__(self):
2221 """Convert to formal string, for repr().
2222
2223 >>> tz = timezone.utc
2224 >>> repr(tz)
2225 'datetime.timezone.utc'
2226 >>> tz = timezone(timedelta(hours=-5), 'EST')
2227 >>> repr(tz)
2228 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
2229 """
2230 if self is self.utc:
2231 return 'datetime.timezone.utc'
2232 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03002233 return "%s.%s(%r)" % (self.__class__.__module__,
2234 self.__class__.__qualname__,
2235 self._offset)
2236 return "%s.%s(%r, %r)" % (self.__class__.__module__,
2237 self.__class__.__qualname__,
2238 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002239
2240 def __str__(self):
2241 return self.tzname(None)
2242
2243 def utcoffset(self, dt):
2244 if isinstance(dt, datetime) or dt is None:
2245 return self._offset
2246 raise TypeError("utcoffset() argument must be a datetime instance"
2247 " or None")
2248
2249 def tzname(self, dt):
2250 if isinstance(dt, datetime) or dt is None:
2251 if self._name is None:
2252 return self._name_from_offset(self._offset)
2253 return self._name
2254 raise TypeError("tzname() argument must be a datetime instance"
2255 " or None")
2256
2257 def dst(self, dt):
2258 if isinstance(dt, datetime) or dt is None:
2259 return None
2260 raise TypeError("dst() argument must be a datetime instance"
2261 " or None")
2262
2263 def fromutc(self, dt):
2264 if isinstance(dt, datetime):
2265 if dt.tzinfo is not self:
2266 raise ValueError("fromutc: dt.tzinfo "
2267 "is not self")
2268 return dt + self._offset
2269 raise TypeError("fromutc() argument must be a datetime instance"
2270 " or None")
2271
2272 _maxoffset = timedelta(hours=23, minutes=59)
2273 _minoffset = -_maxoffset
2274
2275 @staticmethod
2276 def _name_from_offset(delta):
Alexander Belopolsky7827a5b2015-09-06 13:07:21 -04002277 if not delta:
2278 return 'UTC'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002279 if delta < timedelta(0):
2280 sign = '-'
2281 delta = -delta
2282 else:
2283 sign = '+'
2284 hours, rest = divmod(delta, timedelta(hours=1))
Alexander Belopolsky018d3532017-07-31 10:26:50 -04002285 minutes, rest = divmod(rest, timedelta(minutes=1))
2286 seconds = rest.seconds
2287 microseconds = rest.microseconds
2288 if microseconds:
2289 return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2290 f'.{microseconds:06d}')
2291 if seconds:
2292 return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2293 return f'UTC{sign}{hours:02d}:{minutes:02d}'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002294
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002295timezone.utc = timezone._create(timedelta(0))
2296timezone.min = timezone._create(timezone._minoffset)
2297timezone.max = timezone._create(timezone._maxoffset)
Alexander Belopolskya4415142012-06-08 12:33:09 -04002298_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002299
Victor Stinner765531d2013-03-26 01:11:54 +01002300# Some time zone algebra. For a datetime x, let
2301# x.n = x stripped of its timezone -- its naive time.
2302# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2303# return None
2304# x.d = x.dst(), and assuming that doesn't raise an exception or
2305# return None
2306# x.s = x's standard offset, x.o - x.d
2307#
2308# Now some derived rules, where k is a duration (timedelta).
2309#
2310# 1. x.o = x.s + x.d
2311# This follows from the definition of x.s.
2312#
2313# 2. If x and y have the same tzinfo member, x.s = y.s.
2314# This is actually a requirement, an assumption we need to make about
2315# sane tzinfo classes.
2316#
2317# 3. The naive UTC time corresponding to x is x.n - x.o.
2318# This is again a requirement for a sane tzinfo class.
2319#
2320# 4. (x+k).s = x.s
2321# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
2322#
2323# 5. (x+k).n = x.n + k
2324# Again follows from how arithmetic is defined.
2325#
2326# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
2327# (meaning that the various tzinfo methods exist, and don't blow up or return
2328# None when called).
2329#
2330# The function wants to return a datetime y with timezone tz, equivalent to x.
2331# x is already in UTC.
2332#
2333# By #3, we want
2334#
2335# y.n - y.o = x.n [1]
2336#
2337# The algorithm starts by attaching tz to x.n, and calling that y. So
2338# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
2339# becomes true; in effect, we want to solve [2] for k:
2340#
2341# (y+k).n - (y+k).o = x.n [2]
2342#
2343# By #1, this is the same as
2344#
2345# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
2346#
2347# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2348# Substituting that into [3],
2349#
2350# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2351# k - (y+k).s - (y+k).d = 0; rearranging,
2352# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2353# k = y.s - (y+k).d
2354#
2355# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2356# approximate k by ignoring the (y+k).d term at first. Note that k can't be
2357# very large, since all offset-returning methods return a duration of magnitude
2358# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
2359# be 0, so ignoring it has no consequence then.
2360#
2361# In any case, the new value is
2362#
2363# z = y + y.s [4]
2364#
2365# It's helpful to step back at look at [4] from a higher level: it's simply
2366# mapping from UTC to tz's standard time.
2367#
2368# At this point, if
2369#
2370# z.n - z.o = x.n [5]
2371#
2372# we have an equivalent time, and are almost done. The insecurity here is
2373# at the start of daylight time. Picture US Eastern for concreteness. The wall
2374# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2375# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2376# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2377# on the day DST starts. We want to return the 1:MM EST spelling because that's
2378# the only spelling that makes sense on the local wall clock.
2379#
2380# In fact, if [5] holds at this point, we do have the standard-time spelling,
2381# but that takes a bit of proof. We first prove a stronger result. What's the
2382# difference between the LHS and RHS of [5]? Let
2383#
2384# diff = x.n - (z.n - z.o) [6]
2385#
2386# Now
2387# z.n = by [4]
2388# (y + y.s).n = by #5
2389# y.n + y.s = since y.n = x.n
2390# x.n + y.s = since z and y are have the same tzinfo member,
2391# y.s = z.s by #2
2392# x.n + z.s
2393#
2394# Plugging that back into [6] gives
2395#
2396# diff =
2397# x.n - ((x.n + z.s) - z.o) = expanding
2398# x.n - x.n - z.s + z.o = cancelling
2399# - z.s + z.o = by #2
2400# z.d
2401#
2402# So diff = z.d.
2403#
2404# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2405# spelling we wanted in the endcase described above. We're done. Contrarily,
2406# if z.d = 0, then we have a UTC equivalent, and are also done.
2407#
2408# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2409# add to z (in effect, z is in tz's standard time, and we need to shift the
2410# local clock into tz's daylight time).
2411#
2412# Let
2413#
2414# z' = z + z.d = z + diff [7]
2415#
2416# and we can again ask whether
2417#
2418# z'.n - z'.o = x.n [8]
2419#
2420# If so, we're done. If not, the tzinfo class is insane, according to the
2421# assumptions we've made. This also requires a bit of proof. As before, let's
2422# compute the difference between the LHS and RHS of [8] (and skipping some of
2423# the justifications for the kinds of substitutions we've done several times
2424# already):
2425#
2426# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2427# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2428# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2429# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2430# - z.n + z.n - z.o + z'.o = cancel z.n
2431# - z.o + z'.o = #1 twice
2432# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2433# z'.d - z.d
2434#
2435# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2436# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2437# return z', not bothering to compute z'.d.
2438#
2439# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2440# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2441# would have to change the result dst() returns: we start in DST, and moving
2442# a little further into it takes us out of DST.
2443#
2444# There isn't a sane case where this can happen. The closest it gets is at
2445# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2446# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2447# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2448# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2449# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2450# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2451# standard time. Since that's what the local clock *does*, we want to map both
2452# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2453# in local time, but so it goes -- it's the way the local clock works.
2454#
2455# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2456# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2457# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2458# (correctly) concludes that z' is not UTC-equivalent to x.
2459#
2460# Because we know z.d said z was in daylight time (else [5] would have held and
2461# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2462# and we have stopped then), and there are only 2 possible values dst() can
2463# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2464# but the reasoning doesn't depend on the example -- it depends on there being
2465# two possible dst() outcomes, one zero and the other non-zero). Therefore
2466# z' must be in standard time, and is the spelling we want in this case.
2467#
2468# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2469# concerned (because it takes z' as being in standard time rather than the
2470# daylight time we intend here), but returning it gives the real-life "local
2471# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2472# tz.
2473#
2474# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2475# the 1:MM standard time spelling we want.
2476#
2477# So how can this break? One of the assumptions must be violated. Two
2478# possibilities:
2479#
2480# 1) [2] effectively says that y.s is invariant across all y belong to a given
2481# time zone. This isn't true if, for political reasons or continental drift,
2482# a region decides to change its base offset from UTC.
2483#
2484# 2) There may be versions of "double daylight" time where the tail end of
2485# the analysis gives up a step too early. I haven't thought about that
2486# enough to say.
2487#
2488# In any case, it's clear that the default fromutc() is strong enough to handle
2489# "almost all" time zones: so long as the standard offset is invariant, it
2490# doesn't matter if daylight time transition points change from year to year, or
2491# if daylight time is skipped in some years; it doesn't matter how large or
2492# small dst() may get within its bounds; and it doesn't even matter if some
2493# perverse time zone returns a negative dst()). So a breaking case must be
2494# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002495
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002496try:
2497 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002498except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002499 pass
2500else:
2501 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002502 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2503 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2504 _check_date_fields, _check_int_field, _check_time_fields,
2505 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2506 _date_class, _days_before_month, _days_before_year, _days_in_month,
Paul Ganssle09dc2f52017-12-21 00:33:49 -05002507 _format_time, _format_offset, _is_leap, _isoweek1monday, _math,
2508 _ord2ymd, _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord,
2509 _divide_and_round, _parse_isoformat_date, _parse_isoformat_time,
2510 _parse_hh_mm_ss_ff)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002511 # XXX Since import * above excludes names that start with _,
2512 # docstring does not get overwritten. In the future, it may be
2513 # appropriate to maintain a single module level docstring and
2514 # remove the following line.
2515 from _datetime import __doc__