blob: 5e922c80b017ffb2f36873a56ca42037c8425be6 [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])
Alexander Belopolskybcb032e2018-06-08 19:22:33 -04001762 # Extract TZ data
1763 gmtoff = localtm.tm_gmtoff
1764 zone = localtm.tm_zone
1765 return timezone(timedelta(seconds=gmtoff), zone)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001766
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001767 def astimezone(self, tz=None):
1768 if tz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001769 tz = self._local_timezone()
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001770 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001771 raise TypeError("tz argument must be an instance of tzinfo")
1772
1773 mytz = self.tzinfo
1774 if mytz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001775 mytz = self._local_timezone()
Alexander Belopolsky877b2322018-06-10 17:02:58 -04001776 myoffset = mytz.utcoffset(self)
1777 else:
1778 myoffset = mytz.utcoffset(self)
1779 if myoffset is None:
1780 mytz = self.replace(tzinfo=None)._local_timezone()
1781 myoffset = mytz.utcoffset(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001782
1783 if tz is mytz:
1784 return self
1785
1786 # Convert self to UTC, and attach the new time zone object.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001787 utc = (self - myoffset).replace(tzinfo=tz)
1788
1789 # Convert from UTC to tz's local time.
1790 return tz.fromutc(utc)
1791
1792 # Ways to produce a string.
1793
1794 def ctime(self):
1795 "Return ctime() style string."
1796 weekday = self.toordinal() % 7 or 7
1797 return "%s %s %2d %02d:%02d:%02d %04d" % (
1798 _DAYNAMES[weekday],
1799 _MONTHNAMES[self._month],
1800 self._day,
1801 self._hour, self._minute, self._second,
1802 self._year)
1803
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001804 def isoformat(self, sep='T', timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001805 """Return the time formatted according to ISO.
1806
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001807 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1808 By default, the fractional part is omitted if self.microsecond == 0.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001809
1810 If self.tzinfo is not None, the UTC offset is also attached, giving
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001811 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001812
1813 Optional argument sep specifies the separator between date and
1814 time, default 'T'.
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001815
1816 The optional argument timespec specifies the number of additional
1817 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001818 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001819 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1820 _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001821 self._microsecond, timespec))
1822
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001823 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001824 tz = _format_offset(off)
1825 if tz:
1826 s += tz
1827
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001828 return s
1829
1830 def __repr__(self):
1831 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001832 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001833 self._hour, self._minute, self._second, self._microsecond]
1834 if L[-1] == 0:
1835 del L[-1]
1836 if L[-1] == 0:
1837 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001838 s = "%s.%s(%s)" % (self.__class__.__module__,
1839 self.__class__.__qualname__,
1840 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001841 if self._tzinfo is not None:
1842 assert s[-1:] == ")"
1843 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001844 if self._fold:
1845 assert s[-1:] == ")"
1846 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001847 return s
1848
1849 def __str__(self):
1850 "Convert to string, for str()."
1851 return self.isoformat(sep=' ')
1852
1853 @classmethod
1854 def strptime(cls, date_string, format):
1855 'string, format -> new datetime parsed from a string (like time.strptime()).'
1856 import _strptime
1857 return _strptime._strptime_datetime(cls, date_string, format)
1858
1859 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001860 """Return the timezone offset as timedelta positive east of UTC (negative west of
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001861 UTC)."""
1862 if self._tzinfo is None:
1863 return None
1864 offset = self._tzinfo.utcoffset(self)
1865 _check_utc_offset("utcoffset", offset)
1866 return offset
1867
1868 def tzname(self):
1869 """Return the timezone name.
1870
1871 Note that the name is 100% informational -- there's no requirement that
1872 it mean anything in particular. For example, "GMT", "UTC", "-500",
1873 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1874 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001875 if self._tzinfo is None:
1876 return None
1877 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001878 _check_tzname(name)
1879 return name
1880
1881 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001882 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1883 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001884
1885 This is purely informational; the DST offset has already been added to
1886 the UTC offset returned by utcoffset() if applicable, so there's no
1887 need to consult dst() unless you're interested in displaying the DST
1888 info.
1889 """
1890 if self._tzinfo is None:
1891 return None
1892 offset = self._tzinfo.dst(self)
1893 _check_utc_offset("dst", offset)
1894 return offset
1895
1896 # Comparisons of datetime objects with other.
1897
1898 def __eq__(self, other):
1899 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001900 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001901 elif not isinstance(other, date):
1902 return NotImplemented
1903 else:
1904 return False
1905
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001906 def __le__(self, other):
1907 if isinstance(other, datetime):
1908 return self._cmp(other) <= 0
1909 elif not isinstance(other, date):
1910 return NotImplemented
1911 else:
1912 _cmperror(self, other)
1913
1914 def __lt__(self, other):
1915 if isinstance(other, datetime):
1916 return self._cmp(other) < 0
1917 elif not isinstance(other, date):
1918 return NotImplemented
1919 else:
1920 _cmperror(self, other)
1921
1922 def __ge__(self, other):
1923 if isinstance(other, datetime):
1924 return self._cmp(other) >= 0
1925 elif not isinstance(other, date):
1926 return NotImplemented
1927 else:
1928 _cmperror(self, other)
1929
1930 def __gt__(self, other):
1931 if isinstance(other, datetime):
1932 return self._cmp(other) > 0
1933 elif not isinstance(other, date):
1934 return NotImplemented
1935 else:
1936 _cmperror(self, other)
1937
Alexander Belopolsky08313822012-06-15 20:19:47 -04001938 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001939 assert isinstance(other, datetime)
1940 mytz = self._tzinfo
1941 ottz = other._tzinfo
1942 myoff = otoff = None
1943
1944 if mytz is ottz:
1945 base_compare = True
1946 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04001947 myoff = self.utcoffset()
1948 otoff = other.utcoffset()
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001949 # Assume that allow_mixed means that we are called from __eq__
1950 if allow_mixed:
1951 if myoff != self.replace(fold=not self.fold).utcoffset():
1952 return 2
1953 if otoff != other.replace(fold=not other.fold).utcoffset():
1954 return 2
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001955 base_compare = myoff == otoff
1956
1957 if base_compare:
1958 return _cmp((self._year, self._month, self._day,
1959 self._hour, self._minute, self._second,
1960 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001961 (other._year, other._month, other._day,
1962 other._hour, other._minute, other._second,
1963 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001964 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001965 if allow_mixed:
1966 return 2 # arbitrary non-zero value
1967 else:
1968 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001969 # XXX What follows could be done more efficiently...
1970 diff = self - other # this will take offsets into account
1971 if diff.days < 0:
1972 return -1
1973 return diff and 1 or 0
1974
1975 def __add__(self, other):
1976 "Add a datetime and a timedelta."
1977 if not isinstance(other, timedelta):
1978 return NotImplemented
1979 delta = timedelta(self.toordinal(),
1980 hours=self._hour,
1981 minutes=self._minute,
1982 seconds=self._second,
1983 microseconds=self._microsecond)
1984 delta += other
1985 hour, rem = divmod(delta.seconds, 3600)
1986 minute, second = divmod(rem, 60)
1987 if 0 < delta.days <= _MAXORDINAL:
1988 return datetime.combine(date.fromordinal(delta.days),
1989 time(hour, minute, second,
1990 delta.microseconds,
1991 tzinfo=self._tzinfo))
1992 raise OverflowError("result out of range")
1993
1994 __radd__ = __add__
1995
1996 def __sub__(self, other):
1997 "Subtract two datetimes, or a datetime and a timedelta."
1998 if not isinstance(other, datetime):
1999 if isinstance(other, timedelta):
2000 return self + -other
2001 return NotImplemented
2002
2003 days1 = self.toordinal()
2004 days2 = other.toordinal()
2005 secs1 = self._second + self._minute * 60 + self._hour * 3600
2006 secs2 = other._second + other._minute * 60 + other._hour * 3600
2007 base = timedelta(days1 - days2,
2008 secs1 - secs2,
2009 self._microsecond - other._microsecond)
2010 if self._tzinfo is other._tzinfo:
2011 return base
2012 myoff = self.utcoffset()
2013 otoff = other.utcoffset()
2014 if myoff == otoff:
2015 return base
2016 if myoff is None or otoff is None:
2017 raise TypeError("cannot mix naive and timezone-aware time")
2018 return base + otoff - myoff
2019
2020 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002021 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002022 if self.fold:
2023 t = self.replace(fold=0)
2024 else:
2025 t = self
2026 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002027 if tzoff is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002028 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002029 else:
2030 days = _ymd2ord(self.year, self.month, self.day)
2031 seconds = self.hour * 3600 + self.minute * 60 + self.second
2032 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
2033 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002034
2035 # Pickle support.
2036
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002037 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002038 yhi, ylo = divmod(self._year, 256)
2039 us2, us3 = divmod(self._microsecond, 256)
2040 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002041 m = self._month
2042 if self._fold and protocol > 3:
2043 m += 128
2044 basestate = bytes([yhi, ylo, m, self._day,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002045 self._hour, self._minute, self._second,
2046 us1, us2, us3])
2047 if self._tzinfo is None:
2048 return (basestate,)
2049 else:
2050 return (basestate, self._tzinfo)
2051
2052 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002053 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
2054 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002055 (yhi, ylo, m, self._day, self._hour,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002056 self._minute, self._second, us1, us2, us3) = string
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002057 if m > 127:
2058 self._fold = 1
2059 self._month = m - 128
2060 else:
2061 self._fold = 0
2062 self._month = m
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002063 self._year = yhi * 256 + ylo
2064 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002065 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002066
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002067 def __reduce_ex__(self, protocol):
2068 return (self.__class__, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002069
Serhiy Storchaka546ce652016-11-22 00:29:42 +02002070 def __reduce__(self):
2071 return self.__reduce_ex__(2)
2072
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002073
2074datetime.min = datetime(1, 1, 1)
2075datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
2076datetime.resolution = timedelta(microseconds=1)
2077
2078
2079def _isoweek1monday(year):
2080 # Helper to calculate the day number of the Monday starting week 1
2081 # XXX This could be done more efficiently
2082 THURSDAY = 3
2083 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002084 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002085 week1monday = firstday - firstweekday
2086 if firstweekday > THURSDAY:
2087 week1monday += 7
2088 return week1monday
2089
2090class timezone(tzinfo):
2091 __slots__ = '_offset', '_name'
2092
2093 # Sentinel value to disallow None
2094 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002095 def __new__(cls, offset, name=_Omitted):
2096 if not isinstance(offset, timedelta):
2097 raise TypeError("offset must be a timedelta")
2098 if name is cls._Omitted:
2099 if not offset:
2100 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002101 name = None
2102 elif not isinstance(name, str):
2103 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002104 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002105 raise ValueError("offset must be a timedelta "
2106 "strictly between -timedelta(hours=24) and "
2107 "timedelta(hours=24).")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002108 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002109
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002110 @classmethod
2111 def _create(cls, offset, name=None):
2112 self = tzinfo.__new__(cls)
2113 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002114 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002115 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002116
2117 def __getinitargs__(self):
2118 """pickle support"""
2119 if self._name is None:
2120 return (self._offset,)
2121 return (self._offset, self._name)
2122
2123 def __eq__(self, other):
Georg Brandl0085a242012-09-22 09:23:12 +02002124 if type(other) != timezone:
2125 return False
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002126 return self._offset == other._offset
2127
2128 def __hash__(self):
2129 return hash(self._offset)
2130
2131 def __repr__(self):
2132 """Convert to formal string, for repr().
2133
2134 >>> tz = timezone.utc
2135 >>> repr(tz)
2136 'datetime.timezone.utc'
2137 >>> tz = timezone(timedelta(hours=-5), 'EST')
2138 >>> repr(tz)
2139 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
2140 """
2141 if self is self.utc:
2142 return 'datetime.timezone.utc'
2143 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03002144 return "%s.%s(%r)" % (self.__class__.__module__,
2145 self.__class__.__qualname__,
2146 self._offset)
2147 return "%s.%s(%r, %r)" % (self.__class__.__module__,
2148 self.__class__.__qualname__,
2149 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002150
2151 def __str__(self):
2152 return self.tzname(None)
2153
2154 def utcoffset(self, dt):
2155 if isinstance(dt, datetime) or dt is None:
2156 return self._offset
2157 raise TypeError("utcoffset() argument must be a datetime instance"
2158 " or None")
2159
2160 def tzname(self, dt):
2161 if isinstance(dt, datetime) or dt is None:
2162 if self._name is None:
2163 return self._name_from_offset(self._offset)
2164 return self._name
2165 raise TypeError("tzname() argument must be a datetime instance"
2166 " or None")
2167
2168 def dst(self, dt):
2169 if isinstance(dt, datetime) or dt is None:
2170 return None
2171 raise TypeError("dst() argument must be a datetime instance"
2172 " or None")
2173
2174 def fromutc(self, dt):
2175 if isinstance(dt, datetime):
2176 if dt.tzinfo is not self:
2177 raise ValueError("fromutc: dt.tzinfo "
2178 "is not self")
2179 return dt + self._offset
2180 raise TypeError("fromutc() argument must be a datetime instance"
2181 " or None")
2182
2183 _maxoffset = timedelta(hours=23, minutes=59)
2184 _minoffset = -_maxoffset
2185
2186 @staticmethod
2187 def _name_from_offset(delta):
Alexander Belopolsky7827a5b2015-09-06 13:07:21 -04002188 if not delta:
2189 return 'UTC'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002190 if delta < timedelta(0):
2191 sign = '-'
2192 delta = -delta
2193 else:
2194 sign = '+'
2195 hours, rest = divmod(delta, timedelta(hours=1))
Alexander Belopolsky018d3532017-07-31 10:26:50 -04002196 minutes, rest = divmod(rest, timedelta(minutes=1))
2197 seconds = rest.seconds
2198 microseconds = rest.microseconds
2199 if microseconds:
2200 return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2201 f'.{microseconds:06d}')
2202 if seconds:
2203 return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2204 return f'UTC{sign}{hours:02d}:{minutes:02d}'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002205
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002206timezone.utc = timezone._create(timedelta(0))
2207timezone.min = timezone._create(timezone._minoffset)
2208timezone.max = timezone._create(timezone._maxoffset)
Alexander Belopolskya4415142012-06-08 12:33:09 -04002209_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002210
Victor Stinner765531d2013-03-26 01:11:54 +01002211# Some time zone algebra. For a datetime x, let
2212# x.n = x stripped of its timezone -- its naive time.
2213# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2214# return None
2215# x.d = x.dst(), and assuming that doesn't raise an exception or
2216# return None
2217# x.s = x's standard offset, x.o - x.d
2218#
2219# Now some derived rules, where k is a duration (timedelta).
2220#
2221# 1. x.o = x.s + x.d
2222# This follows from the definition of x.s.
2223#
2224# 2. If x and y have the same tzinfo member, x.s = y.s.
2225# This is actually a requirement, an assumption we need to make about
2226# sane tzinfo classes.
2227#
2228# 3. The naive UTC time corresponding to x is x.n - x.o.
2229# This is again a requirement for a sane tzinfo class.
2230#
2231# 4. (x+k).s = x.s
2232# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
2233#
2234# 5. (x+k).n = x.n + k
2235# Again follows from how arithmetic is defined.
2236#
2237# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
2238# (meaning that the various tzinfo methods exist, and don't blow up or return
2239# None when called).
2240#
2241# The function wants to return a datetime y with timezone tz, equivalent to x.
2242# x is already in UTC.
2243#
2244# By #3, we want
2245#
2246# y.n - y.o = x.n [1]
2247#
2248# The algorithm starts by attaching tz to x.n, and calling that y. So
2249# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
2250# becomes true; in effect, we want to solve [2] for k:
2251#
2252# (y+k).n - (y+k).o = x.n [2]
2253#
2254# By #1, this is the same as
2255#
2256# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
2257#
2258# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2259# Substituting that into [3],
2260#
2261# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2262# k - (y+k).s - (y+k).d = 0; rearranging,
2263# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2264# k = y.s - (y+k).d
2265#
2266# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2267# approximate k by ignoring the (y+k).d term at first. Note that k can't be
2268# very large, since all offset-returning methods return a duration of magnitude
2269# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
2270# be 0, so ignoring it has no consequence then.
2271#
2272# In any case, the new value is
2273#
2274# z = y + y.s [4]
2275#
2276# It's helpful to step back at look at [4] from a higher level: it's simply
2277# mapping from UTC to tz's standard time.
2278#
2279# At this point, if
2280#
2281# z.n - z.o = x.n [5]
2282#
2283# we have an equivalent time, and are almost done. The insecurity here is
2284# at the start of daylight time. Picture US Eastern for concreteness. The wall
2285# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2286# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2287# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2288# on the day DST starts. We want to return the 1:MM EST spelling because that's
2289# the only spelling that makes sense on the local wall clock.
2290#
2291# In fact, if [5] holds at this point, we do have the standard-time spelling,
2292# but that takes a bit of proof. We first prove a stronger result. What's the
2293# difference between the LHS and RHS of [5]? Let
2294#
2295# diff = x.n - (z.n - z.o) [6]
2296#
2297# Now
2298# z.n = by [4]
2299# (y + y.s).n = by #5
2300# y.n + y.s = since y.n = x.n
2301# x.n + y.s = since z and y are have the same tzinfo member,
2302# y.s = z.s by #2
2303# x.n + z.s
2304#
2305# Plugging that back into [6] gives
2306#
2307# diff =
2308# x.n - ((x.n + z.s) - z.o) = expanding
2309# x.n - x.n - z.s + z.o = cancelling
2310# - z.s + z.o = by #2
2311# z.d
2312#
2313# So diff = z.d.
2314#
2315# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2316# spelling we wanted in the endcase described above. We're done. Contrarily,
2317# if z.d = 0, then we have a UTC equivalent, and are also done.
2318#
2319# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2320# add to z (in effect, z is in tz's standard time, and we need to shift the
2321# local clock into tz's daylight time).
2322#
2323# Let
2324#
2325# z' = z + z.d = z + diff [7]
2326#
2327# and we can again ask whether
2328#
2329# z'.n - z'.o = x.n [8]
2330#
2331# If so, we're done. If not, the tzinfo class is insane, according to the
2332# assumptions we've made. This also requires a bit of proof. As before, let's
2333# compute the difference between the LHS and RHS of [8] (and skipping some of
2334# the justifications for the kinds of substitutions we've done several times
2335# already):
2336#
2337# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2338# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2339# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2340# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2341# - z.n + z.n - z.o + z'.o = cancel z.n
2342# - z.o + z'.o = #1 twice
2343# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2344# z'.d - z.d
2345#
2346# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2347# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2348# return z', not bothering to compute z'.d.
2349#
2350# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2351# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2352# would have to change the result dst() returns: we start in DST, and moving
2353# a little further into it takes us out of DST.
2354#
2355# There isn't a sane case where this can happen. The closest it gets is at
2356# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2357# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2358# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2359# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2360# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2361# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2362# standard time. Since that's what the local clock *does*, we want to map both
2363# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2364# in local time, but so it goes -- it's the way the local clock works.
2365#
2366# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2367# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2368# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2369# (correctly) concludes that z' is not UTC-equivalent to x.
2370#
2371# Because we know z.d said z was in daylight time (else [5] would have held and
2372# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2373# and we have stopped then), and there are only 2 possible values dst() can
2374# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2375# but the reasoning doesn't depend on the example -- it depends on there being
2376# two possible dst() outcomes, one zero and the other non-zero). Therefore
2377# z' must be in standard time, and is the spelling we want in this case.
2378#
2379# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2380# concerned (because it takes z' as being in standard time rather than the
2381# daylight time we intend here), but returning it gives the real-life "local
2382# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2383# tz.
2384#
2385# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2386# the 1:MM standard time spelling we want.
2387#
2388# So how can this break? One of the assumptions must be violated. Two
2389# possibilities:
2390#
2391# 1) [2] effectively says that y.s is invariant across all y belong to a given
2392# time zone. This isn't true if, for political reasons or continental drift,
2393# a region decides to change its base offset from UTC.
2394#
2395# 2) There may be versions of "double daylight" time where the tail end of
2396# the analysis gives up a step too early. I haven't thought about that
2397# enough to say.
2398#
2399# In any case, it's clear that the default fromutc() is strong enough to handle
2400# "almost all" time zones: so long as the standard offset is invariant, it
2401# doesn't matter if daylight time transition points change from year to year, or
2402# if daylight time is skipped in some years; it doesn't matter how large or
2403# small dst() may get within its bounds; and it doesn't even matter if some
2404# perverse time zone returns a negative dst()). So a breaking case must be
2405# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002406
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002407try:
2408 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002409except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002410 pass
2411else:
2412 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002413 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2414 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2415 _check_date_fields, _check_int_field, _check_time_fields,
2416 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2417 _date_class, _days_before_month, _days_before_year, _days_in_month,
Paul Ganssle09dc2f52017-12-21 00:33:49 -05002418 _format_time, _format_offset, _is_leap, _isoweek1monday, _math,
2419 _ord2ymd, _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord,
2420 _divide_and_round, _parse_isoformat_date, _parse_isoformat_time,
2421 _parse_hh_mm_ss_ff)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002422 # XXX Since import * above excludes names that start with _,
2423 # docstring does not get overwritten. In the future, it may be
2424 # appropriate to maintain a single module level docstring and
2425 # remove the following line.
2426 from _datetime import __doc__