blob: 8fa18a78932c0481f4890d2fe53ca9a19fccafe2 [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
9
10def _cmp(x, y):
11 return 0 if x == y else 1 if x > y else -1
12
13MINYEAR = 1
14MAXYEAR = 9999
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -040015_MAXORDINAL = 3652059 # date.max.toordinal()
Alexander Belopolskycf86e362010-07-23 19:25:47 +000016
17# Utility functions, adapted from Python's Demo/classes/Dates.py, which
18# also assumes the current Gregorian calendar indefinitely extended in
19# both directions. Difference: Dates.py calls January 1 of year 0 day
20# number 1. The code here calls January 1 of year 1 day number 1. This is
21# to match the definition of the "proleptic Gregorian" calendar in Dershowitz
22# and Reingold's "Calendrical Calculations", where it's the base calendar
23# for all computations. See the book for algorithms for converting between
24# proleptic Gregorian ordinals and many other calendar systems.
25
Benjamin Petersonda0bea22013-08-29 17:29:30 -040026# -1 is a placeholder for indexing purposes.
Benjamin Petersonf908efb2013-08-29 17:27:57 -040027_DAYS_IN_MONTH = [-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
Alexander Belopolskycf86e362010-07-23 19:25:47 +000028
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -040029_DAYS_BEFORE_MONTH = [-1] # -1 is a placeholder for indexing purposes.
Alexander Belopolskycf86e362010-07-23 19:25:47 +000030dbm = 0
31for dim in _DAYS_IN_MONTH[1:]:
32 _DAYS_BEFORE_MONTH.append(dbm)
33 dbm += dim
34del dbm, dim
35
36def _is_leap(year):
37 "year -> 1 if leap year, else 0."
38 return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
39
40def _days_before_year(year):
41 "year -> number of days before January 1st of year."
42 y = year - 1
43 return y*365 + y//4 - y//100 + y//400
44
45def _days_in_month(year, month):
46 "year, month -> number of days in that month in that year."
47 assert 1 <= month <= 12, month
48 if month == 2 and _is_leap(year):
49 return 29
50 return _DAYS_IN_MONTH[month]
51
52def _days_before_month(year, month):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +030053 "year, month -> number of days in year preceding first day of month."
Alexander Belopolskycf86e362010-07-23 19:25:47 +000054 assert 1 <= month <= 12, 'month must be in 1..12'
55 return _DAYS_BEFORE_MONTH[month] + (month > 2 and _is_leap(year))
56
57def _ymd2ord(year, month, day):
58 "year, month, day -> ordinal, considering 01-Jan-0001 as day 1."
59 assert 1 <= month <= 12, 'month must be in 1..12'
60 dim = _days_in_month(year, month)
61 assert 1 <= day <= dim, ('day must be in 1..%d' % dim)
62 return (_days_before_year(year) +
63 _days_before_month(year, month) +
64 day)
65
66_DI400Y = _days_before_year(401) # number of days in 400 years
67_DI100Y = _days_before_year(101) # " " " " 100 "
68_DI4Y = _days_before_year(5) # " " " " 4 "
69
70# A 4-year cycle has an extra leap day over what we'd get from pasting
71# together 4 single years.
72assert _DI4Y == 4 * 365 + 1
73
74# Similarly, a 400-year cycle has an extra leap day over what we'd get from
75# pasting together 4 100-year cycles.
76assert _DI400Y == 4 * _DI100Y + 1
77
78# OTOH, a 100-year cycle has one fewer leap day than we'd get from
79# pasting together 25 4-year cycles.
80assert _DI100Y == 25 * _DI4Y - 1
81
82def _ord2ymd(n):
83 "ordinal -> (year, month, day), considering 01-Jan-0001 as day 1."
84
85 # n is a 1-based index, starting at 1-Jan-1. The pattern of leap years
86 # repeats exactly every 400 years. The basic strategy is to find the
87 # closest 400-year boundary at or before n, then work with the offset
88 # from that boundary to n. Life is much clearer if we subtract 1 from
89 # n first -- then the values of n at 400-year boundaries are exactly
90 # those divisible by _DI400Y:
91 #
92 # D M Y n n-1
93 # -- --- ---- ---------- ----------------
94 # 31 Dec -400 -_DI400Y -_DI400Y -1
95 # 1 Jan -399 -_DI400Y +1 -_DI400Y 400-year boundary
96 # ...
97 # 30 Dec 000 -1 -2
98 # 31 Dec 000 0 -1
99 # 1 Jan 001 1 0 400-year boundary
100 # 2 Jan 001 2 1
101 # 3 Jan 001 3 2
102 # ...
103 # 31 Dec 400 _DI400Y _DI400Y -1
104 # 1 Jan 401 _DI400Y +1 _DI400Y 400-year boundary
105 n -= 1
106 n400, n = divmod(n, _DI400Y)
107 year = n400 * 400 + 1 # ..., -399, 1, 401, ...
108
109 # Now n is the (non-negative) offset, in days, from January 1 of year, to
110 # the desired date. Now compute how many 100-year cycles precede n.
111 # Note that it's possible for n100 to equal 4! In that case 4 full
112 # 100-year cycles precede the desired day, which implies the desired
113 # day is December 31 at the end of a 400-year cycle.
114 n100, n = divmod(n, _DI100Y)
115
116 # Now compute how many 4-year cycles precede it.
117 n4, n = divmod(n, _DI4Y)
118
119 # And now how many single years. Again n1 can be 4, and again meaning
120 # that the desired day is December 31 at the end of the 4-year cycle.
121 n1, n = divmod(n, 365)
122
123 year += n100 * 100 + n4 * 4 + n1
124 if n1 == 4 or n100 == 4:
125 assert n == 0
126 return year-1, 12, 31
127
128 # Now the year is correct, and n is the offset from January 1. We find
129 # the month via an estimate that's either exact or one too large.
130 leapyear = n1 == 3 and (n4 != 24 or n100 == 3)
131 assert leapyear == _is_leap(year)
132 month = (n + 50) >> 5
133 preceding = _DAYS_BEFORE_MONTH[month] + (month > 2 and leapyear)
134 if preceding > n: # estimate is too large
135 month -= 1
136 preceding -= _DAYS_IN_MONTH[month] + (month == 2 and leapyear)
137 n -= preceding
138 assert 0 <= n < _days_in_month(year, month)
139
140 # Now the year and month are correct, and n is the offset from the
141 # start of that month: we're done!
142 return year, month, n+1
143
144# Month and day names. For localized versions, see the calendar module.
145_MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
146 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
147_DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
148
149
150def _build_struct_time(y, m, d, hh, mm, ss, dstflag):
151 wday = (_ymd2ord(y, m, d) + 6) % 7
152 dnum = _days_before_month(y, m) + d
153 return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag))
154
Alexander Belopolskya2998a62016-03-06 14:58:43 -0500155def _format_time(hh, mm, ss, us, timespec='auto'):
156 specs = {
157 'hours': '{:02d}',
158 'minutes': '{:02d}:{:02d}',
159 'seconds': '{:02d}:{:02d}:{:02d}',
160 'milliseconds': '{:02d}:{:02d}:{:02d}.{:03d}',
161 'microseconds': '{:02d}:{:02d}:{:02d}.{:06d}'
162 }
163
164 if timespec == 'auto':
165 # Skip trailing microseconds when us==0.
166 timespec = 'microseconds' if us else 'seconds'
167 elif timespec == 'milliseconds':
168 us //= 1000
169 try:
170 fmt = specs[timespec]
171 except KeyError:
172 raise ValueError('Unknown timespec value')
173 else:
174 return fmt.format(hh, mm, ss, us)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000175
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500176def _format_offset(off):
177 s = ''
178 if off is not None:
179 if off.days < 0:
180 sign = "-"
181 off = -off
182 else:
183 sign = "+"
184 hh, mm = divmod(off, timedelta(hours=1))
185 mm, ss = divmod(mm, timedelta(minutes=1))
186 s += "%s%02d:%02d" % (sign, hh, mm)
187 if ss or ss.microseconds:
188 s += ":%02d" % ss.seconds
189
190 if ss.microseconds:
191 s += '.%06d' % ss.microseconds
192 return s
193
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000194# Correctly substitute for %z and %Z escapes in strftime formats.
195def _wrap_strftime(object, format, timetuple):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000196 # Don't call utcoffset() or tzname() unless actually needed.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400197 freplace = None # the string to use for %f
198 zreplace = None # the string to use for %z
199 Zreplace = None # the string to use for %Z
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000200
201 # Scan format for %z and %Z escapes, replacing as needed.
202 newformat = []
203 push = newformat.append
204 i, n = 0, len(format)
205 while i < n:
206 ch = format[i]
207 i += 1
208 if ch == '%':
209 if i < n:
210 ch = format[i]
211 i += 1
212 if ch == 'f':
213 if freplace is None:
214 freplace = '%06d' % getattr(object,
215 'microsecond', 0)
216 newformat.append(freplace)
217 elif ch == 'z':
218 if zreplace is None:
219 zreplace = ""
220 if hasattr(object, "utcoffset"):
221 offset = object.utcoffset()
222 if offset is not None:
223 sign = '+'
224 if offset.days < 0:
225 offset = -offset
226 sign = '-'
Alexander Belopolsky018d3532017-07-31 10:26:50 -0400227 h, rest = divmod(offset, timedelta(hours=1))
228 m, rest = divmod(rest, timedelta(minutes=1))
229 s = rest.seconds
230 u = offset.microseconds
231 if u:
232 zreplace = '%c%02d%02d%02d.%06d' % (sign, h, m, s, u)
233 elif s:
234 zreplace = '%c%02d%02d%02d' % (sign, h, m, s)
235 else:
236 zreplace = '%c%02d%02d' % (sign, h, m)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000237 assert '%' not in zreplace
238 newformat.append(zreplace)
239 elif ch == 'Z':
240 if Zreplace is None:
241 Zreplace = ""
242 if hasattr(object, "tzname"):
243 s = object.tzname()
244 if s is not None:
245 # strftime is going to have at this: escape %
246 Zreplace = s.replace('%', '%%')
247 newformat.append(Zreplace)
248 else:
249 push('%')
250 push(ch)
251 else:
252 push('%')
253 else:
254 push(ch)
255 newformat = "".join(newformat)
256 return _time.strftime(newformat, timetuple)
257
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500258# Helpers for parsing the result of isoformat()
259def _parse_isoformat_date(dtstr):
260 # It is assumed that this function will only be called with a
261 # string of length exactly 10, and (though this is not used) ASCII-only
262 year = int(dtstr[0:4])
263 if dtstr[4] != '-':
264 raise ValueError('Invalid date separator: %s' % dtstr[4])
265
266 month = int(dtstr[5:7])
267
268 if dtstr[7] != '-':
269 raise ValueError('Invalid date separator')
270
271 day = int(dtstr[8:10])
272
273 return [year, month, day]
274
275def _parse_hh_mm_ss_ff(tstr):
276 # Parses things of the form HH[:MM[:SS[.fff[fff]]]]
277 len_str = len(tstr)
278
279 time_comps = [0, 0, 0, 0]
280 pos = 0
281 for comp in range(0, 3):
282 if (len_str - pos) < 2:
283 raise ValueError('Incomplete time component')
284
285 time_comps[comp] = int(tstr[pos:pos+2])
286
287 pos += 2
288 next_char = tstr[pos:pos+1]
289
290 if not next_char or comp >= 2:
291 break
292
293 if next_char != ':':
294 raise ValueError('Invalid time separator: %c' % next_char)
295
296 pos += 1
297
298 if pos < len_str:
299 if tstr[pos] != '.':
300 raise ValueError('Invalid microsecond component')
301 else:
302 pos += 1
303
304 len_remainder = len_str - pos
305 if len_remainder not in (3, 6):
306 raise ValueError('Invalid microsecond component')
307
308 time_comps[3] = int(tstr[pos:])
309 if len_remainder == 3:
310 time_comps[3] *= 1000
311
312 return time_comps
313
314def _parse_isoformat_time(tstr):
315 # Format supported is HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]
316 len_str = len(tstr)
317 if len_str < 2:
318 raise ValueError('Isoformat time too short')
319
320 # This is equivalent to re.search('[+-]', tstr), but faster
321 tz_pos = (tstr.find('-') + 1 or tstr.find('+') + 1)
322 timestr = tstr[:tz_pos-1] if tz_pos > 0 else tstr
323
324 time_comps = _parse_hh_mm_ss_ff(timestr)
325
326 tzi = None
327 if tz_pos > 0:
328 tzstr = tstr[tz_pos:]
329
330 # Valid time zone strings are:
331 # HH:MM len: 5
332 # HH:MM:SS len: 8
333 # HH:MM:SS.ffffff len: 15
334
335 if len(tzstr) not in (5, 8, 15):
336 raise ValueError('Malformed time zone string')
337
338 tz_comps = _parse_hh_mm_ss_ff(tzstr)
339 if all(x == 0 for x in tz_comps):
340 tzi = timezone.utc
341 else:
342 tzsign = -1 if tstr[tz_pos - 1] == '-' else 1
343
344 td = timedelta(hours=tz_comps[0], minutes=tz_comps[1],
345 seconds=tz_comps[2], microseconds=tz_comps[3])
346
347 tzi = timezone(tzsign * td)
348
349 time_comps.append(tzi)
350
351 return time_comps
352
353
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000354# Just raise TypeError if the arg isn't None or a string.
355def _check_tzname(name):
356 if name is not None and not isinstance(name, str):
357 raise TypeError("tzinfo.tzname() must return None or string, "
358 "not '%s'" % type(name))
359
360# name is the offset-producing method, "utcoffset" or "dst".
361# offset is what it returned.
362# If offset isn't None or timedelta, raises TypeError.
363# If offset is None, returns None.
Alexander Belopolsky018d3532017-07-31 10:26:50 -0400364# Else offset is checked for being in range.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000365# If it is, its integer value is returned. Else ValueError is raised.
366def _check_utc_offset(name, offset):
367 assert name in ("utcoffset", "dst")
368 if offset is None:
369 return
370 if not isinstance(offset, timedelta):
371 raise TypeError("tzinfo.%s() must return None "
372 "or timedelta, not '%s'" % (name, type(offset)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000373 if not -timedelta(1) < offset < timedelta(1):
Martin Panterdd780e42016-05-30 04:08:23 +0000374 raise ValueError("%s()=%s, must be strictly between "
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400375 "-timedelta(hours=24) and timedelta(hours=24)" %
376 (name, offset))
377
378def _check_int_field(value):
379 if isinstance(value, int):
380 return value
381 if not isinstance(value, float):
382 try:
383 value = value.__int__()
384 except AttributeError:
385 pass
386 else:
387 if isinstance(value, int):
388 return value
389 raise TypeError('__int__ returned non-int (type %s)' %
390 type(value).__name__)
391 raise TypeError('an integer is required (got type %s)' %
392 type(value).__name__)
393 raise TypeError('integer argument expected, got float')
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000394
395def _check_date_fields(year, month, day):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400396 year = _check_int_field(year)
397 month = _check_int_field(month)
398 day = _check_int_field(day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000399 if not MINYEAR <= year <= MAXYEAR:
400 raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year)
401 if not 1 <= month <= 12:
402 raise ValueError('month must be in 1..12', month)
403 dim = _days_in_month(year, month)
404 if not 1 <= day <= dim:
405 raise ValueError('day must be in 1..%d' % dim, day)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400406 return year, month, day
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000407
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400408def _check_time_fields(hour, minute, second, microsecond, fold):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400409 hour = _check_int_field(hour)
410 minute = _check_int_field(minute)
411 second = _check_int_field(second)
412 microsecond = _check_int_field(microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000413 if not 0 <= hour <= 23:
414 raise ValueError('hour must be in 0..23', hour)
415 if not 0 <= minute <= 59:
416 raise ValueError('minute must be in 0..59', minute)
417 if not 0 <= second <= 59:
418 raise ValueError('second must be in 0..59', second)
419 if not 0 <= microsecond <= 999999:
420 raise ValueError('microsecond must be in 0..999999', microsecond)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400421 if fold not in (0, 1):
422 raise ValueError('fold must be either 0 or 1', fold)
423 return hour, minute, second, microsecond, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000424
425def _check_tzinfo_arg(tz):
426 if tz is not None and not isinstance(tz, tzinfo):
427 raise TypeError("tzinfo argument must be None or of a tzinfo subclass")
428
429def _cmperror(x, y):
430 raise TypeError("can't compare '%s' to '%s'" % (
431 type(x).__name__, type(y).__name__))
432
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500433def _divide_and_round(a, b):
434 """divide a by b and round result to the nearest integer
435
436 When the ratio is exactly half-way between two integers,
437 the even integer is returned.
438 """
439 # Based on the reference implementation for divmod_near
440 # in Objects/longobject.c.
441 q, r = divmod(a, b)
442 # round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
443 # The expression r / b > 0.5 is equivalent to 2 * r > b if b is
444 # positive, 2 * r < b if b negative.
445 r *= 2
446 greater_than_half = r > b if b > 0 else r < b
447 if greater_than_half or r == b and q % 2 == 1:
448 q += 1
449
450 return q
451
Victor Stinner2ec55872015-09-02 19:16:07 +0200452
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000453class timedelta:
454 """Represent the difference between two datetime objects.
455
456 Supported operators:
457
458 - add, subtract timedelta
459 - unary plus, minus, abs
460 - compare to timedelta
Serhiy Storchaka95949422013-08-27 19:40:23 +0300461 - multiply, divide by int
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000462
463 In addition, datetime supports subtraction of two datetime objects
464 returning a timedelta, and addition or subtraction of a datetime
465 and a timedelta giving a datetime.
466
467 Representation: (days, seconds, microseconds). Why? Because I
468 felt like it.
469 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400470 __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000471
472 def __new__(cls, days=0, seconds=0, microseconds=0,
473 milliseconds=0, minutes=0, hours=0, weeks=0):
474 # Doing this efficiently and accurately in C is going to be difficult
475 # and error-prone, due to ubiquitous overflow possibilities, and that
476 # C double doesn't have enough bits of precision to represent
477 # microseconds over 10K years faithfully. The code here tries to make
478 # explicit where go-fast assumptions can be relied on, in order to
479 # guide the C implementation; it's way more convoluted than speed-
480 # ignoring auto-overflow-to-long idiomatic Python could be.
481
482 # XXX Check that all inputs are ints or floats.
483
484 # Final values, all integer.
485 # s and us fit in 32-bit signed ints; d isn't bounded.
486 d = s = us = 0
487
488 # Normalize everything to days, seconds, microseconds.
489 days += weeks*7
490 seconds += minutes*60 + hours*3600
491 microseconds += milliseconds*1000
492
493 # Get rid of all fractions, and normalize s and us.
494 # Take a deep breath <wink>.
495 if isinstance(days, float):
496 dayfrac, days = _math.modf(days)
497 daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
498 assert daysecondswhole == int(daysecondswhole) # can't overflow
499 s = int(daysecondswhole)
500 assert days == int(days)
501 d = int(days)
502 else:
503 daysecondsfrac = 0.0
504 d = days
505 assert isinstance(daysecondsfrac, float)
506 assert abs(daysecondsfrac) <= 1.0
507 assert isinstance(d, int)
508 assert abs(s) <= 24 * 3600
509 # days isn't referenced again before redefinition
510
511 if isinstance(seconds, float):
512 secondsfrac, seconds = _math.modf(seconds)
513 assert seconds == int(seconds)
514 seconds = int(seconds)
515 secondsfrac += daysecondsfrac
516 assert abs(secondsfrac) <= 2.0
517 else:
518 secondsfrac = daysecondsfrac
519 # daysecondsfrac isn't referenced again
520 assert isinstance(secondsfrac, float)
521 assert abs(secondsfrac) <= 2.0
522
523 assert isinstance(seconds, int)
524 days, seconds = divmod(seconds, 24*3600)
525 d += days
526 s += int(seconds) # can't overflow
527 assert isinstance(s, int)
528 assert abs(s) <= 2 * 24 * 3600
529 # seconds isn't referenced again before redefinition
530
531 usdouble = secondsfrac * 1e6
532 assert abs(usdouble) < 2.1e6 # exact value not critical
533 # secondsfrac isn't referenced again
534
535 if isinstance(microseconds, float):
Victor Stinner69cc4872015-09-08 23:58:54 +0200536 microseconds = round(microseconds + usdouble)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000537 seconds, microseconds = divmod(microseconds, 1000000)
538 days, seconds = divmod(seconds, 24*3600)
539 d += days
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400540 s += seconds
541 else:
542 microseconds = int(microseconds)
543 seconds, microseconds = divmod(microseconds, 1000000)
544 days, seconds = divmod(seconds, 24*3600)
545 d += days
546 s += seconds
Victor Stinner69cc4872015-09-08 23:58:54 +0200547 microseconds = round(microseconds + usdouble)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400548 assert isinstance(s, int)
549 assert isinstance(microseconds, int)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000550 assert abs(s) <= 3 * 24 * 3600
551 assert abs(microseconds) < 3.1e6
552
553 # Just a little bit of carrying possible for microseconds and seconds.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400554 seconds, us = divmod(microseconds, 1000000)
555 s += seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000556 days, s = divmod(s, 24*3600)
557 d += days
558
559 assert isinstance(d, int)
560 assert isinstance(s, int) and 0 <= s < 24*3600
561 assert isinstance(us, int) and 0 <= us < 1000000
562
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000563 if abs(d) > 999999999:
564 raise OverflowError("timedelta # of days is too large: %d" % d)
565
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400566 self = object.__new__(cls)
567 self._days = d
568 self._seconds = s
569 self._microseconds = us
570 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000571 return self
572
573 def __repr__(self):
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200574 args = []
575 if self._days:
576 args.append("days=%d" % self._days)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000577 if self._seconds:
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200578 args.append("seconds=%d" % self._seconds)
579 if self._microseconds:
580 args.append("microseconds=%d" % self._microseconds)
581 if not args:
582 args.append('0')
583 return "%s.%s(%s)" % (self.__class__.__module__,
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300584 self.__class__.__qualname__,
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200585 ', '.join(args))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000586
587 def __str__(self):
588 mm, ss = divmod(self._seconds, 60)
589 hh, mm = divmod(mm, 60)
590 s = "%d:%02d:%02d" % (hh, mm, ss)
591 if self._days:
592 def plural(n):
593 return n, abs(n) != 1 and "s" or ""
594 s = ("%d day%s, " % plural(self._days)) + s
595 if self._microseconds:
596 s = s + ".%06d" % self._microseconds
597 return s
598
599 def total_seconds(self):
600 """Total seconds in the duration."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400601 return ((self.days * 86400 + self.seconds) * 10**6 +
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000602 self.microseconds) / 10**6
603
604 # Read-only field accessors
605 @property
606 def days(self):
607 """days"""
608 return self._days
609
610 @property
611 def seconds(self):
612 """seconds"""
613 return self._seconds
614
615 @property
616 def microseconds(self):
617 """microseconds"""
618 return self._microseconds
619
620 def __add__(self, other):
621 if isinstance(other, timedelta):
622 # for CPython compatibility, we cannot use
623 # our __class__ here, but need a real timedelta
624 return timedelta(self._days + other._days,
625 self._seconds + other._seconds,
626 self._microseconds + other._microseconds)
627 return NotImplemented
628
629 __radd__ = __add__
630
631 def __sub__(self, other):
632 if isinstance(other, timedelta):
Alexander Belopolskyb6f5ec72011-04-05 20:07:38 -0400633 # for CPython compatibility, we cannot use
634 # our __class__ here, but need a real timedelta
635 return timedelta(self._days - other._days,
636 self._seconds - other._seconds,
637 self._microseconds - other._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000638 return NotImplemented
639
640 def __rsub__(self, other):
641 if isinstance(other, timedelta):
642 return -self + other
643 return NotImplemented
644
645 def __neg__(self):
646 # for CPython compatibility, we cannot use
647 # our __class__ here, but need a real timedelta
648 return timedelta(-self._days,
649 -self._seconds,
650 -self._microseconds)
651
652 def __pos__(self):
653 return self
654
655 def __abs__(self):
656 if self._days < 0:
657 return -self
658 else:
659 return self
660
661 def __mul__(self, other):
662 if isinstance(other, int):
663 # for CPython compatibility, we cannot use
664 # our __class__ here, but need a real timedelta
665 return timedelta(self._days * other,
666 self._seconds * other,
667 self._microseconds * other)
668 if isinstance(other, float):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500669 usec = self._to_microseconds()
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000670 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500671 return timedelta(0, 0, _divide_and_round(usec * a, b))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000672 return NotImplemented
673
674 __rmul__ = __mul__
675
676 def _to_microseconds(self):
677 return ((self._days * (24*3600) + self._seconds) * 1000000 +
678 self._microseconds)
679
680 def __floordiv__(self, other):
681 if not isinstance(other, (int, timedelta)):
682 return NotImplemented
683 usec = self._to_microseconds()
684 if isinstance(other, timedelta):
685 return usec // other._to_microseconds()
686 if isinstance(other, int):
687 return timedelta(0, 0, usec // other)
688
689 def __truediv__(self, other):
690 if not isinstance(other, (int, float, timedelta)):
691 return NotImplemented
692 usec = self._to_microseconds()
693 if isinstance(other, timedelta):
694 return usec / other._to_microseconds()
695 if isinstance(other, int):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500696 return timedelta(0, 0, _divide_and_round(usec, other))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000697 if isinstance(other, float):
698 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500699 return timedelta(0, 0, _divide_and_round(b * usec, a))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000700
701 def __mod__(self, other):
702 if isinstance(other, timedelta):
703 r = self._to_microseconds() % other._to_microseconds()
704 return timedelta(0, 0, r)
705 return NotImplemented
706
707 def __divmod__(self, other):
708 if isinstance(other, timedelta):
709 q, r = divmod(self._to_microseconds(),
710 other._to_microseconds())
711 return q, timedelta(0, 0, r)
712 return NotImplemented
713
714 # Comparisons of timedelta objects with other.
715
716 def __eq__(self, other):
717 if isinstance(other, timedelta):
718 return self._cmp(other) == 0
719 else:
720 return False
721
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000722 def __le__(self, other):
723 if isinstance(other, timedelta):
724 return self._cmp(other) <= 0
725 else:
726 _cmperror(self, other)
727
728 def __lt__(self, other):
729 if isinstance(other, timedelta):
730 return self._cmp(other) < 0
731 else:
732 _cmperror(self, other)
733
734 def __ge__(self, other):
735 if isinstance(other, timedelta):
736 return self._cmp(other) >= 0
737 else:
738 _cmperror(self, other)
739
740 def __gt__(self, other):
741 if isinstance(other, timedelta):
742 return self._cmp(other) > 0
743 else:
744 _cmperror(self, other)
745
746 def _cmp(self, other):
747 assert isinstance(other, timedelta)
748 return _cmp(self._getstate(), other._getstate())
749
750 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400751 if self._hashcode == -1:
752 self._hashcode = hash(self._getstate())
753 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000754
755 def __bool__(self):
756 return (self._days != 0 or
757 self._seconds != 0 or
758 self._microseconds != 0)
759
760 # Pickle support.
761
762 def _getstate(self):
763 return (self._days, self._seconds, self._microseconds)
764
765 def __reduce__(self):
766 return (self.__class__, self._getstate())
767
768timedelta.min = timedelta(-999999999)
769timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
770 microseconds=999999)
771timedelta.resolution = timedelta(microseconds=1)
772
773class date:
774 """Concrete date type.
775
776 Constructors:
777
778 __new__()
779 fromtimestamp()
780 today()
781 fromordinal()
782
783 Operators:
784
785 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200786 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000787 __add__, __radd__, __sub__ (add/radd only with timedelta arg)
788
789 Methods:
790
791 timetuple()
792 toordinal()
793 weekday()
794 isoweekday(), isocalendar(), isoformat()
795 ctime()
796 strftime()
797
798 Properties (readonly):
799 year, month, day
800 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400801 __slots__ = '_year', '_month', '_day', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000802
803 def __new__(cls, year, month=None, day=None):
804 """Constructor.
805
806 Arguments:
807
808 year, month, day (required, base 1)
809 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400810 if month is None and isinstance(year, bytes) and len(year) == 4 and \
811 1 <= year[2] <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000812 # Pickle support
813 self = object.__new__(cls)
814 self.__setstate(year)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400815 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000816 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400817 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000818 self = object.__new__(cls)
819 self._year = year
820 self._month = month
821 self._day = day
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400822 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000823 return self
824
825 # Additional constructors
826
827 @classmethod
828 def fromtimestamp(cls, t):
829 "Construct a date from a POSIX timestamp (like time.time())."
830 y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
831 return cls(y, m, d)
832
833 @classmethod
834 def today(cls):
835 "Construct a date from time.time()."
836 t = _time.time()
837 return cls.fromtimestamp(t)
838
839 @classmethod
840 def fromordinal(cls, n):
Martin Pantereb995702016-07-28 01:11:04 +0000841 """Construct a date from a proleptic Gregorian ordinal.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000842
843 January 1 of year 1 is day 1. Only the year, month and day are
844 non-zero in the result.
845 """
846 y, m, d = _ord2ymd(n)
847 return cls(y, m, d)
848
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500849 @classmethod
850 def fromisoformat(cls, date_string):
851 """Construct a date from the output of date.isoformat()."""
852 if not isinstance(date_string, str):
853 raise TypeError('fromisoformat: argument must be str')
854
855 try:
856 assert len(date_string) == 10
857 return cls(*_parse_isoformat_date(date_string))
858 except Exception:
859 raise ValueError('Invalid isoformat string: %s' % date_string)
860
861
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000862 # Conversions to string
863
864 def __repr__(self):
865 """Convert to formal string, for repr().
866
867 >>> dt = datetime(2010, 1, 1)
868 >>> repr(dt)
869 'datetime.datetime(2010, 1, 1, 0, 0)'
870
871 >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
872 >>> repr(dt)
873 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
874 """
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300875 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
876 self.__class__.__qualname__,
877 self._year,
878 self._month,
879 self._day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000880 # XXX These shouldn't depend on time.localtime(), because that
881 # clips the usable dates to [1970 .. 2038). At least ctime() is
882 # easily done without using strftime() -- that's better too because
883 # strftime("%c", ...) is locale specific.
884
885
886 def ctime(self):
887 "Return ctime() style string."
888 weekday = self.toordinal() % 7 or 7
889 return "%s %s %2d 00:00:00 %04d" % (
890 _DAYNAMES[weekday],
891 _MONTHNAMES[self._month],
892 self._day, self._year)
893
894 def strftime(self, fmt):
895 "Format using strftime()."
896 return _wrap_strftime(self, fmt, self.timetuple())
897
898 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400899 if not isinstance(fmt, str):
900 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000901 if len(fmt) != 0:
902 return self.strftime(fmt)
903 return str(self)
904
905 def isoformat(self):
906 """Return the date formatted according to ISO.
907
908 This is 'YYYY-MM-DD'.
909
910 References:
911 - http://www.w3.org/TR/NOTE-datetime
912 - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
913 """
914 return "%04d-%02d-%02d" % (self._year, self._month, self._day)
915
916 __str__ = isoformat
917
918 # Read-only field accessors
919 @property
920 def year(self):
921 """year (1-9999)"""
922 return self._year
923
924 @property
925 def month(self):
926 """month (1-12)"""
927 return self._month
928
929 @property
930 def day(self):
931 """day (1-31)"""
932 return self._day
933
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200934 # Standard conversions, __eq__, __le__, __lt__, __ge__, __gt__,
935 # __hash__ (and helpers)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000936
937 def timetuple(self):
938 "Return local time tuple compatible with time.localtime()."
939 return _build_struct_time(self._year, self._month, self._day,
940 0, 0, 0, -1)
941
942 def toordinal(self):
943 """Return proleptic Gregorian ordinal for the year, month and day.
944
945 January 1 of year 1 is day 1. Only the year, month and day values
946 contribute to the result.
947 """
948 return _ymd2ord(self._year, self._month, self._day)
949
950 def replace(self, year=None, month=None, day=None):
951 """Return a new date with new values for the specified fields."""
952 if year is None:
953 year = self._year
954 if month is None:
955 month = self._month
956 if day is None:
957 day = self._day
Paul Ganssle191e9932017-11-09 16:34:29 -0500958 return type(self)(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000959
960 # Comparisons of date objects with other.
961
962 def __eq__(self, other):
963 if isinstance(other, date):
964 return self._cmp(other) == 0
965 return NotImplemented
966
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000967 def __le__(self, other):
968 if isinstance(other, date):
969 return self._cmp(other) <= 0
970 return NotImplemented
971
972 def __lt__(self, other):
973 if isinstance(other, date):
974 return self._cmp(other) < 0
975 return NotImplemented
976
977 def __ge__(self, other):
978 if isinstance(other, date):
979 return self._cmp(other) >= 0
980 return NotImplemented
981
982 def __gt__(self, other):
983 if isinstance(other, date):
984 return self._cmp(other) > 0
985 return NotImplemented
986
987 def _cmp(self, other):
988 assert isinstance(other, date)
989 y, m, d = self._year, self._month, self._day
990 y2, m2, d2 = other._year, other._month, other._day
991 return _cmp((y, m, d), (y2, m2, d2))
992
993 def __hash__(self):
994 "Hash."
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400995 if self._hashcode == -1:
996 self._hashcode = hash(self._getstate())
997 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000998
999 # Computations
1000
1001 def __add__(self, other):
1002 "Add a date to a timedelta."
1003 if isinstance(other, timedelta):
1004 o = self.toordinal() + other.days
1005 if 0 < o <= _MAXORDINAL:
1006 return date.fromordinal(o)
1007 raise OverflowError("result out of range")
1008 return NotImplemented
1009
1010 __radd__ = __add__
1011
1012 def __sub__(self, other):
1013 """Subtract two dates, or a date and a timedelta."""
1014 if isinstance(other, timedelta):
1015 return self + timedelta(-other.days)
1016 if isinstance(other, date):
1017 days1 = self.toordinal()
1018 days2 = other.toordinal()
1019 return timedelta(days1 - days2)
1020 return NotImplemented
1021
1022 def weekday(self):
1023 "Return day of the week, where Monday == 0 ... Sunday == 6."
1024 return (self.toordinal() + 6) % 7
1025
1026 # Day-of-the-week and week-of-the-year, according to ISO
1027
1028 def isoweekday(self):
1029 "Return day of the week, where Monday == 1 ... Sunday == 7."
1030 # 1-Jan-0001 is a Monday
1031 return self.toordinal() % 7 or 7
1032
1033 def isocalendar(self):
1034 """Return a 3-tuple containing ISO year, week number, and weekday.
1035
1036 The first ISO week of the year is the (Mon-Sun) week
1037 containing the year's first Thursday; everything else derives
1038 from that.
1039
1040 The first week is 1; Monday is 1 ... Sunday is 7.
1041
1042 ISO calendar algorithm taken from
1043 http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
Brett Cannon07b954d2016-01-15 09:53:51 -08001044 (used with permission)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001045 """
1046 year = self._year
1047 week1monday = _isoweek1monday(year)
1048 today = _ymd2ord(self._year, self._month, self._day)
1049 # Internally, week and day have origin 0
1050 week, day = divmod(today - week1monday, 7)
1051 if week < 0:
1052 year -= 1
1053 week1monday = _isoweek1monday(year)
1054 week, day = divmod(today - week1monday, 7)
1055 elif week >= 52:
1056 if today >= _isoweek1monday(year+1):
1057 year += 1
1058 week = 0
1059 return year, week+1, day+1
1060
1061 # Pickle support.
1062
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001063 def _getstate(self):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001064 yhi, ylo = divmod(self._year, 256)
1065 return bytes([yhi, ylo, self._month, self._day]),
1066
1067 def __setstate(self, string):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001068 yhi, ylo, self._month, self._day = string
1069 self._year = yhi * 256 + ylo
1070
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001071 def __reduce__(self):
1072 return (self.__class__, self._getstate())
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001073
1074_date_class = date # so functions w/ args named "date" can get at the class
1075
1076date.min = date(1, 1, 1)
1077date.max = date(9999, 12, 31)
1078date.resolution = timedelta(days=1)
1079
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001080
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001081class tzinfo:
1082 """Abstract base class for time zone info classes.
1083
1084 Subclasses must override the name(), utcoffset() and dst() methods.
1085 """
1086 __slots__ = ()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001087
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001088 def tzname(self, dt):
1089 "datetime -> string name of time zone."
1090 raise NotImplementedError("tzinfo subclass must override tzname()")
1091
1092 def utcoffset(self, dt):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001093 "datetime -> timedelta, positive for east of UTC, negative for west of UTC"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001094 raise NotImplementedError("tzinfo subclass must override utcoffset()")
1095
1096 def dst(self, dt):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001097 """datetime -> DST offset as timedelta, positive for east of UTC.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001098
1099 Return 0 if DST not in effect. utcoffset() must include the DST
1100 offset.
1101 """
1102 raise NotImplementedError("tzinfo subclass must override dst()")
1103
1104 def fromutc(self, dt):
1105 "datetime in UTC -> datetime in local time."
1106
1107 if not isinstance(dt, datetime):
1108 raise TypeError("fromutc() requires a datetime argument")
1109 if dt.tzinfo is not self:
1110 raise ValueError("dt.tzinfo is not self")
1111
1112 dtoff = dt.utcoffset()
1113 if dtoff is None:
1114 raise ValueError("fromutc() requires a non-None utcoffset() "
1115 "result")
1116
1117 # See the long comment block at the end of this file for an
1118 # explanation of this algorithm.
1119 dtdst = dt.dst()
1120 if dtdst is None:
1121 raise ValueError("fromutc() requires a non-None dst() result")
1122 delta = dtoff - dtdst
1123 if delta:
1124 dt += delta
1125 dtdst = dt.dst()
1126 if dtdst is None:
1127 raise ValueError("fromutc(): dt.dst gave inconsistent "
1128 "results; cannot convert")
1129 return dt + dtdst
1130
1131 # Pickle support.
1132
1133 def __reduce__(self):
1134 getinitargs = getattr(self, "__getinitargs__", None)
1135 if getinitargs:
1136 args = getinitargs()
1137 else:
1138 args = ()
1139 getstate = getattr(self, "__getstate__", None)
1140 if getstate:
1141 state = getstate()
1142 else:
1143 state = getattr(self, "__dict__", None) or None
1144 if state is None:
1145 return (self.__class__, args)
1146 else:
1147 return (self.__class__, args, state)
1148
1149_tzinfo_class = tzinfo
1150
1151class time:
1152 """Time with time zone.
1153
1154 Constructors:
1155
1156 __new__()
1157
1158 Operators:
1159
1160 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +02001161 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001162
1163 Methods:
1164
1165 strftime()
1166 isoformat()
1167 utcoffset()
1168 tzname()
1169 dst()
1170
1171 Properties (readonly):
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001172 hour, minute, second, microsecond, tzinfo, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001173 """
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001174 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode', '_fold'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001175
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001176 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001177 """Constructor.
1178
1179 Arguments:
1180
1181 hour, minute (required)
1182 second, microsecond (default to zero)
1183 tzinfo (default to None)
Victor Stinner51b90d22017-01-04 12:01:16 +01001184 fold (keyword only, default to zero)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001185 """
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001186 if isinstance(hour, bytes) and len(hour) == 6 and hour[0]&0x7F < 24:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001187 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001188 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001189 self.__setstate(hour, minute or None)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001190 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001191 return self
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001192 hour, minute, second, microsecond, fold = _check_time_fields(
1193 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001194 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001195 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001196 self._hour = hour
1197 self._minute = minute
1198 self._second = second
1199 self._microsecond = microsecond
1200 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001201 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001202 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001203 return self
1204
1205 # Read-only field accessors
1206 @property
1207 def hour(self):
1208 """hour (0-23)"""
1209 return self._hour
1210
1211 @property
1212 def minute(self):
1213 """minute (0-59)"""
1214 return self._minute
1215
1216 @property
1217 def second(self):
1218 """second (0-59)"""
1219 return self._second
1220
1221 @property
1222 def microsecond(self):
1223 """microsecond (0-999999)"""
1224 return self._microsecond
1225
1226 @property
1227 def tzinfo(self):
1228 """timezone info object"""
1229 return self._tzinfo
1230
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001231 @property
1232 def fold(self):
1233 return self._fold
1234
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001235 # Standard conversions, __hash__ (and helpers)
1236
1237 # Comparisons of time objects with other.
1238
1239 def __eq__(self, other):
1240 if isinstance(other, time):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001241 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001242 else:
1243 return False
1244
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001245 def __le__(self, other):
1246 if isinstance(other, time):
1247 return self._cmp(other) <= 0
1248 else:
1249 _cmperror(self, other)
1250
1251 def __lt__(self, other):
1252 if isinstance(other, time):
1253 return self._cmp(other) < 0
1254 else:
1255 _cmperror(self, other)
1256
1257 def __ge__(self, other):
1258 if isinstance(other, time):
1259 return self._cmp(other) >= 0
1260 else:
1261 _cmperror(self, other)
1262
1263 def __gt__(self, other):
1264 if isinstance(other, time):
1265 return self._cmp(other) > 0
1266 else:
1267 _cmperror(self, other)
1268
Alexander Belopolsky08313822012-06-15 20:19:47 -04001269 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001270 assert isinstance(other, time)
1271 mytz = self._tzinfo
1272 ottz = other._tzinfo
1273 myoff = otoff = None
1274
1275 if mytz is ottz:
1276 base_compare = True
1277 else:
1278 myoff = self.utcoffset()
1279 otoff = other.utcoffset()
1280 base_compare = myoff == otoff
1281
1282 if base_compare:
1283 return _cmp((self._hour, self._minute, self._second,
1284 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001285 (other._hour, other._minute, other._second,
1286 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001287 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001288 if allow_mixed:
1289 return 2 # arbitrary non-zero value
1290 else:
1291 raise TypeError("cannot compare naive and aware times")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001292 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1293 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1294 return _cmp((myhhmm, self._second, self._microsecond),
1295 (othhmm, other._second, other._microsecond))
1296
1297 def __hash__(self):
1298 """Hash."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001299 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001300 if self.fold:
1301 t = self.replace(fold=0)
1302 else:
1303 t = self
1304 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001305 if not tzoff: # zero or None
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001306 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001307 else:
1308 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1309 timedelta(hours=1))
1310 assert not m % timedelta(minutes=1), "whole minute"
1311 m //= timedelta(minutes=1)
1312 if 0 <= h < 24:
1313 self._hashcode = hash(time(h, m, self.second, self.microsecond))
1314 else:
1315 self._hashcode = hash((h, m, self.second, self.microsecond))
1316 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001317
1318 # Conversion to string
1319
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001320 def _tzstr(self):
1321 """Return formatted timezone offset (+xx:xx) or an empty string."""
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001322 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001323 return _format_offset(off)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001324
1325 def __repr__(self):
1326 """Convert to formal string, for repr()."""
1327 if self._microsecond != 0:
1328 s = ", %d, %d" % (self._second, self._microsecond)
1329 elif self._second != 0:
1330 s = ", %d" % self._second
1331 else:
1332 s = ""
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001333 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1334 self.__class__.__qualname__,
1335 self._hour, self._minute, s)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001336 if self._tzinfo is not None:
1337 assert s[-1:] == ")"
1338 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001339 if self._fold:
1340 assert s[-1:] == ")"
1341 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001342 return s
1343
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001344 def isoformat(self, timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001345 """Return the time formatted according to ISO.
1346
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001347 The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional
1348 part is omitted if self.microsecond == 0.
1349
1350 The optional argument timespec specifies the number of additional
1351 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001352 """
1353 s = _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001354 self._microsecond, timespec)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001355 tz = self._tzstr()
1356 if tz:
1357 s += tz
1358 return s
1359
1360 __str__ = isoformat
1361
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001362 @classmethod
1363 def fromisoformat(cls, time_string):
1364 """Construct a time from the output of isoformat()."""
1365 if not isinstance(time_string, str):
1366 raise TypeError('fromisoformat: argument must be str')
1367
1368 try:
1369 return cls(*_parse_isoformat_time(time_string))
1370 except Exception:
1371 raise ValueError('Invalid isoformat string: %s' % time_string)
1372
1373
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001374 def strftime(self, fmt):
1375 """Format using strftime(). The date part of the timestamp passed
1376 to underlying strftime should not be used.
1377 """
Alexander Belopolskyb8bb4662011-01-08 00:13:34 +00001378 # The year must be >= 1000 else Python's strftime implementation
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001379 # can raise a bogus exception.
1380 timetuple = (1900, 1, 1,
1381 self._hour, self._minute, self._second,
1382 0, 1, -1)
1383 return _wrap_strftime(self, fmt, timetuple)
1384
1385 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001386 if not isinstance(fmt, str):
1387 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001388 if len(fmt) != 0:
1389 return self.strftime(fmt)
1390 return str(self)
1391
1392 # Timezone functions
1393
1394 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001395 """Return the timezone offset as timedelta, positive east of UTC
1396 (negative west of UTC)."""
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001397 if self._tzinfo is None:
1398 return None
1399 offset = self._tzinfo.utcoffset(None)
1400 _check_utc_offset("utcoffset", offset)
1401 return offset
1402
1403 def tzname(self):
1404 """Return the timezone name.
1405
1406 Note that the name is 100% informational -- there's no requirement that
1407 it mean anything in particular. For example, "GMT", "UTC", "-500",
1408 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1409 """
1410 if self._tzinfo is None:
1411 return None
1412 name = self._tzinfo.tzname(None)
1413 _check_tzname(name)
1414 return name
1415
1416 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001417 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1418 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001419
1420 This is purely informational; the DST offset has already been added to
1421 the UTC offset returned by utcoffset() if applicable, so there's no
1422 need to consult dst() unless you're interested in displaying the DST
1423 info.
1424 """
1425 if self._tzinfo is None:
1426 return None
1427 offset = self._tzinfo.dst(None)
1428 _check_utc_offset("dst", offset)
1429 return offset
1430
1431 def replace(self, hour=None, minute=None, second=None, microsecond=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001432 tzinfo=True, *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001433 """Return a new time with new values for the specified fields."""
1434 if hour is None:
1435 hour = self.hour
1436 if minute is None:
1437 minute = self.minute
1438 if second is None:
1439 second = self.second
1440 if microsecond is None:
1441 microsecond = self.microsecond
1442 if tzinfo is True:
1443 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001444 if fold is None:
1445 fold = self._fold
Paul Ganssle191e9932017-11-09 16:34:29 -05001446 return type(self)(hour, minute, second, microsecond, tzinfo, fold=fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001447
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001448 # Pickle support.
1449
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001450 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001451 us2, us3 = divmod(self._microsecond, 256)
1452 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001453 h = self._hour
1454 if self._fold and protocol > 3:
1455 h += 128
1456 basestate = bytes([h, self._minute, self._second,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001457 us1, us2, us3])
1458 if self._tzinfo is None:
1459 return (basestate,)
1460 else:
1461 return (basestate, self._tzinfo)
1462
1463 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001464 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1465 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001466 h, self._minute, self._second, us1, us2, us3 = string
1467 if h > 127:
1468 self._fold = 1
1469 self._hour = h - 128
1470 else:
1471 self._fold = 0
1472 self._hour = h
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001473 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001474 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001475
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001476 def __reduce_ex__(self, protocol):
1477 return (time, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001478
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001479 def __reduce__(self):
1480 return self.__reduce_ex__(2)
1481
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001482_time_class = time # so functions w/ args named "time" can get at the class
1483
1484time.min = time(0, 0, 0)
1485time.max = time(23, 59, 59, 999999)
1486time.resolution = timedelta(microseconds=1)
1487
1488class datetime(date):
1489 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1490
1491 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001492 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001493 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001494 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001495
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001496 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001497 microsecond=0, tzinfo=None, *, fold=0):
1498 if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2]&0x7F <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001499 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001500 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001501 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001502 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001503 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001504 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001505 hour, minute, second, microsecond, fold = _check_time_fields(
1506 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001507 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001508 self = object.__new__(cls)
1509 self._year = year
1510 self._month = month
1511 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001512 self._hour = hour
1513 self._minute = minute
1514 self._second = second
1515 self._microsecond = microsecond
1516 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001517 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001518 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001519 return self
1520
1521 # Read-only field accessors
1522 @property
1523 def hour(self):
1524 """hour (0-23)"""
1525 return self._hour
1526
1527 @property
1528 def minute(self):
1529 """minute (0-59)"""
1530 return self._minute
1531
1532 @property
1533 def second(self):
1534 """second (0-59)"""
1535 return self._second
1536
1537 @property
1538 def microsecond(self):
1539 """microsecond (0-999999)"""
1540 return self._microsecond
1541
1542 @property
1543 def tzinfo(self):
1544 """timezone info object"""
1545 return self._tzinfo
1546
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001547 @property
1548 def fold(self):
1549 return self._fold
1550
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001551 @classmethod
Victor Stinneradfefa52015-09-04 23:57:25 +02001552 def _fromtimestamp(cls, t, utc, tz):
1553 """Construct a datetime from a POSIX timestamp (like time.time()).
1554
1555 A timezone info object may be passed in as well.
1556 """
1557 frac, t = _math.modf(t)
Victor Stinner7667f582015-09-09 01:02:23 +02001558 us = round(frac * 1e6)
Victor Stinneradfefa52015-09-04 23:57:25 +02001559 if us >= 1000000:
1560 t += 1
1561 us -= 1000000
1562 elif us < 0:
1563 t -= 1
1564 us += 1000000
1565
1566 converter = _time.gmtime if utc else _time.localtime
1567 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1568 ss = min(ss, 59) # clamp out leap seconds if the platform has them
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001569 result = cls(y, m, d, hh, mm, ss, us, tz)
1570 if tz is None:
1571 # As of version 2015f max fold in IANA database is
1572 # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
1573 # Let's probe 24 hours in the past to detect a transition:
1574 max_fold_seconds = 24 * 3600
1575 y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1576 probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1577 trans = result - probe1 - timedelta(0, max_fold_seconds)
1578 if trans.days < 0:
1579 y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
1580 probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1581 if probe2 == result:
1582 result._fold = 1
1583 else:
1584 result = tz.fromutc(result)
1585 return result
Victor Stinneradfefa52015-09-04 23:57:25 +02001586
1587 @classmethod
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001588 def fromtimestamp(cls, t, tz=None):
1589 """Construct a datetime from a POSIX timestamp (like time.time()).
1590
1591 A timezone info object may be passed in as well.
1592 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001593 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001594
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001595 return cls._fromtimestamp(t, tz is not None, tz)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001596
1597 @classmethod
1598 def utcfromtimestamp(cls, t):
Alexander Belopolskye2e178e2015-03-01 14:52:07 -05001599 """Construct a naive UTC datetime from a POSIX timestamp."""
Victor Stinneradfefa52015-09-04 23:57:25 +02001600 return cls._fromtimestamp(t, True, None)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001601
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001602 @classmethod
1603 def now(cls, tz=None):
1604 "Construct a datetime from time.time() and optional time zone info."
1605 t = _time.time()
1606 return cls.fromtimestamp(t, tz)
1607
1608 @classmethod
1609 def utcnow(cls):
1610 "Construct a UTC datetime from time.time()."
1611 t = _time.time()
1612 return cls.utcfromtimestamp(t)
1613
1614 @classmethod
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001615 def combine(cls, date, time, tzinfo=True):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001616 "Construct a datetime from a given date and a given time."
1617 if not isinstance(date, _date_class):
1618 raise TypeError("date argument must be a date instance")
1619 if not isinstance(time, _time_class):
1620 raise TypeError("time argument must be a time instance")
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001621 if tzinfo is True:
1622 tzinfo = time.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001623 return cls(date.year, date.month, date.day,
1624 time.hour, time.minute, time.second, time.microsecond,
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001625 tzinfo, fold=time.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001626
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001627 @classmethod
1628 def fromisoformat(cls, date_string):
1629 """Construct a datetime from the output of datetime.isoformat()."""
1630 if not isinstance(date_string, str):
1631 raise TypeError('fromisoformat: argument must be str')
1632
1633 # Split this at the separator
1634 dstr = date_string[0:10]
1635 tstr = date_string[11:]
1636
1637 try:
1638 date_components = _parse_isoformat_date(dstr)
1639 except ValueError:
1640 raise ValueError('Invalid isoformat string: %s' % date_string)
1641
1642 if tstr:
1643 try:
1644 time_components = _parse_isoformat_time(tstr)
1645 except ValueError:
1646 raise ValueError('Invalid isoformat string: %s' % date_string)
1647 else:
1648 time_components = [0, 0, 0, 0, None]
1649
1650 return cls(*(date_components + time_components))
1651
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001652 def timetuple(self):
1653 "Return local time tuple compatible with time.localtime()."
1654 dst = self.dst()
1655 if dst is None:
1656 dst = -1
1657 elif dst:
1658 dst = 1
1659 else:
1660 dst = 0
1661 return _build_struct_time(self.year, self.month, self.day,
1662 self.hour, self.minute, self.second,
1663 dst)
1664
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001665 def _mktime(self):
1666 """Return integer POSIX timestamp."""
1667 epoch = datetime(1970, 1, 1)
1668 max_fold_seconds = 24 * 3600
1669 t = (self - epoch) // timedelta(0, 1)
1670 def local(u):
1671 y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1672 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1673
1674 # Our goal is to solve t = local(u) for u.
1675 a = local(t) - t
1676 u1 = t - a
1677 t1 = local(u1)
1678 if t1 == t:
1679 # We found one solution, but it may not be the one we need.
1680 # Look for an earlier solution (if `fold` is 0), or a
1681 # later one (if `fold` is 1).
1682 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1683 b = local(u2) - u2
1684 if a == b:
1685 return u1
1686 else:
1687 b = t1 - u1
1688 assert a != b
1689 u2 = t - b
1690 t2 = local(u2)
1691 if t2 == t:
1692 return u2
1693 if t1 == t:
1694 return u1
1695 # We have found both offsets a and b, but neither t - a nor t - b is
1696 # a solution. This means t is in the gap.
1697 return (max, min)[self.fold](u1, u2)
1698
1699
Alexander Belopolskya4415142012-06-08 12:33:09 -04001700 def timestamp(self):
1701 "Return POSIX timestamp as float"
1702 if self._tzinfo is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001703 s = self._mktime()
1704 return s + self.microsecond / 1e6
Alexander Belopolskya4415142012-06-08 12:33:09 -04001705 else:
1706 return (self - _EPOCH).total_seconds()
1707
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001708 def utctimetuple(self):
1709 "Return UTC time tuple compatible with time.gmtime()."
1710 offset = self.utcoffset()
1711 if offset:
1712 self -= offset
1713 y, m, d = self.year, self.month, self.day
1714 hh, mm, ss = self.hour, self.minute, self.second
1715 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1716
1717 def date(self):
1718 "Return the date part."
1719 return date(self._year, self._month, self._day)
1720
1721 def time(self):
1722 "Return the time part, with tzinfo None."
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001723 return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001724
1725 def timetz(self):
1726 "Return the time part, with same tzinfo."
1727 return time(self.hour, self.minute, self.second, self.microsecond,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001728 self._tzinfo, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001729
1730 def replace(self, year=None, month=None, day=None, hour=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001731 minute=None, second=None, microsecond=None, tzinfo=True,
1732 *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001733 """Return a new datetime with new values for the specified fields."""
1734 if year is None:
1735 year = self.year
1736 if month is None:
1737 month = self.month
1738 if day is None:
1739 day = self.day
1740 if hour is None:
1741 hour = self.hour
1742 if minute is None:
1743 minute = self.minute
1744 if second is None:
1745 second = self.second
1746 if microsecond is None:
1747 microsecond = self.microsecond
1748 if tzinfo is True:
1749 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001750 if fold is None:
1751 fold = self.fold
Paul Ganssle191e9932017-11-09 16:34:29 -05001752 return type(self)(year, month, day, hour, minute, second,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001753 microsecond, tzinfo, fold=fold)
1754
1755 def _local_timezone(self):
1756 if self.tzinfo is None:
1757 ts = self._mktime()
1758 else:
1759 ts = (self - _EPOCH) // timedelta(seconds=1)
1760 localtm = _time.localtime(ts)
1761 local = datetime(*localtm[:6])
1762 try:
1763 # Extract TZ data if available
1764 gmtoff = localtm.tm_gmtoff
1765 zone = localtm.tm_zone
1766 except AttributeError:
1767 delta = local - datetime(*_time.gmtime(ts)[:6])
1768 zone = _time.strftime('%Z', localtm)
1769 tz = timezone(delta, zone)
1770 else:
1771 tz = timezone(timedelta(seconds=gmtoff), zone)
1772 return tz
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001773
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001774 def astimezone(self, tz=None):
1775 if tz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001776 tz = self._local_timezone()
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001777 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001778 raise TypeError("tz argument must be an instance of tzinfo")
1779
1780 mytz = self.tzinfo
1781 if mytz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001782 mytz = self._local_timezone()
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001783
1784 if tz is mytz:
1785 return self
1786
1787 # Convert self to UTC, and attach the new time zone object.
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001788 myoffset = mytz.utcoffset(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001789 if myoffset is None:
1790 raise ValueError("astimezone() requires an aware datetime")
1791 utc = (self - myoffset).replace(tzinfo=tz)
1792
1793 # Convert from UTC to tz's local time.
1794 return tz.fromutc(utc)
1795
1796 # Ways to produce a string.
1797
1798 def ctime(self):
1799 "Return ctime() style string."
1800 weekday = self.toordinal() % 7 or 7
1801 return "%s %s %2d %02d:%02d:%02d %04d" % (
1802 _DAYNAMES[weekday],
1803 _MONTHNAMES[self._month],
1804 self._day,
1805 self._hour, self._minute, self._second,
1806 self._year)
1807
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001808 def isoformat(self, sep='T', timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001809 """Return the time formatted according to ISO.
1810
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001811 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1812 By default, the fractional part is omitted if self.microsecond == 0.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001813
1814 If self.tzinfo is not None, the UTC offset is also attached, giving
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001815 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001816
1817 Optional argument sep specifies the separator between date and
1818 time, default 'T'.
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001819
1820 The optional argument timespec specifies the number of additional
1821 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001822 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001823 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1824 _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001825 self._microsecond, timespec))
1826
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001827 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001828 tz = _format_offset(off)
1829 if tz:
1830 s += tz
1831
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001832 return s
1833
1834 def __repr__(self):
1835 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001836 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001837 self._hour, self._minute, self._second, self._microsecond]
1838 if L[-1] == 0:
1839 del L[-1]
1840 if L[-1] == 0:
1841 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001842 s = "%s.%s(%s)" % (self.__class__.__module__,
1843 self.__class__.__qualname__,
1844 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001845 if self._tzinfo is not None:
1846 assert s[-1:] == ")"
1847 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001848 if self._fold:
1849 assert s[-1:] == ")"
1850 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001851 return s
1852
1853 def __str__(self):
1854 "Convert to string, for str()."
1855 return self.isoformat(sep=' ')
1856
1857 @classmethod
1858 def strptime(cls, date_string, format):
1859 'string, format -> new datetime parsed from a string (like time.strptime()).'
1860 import _strptime
1861 return _strptime._strptime_datetime(cls, date_string, format)
1862
1863 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001864 """Return the timezone offset as timedelta positive east of UTC (negative west of
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001865 UTC)."""
1866 if self._tzinfo is None:
1867 return None
1868 offset = self._tzinfo.utcoffset(self)
1869 _check_utc_offset("utcoffset", offset)
1870 return offset
1871
1872 def tzname(self):
1873 """Return the timezone name.
1874
1875 Note that the name is 100% informational -- there's no requirement that
1876 it mean anything in particular. For example, "GMT", "UTC", "-500",
1877 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1878 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001879 if self._tzinfo is None:
1880 return None
1881 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001882 _check_tzname(name)
1883 return name
1884
1885 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001886 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1887 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001888
1889 This is purely informational; the DST offset has already been added to
1890 the UTC offset returned by utcoffset() if applicable, so there's no
1891 need to consult dst() unless you're interested in displaying the DST
1892 info.
1893 """
1894 if self._tzinfo is None:
1895 return None
1896 offset = self._tzinfo.dst(self)
1897 _check_utc_offset("dst", offset)
1898 return offset
1899
1900 # Comparisons of datetime objects with other.
1901
1902 def __eq__(self, other):
1903 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001904 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001905 elif not isinstance(other, date):
1906 return NotImplemented
1907 else:
1908 return False
1909
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001910 def __le__(self, other):
1911 if isinstance(other, datetime):
1912 return self._cmp(other) <= 0
1913 elif not isinstance(other, date):
1914 return NotImplemented
1915 else:
1916 _cmperror(self, other)
1917
1918 def __lt__(self, other):
1919 if isinstance(other, datetime):
1920 return self._cmp(other) < 0
1921 elif not isinstance(other, date):
1922 return NotImplemented
1923 else:
1924 _cmperror(self, other)
1925
1926 def __ge__(self, other):
1927 if isinstance(other, datetime):
1928 return self._cmp(other) >= 0
1929 elif not isinstance(other, date):
1930 return NotImplemented
1931 else:
1932 _cmperror(self, other)
1933
1934 def __gt__(self, other):
1935 if isinstance(other, datetime):
1936 return self._cmp(other) > 0
1937 elif not isinstance(other, date):
1938 return NotImplemented
1939 else:
1940 _cmperror(self, other)
1941
Alexander Belopolsky08313822012-06-15 20:19:47 -04001942 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001943 assert isinstance(other, datetime)
1944 mytz = self._tzinfo
1945 ottz = other._tzinfo
1946 myoff = otoff = None
1947
1948 if mytz is ottz:
1949 base_compare = True
1950 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04001951 myoff = self.utcoffset()
1952 otoff = other.utcoffset()
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001953 # Assume that allow_mixed means that we are called from __eq__
1954 if allow_mixed:
1955 if myoff != self.replace(fold=not self.fold).utcoffset():
1956 return 2
1957 if otoff != other.replace(fold=not other.fold).utcoffset():
1958 return 2
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001959 base_compare = myoff == otoff
1960
1961 if base_compare:
1962 return _cmp((self._year, self._month, self._day,
1963 self._hour, self._minute, self._second,
1964 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001965 (other._year, other._month, other._day,
1966 other._hour, other._minute, other._second,
1967 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001968 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001969 if allow_mixed:
1970 return 2 # arbitrary non-zero value
1971 else:
1972 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001973 # XXX What follows could be done more efficiently...
1974 diff = self - other # this will take offsets into account
1975 if diff.days < 0:
1976 return -1
1977 return diff and 1 or 0
1978
1979 def __add__(self, other):
1980 "Add a datetime and a timedelta."
1981 if not isinstance(other, timedelta):
1982 return NotImplemented
1983 delta = timedelta(self.toordinal(),
1984 hours=self._hour,
1985 minutes=self._minute,
1986 seconds=self._second,
1987 microseconds=self._microsecond)
1988 delta += other
1989 hour, rem = divmod(delta.seconds, 3600)
1990 minute, second = divmod(rem, 60)
1991 if 0 < delta.days <= _MAXORDINAL:
1992 return datetime.combine(date.fromordinal(delta.days),
1993 time(hour, minute, second,
1994 delta.microseconds,
1995 tzinfo=self._tzinfo))
1996 raise OverflowError("result out of range")
1997
1998 __radd__ = __add__
1999
2000 def __sub__(self, other):
2001 "Subtract two datetimes, or a datetime and a timedelta."
2002 if not isinstance(other, datetime):
2003 if isinstance(other, timedelta):
2004 return self + -other
2005 return NotImplemented
2006
2007 days1 = self.toordinal()
2008 days2 = other.toordinal()
2009 secs1 = self._second + self._minute * 60 + self._hour * 3600
2010 secs2 = other._second + other._minute * 60 + other._hour * 3600
2011 base = timedelta(days1 - days2,
2012 secs1 - secs2,
2013 self._microsecond - other._microsecond)
2014 if self._tzinfo is other._tzinfo:
2015 return base
2016 myoff = self.utcoffset()
2017 otoff = other.utcoffset()
2018 if myoff == otoff:
2019 return base
2020 if myoff is None or otoff is None:
2021 raise TypeError("cannot mix naive and timezone-aware time")
2022 return base + otoff - myoff
2023
2024 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002025 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002026 if self.fold:
2027 t = self.replace(fold=0)
2028 else:
2029 t = self
2030 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002031 if tzoff is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002032 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002033 else:
2034 days = _ymd2ord(self.year, self.month, self.day)
2035 seconds = self.hour * 3600 + self.minute * 60 + self.second
2036 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
2037 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002038
2039 # Pickle support.
2040
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002041 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002042 yhi, ylo = divmod(self._year, 256)
2043 us2, us3 = divmod(self._microsecond, 256)
2044 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002045 m = self._month
2046 if self._fold and protocol > 3:
2047 m += 128
2048 basestate = bytes([yhi, ylo, m, self._day,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002049 self._hour, self._minute, self._second,
2050 us1, us2, us3])
2051 if self._tzinfo is None:
2052 return (basestate,)
2053 else:
2054 return (basestate, self._tzinfo)
2055
2056 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002057 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
2058 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002059 (yhi, ylo, m, self._day, self._hour,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002060 self._minute, self._second, us1, us2, us3) = string
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002061 if m > 127:
2062 self._fold = 1
2063 self._month = m - 128
2064 else:
2065 self._fold = 0
2066 self._month = m
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002067 self._year = yhi * 256 + ylo
2068 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002069 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002070
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002071 def __reduce_ex__(self, protocol):
2072 return (self.__class__, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002073
Serhiy Storchaka546ce652016-11-22 00:29:42 +02002074 def __reduce__(self):
2075 return self.__reduce_ex__(2)
2076
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002077
2078datetime.min = datetime(1, 1, 1)
2079datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
2080datetime.resolution = timedelta(microseconds=1)
2081
2082
2083def _isoweek1monday(year):
2084 # Helper to calculate the day number of the Monday starting week 1
2085 # XXX This could be done more efficiently
2086 THURSDAY = 3
2087 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002088 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002089 week1monday = firstday - firstweekday
2090 if firstweekday > THURSDAY:
2091 week1monday += 7
2092 return week1monday
2093
2094class timezone(tzinfo):
2095 __slots__ = '_offset', '_name'
2096
2097 # Sentinel value to disallow None
2098 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002099 def __new__(cls, offset, name=_Omitted):
2100 if not isinstance(offset, timedelta):
2101 raise TypeError("offset must be a timedelta")
2102 if name is cls._Omitted:
2103 if not offset:
2104 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002105 name = None
2106 elif not isinstance(name, str):
2107 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002108 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002109 raise ValueError("offset must be a timedelta "
2110 "strictly between -timedelta(hours=24) and "
2111 "timedelta(hours=24).")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002112 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002113
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002114 @classmethod
2115 def _create(cls, offset, name=None):
2116 self = tzinfo.__new__(cls)
2117 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002118 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002119 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002120
2121 def __getinitargs__(self):
2122 """pickle support"""
2123 if self._name is None:
2124 return (self._offset,)
2125 return (self._offset, self._name)
2126
2127 def __eq__(self, other):
Georg Brandl0085a242012-09-22 09:23:12 +02002128 if type(other) != timezone:
2129 return False
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002130 return self._offset == other._offset
2131
2132 def __hash__(self):
2133 return hash(self._offset)
2134
2135 def __repr__(self):
2136 """Convert to formal string, for repr().
2137
2138 >>> tz = timezone.utc
2139 >>> repr(tz)
2140 'datetime.timezone.utc'
2141 >>> tz = timezone(timedelta(hours=-5), 'EST')
2142 >>> repr(tz)
2143 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
2144 """
2145 if self is self.utc:
2146 return 'datetime.timezone.utc'
2147 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03002148 return "%s.%s(%r)" % (self.__class__.__module__,
2149 self.__class__.__qualname__,
2150 self._offset)
2151 return "%s.%s(%r, %r)" % (self.__class__.__module__,
2152 self.__class__.__qualname__,
2153 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002154
2155 def __str__(self):
2156 return self.tzname(None)
2157
2158 def utcoffset(self, dt):
2159 if isinstance(dt, datetime) or dt is None:
2160 return self._offset
2161 raise TypeError("utcoffset() argument must be a datetime instance"
2162 " or None")
2163
2164 def tzname(self, dt):
2165 if isinstance(dt, datetime) or dt is None:
2166 if self._name is None:
2167 return self._name_from_offset(self._offset)
2168 return self._name
2169 raise TypeError("tzname() argument must be a datetime instance"
2170 " or None")
2171
2172 def dst(self, dt):
2173 if isinstance(dt, datetime) or dt is None:
2174 return None
2175 raise TypeError("dst() argument must be a datetime instance"
2176 " or None")
2177
2178 def fromutc(self, dt):
2179 if isinstance(dt, datetime):
2180 if dt.tzinfo is not self:
2181 raise ValueError("fromutc: dt.tzinfo "
2182 "is not self")
2183 return dt + self._offset
2184 raise TypeError("fromutc() argument must be a datetime instance"
2185 " or None")
2186
2187 _maxoffset = timedelta(hours=23, minutes=59)
2188 _minoffset = -_maxoffset
2189
2190 @staticmethod
2191 def _name_from_offset(delta):
Alexander Belopolsky7827a5b2015-09-06 13:07:21 -04002192 if not delta:
2193 return 'UTC'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002194 if delta < timedelta(0):
2195 sign = '-'
2196 delta = -delta
2197 else:
2198 sign = '+'
2199 hours, rest = divmod(delta, timedelta(hours=1))
Alexander Belopolsky018d3532017-07-31 10:26:50 -04002200 minutes, rest = divmod(rest, timedelta(minutes=1))
2201 seconds = rest.seconds
2202 microseconds = rest.microseconds
2203 if microseconds:
2204 return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2205 f'.{microseconds:06d}')
2206 if seconds:
2207 return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2208 return f'UTC{sign}{hours:02d}:{minutes:02d}'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002209
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002210timezone.utc = timezone._create(timedelta(0))
2211timezone.min = timezone._create(timezone._minoffset)
2212timezone.max = timezone._create(timezone._maxoffset)
Alexander Belopolskya4415142012-06-08 12:33:09 -04002213_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002214
Victor Stinner765531d2013-03-26 01:11:54 +01002215# Some time zone algebra. For a datetime x, let
2216# x.n = x stripped of its timezone -- its naive time.
2217# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2218# return None
2219# x.d = x.dst(), and assuming that doesn't raise an exception or
2220# return None
2221# x.s = x's standard offset, x.o - x.d
2222#
2223# Now some derived rules, where k is a duration (timedelta).
2224#
2225# 1. x.o = x.s + x.d
2226# This follows from the definition of x.s.
2227#
2228# 2. If x and y have the same tzinfo member, x.s = y.s.
2229# This is actually a requirement, an assumption we need to make about
2230# sane tzinfo classes.
2231#
2232# 3. The naive UTC time corresponding to x is x.n - x.o.
2233# This is again a requirement for a sane tzinfo class.
2234#
2235# 4. (x+k).s = x.s
2236# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
2237#
2238# 5. (x+k).n = x.n + k
2239# Again follows from how arithmetic is defined.
2240#
2241# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
2242# (meaning that the various tzinfo methods exist, and don't blow up or return
2243# None when called).
2244#
2245# The function wants to return a datetime y with timezone tz, equivalent to x.
2246# x is already in UTC.
2247#
2248# By #3, we want
2249#
2250# y.n - y.o = x.n [1]
2251#
2252# The algorithm starts by attaching tz to x.n, and calling that y. So
2253# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
2254# becomes true; in effect, we want to solve [2] for k:
2255#
2256# (y+k).n - (y+k).o = x.n [2]
2257#
2258# By #1, this is the same as
2259#
2260# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
2261#
2262# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2263# Substituting that into [3],
2264#
2265# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2266# k - (y+k).s - (y+k).d = 0; rearranging,
2267# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2268# k = y.s - (y+k).d
2269#
2270# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2271# approximate k by ignoring the (y+k).d term at first. Note that k can't be
2272# very large, since all offset-returning methods return a duration of magnitude
2273# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
2274# be 0, so ignoring it has no consequence then.
2275#
2276# In any case, the new value is
2277#
2278# z = y + y.s [4]
2279#
2280# It's helpful to step back at look at [4] from a higher level: it's simply
2281# mapping from UTC to tz's standard time.
2282#
2283# At this point, if
2284#
2285# z.n - z.o = x.n [5]
2286#
2287# we have an equivalent time, and are almost done. The insecurity here is
2288# at the start of daylight time. Picture US Eastern for concreteness. The wall
2289# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2290# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2291# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2292# on the day DST starts. We want to return the 1:MM EST spelling because that's
2293# the only spelling that makes sense on the local wall clock.
2294#
2295# In fact, if [5] holds at this point, we do have the standard-time spelling,
2296# but that takes a bit of proof. We first prove a stronger result. What's the
2297# difference between the LHS and RHS of [5]? Let
2298#
2299# diff = x.n - (z.n - z.o) [6]
2300#
2301# Now
2302# z.n = by [4]
2303# (y + y.s).n = by #5
2304# y.n + y.s = since y.n = x.n
2305# x.n + y.s = since z and y are have the same tzinfo member,
2306# y.s = z.s by #2
2307# x.n + z.s
2308#
2309# Plugging that back into [6] gives
2310#
2311# diff =
2312# x.n - ((x.n + z.s) - z.o) = expanding
2313# x.n - x.n - z.s + z.o = cancelling
2314# - z.s + z.o = by #2
2315# z.d
2316#
2317# So diff = z.d.
2318#
2319# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2320# spelling we wanted in the endcase described above. We're done. Contrarily,
2321# if z.d = 0, then we have a UTC equivalent, and are also done.
2322#
2323# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2324# add to z (in effect, z is in tz's standard time, and we need to shift the
2325# local clock into tz's daylight time).
2326#
2327# Let
2328#
2329# z' = z + z.d = z + diff [7]
2330#
2331# and we can again ask whether
2332#
2333# z'.n - z'.o = x.n [8]
2334#
2335# If so, we're done. If not, the tzinfo class is insane, according to the
2336# assumptions we've made. This also requires a bit of proof. As before, let's
2337# compute the difference between the LHS and RHS of [8] (and skipping some of
2338# the justifications for the kinds of substitutions we've done several times
2339# already):
2340#
2341# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2342# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2343# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2344# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2345# - z.n + z.n - z.o + z'.o = cancel z.n
2346# - z.o + z'.o = #1 twice
2347# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2348# z'.d - z.d
2349#
2350# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2351# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2352# return z', not bothering to compute z'.d.
2353#
2354# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2355# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2356# would have to change the result dst() returns: we start in DST, and moving
2357# a little further into it takes us out of DST.
2358#
2359# There isn't a sane case where this can happen. The closest it gets is at
2360# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2361# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2362# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2363# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2364# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2365# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2366# standard time. Since that's what the local clock *does*, we want to map both
2367# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2368# in local time, but so it goes -- it's the way the local clock works.
2369#
2370# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2371# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2372# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2373# (correctly) concludes that z' is not UTC-equivalent to x.
2374#
2375# Because we know z.d said z was in daylight time (else [5] would have held and
2376# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2377# and we have stopped then), and there are only 2 possible values dst() can
2378# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2379# but the reasoning doesn't depend on the example -- it depends on there being
2380# two possible dst() outcomes, one zero and the other non-zero). Therefore
2381# z' must be in standard time, and is the spelling we want in this case.
2382#
2383# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2384# concerned (because it takes z' as being in standard time rather than the
2385# daylight time we intend here), but returning it gives the real-life "local
2386# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2387# tz.
2388#
2389# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2390# the 1:MM standard time spelling we want.
2391#
2392# So how can this break? One of the assumptions must be violated. Two
2393# possibilities:
2394#
2395# 1) [2] effectively says that y.s is invariant across all y belong to a given
2396# time zone. This isn't true if, for political reasons or continental drift,
2397# a region decides to change its base offset from UTC.
2398#
2399# 2) There may be versions of "double daylight" time where the tail end of
2400# the analysis gives up a step too early. I haven't thought about that
2401# enough to say.
2402#
2403# In any case, it's clear that the default fromutc() is strong enough to handle
2404# "almost all" time zones: so long as the standard offset is invariant, it
2405# doesn't matter if daylight time transition points change from year to year, or
2406# if daylight time is skipped in some years; it doesn't matter how large or
2407# small dst() may get within its bounds; and it doesn't even matter if some
2408# perverse time zone returns a negative dst()). So a breaking case must be
2409# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002410
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002411try:
2412 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002413except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002414 pass
2415else:
2416 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002417 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2418 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2419 _check_date_fields, _check_int_field, _check_time_fields,
2420 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2421 _date_class, _days_before_month, _days_before_year, _days_in_month,
Paul Ganssle09dc2f52017-12-21 00:33:49 -05002422 _format_time, _format_offset, _is_leap, _isoweek1monday, _math,
2423 _ord2ymd, _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord,
2424 _divide_and_round, _parse_isoformat_date, _parse_isoformat_time,
2425 _parse_hh_mm_ss_ff)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002426 # XXX Since import * above excludes names that start with _,
2427 # docstring does not get overwritten. In the future, it may be
2428 # appropriate to maintain a single module level docstring and
2429 # remove the following line.
2430 from _datetime import __doc__