blob: 292919fd7988e7df959aa8cce9c076492bf4b94d [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
382 if not isinstance(value, float):
383 try:
384 value = value.__int__()
385 except AttributeError:
386 pass
387 else:
388 if isinstance(value, int):
389 return value
390 raise TypeError('__int__ returned non-int (type %s)' %
391 type(value).__name__)
392 raise TypeError('an integer is required (got type %s)' %
393 type(value).__name__)
394 raise TypeError('integer argument expected, got float')
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000395
396def _check_date_fields(year, month, day):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400397 year = _check_int_field(year)
398 month = _check_int_field(month)
399 day = _check_int_field(day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000400 if not MINYEAR <= year <= MAXYEAR:
401 raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year)
402 if not 1 <= month <= 12:
403 raise ValueError('month must be in 1..12', month)
404 dim = _days_in_month(year, month)
405 if not 1 <= day <= dim:
406 raise ValueError('day must be in 1..%d' % dim, day)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400407 return year, month, day
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000408
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400409def _check_time_fields(hour, minute, second, microsecond, fold):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400410 hour = _check_int_field(hour)
411 minute = _check_int_field(minute)
412 second = _check_int_field(second)
413 microsecond = _check_int_field(microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000414 if not 0 <= hour <= 23:
415 raise ValueError('hour must be in 0..23', hour)
416 if not 0 <= minute <= 59:
417 raise ValueError('minute must be in 0..59', minute)
418 if not 0 <= second <= 59:
419 raise ValueError('second must be in 0..59', second)
420 if not 0 <= microsecond <= 999999:
421 raise ValueError('microsecond must be in 0..999999', microsecond)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400422 if fold not in (0, 1):
423 raise ValueError('fold must be either 0 or 1', fold)
424 return hour, minute, second, microsecond, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000425
426def _check_tzinfo_arg(tz):
427 if tz is not None and not isinstance(tz, tzinfo):
428 raise TypeError("tzinfo argument must be None or of a tzinfo subclass")
429
430def _cmperror(x, y):
431 raise TypeError("can't compare '%s' to '%s'" % (
432 type(x).__name__, type(y).__name__))
433
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500434def _divide_and_round(a, b):
435 """divide a by b and round result to the nearest integer
436
437 When the ratio is exactly half-way between two integers,
438 the even integer is returned.
439 """
440 # Based on the reference implementation for divmod_near
441 # in Objects/longobject.c.
442 q, r = divmod(a, b)
443 # round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
444 # The expression r / b > 0.5 is equivalent to 2 * r > b if b is
445 # positive, 2 * r < b if b negative.
446 r *= 2
447 greater_than_half = r > b if b > 0 else r < b
448 if greater_than_half or r == b and q % 2 == 1:
449 q += 1
450
451 return q
452
Victor Stinner2ec55872015-09-02 19:16:07 +0200453
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000454class timedelta:
455 """Represent the difference between two datetime objects.
456
457 Supported operators:
458
459 - add, subtract timedelta
460 - unary plus, minus, abs
461 - compare to timedelta
Serhiy Storchaka95949422013-08-27 19:40:23 +0300462 - multiply, divide by int
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000463
464 In addition, datetime supports subtraction of two datetime objects
465 returning a timedelta, and addition or subtraction of a datetime
466 and a timedelta giving a datetime.
467
468 Representation: (days, seconds, microseconds). Why? Because I
469 felt like it.
470 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400471 __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000472
473 def __new__(cls, days=0, seconds=0, microseconds=0,
474 milliseconds=0, minutes=0, hours=0, weeks=0):
475 # Doing this efficiently and accurately in C is going to be difficult
476 # and error-prone, due to ubiquitous overflow possibilities, and that
477 # C double doesn't have enough bits of precision to represent
478 # microseconds over 10K years faithfully. The code here tries to make
479 # explicit where go-fast assumptions can be relied on, in order to
480 # guide the C implementation; it's way more convoluted than speed-
481 # ignoring auto-overflow-to-long idiomatic Python could be.
482
483 # XXX Check that all inputs are ints or floats.
484
485 # Final values, all integer.
486 # s and us fit in 32-bit signed ints; d isn't bounded.
487 d = s = us = 0
488
489 # Normalize everything to days, seconds, microseconds.
490 days += weeks*7
491 seconds += minutes*60 + hours*3600
492 microseconds += milliseconds*1000
493
494 # Get rid of all fractions, and normalize s and us.
495 # Take a deep breath <wink>.
496 if isinstance(days, float):
497 dayfrac, days = _math.modf(days)
498 daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
499 assert daysecondswhole == int(daysecondswhole) # can't overflow
500 s = int(daysecondswhole)
501 assert days == int(days)
502 d = int(days)
503 else:
504 daysecondsfrac = 0.0
505 d = days
506 assert isinstance(daysecondsfrac, float)
507 assert abs(daysecondsfrac) <= 1.0
508 assert isinstance(d, int)
509 assert abs(s) <= 24 * 3600
510 # days isn't referenced again before redefinition
511
512 if isinstance(seconds, float):
513 secondsfrac, seconds = _math.modf(seconds)
514 assert seconds == int(seconds)
515 seconds = int(seconds)
516 secondsfrac += daysecondsfrac
517 assert abs(secondsfrac) <= 2.0
518 else:
519 secondsfrac = daysecondsfrac
520 # daysecondsfrac isn't referenced again
521 assert isinstance(secondsfrac, float)
522 assert abs(secondsfrac) <= 2.0
523
524 assert isinstance(seconds, int)
525 days, seconds = divmod(seconds, 24*3600)
526 d += days
527 s += int(seconds) # can't overflow
528 assert isinstance(s, int)
529 assert abs(s) <= 2 * 24 * 3600
530 # seconds isn't referenced again before redefinition
531
532 usdouble = secondsfrac * 1e6
533 assert abs(usdouble) < 2.1e6 # exact value not critical
534 # secondsfrac isn't referenced again
535
536 if isinstance(microseconds, float):
Victor Stinner69cc4872015-09-08 23:58:54 +0200537 microseconds = round(microseconds + usdouble)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000538 seconds, microseconds = divmod(microseconds, 1000000)
539 days, seconds = divmod(seconds, 24*3600)
540 d += days
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400541 s += seconds
542 else:
543 microseconds = int(microseconds)
544 seconds, microseconds = divmod(microseconds, 1000000)
545 days, seconds = divmod(seconds, 24*3600)
546 d += days
547 s += seconds
Victor Stinner69cc4872015-09-08 23:58:54 +0200548 microseconds = round(microseconds + usdouble)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400549 assert isinstance(s, int)
550 assert isinstance(microseconds, int)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000551 assert abs(s) <= 3 * 24 * 3600
552 assert abs(microseconds) < 3.1e6
553
554 # Just a little bit of carrying possible for microseconds and seconds.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400555 seconds, us = divmod(microseconds, 1000000)
556 s += seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000557 days, s = divmod(s, 24*3600)
558 d += days
559
560 assert isinstance(d, int)
561 assert isinstance(s, int) and 0 <= s < 24*3600
562 assert isinstance(us, int) and 0 <= us < 1000000
563
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000564 if abs(d) > 999999999:
565 raise OverflowError("timedelta # of days is too large: %d" % d)
566
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400567 self = object.__new__(cls)
568 self._days = d
569 self._seconds = s
570 self._microseconds = us
571 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000572 return self
573
574 def __repr__(self):
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200575 args = []
576 if self._days:
577 args.append("days=%d" % self._days)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000578 if self._seconds:
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200579 args.append("seconds=%d" % self._seconds)
580 if self._microseconds:
581 args.append("microseconds=%d" % self._microseconds)
582 if not args:
583 args.append('0')
584 return "%s.%s(%s)" % (self.__class__.__module__,
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300585 self.__class__.__qualname__,
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200586 ', '.join(args))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000587
588 def __str__(self):
589 mm, ss = divmod(self._seconds, 60)
590 hh, mm = divmod(mm, 60)
591 s = "%d:%02d:%02d" % (hh, mm, ss)
592 if self._days:
593 def plural(n):
594 return n, abs(n) != 1 and "s" or ""
595 s = ("%d day%s, " % plural(self._days)) + s
596 if self._microseconds:
597 s = s + ".%06d" % self._microseconds
598 return s
599
600 def total_seconds(self):
601 """Total seconds in the duration."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400602 return ((self.days * 86400 + self.seconds) * 10**6 +
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000603 self.microseconds) / 10**6
604
605 # Read-only field accessors
606 @property
607 def days(self):
608 """days"""
609 return self._days
610
611 @property
612 def seconds(self):
613 """seconds"""
614 return self._seconds
615
616 @property
617 def microseconds(self):
618 """microseconds"""
619 return self._microseconds
620
621 def __add__(self, other):
622 if isinstance(other, timedelta):
623 # for CPython compatibility, we cannot use
624 # our __class__ here, but need a real timedelta
625 return timedelta(self._days + other._days,
626 self._seconds + other._seconds,
627 self._microseconds + other._microseconds)
628 return NotImplemented
629
630 __radd__ = __add__
631
632 def __sub__(self, other):
633 if isinstance(other, timedelta):
Alexander Belopolskyb6f5ec72011-04-05 20:07:38 -0400634 # for CPython compatibility, we cannot use
635 # our __class__ here, but need a real timedelta
636 return timedelta(self._days - other._days,
637 self._seconds - other._seconds,
638 self._microseconds - other._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000639 return NotImplemented
640
641 def __rsub__(self, other):
642 if isinstance(other, timedelta):
643 return -self + other
644 return NotImplemented
645
646 def __neg__(self):
647 # for CPython compatibility, we cannot use
648 # our __class__ here, but need a real timedelta
649 return timedelta(-self._days,
650 -self._seconds,
651 -self._microseconds)
652
653 def __pos__(self):
654 return self
655
656 def __abs__(self):
657 if self._days < 0:
658 return -self
659 else:
660 return self
661
662 def __mul__(self, other):
663 if isinstance(other, int):
664 # for CPython compatibility, we cannot use
665 # our __class__ here, but need a real timedelta
666 return timedelta(self._days * other,
667 self._seconds * other,
668 self._microseconds * other)
669 if isinstance(other, float):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500670 usec = self._to_microseconds()
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000671 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500672 return timedelta(0, 0, _divide_and_round(usec * a, b))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000673 return NotImplemented
674
675 __rmul__ = __mul__
676
677 def _to_microseconds(self):
678 return ((self._days * (24*3600) + self._seconds) * 1000000 +
679 self._microseconds)
680
681 def __floordiv__(self, other):
682 if not isinstance(other, (int, timedelta)):
683 return NotImplemented
684 usec = self._to_microseconds()
685 if isinstance(other, timedelta):
686 return usec // other._to_microseconds()
687 if isinstance(other, int):
688 return timedelta(0, 0, usec // other)
689
690 def __truediv__(self, other):
691 if not isinstance(other, (int, float, timedelta)):
692 return NotImplemented
693 usec = self._to_microseconds()
694 if isinstance(other, timedelta):
695 return usec / other._to_microseconds()
696 if isinstance(other, int):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500697 return timedelta(0, 0, _divide_and_round(usec, other))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000698 if isinstance(other, float):
699 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500700 return timedelta(0, 0, _divide_and_round(b * usec, a))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000701
702 def __mod__(self, other):
703 if isinstance(other, timedelta):
704 r = self._to_microseconds() % other._to_microseconds()
705 return timedelta(0, 0, r)
706 return NotImplemented
707
708 def __divmod__(self, other):
709 if isinstance(other, timedelta):
710 q, r = divmod(self._to_microseconds(),
711 other._to_microseconds())
712 return q, timedelta(0, 0, r)
713 return NotImplemented
714
715 # Comparisons of timedelta objects with other.
716
717 def __eq__(self, other):
718 if isinstance(other, timedelta):
719 return self._cmp(other) == 0
720 else:
721 return False
722
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000723 def __le__(self, other):
724 if isinstance(other, timedelta):
725 return self._cmp(other) <= 0
726 else:
727 _cmperror(self, other)
728
729 def __lt__(self, other):
730 if isinstance(other, timedelta):
731 return self._cmp(other) < 0
732 else:
733 _cmperror(self, other)
734
735 def __ge__(self, other):
736 if isinstance(other, timedelta):
737 return self._cmp(other) >= 0
738 else:
739 _cmperror(self, other)
740
741 def __gt__(self, other):
742 if isinstance(other, timedelta):
743 return self._cmp(other) > 0
744 else:
745 _cmperror(self, other)
746
747 def _cmp(self, other):
748 assert isinstance(other, timedelta)
749 return _cmp(self._getstate(), other._getstate())
750
751 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400752 if self._hashcode == -1:
753 self._hashcode = hash(self._getstate())
754 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000755
756 def __bool__(self):
757 return (self._days != 0 or
758 self._seconds != 0 or
759 self._microseconds != 0)
760
761 # Pickle support.
762
763 def _getstate(self):
764 return (self._days, self._seconds, self._microseconds)
765
766 def __reduce__(self):
767 return (self.__class__, self._getstate())
768
769timedelta.min = timedelta(-999999999)
770timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
771 microseconds=999999)
772timedelta.resolution = timedelta(microseconds=1)
773
774class date:
775 """Concrete date type.
776
777 Constructors:
778
779 __new__()
780 fromtimestamp()
781 today()
782 fromordinal()
783
784 Operators:
785
786 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200787 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000788 __add__, __radd__, __sub__ (add/radd only with timedelta arg)
789
790 Methods:
791
792 timetuple()
793 toordinal()
794 weekday()
795 isoweekday(), isocalendar(), isoformat()
796 ctime()
797 strftime()
798
799 Properties (readonly):
800 year, month, day
801 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400802 __slots__ = '_year', '_month', '_day', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000803
804 def __new__(cls, year, month=None, day=None):
805 """Constructor.
806
807 Arguments:
808
809 year, month, day (required, base 1)
810 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400811 if month is None and isinstance(year, bytes) and len(year) == 4 and \
812 1 <= year[2] <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000813 # Pickle support
814 self = object.__new__(cls)
815 self.__setstate(year)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400816 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000817 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400818 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000819 self = object.__new__(cls)
820 self._year = year
821 self._month = month
822 self._day = day
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400823 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000824 return self
825
826 # Additional constructors
827
828 @classmethod
829 def fromtimestamp(cls, t):
830 "Construct a date from a POSIX timestamp (like time.time())."
831 y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
832 return cls(y, m, d)
833
834 @classmethod
835 def today(cls):
836 "Construct a date from time.time()."
837 t = _time.time()
838 return cls.fromtimestamp(t)
839
840 @classmethod
841 def fromordinal(cls, n):
Martin Pantereb995702016-07-28 01:11:04 +0000842 """Construct a date from a proleptic Gregorian ordinal.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000843
844 January 1 of year 1 is day 1. Only the year, month and day are
845 non-zero in the result.
846 """
847 y, m, d = _ord2ymd(n)
848 return cls(y, m, d)
849
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500850 @classmethod
851 def fromisoformat(cls, date_string):
852 """Construct a date from the output of date.isoformat()."""
853 if not isinstance(date_string, str):
854 raise TypeError('fromisoformat: argument must be str')
855
856 try:
857 assert len(date_string) == 10
858 return cls(*_parse_isoformat_date(date_string))
859 except Exception:
Paul Ganssle3df85402018-10-22 12:32:52 -0400860 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500861
862
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000863 # Conversions to string
864
865 def __repr__(self):
866 """Convert to formal string, for repr().
867
868 >>> dt = datetime(2010, 1, 1)
869 >>> repr(dt)
870 'datetime.datetime(2010, 1, 1, 0, 0)'
871
872 >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
873 >>> repr(dt)
874 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
875 """
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300876 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
877 self.__class__.__qualname__,
878 self._year,
879 self._month,
880 self._day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000881 # XXX These shouldn't depend on time.localtime(), because that
882 # clips the usable dates to [1970 .. 2038). At least ctime() is
883 # easily done without using strftime() -- that's better too because
884 # strftime("%c", ...) is locale specific.
885
886
887 def ctime(self):
888 "Return ctime() style string."
889 weekday = self.toordinal() % 7 or 7
890 return "%s %s %2d 00:00:00 %04d" % (
891 _DAYNAMES[weekday],
892 _MONTHNAMES[self._month],
893 self._day, self._year)
894
895 def strftime(self, fmt):
896 "Format using strftime()."
897 return _wrap_strftime(self, fmt, self.timetuple())
898
899 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400900 if not isinstance(fmt, str):
901 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000902 if len(fmt) != 0:
903 return self.strftime(fmt)
904 return str(self)
905
906 def isoformat(self):
907 """Return the date formatted according to ISO.
908
909 This is 'YYYY-MM-DD'.
910
911 References:
912 - http://www.w3.org/TR/NOTE-datetime
913 - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
914 """
915 return "%04d-%02d-%02d" % (self._year, self._month, self._day)
916
917 __str__ = isoformat
918
919 # Read-only field accessors
920 @property
921 def year(self):
922 """year (1-9999)"""
923 return self._year
924
925 @property
926 def month(self):
927 """month (1-12)"""
928 return self._month
929
930 @property
931 def day(self):
932 """day (1-31)"""
933 return self._day
934
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200935 # Standard conversions, __eq__, __le__, __lt__, __ge__, __gt__,
936 # __hash__ (and helpers)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000937
938 def timetuple(self):
939 "Return local time tuple compatible with time.localtime()."
940 return _build_struct_time(self._year, self._month, self._day,
941 0, 0, 0, -1)
942
943 def toordinal(self):
944 """Return proleptic Gregorian ordinal for the year, month and day.
945
946 January 1 of year 1 is day 1. Only the year, month and day values
947 contribute to the result.
948 """
949 return _ymd2ord(self._year, self._month, self._day)
950
951 def replace(self, year=None, month=None, day=None):
952 """Return a new date with new values for the specified fields."""
953 if year is None:
954 year = self._year
955 if month is None:
956 month = self._month
957 if day is None:
958 day = self._day
Paul Ganssle191e9932017-11-09 16:34:29 -0500959 return type(self)(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000960
961 # Comparisons of date objects with other.
962
963 def __eq__(self, other):
964 if isinstance(other, date):
965 return self._cmp(other) == 0
966 return NotImplemented
967
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000968 def __le__(self, other):
969 if isinstance(other, date):
970 return self._cmp(other) <= 0
971 return NotImplemented
972
973 def __lt__(self, other):
974 if isinstance(other, date):
975 return self._cmp(other) < 0
976 return NotImplemented
977
978 def __ge__(self, other):
979 if isinstance(other, date):
980 return self._cmp(other) >= 0
981 return NotImplemented
982
983 def __gt__(self, other):
984 if isinstance(other, date):
985 return self._cmp(other) > 0
986 return NotImplemented
987
988 def _cmp(self, other):
989 assert isinstance(other, date)
990 y, m, d = self._year, self._month, self._day
991 y2, m2, d2 = other._year, other._month, other._day
992 return _cmp((y, m, d), (y2, m2, d2))
993
994 def __hash__(self):
995 "Hash."
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400996 if self._hashcode == -1:
997 self._hashcode = hash(self._getstate())
998 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000999
1000 # Computations
1001
1002 def __add__(self, other):
1003 "Add a date to a timedelta."
1004 if isinstance(other, timedelta):
1005 o = self.toordinal() + other.days
1006 if 0 < o <= _MAXORDINAL:
1007 return date.fromordinal(o)
1008 raise OverflowError("result out of range")
1009 return NotImplemented
1010
1011 __radd__ = __add__
1012
1013 def __sub__(self, other):
1014 """Subtract two dates, or a date and a timedelta."""
1015 if isinstance(other, timedelta):
1016 return self + timedelta(-other.days)
1017 if isinstance(other, date):
1018 days1 = self.toordinal()
1019 days2 = other.toordinal()
1020 return timedelta(days1 - days2)
1021 return NotImplemented
1022
1023 def weekday(self):
1024 "Return day of the week, where Monday == 0 ... Sunday == 6."
1025 return (self.toordinal() + 6) % 7
1026
1027 # Day-of-the-week and week-of-the-year, according to ISO
1028
1029 def isoweekday(self):
1030 "Return day of the week, where Monday == 1 ... Sunday == 7."
1031 # 1-Jan-0001 is a Monday
1032 return self.toordinal() % 7 or 7
1033
1034 def isocalendar(self):
1035 """Return a 3-tuple containing ISO year, week number, and weekday.
1036
1037 The first ISO week of the year is the (Mon-Sun) week
1038 containing the year's first Thursday; everything else derives
1039 from that.
1040
1041 The first week is 1; Monday is 1 ... Sunday is 7.
1042
1043 ISO calendar algorithm taken from
1044 http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
Brett Cannon07b954d2016-01-15 09:53:51 -08001045 (used with permission)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001046 """
1047 year = self._year
1048 week1monday = _isoweek1monday(year)
1049 today = _ymd2ord(self._year, self._month, self._day)
1050 # Internally, week and day have origin 0
1051 week, day = divmod(today - week1monday, 7)
1052 if week < 0:
1053 year -= 1
1054 week1monday = _isoweek1monday(year)
1055 week, day = divmod(today - week1monday, 7)
1056 elif week >= 52:
1057 if today >= _isoweek1monday(year+1):
1058 year += 1
1059 week = 0
1060 return year, week+1, day+1
1061
1062 # Pickle support.
1063
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001064 def _getstate(self):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001065 yhi, ylo = divmod(self._year, 256)
1066 return bytes([yhi, ylo, self._month, self._day]),
1067
1068 def __setstate(self, string):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001069 yhi, ylo, self._month, self._day = string
1070 self._year = yhi * 256 + ylo
1071
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001072 def __reduce__(self):
1073 return (self.__class__, self._getstate())
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001074
1075_date_class = date # so functions w/ args named "date" can get at the class
1076
1077date.min = date(1, 1, 1)
1078date.max = date(9999, 12, 31)
1079date.resolution = timedelta(days=1)
1080
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001081
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001082class tzinfo:
1083 """Abstract base class for time zone info classes.
1084
1085 Subclasses must override the name(), utcoffset() and dst() methods.
1086 """
1087 __slots__ = ()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001088
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001089 def tzname(self, dt):
1090 "datetime -> string name of time zone."
1091 raise NotImplementedError("tzinfo subclass must override tzname()")
1092
1093 def utcoffset(self, dt):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001094 "datetime -> timedelta, positive for east of UTC, negative for west of UTC"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001095 raise NotImplementedError("tzinfo subclass must override utcoffset()")
1096
1097 def dst(self, dt):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001098 """datetime -> DST offset as timedelta, positive for east of UTC.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001099
1100 Return 0 if DST not in effect. utcoffset() must include the DST
1101 offset.
1102 """
1103 raise NotImplementedError("tzinfo subclass must override dst()")
1104
1105 def fromutc(self, dt):
1106 "datetime in UTC -> datetime in local time."
1107
1108 if not isinstance(dt, datetime):
1109 raise TypeError("fromutc() requires a datetime argument")
1110 if dt.tzinfo is not self:
1111 raise ValueError("dt.tzinfo is not self")
1112
1113 dtoff = dt.utcoffset()
1114 if dtoff is None:
1115 raise ValueError("fromutc() requires a non-None utcoffset() "
1116 "result")
1117
1118 # See the long comment block at the end of this file for an
1119 # explanation of this algorithm.
1120 dtdst = dt.dst()
1121 if dtdst is None:
1122 raise ValueError("fromutc() requires a non-None dst() result")
1123 delta = dtoff - dtdst
1124 if delta:
1125 dt += delta
1126 dtdst = dt.dst()
1127 if dtdst is None:
1128 raise ValueError("fromutc(): dt.dst gave inconsistent "
1129 "results; cannot convert")
1130 return dt + dtdst
1131
1132 # Pickle support.
1133
1134 def __reduce__(self):
1135 getinitargs = getattr(self, "__getinitargs__", None)
1136 if getinitargs:
1137 args = getinitargs()
1138 else:
1139 args = ()
1140 getstate = getattr(self, "__getstate__", None)
1141 if getstate:
1142 state = getstate()
1143 else:
1144 state = getattr(self, "__dict__", None) or None
1145 if state is None:
1146 return (self.__class__, args)
1147 else:
1148 return (self.__class__, args, state)
1149
1150_tzinfo_class = tzinfo
1151
1152class time:
1153 """Time with time zone.
1154
1155 Constructors:
1156
1157 __new__()
1158
1159 Operators:
1160
1161 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +02001162 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001163
1164 Methods:
1165
1166 strftime()
1167 isoformat()
1168 utcoffset()
1169 tzname()
1170 dst()
1171
1172 Properties (readonly):
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001173 hour, minute, second, microsecond, tzinfo, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001174 """
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001175 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode', '_fold'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001176
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001177 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001178 """Constructor.
1179
1180 Arguments:
1181
1182 hour, minute (required)
1183 second, microsecond (default to zero)
1184 tzinfo (default to None)
Victor Stinner51b90d22017-01-04 12:01:16 +01001185 fold (keyword only, default to zero)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001186 """
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001187 if isinstance(hour, bytes) and len(hour) == 6 and hour[0]&0x7F < 24:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001188 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001189 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001190 self.__setstate(hour, minute or None)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001191 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001192 return self
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001193 hour, minute, second, microsecond, fold = _check_time_fields(
1194 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001195 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001196 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001197 self._hour = hour
1198 self._minute = minute
1199 self._second = second
1200 self._microsecond = microsecond
1201 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001202 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001203 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001204 return self
1205
1206 # Read-only field accessors
1207 @property
1208 def hour(self):
1209 """hour (0-23)"""
1210 return self._hour
1211
1212 @property
1213 def minute(self):
1214 """minute (0-59)"""
1215 return self._minute
1216
1217 @property
1218 def second(self):
1219 """second (0-59)"""
1220 return self._second
1221
1222 @property
1223 def microsecond(self):
1224 """microsecond (0-999999)"""
1225 return self._microsecond
1226
1227 @property
1228 def tzinfo(self):
1229 """timezone info object"""
1230 return self._tzinfo
1231
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001232 @property
1233 def fold(self):
1234 return self._fold
1235
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001236 # Standard conversions, __hash__ (and helpers)
1237
1238 # Comparisons of time objects with other.
1239
1240 def __eq__(self, other):
1241 if isinstance(other, time):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001242 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001243 else:
1244 return False
1245
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001246 def __le__(self, other):
1247 if isinstance(other, time):
1248 return self._cmp(other) <= 0
1249 else:
1250 _cmperror(self, other)
1251
1252 def __lt__(self, other):
1253 if isinstance(other, time):
1254 return self._cmp(other) < 0
1255 else:
1256 _cmperror(self, other)
1257
1258 def __ge__(self, other):
1259 if isinstance(other, time):
1260 return self._cmp(other) >= 0
1261 else:
1262 _cmperror(self, other)
1263
1264 def __gt__(self, other):
1265 if isinstance(other, time):
1266 return self._cmp(other) > 0
1267 else:
1268 _cmperror(self, other)
1269
Alexander Belopolsky08313822012-06-15 20:19:47 -04001270 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001271 assert isinstance(other, time)
1272 mytz = self._tzinfo
1273 ottz = other._tzinfo
1274 myoff = otoff = None
1275
1276 if mytz is ottz:
1277 base_compare = True
1278 else:
1279 myoff = self.utcoffset()
1280 otoff = other.utcoffset()
1281 base_compare = myoff == otoff
1282
1283 if base_compare:
1284 return _cmp((self._hour, self._minute, self._second,
1285 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001286 (other._hour, other._minute, other._second,
1287 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001288 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001289 if allow_mixed:
1290 return 2 # arbitrary non-zero value
1291 else:
1292 raise TypeError("cannot compare naive and aware times")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001293 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1294 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1295 return _cmp((myhhmm, self._second, self._microsecond),
1296 (othhmm, other._second, other._microsecond))
1297
1298 def __hash__(self):
1299 """Hash."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001300 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001301 if self.fold:
1302 t = self.replace(fold=0)
1303 else:
1304 t = self
1305 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001306 if not tzoff: # zero or None
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001307 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001308 else:
1309 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1310 timedelta(hours=1))
1311 assert not m % timedelta(minutes=1), "whole minute"
1312 m //= timedelta(minutes=1)
1313 if 0 <= h < 24:
1314 self._hashcode = hash(time(h, m, self.second, self.microsecond))
1315 else:
1316 self._hashcode = hash((h, m, self.second, self.microsecond))
1317 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001318
1319 # Conversion to string
1320
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001321 def _tzstr(self):
1322 """Return formatted timezone offset (+xx:xx) or an empty string."""
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001323 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001324 return _format_offset(off)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001325
1326 def __repr__(self):
1327 """Convert to formal string, for repr()."""
1328 if self._microsecond != 0:
1329 s = ", %d, %d" % (self._second, self._microsecond)
1330 elif self._second != 0:
1331 s = ", %d" % self._second
1332 else:
1333 s = ""
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001334 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1335 self.__class__.__qualname__,
1336 self._hour, self._minute, s)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001337 if self._tzinfo is not None:
1338 assert s[-1:] == ")"
1339 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001340 if self._fold:
1341 assert s[-1:] == ")"
1342 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001343 return s
1344
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001345 def isoformat(self, timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001346 """Return the time formatted according to ISO.
1347
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001348 The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional
1349 part is omitted if self.microsecond == 0.
1350
1351 The optional argument timespec specifies the number of additional
1352 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001353 """
1354 s = _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001355 self._microsecond, timespec)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001356 tz = self._tzstr()
1357 if tz:
1358 s += tz
1359 return s
1360
1361 __str__ = isoformat
1362
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001363 @classmethod
1364 def fromisoformat(cls, time_string):
1365 """Construct a time from the output of isoformat()."""
1366 if not isinstance(time_string, str):
1367 raise TypeError('fromisoformat: argument must be str')
1368
1369 try:
1370 return cls(*_parse_isoformat_time(time_string))
1371 except Exception:
Paul Ganssle3df85402018-10-22 12:32:52 -04001372 raise ValueError(f'Invalid isoformat string: {time_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001373
1374
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001375 def strftime(self, fmt):
1376 """Format using strftime(). The date part of the timestamp passed
1377 to underlying strftime should not be used.
1378 """
Alexander Belopolskyb8bb4662011-01-08 00:13:34 +00001379 # The year must be >= 1000 else Python's strftime implementation
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001380 # can raise a bogus exception.
1381 timetuple = (1900, 1, 1,
1382 self._hour, self._minute, self._second,
1383 0, 1, -1)
1384 return _wrap_strftime(self, fmt, timetuple)
1385
1386 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001387 if not isinstance(fmt, str):
1388 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001389 if len(fmt) != 0:
1390 return self.strftime(fmt)
1391 return str(self)
1392
1393 # Timezone functions
1394
1395 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001396 """Return the timezone offset as timedelta, positive east of UTC
1397 (negative west of UTC)."""
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001398 if self._tzinfo is None:
1399 return None
1400 offset = self._tzinfo.utcoffset(None)
1401 _check_utc_offset("utcoffset", offset)
1402 return offset
1403
1404 def tzname(self):
1405 """Return the timezone name.
1406
1407 Note that the name is 100% informational -- there's no requirement that
1408 it mean anything in particular. For example, "GMT", "UTC", "-500",
1409 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1410 """
1411 if self._tzinfo is None:
1412 return None
1413 name = self._tzinfo.tzname(None)
1414 _check_tzname(name)
1415 return name
1416
1417 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001418 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1419 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001420
1421 This is purely informational; the DST offset has already been added to
1422 the UTC offset returned by utcoffset() if applicable, so there's no
1423 need to consult dst() unless you're interested in displaying the DST
1424 info.
1425 """
1426 if self._tzinfo is None:
1427 return None
1428 offset = self._tzinfo.dst(None)
1429 _check_utc_offset("dst", offset)
1430 return offset
1431
1432 def replace(self, hour=None, minute=None, second=None, microsecond=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001433 tzinfo=True, *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001434 """Return a new time with new values for the specified fields."""
1435 if hour is None:
1436 hour = self.hour
1437 if minute is None:
1438 minute = self.minute
1439 if second is None:
1440 second = self.second
1441 if microsecond is None:
1442 microsecond = self.microsecond
1443 if tzinfo is True:
1444 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001445 if fold is None:
1446 fold = self._fold
Paul Ganssle191e9932017-11-09 16:34:29 -05001447 return type(self)(hour, minute, second, microsecond, tzinfo, fold=fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001448
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001449 # Pickle support.
1450
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001451 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001452 us2, us3 = divmod(self._microsecond, 256)
1453 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001454 h = self._hour
1455 if self._fold and protocol > 3:
1456 h += 128
1457 basestate = bytes([h, self._minute, self._second,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001458 us1, us2, us3])
1459 if self._tzinfo is None:
1460 return (basestate,)
1461 else:
1462 return (basestate, self._tzinfo)
1463
1464 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001465 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1466 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001467 h, self._minute, self._second, us1, us2, us3 = string
1468 if h > 127:
1469 self._fold = 1
1470 self._hour = h - 128
1471 else:
1472 self._fold = 0
1473 self._hour = h
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001474 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001475 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001476
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001477 def __reduce_ex__(self, protocol):
1478 return (time, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001479
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001480 def __reduce__(self):
1481 return self.__reduce_ex__(2)
1482
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001483_time_class = time # so functions w/ args named "time" can get at the class
1484
1485time.min = time(0, 0, 0)
1486time.max = time(23, 59, 59, 999999)
1487time.resolution = timedelta(microseconds=1)
1488
1489class datetime(date):
1490 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1491
1492 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001493 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001494 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001495 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001496
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001497 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001498 microsecond=0, tzinfo=None, *, fold=0):
1499 if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2]&0x7F <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001500 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001501 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001502 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001503 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001504 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001505 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001506 hour, minute, second, microsecond, fold = _check_time_fields(
1507 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001508 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001509 self = object.__new__(cls)
1510 self._year = year
1511 self._month = month
1512 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001513 self._hour = hour
1514 self._minute = minute
1515 self._second = second
1516 self._microsecond = microsecond
1517 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001518 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001519 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001520 return self
1521
1522 # Read-only field accessors
1523 @property
1524 def hour(self):
1525 """hour (0-23)"""
1526 return self._hour
1527
1528 @property
1529 def minute(self):
1530 """minute (0-59)"""
1531 return self._minute
1532
1533 @property
1534 def second(self):
1535 """second (0-59)"""
1536 return self._second
1537
1538 @property
1539 def microsecond(self):
1540 """microsecond (0-999999)"""
1541 return self._microsecond
1542
1543 @property
1544 def tzinfo(self):
1545 """timezone info object"""
1546 return self._tzinfo
1547
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001548 @property
1549 def fold(self):
1550 return self._fold
1551
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001552 @classmethod
Victor Stinneradfefa52015-09-04 23:57:25 +02001553 def _fromtimestamp(cls, t, utc, tz):
1554 """Construct a datetime from a POSIX timestamp (like time.time()).
1555
1556 A timezone info object may be passed in as well.
1557 """
1558 frac, t = _math.modf(t)
Victor Stinner7667f582015-09-09 01:02:23 +02001559 us = round(frac * 1e6)
Victor Stinneradfefa52015-09-04 23:57:25 +02001560 if us >= 1000000:
1561 t += 1
1562 us -= 1000000
1563 elif us < 0:
1564 t -= 1
1565 us += 1000000
1566
1567 converter = _time.gmtime if utc else _time.localtime
1568 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1569 ss = min(ss, 59) # clamp out leap seconds if the platform has them
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001570 result = cls(y, m, d, hh, mm, ss, us, tz)
1571 if tz is None:
1572 # As of version 2015f max fold in IANA database is
1573 # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
1574 # Let's probe 24 hours in the past to detect a transition:
1575 max_fold_seconds = 24 * 3600
Ammar Askar96d1e692018-07-25 09:54:58 -07001576
1577 # On Windows localtime_s throws an OSError for negative values,
1578 # thus we can't perform fold detection for values of time less
1579 # than the max time fold. See comments in _datetimemodule's
1580 # version of this method for more details.
1581 if t < max_fold_seconds and sys.platform.startswith("win"):
1582 return result
1583
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001584 y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1585 probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1586 trans = result - probe1 - timedelta(0, max_fold_seconds)
1587 if trans.days < 0:
1588 y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
1589 probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1590 if probe2 == result:
1591 result._fold = 1
1592 else:
1593 result = tz.fromutc(result)
1594 return result
Victor Stinneradfefa52015-09-04 23:57:25 +02001595
1596 @classmethod
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001597 def fromtimestamp(cls, t, tz=None):
1598 """Construct a datetime from a POSIX timestamp (like time.time()).
1599
1600 A timezone info object may be passed in as well.
1601 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001602 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001603
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001604 return cls._fromtimestamp(t, tz is not None, tz)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001605
1606 @classmethod
1607 def utcfromtimestamp(cls, t):
Alexander Belopolskye2e178e2015-03-01 14:52:07 -05001608 """Construct a naive UTC datetime from a POSIX timestamp."""
Victor Stinneradfefa52015-09-04 23:57:25 +02001609 return cls._fromtimestamp(t, True, None)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001610
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001611 @classmethod
1612 def now(cls, tz=None):
1613 "Construct a datetime from time.time() and optional time zone info."
1614 t = _time.time()
1615 return cls.fromtimestamp(t, tz)
1616
1617 @classmethod
1618 def utcnow(cls):
1619 "Construct a UTC datetime from time.time()."
1620 t = _time.time()
1621 return cls.utcfromtimestamp(t)
1622
1623 @classmethod
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001624 def combine(cls, date, time, tzinfo=True):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001625 "Construct a datetime from a given date and a given time."
1626 if not isinstance(date, _date_class):
1627 raise TypeError("date argument must be a date instance")
1628 if not isinstance(time, _time_class):
1629 raise TypeError("time argument must be a time instance")
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001630 if tzinfo is True:
1631 tzinfo = time.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001632 return cls(date.year, date.month, date.day,
1633 time.hour, time.minute, time.second, time.microsecond,
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001634 tzinfo, fold=time.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001635
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001636 @classmethod
1637 def fromisoformat(cls, date_string):
1638 """Construct a datetime from the output of datetime.isoformat()."""
1639 if not isinstance(date_string, str):
1640 raise TypeError('fromisoformat: argument must be str')
1641
1642 # Split this at the separator
1643 dstr = date_string[0:10]
1644 tstr = date_string[11:]
1645
1646 try:
1647 date_components = _parse_isoformat_date(dstr)
1648 except ValueError:
Paul Ganssle3df85402018-10-22 12:32:52 -04001649 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001650
1651 if tstr:
1652 try:
1653 time_components = _parse_isoformat_time(tstr)
1654 except ValueError:
Paul Ganssle3df85402018-10-22 12:32:52 -04001655 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001656 else:
1657 time_components = [0, 0, 0, 0, None]
1658
1659 return cls(*(date_components + time_components))
1660
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001661 def timetuple(self):
1662 "Return local time tuple compatible with time.localtime()."
1663 dst = self.dst()
1664 if dst is None:
1665 dst = -1
1666 elif dst:
1667 dst = 1
1668 else:
1669 dst = 0
1670 return _build_struct_time(self.year, self.month, self.day,
1671 self.hour, self.minute, self.second,
1672 dst)
1673
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001674 def _mktime(self):
1675 """Return integer POSIX timestamp."""
1676 epoch = datetime(1970, 1, 1)
1677 max_fold_seconds = 24 * 3600
1678 t = (self - epoch) // timedelta(0, 1)
1679 def local(u):
1680 y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1681 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1682
1683 # Our goal is to solve t = local(u) for u.
1684 a = local(t) - t
1685 u1 = t - a
1686 t1 = local(u1)
1687 if t1 == t:
1688 # We found one solution, but it may not be the one we need.
1689 # Look for an earlier solution (if `fold` is 0), or a
1690 # later one (if `fold` is 1).
1691 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1692 b = local(u2) - u2
1693 if a == b:
1694 return u1
1695 else:
1696 b = t1 - u1
1697 assert a != b
1698 u2 = t - b
1699 t2 = local(u2)
1700 if t2 == t:
1701 return u2
1702 if t1 == t:
1703 return u1
1704 # We have found both offsets a and b, but neither t - a nor t - b is
1705 # a solution. This means t is in the gap.
1706 return (max, min)[self.fold](u1, u2)
1707
1708
Alexander Belopolskya4415142012-06-08 12:33:09 -04001709 def timestamp(self):
1710 "Return POSIX timestamp as float"
1711 if self._tzinfo is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001712 s = self._mktime()
1713 return s + self.microsecond / 1e6
Alexander Belopolskya4415142012-06-08 12:33:09 -04001714 else:
1715 return (self - _EPOCH).total_seconds()
1716
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001717 def utctimetuple(self):
1718 "Return UTC time tuple compatible with time.gmtime()."
1719 offset = self.utcoffset()
1720 if offset:
1721 self -= offset
1722 y, m, d = self.year, self.month, self.day
1723 hh, mm, ss = self.hour, self.minute, self.second
1724 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1725
1726 def date(self):
1727 "Return the date part."
1728 return date(self._year, self._month, self._day)
1729
1730 def time(self):
1731 "Return the time part, with tzinfo None."
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001732 return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001733
1734 def timetz(self):
1735 "Return the time part, with same tzinfo."
1736 return time(self.hour, self.minute, self.second, self.microsecond,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001737 self._tzinfo, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001738
1739 def replace(self, year=None, month=None, day=None, hour=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001740 minute=None, second=None, microsecond=None, tzinfo=True,
1741 *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001742 """Return a new datetime with new values for the specified fields."""
1743 if year is None:
1744 year = self.year
1745 if month is None:
1746 month = self.month
1747 if day is None:
1748 day = self.day
1749 if hour is None:
1750 hour = self.hour
1751 if minute is None:
1752 minute = self.minute
1753 if second is None:
1754 second = self.second
1755 if microsecond is None:
1756 microsecond = self.microsecond
1757 if tzinfo is True:
1758 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001759 if fold is None:
1760 fold = self.fold
Paul Ganssle191e9932017-11-09 16:34:29 -05001761 return type(self)(year, month, day, hour, minute, second,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001762 microsecond, tzinfo, fold=fold)
1763
1764 def _local_timezone(self):
1765 if self.tzinfo is None:
1766 ts = self._mktime()
1767 else:
1768 ts = (self - _EPOCH) // timedelta(seconds=1)
1769 localtm = _time.localtime(ts)
1770 local = datetime(*localtm[:6])
Alexander Belopolskybcb032e2018-06-08 19:22:33 -04001771 # Extract TZ data
1772 gmtoff = localtm.tm_gmtoff
1773 zone = localtm.tm_zone
1774 return timezone(timedelta(seconds=gmtoff), zone)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001775
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001776 def astimezone(self, tz=None):
1777 if tz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001778 tz = self._local_timezone()
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001779 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001780 raise TypeError("tz argument must be an instance of tzinfo")
1781
1782 mytz = self.tzinfo
1783 if mytz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001784 mytz = self._local_timezone()
Alexander Belopolsky877b2322018-06-10 17:02:58 -04001785 myoffset = mytz.utcoffset(self)
1786 else:
1787 myoffset = mytz.utcoffset(self)
1788 if myoffset is None:
1789 mytz = self.replace(tzinfo=None)._local_timezone()
1790 myoffset = mytz.utcoffset(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001791
1792 if tz is mytz:
1793 return self
1794
1795 # Convert self to UTC, and attach the new time zone object.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001796 utc = (self - myoffset).replace(tzinfo=tz)
1797
1798 # Convert from UTC to tz's local time.
1799 return tz.fromutc(utc)
1800
1801 # Ways to produce a string.
1802
1803 def ctime(self):
1804 "Return ctime() style string."
1805 weekday = self.toordinal() % 7 or 7
1806 return "%s %s %2d %02d:%02d:%02d %04d" % (
1807 _DAYNAMES[weekday],
1808 _MONTHNAMES[self._month],
1809 self._day,
1810 self._hour, self._minute, self._second,
1811 self._year)
1812
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001813 def isoformat(self, sep='T', timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001814 """Return the time formatted according to ISO.
1815
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001816 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1817 By default, the fractional part is omitted if self.microsecond == 0.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001818
1819 If self.tzinfo is not None, the UTC offset is also attached, giving
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001820 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001821
1822 Optional argument sep specifies the separator between date and
1823 time, default 'T'.
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001824
1825 The optional argument timespec specifies the number of additional
1826 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001827 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001828 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1829 _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001830 self._microsecond, timespec))
1831
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001832 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001833 tz = _format_offset(off)
1834 if tz:
1835 s += tz
1836
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001837 return s
1838
1839 def __repr__(self):
1840 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001841 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001842 self._hour, self._minute, self._second, self._microsecond]
1843 if L[-1] == 0:
1844 del L[-1]
1845 if L[-1] == 0:
1846 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001847 s = "%s.%s(%s)" % (self.__class__.__module__,
1848 self.__class__.__qualname__,
1849 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001850 if self._tzinfo is not None:
1851 assert s[-1:] == ")"
1852 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001853 if self._fold:
1854 assert s[-1:] == ")"
1855 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001856 return s
1857
1858 def __str__(self):
1859 "Convert to string, for str()."
1860 return self.isoformat(sep=' ')
1861
1862 @classmethod
1863 def strptime(cls, date_string, format):
1864 'string, format -> new datetime parsed from a string (like time.strptime()).'
1865 import _strptime
1866 return _strptime._strptime_datetime(cls, date_string, format)
1867
1868 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001869 """Return the timezone offset as timedelta positive east of UTC (negative west of
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001870 UTC)."""
1871 if self._tzinfo is None:
1872 return None
1873 offset = self._tzinfo.utcoffset(self)
1874 _check_utc_offset("utcoffset", offset)
1875 return offset
1876
1877 def tzname(self):
1878 """Return the timezone name.
1879
1880 Note that the name is 100% informational -- there's no requirement that
1881 it mean anything in particular. For example, "GMT", "UTC", "-500",
1882 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1883 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001884 if self._tzinfo is None:
1885 return None
1886 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001887 _check_tzname(name)
1888 return name
1889
1890 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001891 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1892 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001893
1894 This is purely informational; the DST offset has already been added to
1895 the UTC offset returned by utcoffset() if applicable, so there's no
1896 need to consult dst() unless you're interested in displaying the DST
1897 info.
1898 """
1899 if self._tzinfo is None:
1900 return None
1901 offset = self._tzinfo.dst(self)
1902 _check_utc_offset("dst", offset)
1903 return offset
1904
1905 # Comparisons of datetime objects with other.
1906
1907 def __eq__(self, other):
1908 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001909 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001910 elif not isinstance(other, date):
1911 return NotImplemented
1912 else:
1913 return False
1914
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001915 def __le__(self, other):
1916 if isinstance(other, datetime):
1917 return self._cmp(other) <= 0
1918 elif not isinstance(other, date):
1919 return NotImplemented
1920 else:
1921 _cmperror(self, other)
1922
1923 def __lt__(self, other):
1924 if isinstance(other, datetime):
1925 return self._cmp(other) < 0
1926 elif not isinstance(other, date):
1927 return NotImplemented
1928 else:
1929 _cmperror(self, other)
1930
1931 def __ge__(self, other):
1932 if isinstance(other, datetime):
1933 return self._cmp(other) >= 0
1934 elif not isinstance(other, date):
1935 return NotImplemented
1936 else:
1937 _cmperror(self, other)
1938
1939 def __gt__(self, other):
1940 if isinstance(other, datetime):
1941 return self._cmp(other) > 0
1942 elif not isinstance(other, date):
1943 return NotImplemented
1944 else:
1945 _cmperror(self, other)
1946
Alexander Belopolsky08313822012-06-15 20:19:47 -04001947 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001948 assert isinstance(other, datetime)
1949 mytz = self._tzinfo
1950 ottz = other._tzinfo
1951 myoff = otoff = None
1952
1953 if mytz is ottz:
1954 base_compare = True
1955 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04001956 myoff = self.utcoffset()
1957 otoff = other.utcoffset()
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001958 # Assume that allow_mixed means that we are called from __eq__
1959 if allow_mixed:
1960 if myoff != self.replace(fold=not self.fold).utcoffset():
1961 return 2
1962 if otoff != other.replace(fold=not other.fold).utcoffset():
1963 return 2
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001964 base_compare = myoff == otoff
1965
1966 if base_compare:
1967 return _cmp((self._year, self._month, self._day,
1968 self._hour, self._minute, self._second,
1969 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001970 (other._year, other._month, other._day,
1971 other._hour, other._minute, other._second,
1972 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001973 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001974 if allow_mixed:
1975 return 2 # arbitrary non-zero value
1976 else:
1977 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001978 # XXX What follows could be done more efficiently...
1979 diff = self - other # this will take offsets into account
1980 if diff.days < 0:
1981 return -1
1982 return diff and 1 or 0
1983
1984 def __add__(self, other):
1985 "Add a datetime and a timedelta."
1986 if not isinstance(other, timedelta):
1987 return NotImplemented
1988 delta = timedelta(self.toordinal(),
1989 hours=self._hour,
1990 minutes=self._minute,
1991 seconds=self._second,
1992 microseconds=self._microsecond)
1993 delta += other
1994 hour, rem = divmod(delta.seconds, 3600)
1995 minute, second = divmod(rem, 60)
1996 if 0 < delta.days <= _MAXORDINAL:
1997 return datetime.combine(date.fromordinal(delta.days),
1998 time(hour, minute, second,
1999 delta.microseconds,
2000 tzinfo=self._tzinfo))
2001 raise OverflowError("result out of range")
2002
2003 __radd__ = __add__
2004
2005 def __sub__(self, other):
2006 "Subtract two datetimes, or a datetime and a timedelta."
2007 if not isinstance(other, datetime):
2008 if isinstance(other, timedelta):
2009 return self + -other
2010 return NotImplemented
2011
2012 days1 = self.toordinal()
2013 days2 = other.toordinal()
2014 secs1 = self._second + self._minute * 60 + self._hour * 3600
2015 secs2 = other._second + other._minute * 60 + other._hour * 3600
2016 base = timedelta(days1 - days2,
2017 secs1 - secs2,
2018 self._microsecond - other._microsecond)
2019 if self._tzinfo is other._tzinfo:
2020 return base
2021 myoff = self.utcoffset()
2022 otoff = other.utcoffset()
2023 if myoff == otoff:
2024 return base
2025 if myoff is None or otoff is None:
2026 raise TypeError("cannot mix naive and timezone-aware time")
2027 return base + otoff - myoff
2028
2029 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002030 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002031 if self.fold:
2032 t = self.replace(fold=0)
2033 else:
2034 t = self
2035 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002036 if tzoff is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002037 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002038 else:
2039 days = _ymd2ord(self.year, self.month, self.day)
2040 seconds = self.hour * 3600 + self.minute * 60 + self.second
2041 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
2042 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002043
2044 # Pickle support.
2045
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002046 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002047 yhi, ylo = divmod(self._year, 256)
2048 us2, us3 = divmod(self._microsecond, 256)
2049 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002050 m = self._month
2051 if self._fold and protocol > 3:
2052 m += 128
2053 basestate = bytes([yhi, ylo, m, self._day,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002054 self._hour, self._minute, self._second,
2055 us1, us2, us3])
2056 if self._tzinfo is None:
2057 return (basestate,)
2058 else:
2059 return (basestate, self._tzinfo)
2060
2061 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002062 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
2063 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002064 (yhi, ylo, m, self._day, self._hour,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002065 self._minute, self._second, us1, us2, us3) = string
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002066 if m > 127:
2067 self._fold = 1
2068 self._month = m - 128
2069 else:
2070 self._fold = 0
2071 self._month = m
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002072 self._year = yhi * 256 + ylo
2073 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002074 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002075
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002076 def __reduce_ex__(self, protocol):
2077 return (self.__class__, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002078
Serhiy Storchaka546ce652016-11-22 00:29:42 +02002079 def __reduce__(self):
2080 return self.__reduce_ex__(2)
2081
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002082
2083datetime.min = datetime(1, 1, 1)
2084datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
2085datetime.resolution = timedelta(microseconds=1)
2086
2087
2088def _isoweek1monday(year):
2089 # Helper to calculate the day number of the Monday starting week 1
2090 # XXX This could be done more efficiently
2091 THURSDAY = 3
2092 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002093 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002094 week1monday = firstday - firstweekday
2095 if firstweekday > THURSDAY:
2096 week1monday += 7
2097 return week1monday
2098
2099class timezone(tzinfo):
2100 __slots__ = '_offset', '_name'
2101
2102 # Sentinel value to disallow None
2103 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002104 def __new__(cls, offset, name=_Omitted):
2105 if not isinstance(offset, timedelta):
2106 raise TypeError("offset must be a timedelta")
2107 if name is cls._Omitted:
2108 if not offset:
2109 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002110 name = None
2111 elif not isinstance(name, str):
2112 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002113 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002114 raise ValueError("offset must be a timedelta "
2115 "strictly between -timedelta(hours=24) and "
2116 "timedelta(hours=24).")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002117 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002118
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002119 @classmethod
2120 def _create(cls, offset, name=None):
2121 self = tzinfo.__new__(cls)
2122 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002123 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002124 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002125
2126 def __getinitargs__(self):
2127 """pickle support"""
2128 if self._name is None:
2129 return (self._offset,)
2130 return (self._offset, self._name)
2131
2132 def __eq__(self, other):
Georg Brandl0085a242012-09-22 09:23:12 +02002133 if type(other) != timezone:
2134 return False
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002135 return self._offset == other._offset
2136
2137 def __hash__(self):
2138 return hash(self._offset)
2139
2140 def __repr__(self):
2141 """Convert to formal string, for repr().
2142
2143 >>> tz = timezone.utc
2144 >>> repr(tz)
2145 'datetime.timezone.utc'
2146 >>> tz = timezone(timedelta(hours=-5), 'EST')
2147 >>> repr(tz)
2148 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
2149 """
2150 if self is self.utc:
2151 return 'datetime.timezone.utc'
2152 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03002153 return "%s.%s(%r)" % (self.__class__.__module__,
2154 self.__class__.__qualname__,
2155 self._offset)
2156 return "%s.%s(%r, %r)" % (self.__class__.__module__,
2157 self.__class__.__qualname__,
2158 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002159
2160 def __str__(self):
2161 return self.tzname(None)
2162
2163 def utcoffset(self, dt):
2164 if isinstance(dt, datetime) or dt is None:
2165 return self._offset
2166 raise TypeError("utcoffset() argument must be a datetime instance"
2167 " or None")
2168
2169 def tzname(self, dt):
2170 if isinstance(dt, datetime) or dt is None:
2171 if self._name is None:
2172 return self._name_from_offset(self._offset)
2173 return self._name
2174 raise TypeError("tzname() argument must be a datetime instance"
2175 " or None")
2176
2177 def dst(self, dt):
2178 if isinstance(dt, datetime) or dt is None:
2179 return None
2180 raise TypeError("dst() argument must be a datetime instance"
2181 " or None")
2182
2183 def fromutc(self, dt):
2184 if isinstance(dt, datetime):
2185 if dt.tzinfo is not self:
2186 raise ValueError("fromutc: dt.tzinfo "
2187 "is not self")
2188 return dt + self._offset
2189 raise TypeError("fromutc() argument must be a datetime instance"
2190 " or None")
2191
2192 _maxoffset = timedelta(hours=23, minutes=59)
2193 _minoffset = -_maxoffset
2194
2195 @staticmethod
2196 def _name_from_offset(delta):
Alexander Belopolsky7827a5b2015-09-06 13:07:21 -04002197 if not delta:
2198 return 'UTC'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002199 if delta < timedelta(0):
2200 sign = '-'
2201 delta = -delta
2202 else:
2203 sign = '+'
2204 hours, rest = divmod(delta, timedelta(hours=1))
Alexander Belopolsky018d3532017-07-31 10:26:50 -04002205 minutes, rest = divmod(rest, timedelta(minutes=1))
2206 seconds = rest.seconds
2207 microseconds = rest.microseconds
2208 if microseconds:
2209 return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2210 f'.{microseconds:06d}')
2211 if seconds:
2212 return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2213 return f'UTC{sign}{hours:02d}:{minutes:02d}'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002214
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002215timezone.utc = timezone._create(timedelta(0))
2216timezone.min = timezone._create(timezone._minoffset)
2217timezone.max = timezone._create(timezone._maxoffset)
Alexander Belopolskya4415142012-06-08 12:33:09 -04002218_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002219
Victor Stinner765531d2013-03-26 01:11:54 +01002220# Some time zone algebra. For a datetime x, let
2221# x.n = x stripped of its timezone -- its naive time.
2222# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2223# return None
2224# x.d = x.dst(), and assuming that doesn't raise an exception or
2225# return None
2226# x.s = x's standard offset, x.o - x.d
2227#
2228# Now some derived rules, where k is a duration (timedelta).
2229#
2230# 1. x.o = x.s + x.d
2231# This follows from the definition of x.s.
2232#
2233# 2. If x and y have the same tzinfo member, x.s = y.s.
2234# This is actually a requirement, an assumption we need to make about
2235# sane tzinfo classes.
2236#
2237# 3. The naive UTC time corresponding to x is x.n - x.o.
2238# This is again a requirement for a sane tzinfo class.
2239#
2240# 4. (x+k).s = x.s
2241# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
2242#
2243# 5. (x+k).n = x.n + k
2244# Again follows from how arithmetic is defined.
2245#
2246# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
2247# (meaning that the various tzinfo methods exist, and don't blow up or return
2248# None when called).
2249#
2250# The function wants to return a datetime y with timezone tz, equivalent to x.
2251# x is already in UTC.
2252#
2253# By #3, we want
2254#
2255# y.n - y.o = x.n [1]
2256#
2257# The algorithm starts by attaching tz to x.n, and calling that y. So
2258# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
2259# becomes true; in effect, we want to solve [2] for k:
2260#
2261# (y+k).n - (y+k).o = x.n [2]
2262#
2263# By #1, this is the same as
2264#
2265# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
2266#
2267# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2268# Substituting that into [3],
2269#
2270# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2271# k - (y+k).s - (y+k).d = 0; rearranging,
2272# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2273# k = y.s - (y+k).d
2274#
2275# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2276# approximate k by ignoring the (y+k).d term at first. Note that k can't be
2277# very large, since all offset-returning methods return a duration of magnitude
2278# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
2279# be 0, so ignoring it has no consequence then.
2280#
2281# In any case, the new value is
2282#
2283# z = y + y.s [4]
2284#
2285# It's helpful to step back at look at [4] from a higher level: it's simply
2286# mapping from UTC to tz's standard time.
2287#
2288# At this point, if
2289#
2290# z.n - z.o = x.n [5]
2291#
2292# we have an equivalent time, and are almost done. The insecurity here is
2293# at the start of daylight time. Picture US Eastern for concreteness. The wall
2294# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2295# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2296# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2297# on the day DST starts. We want to return the 1:MM EST spelling because that's
2298# the only spelling that makes sense on the local wall clock.
2299#
2300# In fact, if [5] holds at this point, we do have the standard-time spelling,
2301# but that takes a bit of proof. We first prove a stronger result. What's the
2302# difference between the LHS and RHS of [5]? Let
2303#
2304# diff = x.n - (z.n - z.o) [6]
2305#
2306# Now
2307# z.n = by [4]
2308# (y + y.s).n = by #5
2309# y.n + y.s = since y.n = x.n
2310# x.n + y.s = since z and y are have the same tzinfo member,
2311# y.s = z.s by #2
2312# x.n + z.s
2313#
2314# Plugging that back into [6] gives
2315#
2316# diff =
2317# x.n - ((x.n + z.s) - z.o) = expanding
2318# x.n - x.n - z.s + z.o = cancelling
2319# - z.s + z.o = by #2
2320# z.d
2321#
2322# So diff = z.d.
2323#
2324# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2325# spelling we wanted in the endcase described above. We're done. Contrarily,
2326# if z.d = 0, then we have a UTC equivalent, and are also done.
2327#
2328# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2329# add to z (in effect, z is in tz's standard time, and we need to shift the
2330# local clock into tz's daylight time).
2331#
2332# Let
2333#
2334# z' = z + z.d = z + diff [7]
2335#
2336# and we can again ask whether
2337#
2338# z'.n - z'.o = x.n [8]
2339#
2340# If so, we're done. If not, the tzinfo class is insane, according to the
2341# assumptions we've made. This also requires a bit of proof. As before, let's
2342# compute the difference between the LHS and RHS of [8] (and skipping some of
2343# the justifications for the kinds of substitutions we've done several times
2344# already):
2345#
2346# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2347# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2348# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2349# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2350# - z.n + z.n - z.o + z'.o = cancel z.n
2351# - z.o + z'.o = #1 twice
2352# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2353# z'.d - z.d
2354#
2355# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2356# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2357# return z', not bothering to compute z'.d.
2358#
2359# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2360# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2361# would have to change the result dst() returns: we start in DST, and moving
2362# a little further into it takes us out of DST.
2363#
2364# There isn't a sane case where this can happen. The closest it gets is at
2365# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2366# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2367# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2368# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2369# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2370# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2371# standard time. Since that's what the local clock *does*, we want to map both
2372# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2373# in local time, but so it goes -- it's the way the local clock works.
2374#
2375# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2376# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2377# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2378# (correctly) concludes that z' is not UTC-equivalent to x.
2379#
2380# Because we know z.d said z was in daylight time (else [5] would have held and
2381# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2382# and we have stopped then), and there are only 2 possible values dst() can
2383# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2384# but the reasoning doesn't depend on the example -- it depends on there being
2385# two possible dst() outcomes, one zero and the other non-zero). Therefore
2386# z' must be in standard time, and is the spelling we want in this case.
2387#
2388# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2389# concerned (because it takes z' as being in standard time rather than the
2390# daylight time we intend here), but returning it gives the real-life "local
2391# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2392# tz.
2393#
2394# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2395# the 1:MM standard time spelling we want.
2396#
2397# So how can this break? One of the assumptions must be violated. Two
2398# possibilities:
2399#
2400# 1) [2] effectively says that y.s is invariant across all y belong to a given
2401# time zone. This isn't true if, for political reasons or continental drift,
2402# a region decides to change its base offset from UTC.
2403#
2404# 2) There may be versions of "double daylight" time where the tail end of
2405# the analysis gives up a step too early. I haven't thought about that
2406# enough to say.
2407#
2408# In any case, it's clear that the default fromutc() is strong enough to handle
2409# "almost all" time zones: so long as the standard offset is invariant, it
2410# doesn't matter if daylight time transition points change from year to year, or
2411# if daylight time is skipped in some years; it doesn't matter how large or
2412# small dst() may get within its bounds; and it doesn't even matter if some
2413# perverse time zone returns a negative dst()). So a breaking case must be
2414# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002415
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002416try:
2417 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002418except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002419 pass
2420else:
2421 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002422 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2423 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2424 _check_date_fields, _check_int_field, _check_time_fields,
2425 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2426 _date_class, _days_before_month, _days_before_year, _days_in_month,
Paul Ganssle09dc2f52017-12-21 00:33:49 -05002427 _format_time, _format_offset, _is_leap, _isoweek1monday, _math,
2428 _ord2ymd, _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord,
2429 _divide_and_round, _parse_isoformat_date, _parse_isoformat_time,
2430 _parse_hh_mm_ss_ff)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002431 # XXX Since import * above excludes names that start with _,
2432 # docstring does not get overwritten. In the future, it may be
2433 # appropriate to maintain a single module level docstring and
2434 # remove the following line.
2435 from _datetime import __doc__