blob: 85bfa48e05dea4bc9a145efe632c8f0d38e67b33 [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:
736 return False
737
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
887
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000888 # Conversions to string
889
890 def __repr__(self):
891 """Convert to formal string, for repr().
892
893 >>> dt = datetime(2010, 1, 1)
894 >>> repr(dt)
895 'datetime.datetime(2010, 1, 1, 0, 0)'
896
897 >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
898 >>> repr(dt)
899 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
900 """
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300901 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
902 self.__class__.__qualname__,
903 self._year,
904 self._month,
905 self._day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000906 # XXX These shouldn't depend on time.localtime(), because that
907 # clips the usable dates to [1970 .. 2038). At least ctime() is
908 # easily done without using strftime() -- that's better too because
909 # strftime("%c", ...) is locale specific.
910
911
912 def ctime(self):
913 "Return ctime() style string."
914 weekday = self.toordinal() % 7 or 7
915 return "%s %s %2d 00:00:00 %04d" % (
916 _DAYNAMES[weekday],
917 _MONTHNAMES[self._month],
918 self._day, self._year)
919
920 def strftime(self, fmt):
921 "Format using strftime()."
922 return _wrap_strftime(self, fmt, self.timetuple())
923
924 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400925 if not isinstance(fmt, str):
926 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000927 if len(fmt) != 0:
928 return self.strftime(fmt)
929 return str(self)
930
931 def isoformat(self):
932 """Return the date formatted according to ISO.
933
934 This is 'YYYY-MM-DD'.
935
936 References:
937 - http://www.w3.org/TR/NOTE-datetime
938 - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
939 """
940 return "%04d-%02d-%02d" % (self._year, self._month, self._day)
941
942 __str__ = isoformat
943
944 # Read-only field accessors
945 @property
946 def year(self):
947 """year (1-9999)"""
948 return self._year
949
950 @property
951 def month(self):
952 """month (1-12)"""
953 return self._month
954
955 @property
956 def day(self):
957 """day (1-31)"""
958 return self._day
959
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200960 # Standard conversions, __eq__, __le__, __lt__, __ge__, __gt__,
961 # __hash__ (and helpers)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000962
963 def timetuple(self):
964 "Return local time tuple compatible with time.localtime()."
965 return _build_struct_time(self._year, self._month, self._day,
966 0, 0, 0, -1)
967
968 def toordinal(self):
969 """Return proleptic Gregorian ordinal for the year, month and day.
970
971 January 1 of year 1 is day 1. Only the year, month and day values
972 contribute to the result.
973 """
974 return _ymd2ord(self._year, self._month, self._day)
975
976 def replace(self, year=None, month=None, day=None):
977 """Return a new date with new values for the specified fields."""
978 if year is None:
979 year = self._year
980 if month is None:
981 month = self._month
982 if day is None:
983 day = self._day
Paul Ganssle191e9932017-11-09 16:34:29 -0500984 return type(self)(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000985
986 # Comparisons of date objects with other.
987
988 def __eq__(self, other):
989 if isinstance(other, date):
990 return self._cmp(other) == 0
991 return NotImplemented
992
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000993 def __le__(self, other):
994 if isinstance(other, date):
995 return self._cmp(other) <= 0
996 return NotImplemented
997
998 def __lt__(self, other):
999 if isinstance(other, date):
1000 return self._cmp(other) < 0
1001 return NotImplemented
1002
1003 def __ge__(self, other):
1004 if isinstance(other, date):
1005 return self._cmp(other) >= 0
1006 return NotImplemented
1007
1008 def __gt__(self, other):
1009 if isinstance(other, date):
1010 return self._cmp(other) > 0
1011 return NotImplemented
1012
1013 def _cmp(self, other):
1014 assert isinstance(other, date)
1015 y, m, d = self._year, self._month, self._day
1016 y2, m2, d2 = other._year, other._month, other._day
1017 return _cmp((y, m, d), (y2, m2, d2))
1018
1019 def __hash__(self):
1020 "Hash."
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001021 if self._hashcode == -1:
1022 self._hashcode = hash(self._getstate())
1023 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001024
1025 # Computations
1026
1027 def __add__(self, other):
1028 "Add a date to a timedelta."
1029 if isinstance(other, timedelta):
1030 o = self.toordinal() + other.days
1031 if 0 < o <= _MAXORDINAL:
Paul Ganssle89427cd2019-02-04 14:42:04 -05001032 return type(self).fromordinal(o)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001033 raise OverflowError("result out of range")
1034 return NotImplemented
1035
1036 __radd__ = __add__
1037
1038 def __sub__(self, other):
1039 """Subtract two dates, or a date and a timedelta."""
1040 if isinstance(other, timedelta):
1041 return self + timedelta(-other.days)
1042 if isinstance(other, date):
1043 days1 = self.toordinal()
1044 days2 = other.toordinal()
1045 return timedelta(days1 - days2)
1046 return NotImplemented
1047
1048 def weekday(self):
1049 "Return day of the week, where Monday == 0 ... Sunday == 6."
1050 return (self.toordinal() + 6) % 7
1051
1052 # Day-of-the-week and week-of-the-year, according to ISO
1053
1054 def isoweekday(self):
1055 "Return day of the week, where Monday == 1 ... Sunday == 7."
1056 # 1-Jan-0001 is a Monday
1057 return self.toordinal() % 7 or 7
1058
1059 def isocalendar(self):
1060 """Return a 3-tuple containing ISO year, week number, and weekday.
1061
1062 The first ISO week of the year is the (Mon-Sun) week
1063 containing the year's first Thursday; everything else derives
1064 from that.
1065
1066 The first week is 1; Monday is 1 ... Sunday is 7.
1067
1068 ISO calendar algorithm taken from
1069 http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
Brett Cannon07b954d2016-01-15 09:53:51 -08001070 (used with permission)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001071 """
1072 year = self._year
1073 week1monday = _isoweek1monday(year)
1074 today = _ymd2ord(self._year, self._month, self._day)
1075 # Internally, week and day have origin 0
1076 week, day = divmod(today - week1monday, 7)
1077 if week < 0:
1078 year -= 1
1079 week1monday = _isoweek1monday(year)
1080 week, day = divmod(today - week1monday, 7)
1081 elif week >= 52:
1082 if today >= _isoweek1monday(year+1):
1083 year += 1
1084 week = 0
1085 return year, week+1, day+1
1086
1087 # Pickle support.
1088
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001089 def _getstate(self):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001090 yhi, ylo = divmod(self._year, 256)
1091 return bytes([yhi, ylo, self._month, self._day]),
1092
1093 def __setstate(self, string):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001094 yhi, ylo, self._month, self._day = string
1095 self._year = yhi * 256 + ylo
1096
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001097 def __reduce__(self):
1098 return (self.__class__, self._getstate())
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001099
1100_date_class = date # so functions w/ args named "date" can get at the class
1101
1102date.min = date(1, 1, 1)
1103date.max = date(9999, 12, 31)
1104date.resolution = timedelta(days=1)
1105
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001106
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001107class tzinfo:
1108 """Abstract base class for time zone info classes.
1109
1110 Subclasses must override the name(), utcoffset() and dst() methods.
1111 """
1112 __slots__ = ()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001113
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001114 def tzname(self, dt):
1115 "datetime -> string name of time zone."
1116 raise NotImplementedError("tzinfo subclass must override tzname()")
1117
1118 def utcoffset(self, dt):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001119 "datetime -> timedelta, positive for east of UTC, negative for west of UTC"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001120 raise NotImplementedError("tzinfo subclass must override utcoffset()")
1121
1122 def dst(self, dt):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001123 """datetime -> DST offset as timedelta, positive for east of UTC.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001124
1125 Return 0 if DST not in effect. utcoffset() must include the DST
1126 offset.
1127 """
1128 raise NotImplementedError("tzinfo subclass must override dst()")
1129
1130 def fromutc(self, dt):
1131 "datetime in UTC -> datetime in local time."
1132
1133 if not isinstance(dt, datetime):
1134 raise TypeError("fromutc() requires a datetime argument")
1135 if dt.tzinfo is not self:
1136 raise ValueError("dt.tzinfo is not self")
1137
1138 dtoff = dt.utcoffset()
1139 if dtoff is None:
1140 raise ValueError("fromutc() requires a non-None utcoffset() "
1141 "result")
1142
1143 # See the long comment block at the end of this file for an
1144 # explanation of this algorithm.
1145 dtdst = dt.dst()
1146 if dtdst is None:
1147 raise ValueError("fromutc() requires a non-None dst() result")
1148 delta = dtoff - dtdst
1149 if delta:
1150 dt += delta
1151 dtdst = dt.dst()
1152 if dtdst is None:
1153 raise ValueError("fromutc(): dt.dst gave inconsistent "
1154 "results; cannot convert")
1155 return dt + dtdst
1156
1157 # Pickle support.
1158
1159 def __reduce__(self):
1160 getinitargs = getattr(self, "__getinitargs__", None)
1161 if getinitargs:
1162 args = getinitargs()
1163 else:
1164 args = ()
1165 getstate = getattr(self, "__getstate__", None)
1166 if getstate:
1167 state = getstate()
1168 else:
1169 state = getattr(self, "__dict__", None) or None
1170 if state is None:
1171 return (self.__class__, args)
1172 else:
1173 return (self.__class__, args, state)
1174
1175_tzinfo_class = tzinfo
1176
1177class time:
1178 """Time with time zone.
1179
1180 Constructors:
1181
1182 __new__()
1183
1184 Operators:
1185
1186 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +02001187 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001188
1189 Methods:
1190
1191 strftime()
1192 isoformat()
1193 utcoffset()
1194 tzname()
1195 dst()
1196
1197 Properties (readonly):
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001198 hour, minute, second, microsecond, tzinfo, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001199 """
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001200 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode', '_fold'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001201
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001202 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001203 """Constructor.
1204
1205 Arguments:
1206
1207 hour, minute (required)
1208 second, microsecond (default to zero)
1209 tzinfo (default to None)
Victor Stinner51b90d22017-01-04 12:01:16 +01001210 fold (keyword only, default to zero)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001211 """
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001212 if (isinstance(hour, (bytes, str)) and len(hour) == 6 and
1213 ord(hour[0:1])&0x7F < 24):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001214 # Pickle support
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001215 if isinstance(hour, str):
1216 try:
1217 hour = hour.encode('latin1')
1218 except UnicodeEncodeError:
1219 # More informative error message.
1220 raise ValueError(
1221 "Failed to encode latin1 string when unpickling "
1222 "a time object. "
1223 "pickle.load(data, encoding='latin1') is assumed.")
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001224 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001225 self.__setstate(hour, minute or None)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001226 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001227 return self
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001228 hour, minute, second, microsecond, fold = _check_time_fields(
1229 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001230 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001231 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001232 self._hour = hour
1233 self._minute = minute
1234 self._second = second
1235 self._microsecond = microsecond
1236 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001237 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001238 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001239 return self
1240
1241 # Read-only field accessors
1242 @property
1243 def hour(self):
1244 """hour (0-23)"""
1245 return self._hour
1246
1247 @property
1248 def minute(self):
1249 """minute (0-59)"""
1250 return self._minute
1251
1252 @property
1253 def second(self):
1254 """second (0-59)"""
1255 return self._second
1256
1257 @property
1258 def microsecond(self):
1259 """microsecond (0-999999)"""
1260 return self._microsecond
1261
1262 @property
1263 def tzinfo(self):
1264 """timezone info object"""
1265 return self._tzinfo
1266
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001267 @property
1268 def fold(self):
1269 return self._fold
1270
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001271 # Standard conversions, __hash__ (and helpers)
1272
1273 # Comparisons of time objects with other.
1274
1275 def __eq__(self, other):
1276 if isinstance(other, time):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001277 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001278 else:
1279 return False
1280
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001281 def __le__(self, other):
1282 if isinstance(other, time):
1283 return self._cmp(other) <= 0
1284 else:
1285 _cmperror(self, other)
1286
1287 def __lt__(self, other):
1288 if isinstance(other, time):
1289 return self._cmp(other) < 0
1290 else:
1291 _cmperror(self, other)
1292
1293 def __ge__(self, other):
1294 if isinstance(other, time):
1295 return self._cmp(other) >= 0
1296 else:
1297 _cmperror(self, other)
1298
1299 def __gt__(self, other):
1300 if isinstance(other, time):
1301 return self._cmp(other) > 0
1302 else:
1303 _cmperror(self, other)
1304
Alexander Belopolsky08313822012-06-15 20:19:47 -04001305 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001306 assert isinstance(other, time)
1307 mytz = self._tzinfo
1308 ottz = other._tzinfo
1309 myoff = otoff = None
1310
1311 if mytz is ottz:
1312 base_compare = True
1313 else:
1314 myoff = self.utcoffset()
1315 otoff = other.utcoffset()
1316 base_compare = myoff == otoff
1317
1318 if base_compare:
1319 return _cmp((self._hour, self._minute, self._second,
1320 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001321 (other._hour, other._minute, other._second,
1322 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001323 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001324 if allow_mixed:
1325 return 2 # arbitrary non-zero value
1326 else:
1327 raise TypeError("cannot compare naive and aware times")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001328 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1329 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1330 return _cmp((myhhmm, self._second, self._microsecond),
1331 (othhmm, other._second, other._microsecond))
1332
1333 def __hash__(self):
1334 """Hash."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001335 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001336 if self.fold:
1337 t = self.replace(fold=0)
1338 else:
1339 t = self
1340 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001341 if not tzoff: # zero or None
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001342 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001343 else:
1344 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1345 timedelta(hours=1))
1346 assert not m % timedelta(minutes=1), "whole minute"
1347 m //= timedelta(minutes=1)
1348 if 0 <= h < 24:
1349 self._hashcode = hash(time(h, m, self.second, self.microsecond))
1350 else:
1351 self._hashcode = hash((h, m, self.second, self.microsecond))
1352 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001353
1354 # Conversion to string
1355
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001356 def _tzstr(self):
1357 """Return formatted timezone offset (+xx:xx) or an empty string."""
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001358 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001359 return _format_offset(off)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001360
1361 def __repr__(self):
1362 """Convert to formal string, for repr()."""
1363 if self._microsecond != 0:
1364 s = ", %d, %d" % (self._second, self._microsecond)
1365 elif self._second != 0:
1366 s = ", %d" % self._second
1367 else:
1368 s = ""
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001369 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1370 self.__class__.__qualname__,
1371 self._hour, self._minute, s)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001372 if self._tzinfo is not None:
1373 assert s[-1:] == ")"
1374 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001375 if self._fold:
1376 assert s[-1:] == ")"
1377 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001378 return s
1379
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001380 def isoformat(self, timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001381 """Return the time formatted according to ISO.
1382
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001383 The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional
1384 part is omitted if self.microsecond == 0.
1385
1386 The optional argument timespec specifies the number of additional
1387 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001388 """
1389 s = _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001390 self._microsecond, timespec)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001391 tz = self._tzstr()
1392 if tz:
1393 s += tz
1394 return s
1395
1396 __str__ = isoformat
1397
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001398 @classmethod
1399 def fromisoformat(cls, time_string):
1400 """Construct a time from the output of isoformat()."""
1401 if not isinstance(time_string, str):
1402 raise TypeError('fromisoformat: argument must be str')
1403
1404 try:
1405 return cls(*_parse_isoformat_time(time_string))
1406 except Exception:
Paul Ganssle3df85402018-10-22 12:32:52 -04001407 raise ValueError(f'Invalid isoformat string: {time_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001408
1409
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001410 def strftime(self, fmt):
1411 """Format using strftime(). The date part of the timestamp passed
1412 to underlying strftime should not be used.
1413 """
Alexander Belopolskyb8bb4662011-01-08 00:13:34 +00001414 # The year must be >= 1000 else Python's strftime implementation
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001415 # can raise a bogus exception.
1416 timetuple = (1900, 1, 1,
1417 self._hour, self._minute, self._second,
1418 0, 1, -1)
1419 return _wrap_strftime(self, fmt, timetuple)
1420
1421 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001422 if not isinstance(fmt, str):
1423 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001424 if len(fmt) != 0:
1425 return self.strftime(fmt)
1426 return str(self)
1427
1428 # Timezone functions
1429
1430 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001431 """Return the timezone offset as timedelta, positive east of UTC
1432 (negative west of UTC)."""
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001433 if self._tzinfo is None:
1434 return None
1435 offset = self._tzinfo.utcoffset(None)
1436 _check_utc_offset("utcoffset", offset)
1437 return offset
1438
1439 def tzname(self):
1440 """Return the timezone name.
1441
1442 Note that the name is 100% informational -- there's no requirement that
1443 it mean anything in particular. For example, "GMT", "UTC", "-500",
1444 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1445 """
1446 if self._tzinfo is None:
1447 return None
1448 name = self._tzinfo.tzname(None)
1449 _check_tzname(name)
1450 return name
1451
1452 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001453 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1454 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001455
1456 This is purely informational; the DST offset has already been added to
1457 the UTC offset returned by utcoffset() if applicable, so there's no
1458 need to consult dst() unless you're interested in displaying the DST
1459 info.
1460 """
1461 if self._tzinfo is None:
1462 return None
1463 offset = self._tzinfo.dst(None)
1464 _check_utc_offset("dst", offset)
1465 return offset
1466
1467 def replace(self, hour=None, minute=None, second=None, microsecond=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001468 tzinfo=True, *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001469 """Return a new time with new values for the specified fields."""
1470 if hour is None:
1471 hour = self.hour
1472 if minute is None:
1473 minute = self.minute
1474 if second is None:
1475 second = self.second
1476 if microsecond is None:
1477 microsecond = self.microsecond
1478 if tzinfo is True:
1479 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001480 if fold is None:
1481 fold = self._fold
Paul Ganssle191e9932017-11-09 16:34:29 -05001482 return type(self)(hour, minute, second, microsecond, tzinfo, fold=fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001483
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001484 # Pickle support.
1485
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001486 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001487 us2, us3 = divmod(self._microsecond, 256)
1488 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001489 h = self._hour
1490 if self._fold and protocol > 3:
1491 h += 128
1492 basestate = bytes([h, self._minute, self._second,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001493 us1, us2, us3])
1494 if self._tzinfo is None:
1495 return (basestate,)
1496 else:
1497 return (basestate, self._tzinfo)
1498
1499 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001500 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1501 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001502 h, self._minute, self._second, us1, us2, us3 = string
1503 if h > 127:
1504 self._fold = 1
1505 self._hour = h - 128
1506 else:
1507 self._fold = 0
1508 self._hour = h
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001509 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001510 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001511
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001512 def __reduce_ex__(self, protocol):
1513 return (time, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001514
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001515 def __reduce__(self):
1516 return self.__reduce_ex__(2)
1517
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001518_time_class = time # so functions w/ args named "time" can get at the class
1519
1520time.min = time(0, 0, 0)
1521time.max = time(23, 59, 59, 999999)
1522time.resolution = timedelta(microseconds=1)
1523
1524class datetime(date):
1525 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1526
1527 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001528 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001529 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001530 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001531
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001532 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001533 microsecond=0, tzinfo=None, *, fold=0):
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001534 if (isinstance(year, (bytes, str)) and len(year) == 10 and
1535 1 <= ord(year[2:3])&0x7F <= 12):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001536 # Pickle support
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001537 if isinstance(year, str):
1538 try:
1539 year = bytes(year, 'latin1')
1540 except UnicodeEncodeError:
1541 # More informative error message.
1542 raise ValueError(
1543 "Failed to encode latin1 string when unpickling "
1544 "a datetime object. "
1545 "pickle.load(data, encoding='latin1') is assumed.")
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001546 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001547 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001548 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001549 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001550 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001551 hour, minute, second, microsecond, fold = _check_time_fields(
1552 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001553 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001554 self = object.__new__(cls)
1555 self._year = year
1556 self._month = month
1557 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001558 self._hour = hour
1559 self._minute = minute
1560 self._second = second
1561 self._microsecond = microsecond
1562 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001563 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001564 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001565 return self
1566
1567 # Read-only field accessors
1568 @property
1569 def hour(self):
1570 """hour (0-23)"""
1571 return self._hour
1572
1573 @property
1574 def minute(self):
1575 """minute (0-59)"""
1576 return self._minute
1577
1578 @property
1579 def second(self):
1580 """second (0-59)"""
1581 return self._second
1582
1583 @property
1584 def microsecond(self):
1585 """microsecond (0-999999)"""
1586 return self._microsecond
1587
1588 @property
1589 def tzinfo(self):
1590 """timezone info object"""
1591 return self._tzinfo
1592
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001593 @property
1594 def fold(self):
1595 return self._fold
1596
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001597 @classmethod
Victor Stinneradfefa52015-09-04 23:57:25 +02001598 def _fromtimestamp(cls, t, utc, tz):
1599 """Construct a datetime from a POSIX timestamp (like time.time()).
1600
1601 A timezone info object may be passed in as well.
1602 """
1603 frac, t = _math.modf(t)
Victor Stinner7667f582015-09-09 01:02:23 +02001604 us = round(frac * 1e6)
Victor Stinneradfefa52015-09-04 23:57:25 +02001605 if us >= 1000000:
1606 t += 1
1607 us -= 1000000
1608 elif us < 0:
1609 t -= 1
1610 us += 1000000
1611
1612 converter = _time.gmtime if utc else _time.localtime
1613 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1614 ss = min(ss, 59) # clamp out leap seconds if the platform has them
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001615 result = cls(y, m, d, hh, mm, ss, us, tz)
1616 if tz is None:
1617 # As of version 2015f max fold in IANA database is
1618 # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
1619 # Let's probe 24 hours in the past to detect a transition:
1620 max_fold_seconds = 24 * 3600
Ammar Askar96d1e692018-07-25 09:54:58 -07001621
1622 # On Windows localtime_s throws an OSError for negative values,
1623 # thus we can't perform fold detection for values of time less
1624 # than the max time fold. See comments in _datetimemodule's
1625 # version of this method for more details.
1626 if t < max_fold_seconds and sys.platform.startswith("win"):
1627 return result
1628
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001629 y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1630 probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1631 trans = result - probe1 - timedelta(0, max_fold_seconds)
1632 if trans.days < 0:
1633 y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
1634 probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1635 if probe2 == result:
1636 result._fold = 1
1637 else:
1638 result = tz.fromutc(result)
1639 return result
Victor Stinneradfefa52015-09-04 23:57:25 +02001640
1641 @classmethod
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001642 def fromtimestamp(cls, t, tz=None):
1643 """Construct a datetime from a POSIX timestamp (like time.time()).
1644
1645 A timezone info object may be passed in as well.
1646 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001647 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001648
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001649 return cls._fromtimestamp(t, tz is not None, tz)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001650
1651 @classmethod
1652 def utcfromtimestamp(cls, t):
Alexander Belopolskye2e178e2015-03-01 14:52:07 -05001653 """Construct a naive UTC datetime from a POSIX timestamp."""
Victor Stinneradfefa52015-09-04 23:57:25 +02001654 return cls._fromtimestamp(t, True, None)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001655
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001656 @classmethod
1657 def now(cls, tz=None):
1658 "Construct a datetime from time.time() and optional time zone info."
1659 t = _time.time()
1660 return cls.fromtimestamp(t, tz)
1661
1662 @classmethod
1663 def utcnow(cls):
1664 "Construct a UTC datetime from time.time()."
1665 t = _time.time()
1666 return cls.utcfromtimestamp(t)
1667
1668 @classmethod
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001669 def combine(cls, date, time, tzinfo=True):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001670 "Construct a datetime from a given date and a given time."
1671 if not isinstance(date, _date_class):
1672 raise TypeError("date argument must be a date instance")
1673 if not isinstance(time, _time_class):
1674 raise TypeError("time argument must be a time instance")
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001675 if tzinfo is True:
1676 tzinfo = time.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001677 return cls(date.year, date.month, date.day,
1678 time.hour, time.minute, time.second, time.microsecond,
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001679 tzinfo, fold=time.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001680
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001681 @classmethod
1682 def fromisoformat(cls, date_string):
1683 """Construct a datetime from the output of datetime.isoformat()."""
1684 if not isinstance(date_string, str):
1685 raise TypeError('fromisoformat: argument must be str')
1686
1687 # Split this at the separator
1688 dstr = date_string[0:10]
1689 tstr = date_string[11:]
1690
1691 try:
1692 date_components = _parse_isoformat_date(dstr)
1693 except ValueError:
Paul Ganssle3df85402018-10-22 12:32:52 -04001694 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001695
1696 if tstr:
1697 try:
1698 time_components = _parse_isoformat_time(tstr)
1699 except ValueError:
Paul Ganssle3df85402018-10-22 12:32:52 -04001700 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001701 else:
1702 time_components = [0, 0, 0, 0, None]
1703
1704 return cls(*(date_components + time_components))
1705
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001706 def timetuple(self):
1707 "Return local time tuple compatible with time.localtime()."
1708 dst = self.dst()
1709 if dst is None:
1710 dst = -1
1711 elif dst:
1712 dst = 1
1713 else:
1714 dst = 0
1715 return _build_struct_time(self.year, self.month, self.day,
1716 self.hour, self.minute, self.second,
1717 dst)
1718
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001719 def _mktime(self):
1720 """Return integer POSIX timestamp."""
1721 epoch = datetime(1970, 1, 1)
1722 max_fold_seconds = 24 * 3600
1723 t = (self - epoch) // timedelta(0, 1)
1724 def local(u):
1725 y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1726 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1727
1728 # Our goal is to solve t = local(u) for u.
1729 a = local(t) - t
1730 u1 = t - a
1731 t1 = local(u1)
1732 if t1 == t:
1733 # We found one solution, but it may not be the one we need.
1734 # Look for an earlier solution (if `fold` is 0), or a
1735 # later one (if `fold` is 1).
1736 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1737 b = local(u2) - u2
1738 if a == b:
1739 return u1
1740 else:
1741 b = t1 - u1
1742 assert a != b
1743 u2 = t - b
1744 t2 = local(u2)
1745 if t2 == t:
1746 return u2
1747 if t1 == t:
1748 return u1
1749 # We have found both offsets a and b, but neither t - a nor t - b is
1750 # a solution. This means t is in the gap.
1751 return (max, min)[self.fold](u1, u2)
1752
1753
Alexander Belopolskya4415142012-06-08 12:33:09 -04001754 def timestamp(self):
1755 "Return POSIX timestamp as float"
1756 if self._tzinfo is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001757 s = self._mktime()
1758 return s + self.microsecond / 1e6
Alexander Belopolskya4415142012-06-08 12:33:09 -04001759 else:
1760 return (self - _EPOCH).total_seconds()
1761
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001762 def utctimetuple(self):
1763 "Return UTC time tuple compatible with time.gmtime()."
1764 offset = self.utcoffset()
1765 if offset:
1766 self -= offset
1767 y, m, d = self.year, self.month, self.day
1768 hh, mm, ss = self.hour, self.minute, self.second
1769 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1770
1771 def date(self):
1772 "Return the date part."
1773 return date(self._year, self._month, self._day)
1774
1775 def time(self):
1776 "Return the time part, with tzinfo None."
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001777 return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001778
1779 def timetz(self):
1780 "Return the time part, with same tzinfo."
1781 return time(self.hour, self.minute, self.second, self.microsecond,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001782 self._tzinfo, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001783
1784 def replace(self, year=None, month=None, day=None, hour=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001785 minute=None, second=None, microsecond=None, tzinfo=True,
1786 *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001787 """Return a new datetime with new values for the specified fields."""
1788 if year is None:
1789 year = self.year
1790 if month is None:
1791 month = self.month
1792 if day is None:
1793 day = self.day
1794 if hour is None:
1795 hour = self.hour
1796 if minute is None:
1797 minute = self.minute
1798 if second is None:
1799 second = self.second
1800 if microsecond is None:
1801 microsecond = self.microsecond
1802 if tzinfo is True:
1803 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001804 if fold is None:
1805 fold = self.fold
Paul Ganssle191e9932017-11-09 16:34:29 -05001806 return type(self)(year, month, day, hour, minute, second,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001807 microsecond, tzinfo, fold=fold)
1808
1809 def _local_timezone(self):
1810 if self.tzinfo is None:
1811 ts = self._mktime()
1812 else:
1813 ts = (self - _EPOCH) // timedelta(seconds=1)
1814 localtm = _time.localtime(ts)
1815 local = datetime(*localtm[:6])
Alexander Belopolskybcb032e2018-06-08 19:22:33 -04001816 # Extract TZ data
1817 gmtoff = localtm.tm_gmtoff
1818 zone = localtm.tm_zone
1819 return timezone(timedelta(seconds=gmtoff), zone)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001820
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001821 def astimezone(self, tz=None):
1822 if tz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001823 tz = self._local_timezone()
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001824 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001825 raise TypeError("tz argument must be an instance of tzinfo")
1826
1827 mytz = self.tzinfo
1828 if mytz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001829 mytz = self._local_timezone()
Alexander Belopolsky877b2322018-06-10 17:02:58 -04001830 myoffset = mytz.utcoffset(self)
1831 else:
1832 myoffset = mytz.utcoffset(self)
1833 if myoffset is None:
1834 mytz = self.replace(tzinfo=None)._local_timezone()
1835 myoffset = mytz.utcoffset(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001836
1837 if tz is mytz:
1838 return self
1839
1840 # Convert self to UTC, and attach the new time zone object.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001841 utc = (self - myoffset).replace(tzinfo=tz)
1842
1843 # Convert from UTC to tz's local time.
1844 return tz.fromutc(utc)
1845
1846 # Ways to produce a string.
1847
1848 def ctime(self):
1849 "Return ctime() style string."
1850 weekday = self.toordinal() % 7 or 7
1851 return "%s %s %2d %02d:%02d:%02d %04d" % (
1852 _DAYNAMES[weekday],
1853 _MONTHNAMES[self._month],
1854 self._day,
1855 self._hour, self._minute, self._second,
1856 self._year)
1857
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001858 def isoformat(self, sep='T', timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001859 """Return the time formatted according to ISO.
1860
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001861 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1862 By default, the fractional part is omitted if self.microsecond == 0.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001863
1864 If self.tzinfo is not None, the UTC offset is also attached, giving
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001865 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001866
1867 Optional argument sep specifies the separator between date and
1868 time, default 'T'.
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001869
1870 The optional argument timespec specifies the number of additional
1871 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001872 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001873 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1874 _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001875 self._microsecond, timespec))
1876
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001877 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001878 tz = _format_offset(off)
1879 if tz:
1880 s += tz
1881
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001882 return s
1883
1884 def __repr__(self):
1885 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001886 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001887 self._hour, self._minute, self._second, self._microsecond]
1888 if L[-1] == 0:
1889 del L[-1]
1890 if L[-1] == 0:
1891 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001892 s = "%s.%s(%s)" % (self.__class__.__module__,
1893 self.__class__.__qualname__,
1894 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001895 if self._tzinfo is not None:
1896 assert s[-1:] == ")"
1897 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001898 if self._fold:
1899 assert s[-1:] == ")"
1900 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001901 return s
1902
1903 def __str__(self):
1904 "Convert to string, for str()."
1905 return self.isoformat(sep=' ')
1906
1907 @classmethod
1908 def strptime(cls, date_string, format):
1909 'string, format -> new datetime parsed from a string (like time.strptime()).'
1910 import _strptime
1911 return _strptime._strptime_datetime(cls, date_string, format)
1912
1913 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001914 """Return the timezone offset as timedelta positive east of UTC (negative west of
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001915 UTC)."""
1916 if self._tzinfo is None:
1917 return None
1918 offset = self._tzinfo.utcoffset(self)
1919 _check_utc_offset("utcoffset", offset)
1920 return offset
1921
1922 def tzname(self):
1923 """Return the timezone name.
1924
1925 Note that the name is 100% informational -- there's no requirement that
1926 it mean anything in particular. For example, "GMT", "UTC", "-500",
1927 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1928 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001929 if self._tzinfo is None:
1930 return None
1931 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001932 _check_tzname(name)
1933 return name
1934
1935 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001936 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1937 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001938
1939 This is purely informational; the DST offset has already been added to
1940 the UTC offset returned by utcoffset() if applicable, so there's no
1941 need to consult dst() unless you're interested in displaying the DST
1942 info.
1943 """
1944 if self._tzinfo is None:
1945 return None
1946 offset = self._tzinfo.dst(self)
1947 _check_utc_offset("dst", offset)
1948 return offset
1949
1950 # Comparisons of datetime objects with other.
1951
1952 def __eq__(self, other):
1953 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001954 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001955 elif not isinstance(other, date):
1956 return NotImplemented
1957 else:
1958 return False
1959
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001960 def __le__(self, other):
1961 if isinstance(other, datetime):
1962 return self._cmp(other) <= 0
1963 elif not isinstance(other, date):
1964 return NotImplemented
1965 else:
1966 _cmperror(self, other)
1967
1968 def __lt__(self, other):
1969 if isinstance(other, datetime):
1970 return self._cmp(other) < 0
1971 elif not isinstance(other, date):
1972 return NotImplemented
1973 else:
1974 _cmperror(self, other)
1975
1976 def __ge__(self, other):
1977 if isinstance(other, datetime):
1978 return self._cmp(other) >= 0
1979 elif not isinstance(other, date):
1980 return NotImplemented
1981 else:
1982 _cmperror(self, other)
1983
1984 def __gt__(self, other):
1985 if isinstance(other, datetime):
1986 return self._cmp(other) > 0
1987 elif not isinstance(other, date):
1988 return NotImplemented
1989 else:
1990 _cmperror(self, other)
1991
Alexander Belopolsky08313822012-06-15 20:19:47 -04001992 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001993 assert isinstance(other, datetime)
1994 mytz = self._tzinfo
1995 ottz = other._tzinfo
1996 myoff = otoff = None
1997
1998 if mytz is ottz:
1999 base_compare = True
2000 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04002001 myoff = self.utcoffset()
2002 otoff = other.utcoffset()
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002003 # Assume that allow_mixed means that we are called from __eq__
2004 if allow_mixed:
2005 if myoff != self.replace(fold=not self.fold).utcoffset():
2006 return 2
2007 if otoff != other.replace(fold=not other.fold).utcoffset():
2008 return 2
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002009 base_compare = myoff == otoff
2010
2011 if base_compare:
2012 return _cmp((self._year, self._month, self._day,
2013 self._hour, self._minute, self._second,
2014 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002015 (other._year, other._month, other._day,
2016 other._hour, other._minute, other._second,
2017 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002018 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04002019 if allow_mixed:
2020 return 2 # arbitrary non-zero value
2021 else:
2022 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002023 # XXX What follows could be done more efficiently...
2024 diff = self - other # this will take offsets into account
2025 if diff.days < 0:
2026 return -1
2027 return diff and 1 or 0
2028
2029 def __add__(self, other):
2030 "Add a datetime and a timedelta."
2031 if not isinstance(other, timedelta):
2032 return NotImplemented
2033 delta = timedelta(self.toordinal(),
2034 hours=self._hour,
2035 minutes=self._minute,
2036 seconds=self._second,
2037 microseconds=self._microsecond)
2038 delta += other
2039 hour, rem = divmod(delta.seconds, 3600)
2040 minute, second = divmod(rem, 60)
2041 if 0 < delta.days <= _MAXORDINAL:
Paul Ganssle89427cd2019-02-04 14:42:04 -05002042 return type(self).combine(date.fromordinal(delta.days),
2043 time(hour, minute, second,
2044 delta.microseconds,
2045 tzinfo=self._tzinfo))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002046 raise OverflowError("result out of range")
2047
2048 __radd__ = __add__
2049
2050 def __sub__(self, other):
2051 "Subtract two datetimes, or a datetime and a timedelta."
2052 if not isinstance(other, datetime):
2053 if isinstance(other, timedelta):
2054 return self + -other
2055 return NotImplemented
2056
2057 days1 = self.toordinal()
2058 days2 = other.toordinal()
2059 secs1 = self._second + self._minute * 60 + self._hour * 3600
2060 secs2 = other._second + other._minute * 60 + other._hour * 3600
2061 base = timedelta(days1 - days2,
2062 secs1 - secs2,
2063 self._microsecond - other._microsecond)
2064 if self._tzinfo is other._tzinfo:
2065 return base
2066 myoff = self.utcoffset()
2067 otoff = other.utcoffset()
2068 if myoff == otoff:
2069 return base
2070 if myoff is None or otoff is None:
2071 raise TypeError("cannot mix naive and timezone-aware time")
2072 return base + otoff - myoff
2073
2074 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002075 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002076 if self.fold:
2077 t = self.replace(fold=0)
2078 else:
2079 t = self
2080 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002081 if tzoff is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002082 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002083 else:
2084 days = _ymd2ord(self.year, self.month, self.day)
2085 seconds = self.hour * 3600 + self.minute * 60 + self.second
2086 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
2087 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002088
2089 # Pickle support.
2090
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002091 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002092 yhi, ylo = divmod(self._year, 256)
2093 us2, us3 = divmod(self._microsecond, 256)
2094 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002095 m = self._month
2096 if self._fold and protocol > 3:
2097 m += 128
2098 basestate = bytes([yhi, ylo, m, self._day,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002099 self._hour, self._minute, self._second,
2100 us1, us2, us3])
2101 if self._tzinfo is None:
2102 return (basestate,)
2103 else:
2104 return (basestate, self._tzinfo)
2105
2106 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002107 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
2108 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002109 (yhi, ylo, m, self._day, self._hour,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002110 self._minute, self._second, us1, us2, us3) = string
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002111 if m > 127:
2112 self._fold = 1
2113 self._month = m - 128
2114 else:
2115 self._fold = 0
2116 self._month = m
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002117 self._year = yhi * 256 + ylo
2118 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002119 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002120
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002121 def __reduce_ex__(self, protocol):
2122 return (self.__class__, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002123
Serhiy Storchaka546ce652016-11-22 00:29:42 +02002124 def __reduce__(self):
2125 return self.__reduce_ex__(2)
2126
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002127
2128datetime.min = datetime(1, 1, 1)
2129datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
2130datetime.resolution = timedelta(microseconds=1)
2131
2132
2133def _isoweek1monday(year):
2134 # Helper to calculate the day number of the Monday starting week 1
2135 # XXX This could be done more efficiently
2136 THURSDAY = 3
2137 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002138 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002139 week1monday = firstday - firstweekday
2140 if firstweekday > THURSDAY:
2141 week1monday += 7
2142 return week1monday
2143
2144class timezone(tzinfo):
2145 __slots__ = '_offset', '_name'
2146
2147 # Sentinel value to disallow None
2148 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002149 def __new__(cls, offset, name=_Omitted):
2150 if not isinstance(offset, timedelta):
2151 raise TypeError("offset must be a timedelta")
2152 if name is cls._Omitted:
2153 if not offset:
2154 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002155 name = None
2156 elif not isinstance(name, str):
2157 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002158 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002159 raise ValueError("offset must be a timedelta "
2160 "strictly between -timedelta(hours=24) and "
2161 "timedelta(hours=24).")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002162 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002163
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002164 @classmethod
2165 def _create(cls, offset, name=None):
2166 self = tzinfo.__new__(cls)
2167 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002168 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002169 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002170
2171 def __getinitargs__(self):
2172 """pickle support"""
2173 if self._name is None:
2174 return (self._offset,)
2175 return (self._offset, self._name)
2176
2177 def __eq__(self, other):
Georg Brandl0085a242012-09-22 09:23:12 +02002178 if type(other) != timezone:
2179 return False
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002180 return self._offset == other._offset
2181
2182 def __hash__(self):
2183 return hash(self._offset)
2184
2185 def __repr__(self):
2186 """Convert to formal string, for repr().
2187
2188 >>> tz = timezone.utc
2189 >>> repr(tz)
2190 'datetime.timezone.utc'
2191 >>> tz = timezone(timedelta(hours=-5), 'EST')
2192 >>> repr(tz)
2193 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
2194 """
2195 if self is self.utc:
2196 return 'datetime.timezone.utc'
2197 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03002198 return "%s.%s(%r)" % (self.__class__.__module__,
2199 self.__class__.__qualname__,
2200 self._offset)
2201 return "%s.%s(%r, %r)" % (self.__class__.__module__,
2202 self.__class__.__qualname__,
2203 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002204
2205 def __str__(self):
2206 return self.tzname(None)
2207
2208 def utcoffset(self, dt):
2209 if isinstance(dt, datetime) or dt is None:
2210 return self._offset
2211 raise TypeError("utcoffset() argument must be a datetime instance"
2212 " or None")
2213
2214 def tzname(self, dt):
2215 if isinstance(dt, datetime) or dt is None:
2216 if self._name is None:
2217 return self._name_from_offset(self._offset)
2218 return self._name
2219 raise TypeError("tzname() argument must be a datetime instance"
2220 " or None")
2221
2222 def dst(self, dt):
2223 if isinstance(dt, datetime) or dt is None:
2224 return None
2225 raise TypeError("dst() argument must be a datetime instance"
2226 " or None")
2227
2228 def fromutc(self, dt):
2229 if isinstance(dt, datetime):
2230 if dt.tzinfo is not self:
2231 raise ValueError("fromutc: dt.tzinfo "
2232 "is not self")
2233 return dt + self._offset
2234 raise TypeError("fromutc() argument must be a datetime instance"
2235 " or None")
2236
2237 _maxoffset = timedelta(hours=23, minutes=59)
2238 _minoffset = -_maxoffset
2239
2240 @staticmethod
2241 def _name_from_offset(delta):
Alexander Belopolsky7827a5b2015-09-06 13:07:21 -04002242 if not delta:
2243 return 'UTC'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002244 if delta < timedelta(0):
2245 sign = '-'
2246 delta = -delta
2247 else:
2248 sign = '+'
2249 hours, rest = divmod(delta, timedelta(hours=1))
Alexander Belopolsky018d3532017-07-31 10:26:50 -04002250 minutes, rest = divmod(rest, timedelta(minutes=1))
2251 seconds = rest.seconds
2252 microseconds = rest.microseconds
2253 if microseconds:
2254 return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2255 f'.{microseconds:06d}')
2256 if seconds:
2257 return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2258 return f'UTC{sign}{hours:02d}:{minutes:02d}'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002259
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002260timezone.utc = timezone._create(timedelta(0))
2261timezone.min = timezone._create(timezone._minoffset)
2262timezone.max = timezone._create(timezone._maxoffset)
Alexander Belopolskya4415142012-06-08 12:33:09 -04002263_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002264
Victor Stinner765531d2013-03-26 01:11:54 +01002265# Some time zone algebra. For a datetime x, let
2266# x.n = x stripped of its timezone -- its naive time.
2267# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2268# return None
2269# x.d = x.dst(), and assuming that doesn't raise an exception or
2270# return None
2271# x.s = x's standard offset, x.o - x.d
2272#
2273# Now some derived rules, where k is a duration (timedelta).
2274#
2275# 1. x.o = x.s + x.d
2276# This follows from the definition of x.s.
2277#
2278# 2. If x and y have the same tzinfo member, x.s = y.s.
2279# This is actually a requirement, an assumption we need to make about
2280# sane tzinfo classes.
2281#
2282# 3. The naive UTC time corresponding to x is x.n - x.o.
2283# This is again a requirement for a sane tzinfo class.
2284#
2285# 4. (x+k).s = x.s
2286# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
2287#
2288# 5. (x+k).n = x.n + k
2289# Again follows from how arithmetic is defined.
2290#
2291# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
2292# (meaning that the various tzinfo methods exist, and don't blow up or return
2293# None when called).
2294#
2295# The function wants to return a datetime y with timezone tz, equivalent to x.
2296# x is already in UTC.
2297#
2298# By #3, we want
2299#
2300# y.n - y.o = x.n [1]
2301#
2302# The algorithm starts by attaching tz to x.n, and calling that y. So
2303# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
2304# becomes true; in effect, we want to solve [2] for k:
2305#
2306# (y+k).n - (y+k).o = x.n [2]
2307#
2308# By #1, this is the same as
2309#
2310# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
2311#
2312# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2313# Substituting that into [3],
2314#
2315# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2316# k - (y+k).s - (y+k).d = 0; rearranging,
2317# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2318# k = y.s - (y+k).d
2319#
2320# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2321# approximate k by ignoring the (y+k).d term at first. Note that k can't be
2322# very large, since all offset-returning methods return a duration of magnitude
2323# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
2324# be 0, so ignoring it has no consequence then.
2325#
2326# In any case, the new value is
2327#
2328# z = y + y.s [4]
2329#
2330# It's helpful to step back at look at [4] from a higher level: it's simply
2331# mapping from UTC to tz's standard time.
2332#
2333# At this point, if
2334#
2335# z.n - z.o = x.n [5]
2336#
2337# we have an equivalent time, and are almost done. The insecurity here is
2338# at the start of daylight time. Picture US Eastern for concreteness. The wall
2339# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2340# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2341# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2342# on the day DST starts. We want to return the 1:MM EST spelling because that's
2343# the only spelling that makes sense on the local wall clock.
2344#
2345# In fact, if [5] holds at this point, we do have the standard-time spelling,
2346# but that takes a bit of proof. We first prove a stronger result. What's the
2347# difference between the LHS and RHS of [5]? Let
2348#
2349# diff = x.n - (z.n - z.o) [6]
2350#
2351# Now
2352# z.n = by [4]
2353# (y + y.s).n = by #5
2354# y.n + y.s = since y.n = x.n
2355# x.n + y.s = since z and y are have the same tzinfo member,
2356# y.s = z.s by #2
2357# x.n + z.s
2358#
2359# Plugging that back into [6] gives
2360#
2361# diff =
2362# x.n - ((x.n + z.s) - z.o) = expanding
2363# x.n - x.n - z.s + z.o = cancelling
2364# - z.s + z.o = by #2
2365# z.d
2366#
2367# So diff = z.d.
2368#
2369# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2370# spelling we wanted in the endcase described above. We're done. Contrarily,
2371# if z.d = 0, then we have a UTC equivalent, and are also done.
2372#
2373# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2374# add to z (in effect, z is in tz's standard time, and we need to shift the
2375# local clock into tz's daylight time).
2376#
2377# Let
2378#
2379# z' = z + z.d = z + diff [7]
2380#
2381# and we can again ask whether
2382#
2383# z'.n - z'.o = x.n [8]
2384#
2385# If so, we're done. If not, the tzinfo class is insane, according to the
2386# assumptions we've made. This also requires a bit of proof. As before, let's
2387# compute the difference between the LHS and RHS of [8] (and skipping some of
2388# the justifications for the kinds of substitutions we've done several times
2389# already):
2390#
2391# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2392# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2393# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2394# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2395# - z.n + z.n - z.o + z'.o = cancel z.n
2396# - z.o + z'.o = #1 twice
2397# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2398# z'.d - z.d
2399#
2400# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2401# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2402# return z', not bothering to compute z'.d.
2403#
2404# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2405# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2406# would have to change the result dst() returns: we start in DST, and moving
2407# a little further into it takes us out of DST.
2408#
2409# There isn't a sane case where this can happen. The closest it gets is at
2410# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2411# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2412# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2413# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2414# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2415# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2416# standard time. Since that's what the local clock *does*, we want to map both
2417# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2418# in local time, but so it goes -- it's the way the local clock works.
2419#
2420# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2421# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2422# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2423# (correctly) concludes that z' is not UTC-equivalent to x.
2424#
2425# Because we know z.d said z was in daylight time (else [5] would have held and
2426# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2427# and we have stopped then), and there are only 2 possible values dst() can
2428# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2429# but the reasoning doesn't depend on the example -- it depends on there being
2430# two possible dst() outcomes, one zero and the other non-zero). Therefore
2431# z' must be in standard time, and is the spelling we want in this case.
2432#
2433# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2434# concerned (because it takes z' as being in standard time rather than the
2435# daylight time we intend here), but returning it gives the real-life "local
2436# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2437# tz.
2438#
2439# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2440# the 1:MM standard time spelling we want.
2441#
2442# So how can this break? One of the assumptions must be violated. Two
2443# possibilities:
2444#
2445# 1) [2] effectively says that y.s is invariant across all y belong to a given
2446# time zone. This isn't true if, for political reasons or continental drift,
2447# a region decides to change its base offset from UTC.
2448#
2449# 2) There may be versions of "double daylight" time where the tail end of
2450# the analysis gives up a step too early. I haven't thought about that
2451# enough to say.
2452#
2453# In any case, it's clear that the default fromutc() is strong enough to handle
2454# "almost all" time zones: so long as the standard offset is invariant, it
2455# doesn't matter if daylight time transition points change from year to year, or
2456# if daylight time is skipped in some years; it doesn't matter how large or
2457# small dst() may get within its bounds; and it doesn't even matter if some
2458# perverse time zone returns a negative dst()). So a breaking case must be
2459# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002460
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002461try:
2462 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002463except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002464 pass
2465else:
2466 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002467 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2468 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2469 _check_date_fields, _check_int_field, _check_time_fields,
2470 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2471 _date_class, _days_before_month, _days_before_year, _days_in_month,
Paul Ganssle09dc2f52017-12-21 00:33:49 -05002472 _format_time, _format_offset, _is_leap, _isoweek1monday, _math,
2473 _ord2ymd, _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord,
2474 _divide_and_round, _parse_isoformat_date, _parse_isoformat_time,
2475 _parse_hh_mm_ss_ff)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002476 # XXX Since import * above excludes names that start with _,
2477 # docstring does not get overwritten. In the future, it may be
2478 # appropriate to maintain a single module level docstring and
2479 # remove the following line.
2480 from _datetime import __doc__