blob: 89c32c0b0a630123c479a134f075b1bca3485567 [file] [log] [blame]
Ezio Melottif756f942013-04-13 20:12:38 +03001"""Concrete date/time and related types.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002
Ezio Melottif756f942013-04-13 20:12:38 +03003See http://www.iana.org/time-zones/repository/tz-link.html for
4time zone and DST data sources.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00005"""
6
7import time as _time
8import math as _math
Ammar Askar96d1e692018-07-25 09:54:58 -07009import sys
Alexander Belopolskycf86e362010-07-23 19:25:47 +000010
11def _cmp(x, y):
12 return 0 if x == y else 1 if x > y else -1
13
14MINYEAR = 1
15MAXYEAR = 9999
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -040016_MAXORDINAL = 3652059 # date.max.toordinal()
Alexander Belopolskycf86e362010-07-23 19:25:47 +000017
18# Utility functions, adapted from Python's Demo/classes/Dates.py, which
19# also assumes the current Gregorian calendar indefinitely extended in
20# both directions. Difference: Dates.py calls January 1 of year 0 day
21# number 1. The code here calls January 1 of year 1 day number 1. This is
22# to match the definition of the "proleptic Gregorian" calendar in Dershowitz
23# and Reingold's "Calendrical Calculations", where it's the base calendar
24# for all computations. See the book for algorithms for converting between
25# proleptic Gregorian ordinals and many other calendar systems.
26
Benjamin Petersonda0bea22013-08-29 17:29:30 -040027# -1 is a placeholder for indexing purposes.
Benjamin Petersonf908efb2013-08-29 17:27:57 -040028_DAYS_IN_MONTH = [-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
Alexander Belopolskycf86e362010-07-23 19:25:47 +000029
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -040030_DAYS_BEFORE_MONTH = [-1] # -1 is a placeholder for indexing purposes.
Alexander Belopolskycf86e362010-07-23 19:25:47 +000031dbm = 0
32for dim in _DAYS_IN_MONTH[1:]:
33 _DAYS_BEFORE_MONTH.append(dbm)
34 dbm += dim
35del dbm, dim
36
37def _is_leap(year):
38 "year -> 1 if leap year, else 0."
39 return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
40
41def _days_before_year(year):
42 "year -> number of days before January 1st of year."
43 y = year - 1
44 return y*365 + y//4 - y//100 + y//400
45
46def _days_in_month(year, month):
47 "year, month -> number of days in that month in that year."
48 assert 1 <= month <= 12, month
49 if month == 2 and _is_leap(year):
50 return 29
51 return _DAYS_IN_MONTH[month]
52
53def _days_before_month(year, month):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +030054 "year, month -> number of days in year preceding first day of month."
Alexander Belopolskycf86e362010-07-23 19:25:47 +000055 assert 1 <= month <= 12, 'month must be in 1..12'
56 return _DAYS_BEFORE_MONTH[month] + (month > 2 and _is_leap(year))
57
58def _ymd2ord(year, month, day):
59 "year, month, day -> ordinal, considering 01-Jan-0001 as day 1."
60 assert 1 <= month <= 12, 'month must be in 1..12'
61 dim = _days_in_month(year, month)
62 assert 1 <= day <= dim, ('day must be in 1..%d' % dim)
63 return (_days_before_year(year) +
64 _days_before_month(year, month) +
65 day)
66
67_DI400Y = _days_before_year(401) # number of days in 400 years
68_DI100Y = _days_before_year(101) # " " " " 100 "
69_DI4Y = _days_before_year(5) # " " " " 4 "
70
71# A 4-year cycle has an extra leap day over what we'd get from pasting
72# together 4 single years.
73assert _DI4Y == 4 * 365 + 1
74
75# Similarly, a 400-year cycle has an extra leap day over what we'd get from
76# pasting together 4 100-year cycles.
77assert _DI400Y == 4 * _DI100Y + 1
78
79# OTOH, a 100-year cycle has one fewer leap day than we'd get from
80# pasting together 25 4-year cycles.
81assert _DI100Y == 25 * _DI4Y - 1
82
83def _ord2ymd(n):
84 "ordinal -> (year, month, day), considering 01-Jan-0001 as day 1."
85
86 # n is a 1-based index, starting at 1-Jan-1. The pattern of leap years
87 # repeats exactly every 400 years. The basic strategy is to find the
88 # closest 400-year boundary at or before n, then work with the offset
89 # from that boundary to n. Life is much clearer if we subtract 1 from
90 # n first -- then the values of n at 400-year boundaries are exactly
91 # those divisible by _DI400Y:
92 #
93 # D M Y n n-1
94 # -- --- ---- ---------- ----------------
95 # 31 Dec -400 -_DI400Y -_DI400Y -1
96 # 1 Jan -399 -_DI400Y +1 -_DI400Y 400-year boundary
97 # ...
98 # 30 Dec 000 -1 -2
99 # 31 Dec 000 0 -1
100 # 1 Jan 001 1 0 400-year boundary
101 # 2 Jan 001 2 1
102 # 3 Jan 001 3 2
103 # ...
104 # 31 Dec 400 _DI400Y _DI400Y -1
105 # 1 Jan 401 _DI400Y +1 _DI400Y 400-year boundary
106 n -= 1
107 n400, n = divmod(n, _DI400Y)
108 year = n400 * 400 + 1 # ..., -399, 1, 401, ...
109
110 # Now n is the (non-negative) offset, in days, from January 1 of year, to
111 # the desired date. Now compute how many 100-year cycles precede n.
112 # Note that it's possible for n100 to equal 4! In that case 4 full
113 # 100-year cycles precede the desired day, which implies the desired
114 # day is December 31 at the end of a 400-year cycle.
115 n100, n = divmod(n, _DI100Y)
116
117 # Now compute how many 4-year cycles precede it.
118 n4, n = divmod(n, _DI4Y)
119
120 # And now how many single years. Again n1 can be 4, and again meaning
121 # that the desired day is December 31 at the end of the 4-year cycle.
122 n1, n = divmod(n, 365)
123
124 year += n100 * 100 + n4 * 4 + n1
125 if n1 == 4 or n100 == 4:
126 assert n == 0
127 return year-1, 12, 31
128
129 # Now the year is correct, and n is the offset from January 1. We find
130 # the month via an estimate that's either exact or one too large.
131 leapyear = n1 == 3 and (n4 != 24 or n100 == 3)
132 assert leapyear == _is_leap(year)
133 month = (n + 50) >> 5
134 preceding = _DAYS_BEFORE_MONTH[month] + (month > 2 and leapyear)
135 if preceding > n: # estimate is too large
136 month -= 1
137 preceding -= _DAYS_IN_MONTH[month] + (month == 2 and leapyear)
138 n -= preceding
139 assert 0 <= n < _days_in_month(year, month)
140
141 # Now the year and month are correct, and n is the offset from the
142 # start of that month: we're done!
143 return year, month, n+1
144
145# Month and day names. For localized versions, see the calendar module.
146_MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
147 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
148_DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
149
150
151def _build_struct_time(y, m, d, hh, mm, ss, dstflag):
152 wday = (_ymd2ord(y, m, d) + 6) % 7
153 dnum = _days_before_month(y, m) + d
154 return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag))
155
Alexander Belopolskya2998a62016-03-06 14:58:43 -0500156def _format_time(hh, mm, ss, us, timespec='auto'):
157 specs = {
158 'hours': '{:02d}',
159 'minutes': '{:02d}:{:02d}',
160 'seconds': '{:02d}:{:02d}:{:02d}',
161 'milliseconds': '{:02d}:{:02d}:{:02d}.{:03d}',
162 'microseconds': '{:02d}:{:02d}:{:02d}.{:06d}'
163 }
164
165 if timespec == 'auto':
166 # Skip trailing microseconds when us==0.
167 timespec = 'microseconds' if us else 'seconds'
168 elif timespec == 'milliseconds':
169 us //= 1000
170 try:
171 fmt = specs[timespec]
172 except KeyError:
173 raise ValueError('Unknown timespec value')
174 else:
175 return fmt.format(hh, mm, ss, us)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000176
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500177def _format_offset(off):
178 s = ''
179 if off is not None:
180 if off.days < 0:
181 sign = "-"
182 off = -off
183 else:
184 sign = "+"
185 hh, mm = divmod(off, timedelta(hours=1))
186 mm, ss = divmod(mm, timedelta(minutes=1))
187 s += "%s%02d:%02d" % (sign, hh, mm)
188 if ss or ss.microseconds:
189 s += ":%02d" % ss.seconds
190
191 if ss.microseconds:
192 s += '.%06d' % ss.microseconds
193 return s
194
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000195# Correctly substitute for %z and %Z escapes in strftime formats.
196def _wrap_strftime(object, format, timetuple):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000197 # Don't call utcoffset() or tzname() unless actually needed.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400198 freplace = None # the string to use for %f
199 zreplace = None # the string to use for %z
200 Zreplace = None # the string to use for %Z
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000201
202 # Scan format for %z and %Z escapes, replacing as needed.
203 newformat = []
204 push = newformat.append
205 i, n = 0, len(format)
206 while i < n:
207 ch = format[i]
208 i += 1
209 if ch == '%':
210 if i < n:
211 ch = format[i]
212 i += 1
213 if ch == 'f':
214 if freplace is None:
215 freplace = '%06d' % getattr(object,
216 'microsecond', 0)
217 newformat.append(freplace)
218 elif ch == 'z':
219 if zreplace is None:
220 zreplace = ""
221 if hasattr(object, "utcoffset"):
222 offset = object.utcoffset()
223 if offset is not None:
224 sign = '+'
225 if offset.days < 0:
226 offset = -offset
227 sign = '-'
Alexander Belopolsky018d3532017-07-31 10:26:50 -0400228 h, rest = divmod(offset, timedelta(hours=1))
229 m, rest = divmod(rest, timedelta(minutes=1))
230 s = rest.seconds
231 u = offset.microseconds
232 if u:
233 zreplace = '%c%02d%02d%02d.%06d' % (sign, h, m, s, u)
234 elif s:
235 zreplace = '%c%02d%02d%02d' % (sign, h, m, s)
236 else:
237 zreplace = '%c%02d%02d' % (sign, h, m)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000238 assert '%' not in zreplace
239 newformat.append(zreplace)
240 elif ch == 'Z':
241 if Zreplace is None:
242 Zreplace = ""
243 if hasattr(object, "tzname"):
244 s = object.tzname()
245 if s is not None:
246 # strftime is going to have at this: escape %
247 Zreplace = s.replace('%', '%%')
248 newformat.append(Zreplace)
249 else:
250 push('%')
251 push(ch)
252 else:
253 push('%')
254 else:
255 push(ch)
256 newformat = "".join(newformat)
257 return _time.strftime(newformat, timetuple)
258
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500259# Helpers for parsing the result of isoformat()
260def _parse_isoformat_date(dtstr):
261 # It is assumed that this function will only be called with a
262 # string of length exactly 10, and (though this is not used) ASCII-only
263 year = int(dtstr[0:4])
264 if dtstr[4] != '-':
265 raise ValueError('Invalid date separator: %s' % dtstr[4])
266
267 month = int(dtstr[5:7])
268
269 if dtstr[7] != '-':
270 raise ValueError('Invalid date separator')
271
272 day = int(dtstr[8:10])
273
274 return [year, month, day]
275
276def _parse_hh_mm_ss_ff(tstr):
277 # Parses things of the form HH[:MM[:SS[.fff[fff]]]]
278 len_str = len(tstr)
279
280 time_comps = [0, 0, 0, 0]
281 pos = 0
282 for comp in range(0, 3):
283 if (len_str - pos) < 2:
284 raise ValueError('Incomplete time component')
285
286 time_comps[comp] = int(tstr[pos:pos+2])
287
288 pos += 2
289 next_char = tstr[pos:pos+1]
290
291 if not next_char or comp >= 2:
292 break
293
294 if next_char != ':':
295 raise ValueError('Invalid time separator: %c' % next_char)
296
297 pos += 1
298
299 if pos < len_str:
300 if tstr[pos] != '.':
301 raise ValueError('Invalid microsecond component')
302 else:
303 pos += 1
304
305 len_remainder = len_str - pos
306 if len_remainder not in (3, 6):
307 raise ValueError('Invalid microsecond component')
308
309 time_comps[3] = int(tstr[pos:])
310 if len_remainder == 3:
311 time_comps[3] *= 1000
312
313 return time_comps
314
315def _parse_isoformat_time(tstr):
316 # Format supported is HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]
317 len_str = len(tstr)
318 if len_str < 2:
319 raise ValueError('Isoformat time too short')
320
321 # This is equivalent to re.search('[+-]', tstr), but faster
322 tz_pos = (tstr.find('-') + 1 or tstr.find('+') + 1)
323 timestr = tstr[:tz_pos-1] if tz_pos > 0 else tstr
324
325 time_comps = _parse_hh_mm_ss_ff(timestr)
326
327 tzi = None
328 if tz_pos > 0:
329 tzstr = tstr[tz_pos:]
330
331 # Valid time zone strings are:
332 # HH:MM len: 5
333 # HH:MM:SS len: 8
334 # HH:MM:SS.ffffff len: 15
335
336 if len(tzstr) not in (5, 8, 15):
337 raise ValueError('Malformed time zone string')
338
339 tz_comps = _parse_hh_mm_ss_ff(tzstr)
340 if all(x == 0 for x in tz_comps):
341 tzi = timezone.utc
342 else:
343 tzsign = -1 if tstr[tz_pos - 1] == '-' else 1
344
345 td = timedelta(hours=tz_comps[0], minutes=tz_comps[1],
346 seconds=tz_comps[2], microseconds=tz_comps[3])
347
348 tzi = timezone(tzsign * td)
349
350 time_comps.append(tzi)
351
352 return time_comps
353
354
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000355# Just raise TypeError if the arg isn't None or a string.
356def _check_tzname(name):
357 if name is not None and not isinstance(name, str):
358 raise TypeError("tzinfo.tzname() must return None or string, "
359 "not '%s'" % type(name))
360
361# name is the offset-producing method, "utcoffset" or "dst".
362# offset is what it returned.
363# If offset isn't None or timedelta, raises TypeError.
364# If offset is None, returns None.
Alexander Belopolsky018d3532017-07-31 10:26:50 -0400365# Else offset is checked for being in range.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000366# If it is, its integer value is returned. Else ValueError is raised.
367def _check_utc_offset(name, offset):
368 assert name in ("utcoffset", "dst")
369 if offset is None:
370 return
371 if not isinstance(offset, timedelta):
372 raise TypeError("tzinfo.%s() must return None "
373 "or timedelta, not '%s'" % (name, type(offset)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000374 if not -timedelta(1) < offset < timedelta(1):
Martin Panterdd780e42016-05-30 04:08:23 +0000375 raise ValueError("%s()=%s, must be strictly between "
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400376 "-timedelta(hours=24) and timedelta(hours=24)" %
377 (name, offset))
378
379def _check_int_field(value):
380 if isinstance(value, int):
381 return value
382 if not isinstance(value, float):
383 try:
384 value = value.__int__()
385 except AttributeError:
386 pass
387 else:
388 if isinstance(value, int):
389 return value
390 raise TypeError('__int__ returned non-int (type %s)' %
391 type(value).__name__)
392 raise TypeError('an integer is required (got type %s)' %
393 type(value).__name__)
394 raise TypeError('integer argument expected, got float')
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000395
396def _check_date_fields(year, month, day):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400397 year = _check_int_field(year)
398 month = _check_int_field(month)
399 day = _check_int_field(day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000400 if not MINYEAR <= year <= MAXYEAR:
401 raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year)
402 if not 1 <= month <= 12:
403 raise ValueError('month must be in 1..12', month)
404 dim = _days_in_month(year, month)
405 if not 1 <= day <= dim:
406 raise ValueError('day must be in 1..%d' % dim, day)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400407 return year, month, day
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000408
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400409def _check_time_fields(hour, minute, second, microsecond, fold):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400410 hour = _check_int_field(hour)
411 minute = _check_int_field(minute)
412 second = _check_int_field(second)
413 microsecond = _check_int_field(microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000414 if not 0 <= hour <= 23:
415 raise ValueError('hour must be in 0..23', hour)
416 if not 0 <= minute <= 59:
417 raise ValueError('minute must be in 0..59', minute)
418 if not 0 <= second <= 59:
419 raise ValueError('second must be in 0..59', second)
420 if not 0 <= microsecond <= 999999:
421 raise ValueError('microsecond must be in 0..999999', microsecond)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400422 if fold not in (0, 1):
423 raise ValueError('fold must be either 0 or 1', fold)
424 return hour, minute, second, microsecond, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000425
426def _check_tzinfo_arg(tz):
427 if tz is not None and not isinstance(tz, tzinfo):
428 raise TypeError("tzinfo argument must be None or of a tzinfo subclass")
429
430def _cmperror(x, y):
431 raise TypeError("can't compare '%s' to '%s'" % (
432 type(x).__name__, type(y).__name__))
433
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500434def _divide_and_round(a, b):
435 """divide a by b and round result to the nearest integer
436
437 When the ratio is exactly half-way between two integers,
438 the even integer is returned.
439 """
440 # Based on the reference implementation for divmod_near
441 # in Objects/longobject.c.
442 q, r = divmod(a, b)
443 # round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
444 # The expression r / b > 0.5 is equivalent to 2 * r > b if b is
445 # positive, 2 * r < b if b negative.
446 r *= 2
447 greater_than_half = r > b if b > 0 else r < b
448 if greater_than_half or r == b and q % 2 == 1:
449 q += 1
450
451 return q
452
Victor Stinner2ec55872015-09-02 19:16:07 +0200453
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000454class timedelta:
455 """Represent the difference between two datetime objects.
456
457 Supported operators:
458
459 - add, subtract timedelta
460 - unary plus, minus, abs
461 - compare to timedelta
Serhiy Storchaka95949422013-08-27 19:40:23 +0300462 - multiply, divide by int
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000463
464 In addition, datetime supports subtraction of two datetime objects
465 returning a timedelta, and addition or subtraction of a datetime
466 and a timedelta giving a datetime.
467
468 Representation: (days, seconds, microseconds). Why? Because I
469 felt like it.
470 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400471 __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000472
473 def __new__(cls, days=0, seconds=0, microseconds=0,
474 milliseconds=0, minutes=0, hours=0, weeks=0):
475 # Doing this efficiently and accurately in C is going to be difficult
476 # and error-prone, due to ubiquitous overflow possibilities, and that
477 # C double doesn't have enough bits of precision to represent
478 # microseconds over 10K years faithfully. The code here tries to make
479 # explicit where go-fast assumptions can be relied on, in order to
480 # guide the C implementation; it's way more convoluted than speed-
481 # ignoring auto-overflow-to-long idiomatic Python could be.
482
483 # XXX Check that all inputs are ints or floats.
484
485 # Final values, all integer.
486 # s and us fit in 32-bit signed ints; d isn't bounded.
487 d = s = us = 0
488
489 # Normalize everything to days, seconds, microseconds.
490 days += weeks*7
491 seconds += minutes*60 + hours*3600
492 microseconds += milliseconds*1000
493
494 # Get rid of all fractions, and normalize s and us.
495 # Take a deep breath <wink>.
496 if isinstance(days, float):
497 dayfrac, days = _math.modf(days)
498 daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
499 assert daysecondswhole == int(daysecondswhole) # can't overflow
500 s = int(daysecondswhole)
501 assert days == int(days)
502 d = int(days)
503 else:
504 daysecondsfrac = 0.0
505 d = days
506 assert isinstance(daysecondsfrac, float)
507 assert abs(daysecondsfrac) <= 1.0
508 assert isinstance(d, int)
509 assert abs(s) <= 24 * 3600
510 # days isn't referenced again before redefinition
511
512 if isinstance(seconds, float):
513 secondsfrac, seconds = _math.modf(seconds)
514 assert seconds == int(seconds)
515 seconds = int(seconds)
516 secondsfrac += daysecondsfrac
517 assert abs(secondsfrac) <= 2.0
518 else:
519 secondsfrac = daysecondsfrac
520 # daysecondsfrac isn't referenced again
521 assert isinstance(secondsfrac, float)
522 assert abs(secondsfrac) <= 2.0
523
524 assert isinstance(seconds, int)
525 days, seconds = divmod(seconds, 24*3600)
526 d += days
527 s += int(seconds) # can't overflow
528 assert isinstance(s, int)
529 assert abs(s) <= 2 * 24 * 3600
530 # seconds isn't referenced again before redefinition
531
532 usdouble = secondsfrac * 1e6
533 assert abs(usdouble) < 2.1e6 # exact value not critical
534 # secondsfrac isn't referenced again
535
536 if isinstance(microseconds, float):
Victor Stinner69cc4872015-09-08 23:58:54 +0200537 microseconds = round(microseconds + usdouble)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000538 seconds, microseconds = divmod(microseconds, 1000000)
539 days, seconds = divmod(seconds, 24*3600)
540 d += days
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400541 s += seconds
542 else:
543 microseconds = int(microseconds)
544 seconds, microseconds = divmod(microseconds, 1000000)
545 days, seconds = divmod(seconds, 24*3600)
546 d += days
547 s += seconds
Victor Stinner69cc4872015-09-08 23:58:54 +0200548 microseconds = round(microseconds + usdouble)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400549 assert isinstance(s, int)
550 assert isinstance(microseconds, int)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000551 assert abs(s) <= 3 * 24 * 3600
552 assert abs(microseconds) < 3.1e6
553
554 # Just a little bit of carrying possible for microseconds and seconds.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400555 seconds, us = divmod(microseconds, 1000000)
556 s += seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000557 days, s = divmod(s, 24*3600)
558 d += days
559
560 assert isinstance(d, int)
561 assert isinstance(s, int) and 0 <= s < 24*3600
562 assert isinstance(us, int) and 0 <= us < 1000000
563
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000564 if abs(d) > 999999999:
565 raise OverflowError("timedelta # of days is too large: %d" % d)
566
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400567 self = object.__new__(cls)
568 self._days = d
569 self._seconds = s
570 self._microseconds = us
571 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000572 return self
573
574 def __repr__(self):
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200575 args = []
576 if self._days:
577 args.append("days=%d" % self._days)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000578 if self._seconds:
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200579 args.append("seconds=%d" % self._seconds)
580 if self._microseconds:
581 args.append("microseconds=%d" % self._microseconds)
582 if not args:
583 args.append('0')
584 return "%s.%s(%s)" % (self.__class__.__module__,
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300585 self.__class__.__qualname__,
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200586 ', '.join(args))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000587
588 def __str__(self):
589 mm, ss = divmod(self._seconds, 60)
590 hh, mm = divmod(mm, 60)
591 s = "%d:%02d:%02d" % (hh, mm, ss)
592 if self._days:
593 def plural(n):
594 return n, abs(n) != 1 and "s" or ""
595 s = ("%d day%s, " % plural(self._days)) + s
596 if self._microseconds:
597 s = s + ".%06d" % self._microseconds
598 return s
599
600 def total_seconds(self):
601 """Total seconds in the duration."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400602 return ((self.days * 86400 + self.seconds) * 10**6 +
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000603 self.microseconds) / 10**6
604
605 # Read-only field accessors
606 @property
607 def days(self):
608 """days"""
609 return self._days
610
611 @property
612 def seconds(self):
613 """seconds"""
614 return self._seconds
615
616 @property
617 def microseconds(self):
618 """microseconds"""
619 return self._microseconds
620
621 def __add__(self, other):
622 if isinstance(other, timedelta):
623 # for CPython compatibility, we cannot use
624 # our __class__ here, but need a real timedelta
625 return timedelta(self._days + other._days,
626 self._seconds + other._seconds,
627 self._microseconds + other._microseconds)
628 return NotImplemented
629
630 __radd__ = __add__
631
632 def __sub__(self, other):
633 if isinstance(other, timedelta):
Alexander Belopolskyb6f5ec72011-04-05 20:07:38 -0400634 # for CPython compatibility, we cannot use
635 # our __class__ here, but need a real timedelta
636 return timedelta(self._days - other._days,
637 self._seconds - other._seconds,
638 self._microseconds - other._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000639 return NotImplemented
640
641 def __rsub__(self, other):
642 if isinstance(other, timedelta):
643 return -self + other
644 return NotImplemented
645
646 def __neg__(self):
647 # for CPython compatibility, we cannot use
648 # our __class__ here, but need a real timedelta
649 return timedelta(-self._days,
650 -self._seconds,
651 -self._microseconds)
652
653 def __pos__(self):
654 return self
655
656 def __abs__(self):
657 if self._days < 0:
658 return -self
659 else:
660 return self
661
662 def __mul__(self, other):
663 if isinstance(other, int):
664 # for CPython compatibility, we cannot use
665 # our __class__ here, but need a real timedelta
666 return timedelta(self._days * other,
667 self._seconds * other,
668 self._microseconds * other)
669 if isinstance(other, float):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500670 usec = self._to_microseconds()
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000671 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500672 return timedelta(0, 0, _divide_and_round(usec * a, b))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000673 return NotImplemented
674
675 __rmul__ = __mul__
676
677 def _to_microseconds(self):
678 return ((self._days * (24*3600) + self._seconds) * 1000000 +
679 self._microseconds)
680
681 def __floordiv__(self, other):
682 if not isinstance(other, (int, timedelta)):
683 return NotImplemented
684 usec = self._to_microseconds()
685 if isinstance(other, timedelta):
686 return usec // other._to_microseconds()
687 if isinstance(other, int):
688 return timedelta(0, 0, usec // other)
689
690 def __truediv__(self, other):
691 if not isinstance(other, (int, float, timedelta)):
692 return NotImplemented
693 usec = self._to_microseconds()
694 if isinstance(other, timedelta):
695 return usec / other._to_microseconds()
696 if isinstance(other, int):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500697 return timedelta(0, 0, _divide_and_round(usec, other))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000698 if isinstance(other, float):
699 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500700 return timedelta(0, 0, _divide_and_round(b * usec, a))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000701
702 def __mod__(self, other):
703 if isinstance(other, timedelta):
704 r = self._to_microseconds() % other._to_microseconds()
705 return timedelta(0, 0, r)
706 return NotImplemented
707
708 def __divmod__(self, other):
709 if isinstance(other, timedelta):
710 q, r = divmod(self._to_microseconds(),
711 other._to_microseconds())
712 return q, timedelta(0, 0, r)
713 return NotImplemented
714
715 # Comparisons of timedelta objects with other.
716
717 def __eq__(self, other):
718 if isinstance(other, timedelta):
719 return self._cmp(other) == 0
720 else:
721 return False
722
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000723 def __le__(self, other):
724 if isinstance(other, timedelta):
725 return self._cmp(other) <= 0
726 else:
727 _cmperror(self, other)
728
729 def __lt__(self, other):
730 if isinstance(other, timedelta):
731 return self._cmp(other) < 0
732 else:
733 _cmperror(self, other)
734
735 def __ge__(self, other):
736 if isinstance(other, timedelta):
737 return self._cmp(other) >= 0
738 else:
739 _cmperror(self, other)
740
741 def __gt__(self, other):
742 if isinstance(other, timedelta):
743 return self._cmp(other) > 0
744 else:
745 _cmperror(self, other)
746
747 def _cmp(self, other):
748 assert isinstance(other, timedelta)
749 return _cmp(self._getstate(), other._getstate())
750
751 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400752 if self._hashcode == -1:
753 self._hashcode = hash(self._getstate())
754 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000755
756 def __bool__(self):
757 return (self._days != 0 or
758 self._seconds != 0 or
759 self._microseconds != 0)
760
761 # Pickle support.
762
763 def _getstate(self):
764 return (self._days, self._seconds, self._microseconds)
765
766 def __reduce__(self):
767 return (self.__class__, self._getstate())
768
769timedelta.min = timedelta(-999999999)
770timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
771 microseconds=999999)
772timedelta.resolution = timedelta(microseconds=1)
773
774class date:
775 """Concrete date type.
776
777 Constructors:
778
779 __new__()
780 fromtimestamp()
781 today()
782 fromordinal()
783
784 Operators:
785
786 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200787 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000788 __add__, __radd__, __sub__ (add/radd only with timedelta arg)
789
790 Methods:
791
792 timetuple()
793 toordinal()
794 weekday()
795 isoweekday(), isocalendar(), isoformat()
796 ctime()
797 strftime()
798
799 Properties (readonly):
800 year, month, day
801 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400802 __slots__ = '_year', '_month', '_day', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000803
804 def __new__(cls, year, month=None, day=None):
805 """Constructor.
806
807 Arguments:
808
809 year, month, day (required, base 1)
810 """
Serhiy Storchaka8452ca12018-12-07 13:42:10 +0200811 if (month is None and
812 isinstance(year, (bytes, str)) and len(year) == 4 and
813 1 <= ord(year[2:3]) <= 12):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000814 # Pickle support
Serhiy Storchaka8452ca12018-12-07 13:42:10 +0200815 if isinstance(year, str):
816 try:
817 year = year.encode('latin1')
818 except UnicodeEncodeError:
819 # More informative error message.
820 raise ValueError(
821 "Failed to encode latin1 string when unpickling "
822 "a date object. "
823 "pickle.load(data, encoding='latin1') is assumed.")
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000824 self = object.__new__(cls)
825 self.__setstate(year)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400826 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000827 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400828 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000829 self = object.__new__(cls)
830 self._year = year
831 self._month = month
832 self._day = day
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400833 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000834 return self
835
836 # Additional constructors
837
838 @classmethod
839 def fromtimestamp(cls, t):
840 "Construct a date from a POSIX timestamp (like time.time())."
841 y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
842 return cls(y, m, d)
843
844 @classmethod
845 def today(cls):
846 "Construct a date from time.time()."
847 t = _time.time()
848 return cls.fromtimestamp(t)
849
850 @classmethod
851 def fromordinal(cls, n):
Martin Pantereb995702016-07-28 01:11:04 +0000852 """Construct a date from a proleptic Gregorian ordinal.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000853
854 January 1 of year 1 is day 1. Only the year, month and day are
855 non-zero in the result.
856 """
857 y, m, d = _ord2ymd(n)
858 return cls(y, m, d)
859
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500860 @classmethod
861 def fromisoformat(cls, date_string):
862 """Construct a date from the output of date.isoformat()."""
863 if not isinstance(date_string, str):
864 raise TypeError('fromisoformat: argument must be str')
865
866 try:
867 assert len(date_string) == 10
868 return cls(*_parse_isoformat_date(date_string))
869 except Exception:
Paul Ganssle3df85402018-10-22 12:32:52 -0400870 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -0500871
872
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000873 # Conversions to string
874
875 def __repr__(self):
876 """Convert to formal string, for repr().
877
878 >>> dt = datetime(2010, 1, 1)
879 >>> repr(dt)
880 'datetime.datetime(2010, 1, 1, 0, 0)'
881
882 >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
883 >>> repr(dt)
884 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
885 """
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300886 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
887 self.__class__.__qualname__,
888 self._year,
889 self._month,
890 self._day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000891 # XXX These shouldn't depend on time.localtime(), because that
892 # clips the usable dates to [1970 .. 2038). At least ctime() is
893 # easily done without using strftime() -- that's better too because
894 # strftime("%c", ...) is locale specific.
895
896
897 def ctime(self):
898 "Return ctime() style string."
899 weekday = self.toordinal() % 7 or 7
900 return "%s %s %2d 00:00:00 %04d" % (
901 _DAYNAMES[weekday],
902 _MONTHNAMES[self._month],
903 self._day, self._year)
904
905 def strftime(self, fmt):
906 "Format using strftime()."
907 return _wrap_strftime(self, fmt, self.timetuple())
908
909 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400910 if not isinstance(fmt, str):
911 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000912 if len(fmt) != 0:
913 return self.strftime(fmt)
914 return str(self)
915
916 def isoformat(self):
917 """Return the date formatted according to ISO.
918
919 This is 'YYYY-MM-DD'.
920
921 References:
922 - http://www.w3.org/TR/NOTE-datetime
923 - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
924 """
925 return "%04d-%02d-%02d" % (self._year, self._month, self._day)
926
927 __str__ = isoformat
928
929 # Read-only field accessors
930 @property
931 def year(self):
932 """year (1-9999)"""
933 return self._year
934
935 @property
936 def month(self):
937 """month (1-12)"""
938 return self._month
939
940 @property
941 def day(self):
942 """day (1-31)"""
943 return self._day
944
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200945 # Standard conversions, __eq__, __le__, __lt__, __ge__, __gt__,
946 # __hash__ (and helpers)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000947
948 def timetuple(self):
949 "Return local time tuple compatible with time.localtime()."
950 return _build_struct_time(self._year, self._month, self._day,
951 0, 0, 0, -1)
952
953 def toordinal(self):
954 """Return proleptic Gregorian ordinal for the year, month and day.
955
956 January 1 of year 1 is day 1. Only the year, month and day values
957 contribute to the result.
958 """
959 return _ymd2ord(self._year, self._month, self._day)
960
961 def replace(self, year=None, month=None, day=None):
962 """Return a new date with new values for the specified fields."""
963 if year is None:
964 year = self._year
965 if month is None:
966 month = self._month
967 if day is None:
968 day = self._day
Paul Ganssle191e9932017-11-09 16:34:29 -0500969 return type(self)(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000970
971 # Comparisons of date objects with other.
972
973 def __eq__(self, other):
974 if isinstance(other, date):
975 return self._cmp(other) == 0
976 return NotImplemented
977
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000978 def __le__(self, other):
979 if isinstance(other, date):
980 return self._cmp(other) <= 0
981 return NotImplemented
982
983 def __lt__(self, other):
984 if isinstance(other, date):
985 return self._cmp(other) < 0
986 return NotImplemented
987
988 def __ge__(self, other):
989 if isinstance(other, date):
990 return self._cmp(other) >= 0
991 return NotImplemented
992
993 def __gt__(self, other):
994 if isinstance(other, date):
995 return self._cmp(other) > 0
996 return NotImplemented
997
998 def _cmp(self, other):
999 assert isinstance(other, date)
1000 y, m, d = self._year, self._month, self._day
1001 y2, m2, d2 = other._year, other._month, other._day
1002 return _cmp((y, m, d), (y2, m2, d2))
1003
1004 def __hash__(self):
1005 "Hash."
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001006 if self._hashcode == -1:
1007 self._hashcode = hash(self._getstate())
1008 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001009
1010 # Computations
1011
1012 def __add__(self, other):
1013 "Add a date to a timedelta."
1014 if isinstance(other, timedelta):
1015 o = self.toordinal() + other.days
1016 if 0 < o <= _MAXORDINAL:
Paul Ganssle89427cd2019-02-04 14:42:04 -05001017 return type(self).fromordinal(o)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001018 raise OverflowError("result out of range")
1019 return NotImplemented
1020
1021 __radd__ = __add__
1022
1023 def __sub__(self, other):
1024 """Subtract two dates, or a date and a timedelta."""
1025 if isinstance(other, timedelta):
1026 return self + timedelta(-other.days)
1027 if isinstance(other, date):
1028 days1 = self.toordinal()
1029 days2 = other.toordinal()
1030 return timedelta(days1 - days2)
1031 return NotImplemented
1032
1033 def weekday(self):
1034 "Return day of the week, where Monday == 0 ... Sunday == 6."
1035 return (self.toordinal() + 6) % 7
1036
1037 # Day-of-the-week and week-of-the-year, according to ISO
1038
1039 def isoweekday(self):
1040 "Return day of the week, where Monday == 1 ... Sunday == 7."
1041 # 1-Jan-0001 is a Monday
1042 return self.toordinal() % 7 or 7
1043
1044 def isocalendar(self):
1045 """Return a 3-tuple containing ISO year, week number, and weekday.
1046
1047 The first ISO week of the year is the (Mon-Sun) week
1048 containing the year's first Thursday; everything else derives
1049 from that.
1050
1051 The first week is 1; Monday is 1 ... Sunday is 7.
1052
1053 ISO calendar algorithm taken from
1054 http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
Brett Cannon07b954d2016-01-15 09:53:51 -08001055 (used with permission)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001056 """
1057 year = self._year
1058 week1monday = _isoweek1monday(year)
1059 today = _ymd2ord(self._year, self._month, self._day)
1060 # Internally, week and day have origin 0
1061 week, day = divmod(today - week1monday, 7)
1062 if week < 0:
1063 year -= 1
1064 week1monday = _isoweek1monday(year)
1065 week, day = divmod(today - week1monday, 7)
1066 elif week >= 52:
1067 if today >= _isoweek1monday(year+1):
1068 year += 1
1069 week = 0
1070 return year, week+1, day+1
1071
1072 # Pickle support.
1073
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001074 def _getstate(self):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001075 yhi, ylo = divmod(self._year, 256)
1076 return bytes([yhi, ylo, self._month, self._day]),
1077
1078 def __setstate(self, string):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001079 yhi, ylo, self._month, self._day = string
1080 self._year = yhi * 256 + ylo
1081
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001082 def __reduce__(self):
1083 return (self.__class__, self._getstate())
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001084
1085_date_class = date # so functions w/ args named "date" can get at the class
1086
1087date.min = date(1, 1, 1)
1088date.max = date(9999, 12, 31)
1089date.resolution = timedelta(days=1)
1090
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001091
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001092class tzinfo:
1093 """Abstract base class for time zone info classes.
1094
1095 Subclasses must override the name(), utcoffset() and dst() methods.
1096 """
1097 __slots__ = ()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001098
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001099 def tzname(self, dt):
1100 "datetime -> string name of time zone."
1101 raise NotImplementedError("tzinfo subclass must override tzname()")
1102
1103 def utcoffset(self, dt):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001104 "datetime -> timedelta, positive for east of UTC, negative for west of UTC"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001105 raise NotImplementedError("tzinfo subclass must override utcoffset()")
1106
1107 def dst(self, dt):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001108 """datetime -> DST offset as timedelta, positive for east of UTC.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001109
1110 Return 0 if DST not in effect. utcoffset() must include the DST
1111 offset.
1112 """
1113 raise NotImplementedError("tzinfo subclass must override dst()")
1114
1115 def fromutc(self, dt):
1116 "datetime in UTC -> datetime in local time."
1117
1118 if not isinstance(dt, datetime):
1119 raise TypeError("fromutc() requires a datetime argument")
1120 if dt.tzinfo is not self:
1121 raise ValueError("dt.tzinfo is not self")
1122
1123 dtoff = dt.utcoffset()
1124 if dtoff is None:
1125 raise ValueError("fromutc() requires a non-None utcoffset() "
1126 "result")
1127
1128 # See the long comment block at the end of this file for an
1129 # explanation of this algorithm.
1130 dtdst = dt.dst()
1131 if dtdst is None:
1132 raise ValueError("fromutc() requires a non-None dst() result")
1133 delta = dtoff - dtdst
1134 if delta:
1135 dt += delta
1136 dtdst = dt.dst()
1137 if dtdst is None:
1138 raise ValueError("fromutc(): dt.dst gave inconsistent "
1139 "results; cannot convert")
1140 return dt + dtdst
1141
1142 # Pickle support.
1143
1144 def __reduce__(self):
1145 getinitargs = getattr(self, "__getinitargs__", None)
1146 if getinitargs:
1147 args = getinitargs()
1148 else:
1149 args = ()
1150 getstate = getattr(self, "__getstate__", None)
1151 if getstate:
1152 state = getstate()
1153 else:
1154 state = getattr(self, "__dict__", None) or None
1155 if state is None:
1156 return (self.__class__, args)
1157 else:
1158 return (self.__class__, args, state)
1159
1160_tzinfo_class = tzinfo
1161
1162class time:
1163 """Time with time zone.
1164
1165 Constructors:
1166
1167 __new__()
1168
1169 Operators:
1170
1171 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +02001172 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001173
1174 Methods:
1175
1176 strftime()
1177 isoformat()
1178 utcoffset()
1179 tzname()
1180 dst()
1181
1182 Properties (readonly):
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001183 hour, minute, second, microsecond, tzinfo, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001184 """
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001185 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode', '_fold'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001186
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001187 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001188 """Constructor.
1189
1190 Arguments:
1191
1192 hour, minute (required)
1193 second, microsecond (default to zero)
1194 tzinfo (default to None)
Victor Stinner51b90d22017-01-04 12:01:16 +01001195 fold (keyword only, default to zero)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001196 """
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001197 if (isinstance(hour, (bytes, str)) and len(hour) == 6 and
1198 ord(hour[0:1])&0x7F < 24):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001199 # Pickle support
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001200 if isinstance(hour, str):
1201 try:
1202 hour = hour.encode('latin1')
1203 except UnicodeEncodeError:
1204 # More informative error message.
1205 raise ValueError(
1206 "Failed to encode latin1 string when unpickling "
1207 "a time object. "
1208 "pickle.load(data, encoding='latin1') is assumed.")
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001209 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001210 self.__setstate(hour, minute or None)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001211 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001212 return self
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001213 hour, minute, second, microsecond, fold = _check_time_fields(
1214 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001215 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001216 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001217 self._hour = hour
1218 self._minute = minute
1219 self._second = second
1220 self._microsecond = microsecond
1221 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001222 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001223 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001224 return self
1225
1226 # Read-only field accessors
1227 @property
1228 def hour(self):
1229 """hour (0-23)"""
1230 return self._hour
1231
1232 @property
1233 def minute(self):
1234 """minute (0-59)"""
1235 return self._minute
1236
1237 @property
1238 def second(self):
1239 """second (0-59)"""
1240 return self._second
1241
1242 @property
1243 def microsecond(self):
1244 """microsecond (0-999999)"""
1245 return self._microsecond
1246
1247 @property
1248 def tzinfo(self):
1249 """timezone info object"""
1250 return self._tzinfo
1251
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001252 @property
1253 def fold(self):
1254 return self._fold
1255
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001256 # Standard conversions, __hash__ (and helpers)
1257
1258 # Comparisons of time objects with other.
1259
1260 def __eq__(self, other):
1261 if isinstance(other, time):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001262 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001263 else:
1264 return False
1265
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001266 def __le__(self, other):
1267 if isinstance(other, time):
1268 return self._cmp(other) <= 0
1269 else:
1270 _cmperror(self, other)
1271
1272 def __lt__(self, other):
1273 if isinstance(other, time):
1274 return self._cmp(other) < 0
1275 else:
1276 _cmperror(self, other)
1277
1278 def __ge__(self, other):
1279 if isinstance(other, time):
1280 return self._cmp(other) >= 0
1281 else:
1282 _cmperror(self, other)
1283
1284 def __gt__(self, other):
1285 if isinstance(other, time):
1286 return self._cmp(other) > 0
1287 else:
1288 _cmperror(self, other)
1289
Alexander Belopolsky08313822012-06-15 20:19:47 -04001290 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001291 assert isinstance(other, time)
1292 mytz = self._tzinfo
1293 ottz = other._tzinfo
1294 myoff = otoff = None
1295
1296 if mytz is ottz:
1297 base_compare = True
1298 else:
1299 myoff = self.utcoffset()
1300 otoff = other.utcoffset()
1301 base_compare = myoff == otoff
1302
1303 if base_compare:
1304 return _cmp((self._hour, self._minute, self._second,
1305 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001306 (other._hour, other._minute, other._second,
1307 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001308 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001309 if allow_mixed:
1310 return 2 # arbitrary non-zero value
1311 else:
1312 raise TypeError("cannot compare naive and aware times")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001313 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1314 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1315 return _cmp((myhhmm, self._second, self._microsecond),
1316 (othhmm, other._second, other._microsecond))
1317
1318 def __hash__(self):
1319 """Hash."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001320 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001321 if self.fold:
1322 t = self.replace(fold=0)
1323 else:
1324 t = self
1325 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001326 if not tzoff: # zero or None
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001327 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001328 else:
1329 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1330 timedelta(hours=1))
1331 assert not m % timedelta(minutes=1), "whole minute"
1332 m //= timedelta(minutes=1)
1333 if 0 <= h < 24:
1334 self._hashcode = hash(time(h, m, self.second, self.microsecond))
1335 else:
1336 self._hashcode = hash((h, m, self.second, self.microsecond))
1337 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001338
1339 # Conversion to string
1340
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001341 def _tzstr(self):
1342 """Return formatted timezone offset (+xx:xx) or an empty string."""
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001343 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001344 return _format_offset(off)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001345
1346 def __repr__(self):
1347 """Convert to formal string, for repr()."""
1348 if self._microsecond != 0:
1349 s = ", %d, %d" % (self._second, self._microsecond)
1350 elif self._second != 0:
1351 s = ", %d" % self._second
1352 else:
1353 s = ""
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001354 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1355 self.__class__.__qualname__,
1356 self._hour, self._minute, s)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001357 if self._tzinfo is not None:
1358 assert s[-1:] == ")"
1359 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001360 if self._fold:
1361 assert s[-1:] == ")"
1362 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001363 return s
1364
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001365 def isoformat(self, timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001366 """Return the time formatted according to ISO.
1367
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001368 The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional
1369 part is omitted if self.microsecond == 0.
1370
1371 The optional argument timespec specifies the number of additional
1372 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001373 """
1374 s = _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001375 self._microsecond, timespec)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001376 tz = self._tzstr()
1377 if tz:
1378 s += tz
1379 return s
1380
1381 __str__ = isoformat
1382
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001383 @classmethod
1384 def fromisoformat(cls, time_string):
1385 """Construct a time from the output of isoformat()."""
1386 if not isinstance(time_string, str):
1387 raise TypeError('fromisoformat: argument must be str')
1388
1389 try:
1390 return cls(*_parse_isoformat_time(time_string))
1391 except Exception:
Paul Ganssle3df85402018-10-22 12:32:52 -04001392 raise ValueError(f'Invalid isoformat string: {time_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001393
1394
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001395 def strftime(self, fmt):
1396 """Format using strftime(). The date part of the timestamp passed
1397 to underlying strftime should not be used.
1398 """
Alexander Belopolskyb8bb4662011-01-08 00:13:34 +00001399 # The year must be >= 1000 else Python's strftime implementation
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001400 # can raise a bogus exception.
1401 timetuple = (1900, 1, 1,
1402 self._hour, self._minute, self._second,
1403 0, 1, -1)
1404 return _wrap_strftime(self, fmt, timetuple)
1405
1406 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001407 if not isinstance(fmt, str):
1408 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001409 if len(fmt) != 0:
1410 return self.strftime(fmt)
1411 return str(self)
1412
1413 # Timezone functions
1414
1415 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001416 """Return the timezone offset as timedelta, positive east of UTC
1417 (negative west of UTC)."""
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001418 if self._tzinfo is None:
1419 return None
1420 offset = self._tzinfo.utcoffset(None)
1421 _check_utc_offset("utcoffset", offset)
1422 return offset
1423
1424 def tzname(self):
1425 """Return the timezone name.
1426
1427 Note that the name is 100% informational -- there's no requirement that
1428 it mean anything in particular. For example, "GMT", "UTC", "-500",
1429 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1430 """
1431 if self._tzinfo is None:
1432 return None
1433 name = self._tzinfo.tzname(None)
1434 _check_tzname(name)
1435 return name
1436
1437 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001438 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1439 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001440
1441 This is purely informational; the DST offset has already been added to
1442 the UTC offset returned by utcoffset() if applicable, so there's no
1443 need to consult dst() unless you're interested in displaying the DST
1444 info.
1445 """
1446 if self._tzinfo is None:
1447 return None
1448 offset = self._tzinfo.dst(None)
1449 _check_utc_offset("dst", offset)
1450 return offset
1451
1452 def replace(self, hour=None, minute=None, second=None, microsecond=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001453 tzinfo=True, *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001454 """Return a new time with new values for the specified fields."""
1455 if hour is None:
1456 hour = self.hour
1457 if minute is None:
1458 minute = self.minute
1459 if second is None:
1460 second = self.second
1461 if microsecond is None:
1462 microsecond = self.microsecond
1463 if tzinfo is True:
1464 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001465 if fold is None:
1466 fold = self._fold
Paul Ganssle191e9932017-11-09 16:34:29 -05001467 return type(self)(hour, minute, second, microsecond, tzinfo, fold=fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001468
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001469 # Pickle support.
1470
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001471 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001472 us2, us3 = divmod(self._microsecond, 256)
1473 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001474 h = self._hour
1475 if self._fold and protocol > 3:
1476 h += 128
1477 basestate = bytes([h, self._minute, self._second,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001478 us1, us2, us3])
1479 if self._tzinfo is None:
1480 return (basestate,)
1481 else:
1482 return (basestate, self._tzinfo)
1483
1484 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001485 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1486 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001487 h, self._minute, self._second, us1, us2, us3 = string
1488 if h > 127:
1489 self._fold = 1
1490 self._hour = h - 128
1491 else:
1492 self._fold = 0
1493 self._hour = h
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001494 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001495 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001496
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001497 def __reduce_ex__(self, protocol):
1498 return (time, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001499
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001500 def __reduce__(self):
1501 return self.__reduce_ex__(2)
1502
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001503_time_class = time # so functions w/ args named "time" can get at the class
1504
1505time.min = time(0, 0, 0)
1506time.max = time(23, 59, 59, 999999)
1507time.resolution = timedelta(microseconds=1)
1508
1509class datetime(date):
1510 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1511
1512 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001513 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001514 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001515 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001516
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001517 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001518 microsecond=0, tzinfo=None, *, fold=0):
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001519 if (isinstance(year, (bytes, str)) and len(year) == 10 and
1520 1 <= ord(year[2:3])&0x7F <= 12):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001521 # Pickle support
Serhiy Storchaka8452ca12018-12-07 13:42:10 +02001522 if isinstance(year, str):
1523 try:
1524 year = bytes(year, 'latin1')
1525 except UnicodeEncodeError:
1526 # More informative error message.
1527 raise ValueError(
1528 "Failed to encode latin1 string when unpickling "
1529 "a datetime object. "
1530 "pickle.load(data, encoding='latin1') is assumed.")
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001531 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001532 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001533 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001534 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001535 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001536 hour, minute, second, microsecond, fold = _check_time_fields(
1537 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001538 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001539 self = object.__new__(cls)
1540 self._year = year
1541 self._month = month
1542 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001543 self._hour = hour
1544 self._minute = minute
1545 self._second = second
1546 self._microsecond = microsecond
1547 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001548 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001549 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001550 return self
1551
1552 # Read-only field accessors
1553 @property
1554 def hour(self):
1555 """hour (0-23)"""
1556 return self._hour
1557
1558 @property
1559 def minute(self):
1560 """minute (0-59)"""
1561 return self._minute
1562
1563 @property
1564 def second(self):
1565 """second (0-59)"""
1566 return self._second
1567
1568 @property
1569 def microsecond(self):
1570 """microsecond (0-999999)"""
1571 return self._microsecond
1572
1573 @property
1574 def tzinfo(self):
1575 """timezone info object"""
1576 return self._tzinfo
1577
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001578 @property
1579 def fold(self):
1580 return self._fold
1581
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001582 @classmethod
Victor Stinneradfefa52015-09-04 23:57:25 +02001583 def _fromtimestamp(cls, t, utc, tz):
1584 """Construct a datetime from a POSIX timestamp (like time.time()).
1585
1586 A timezone info object may be passed in as well.
1587 """
1588 frac, t = _math.modf(t)
Victor Stinner7667f582015-09-09 01:02:23 +02001589 us = round(frac * 1e6)
Victor Stinneradfefa52015-09-04 23:57:25 +02001590 if us >= 1000000:
1591 t += 1
1592 us -= 1000000
1593 elif us < 0:
1594 t -= 1
1595 us += 1000000
1596
1597 converter = _time.gmtime if utc else _time.localtime
1598 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1599 ss = min(ss, 59) # clamp out leap seconds if the platform has them
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001600 result = cls(y, m, d, hh, mm, ss, us, tz)
1601 if tz is None:
1602 # As of version 2015f max fold in IANA database is
1603 # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
1604 # Let's probe 24 hours in the past to detect a transition:
1605 max_fold_seconds = 24 * 3600
Ammar Askar96d1e692018-07-25 09:54:58 -07001606
1607 # On Windows localtime_s throws an OSError for negative values,
1608 # thus we can't perform fold detection for values of time less
1609 # than the max time fold. See comments in _datetimemodule's
1610 # version of this method for more details.
1611 if t < max_fold_seconds and sys.platform.startswith("win"):
1612 return result
1613
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001614 y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1615 probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1616 trans = result - probe1 - timedelta(0, max_fold_seconds)
1617 if trans.days < 0:
1618 y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
1619 probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1620 if probe2 == result:
1621 result._fold = 1
1622 else:
1623 result = tz.fromutc(result)
1624 return result
Victor Stinneradfefa52015-09-04 23:57:25 +02001625
1626 @classmethod
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001627 def fromtimestamp(cls, t, tz=None):
1628 """Construct a datetime from a POSIX timestamp (like time.time()).
1629
1630 A timezone info object may be passed in as well.
1631 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001632 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001633
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001634 return cls._fromtimestamp(t, tz is not None, tz)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001635
1636 @classmethod
1637 def utcfromtimestamp(cls, t):
Alexander Belopolskye2e178e2015-03-01 14:52:07 -05001638 """Construct a naive UTC datetime from a POSIX timestamp."""
Victor Stinneradfefa52015-09-04 23:57:25 +02001639 return cls._fromtimestamp(t, True, None)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001640
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001641 @classmethod
1642 def now(cls, tz=None):
1643 "Construct a datetime from time.time() and optional time zone info."
1644 t = _time.time()
1645 return cls.fromtimestamp(t, tz)
1646
1647 @classmethod
1648 def utcnow(cls):
1649 "Construct a UTC datetime from time.time()."
1650 t = _time.time()
1651 return cls.utcfromtimestamp(t)
1652
1653 @classmethod
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001654 def combine(cls, date, time, tzinfo=True):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001655 "Construct a datetime from a given date and a given time."
1656 if not isinstance(date, _date_class):
1657 raise TypeError("date argument must be a date instance")
1658 if not isinstance(time, _time_class):
1659 raise TypeError("time argument must be a time instance")
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001660 if tzinfo is True:
1661 tzinfo = time.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001662 return cls(date.year, date.month, date.day,
1663 time.hour, time.minute, time.second, time.microsecond,
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001664 tzinfo, fold=time.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001665
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001666 @classmethod
1667 def fromisoformat(cls, date_string):
1668 """Construct a datetime from the output of datetime.isoformat()."""
1669 if not isinstance(date_string, str):
1670 raise TypeError('fromisoformat: argument must be str')
1671
1672 # Split this at the separator
1673 dstr = date_string[0:10]
1674 tstr = date_string[11:]
1675
1676 try:
1677 date_components = _parse_isoformat_date(dstr)
1678 except ValueError:
Paul Ganssle3df85402018-10-22 12:32:52 -04001679 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001680
1681 if tstr:
1682 try:
1683 time_components = _parse_isoformat_time(tstr)
1684 except ValueError:
Paul Ganssle3df85402018-10-22 12:32:52 -04001685 raise ValueError(f'Invalid isoformat string: {date_string!r}')
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001686 else:
1687 time_components = [0, 0, 0, 0, None]
1688
1689 return cls(*(date_components + time_components))
1690
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001691 def timetuple(self):
1692 "Return local time tuple compatible with time.localtime()."
1693 dst = self.dst()
1694 if dst is None:
1695 dst = -1
1696 elif dst:
1697 dst = 1
1698 else:
1699 dst = 0
1700 return _build_struct_time(self.year, self.month, self.day,
1701 self.hour, self.minute, self.second,
1702 dst)
1703
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001704 def _mktime(self):
1705 """Return integer POSIX timestamp."""
1706 epoch = datetime(1970, 1, 1)
1707 max_fold_seconds = 24 * 3600
1708 t = (self - epoch) // timedelta(0, 1)
1709 def local(u):
1710 y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1711 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1712
1713 # Our goal is to solve t = local(u) for u.
1714 a = local(t) - t
1715 u1 = t - a
1716 t1 = local(u1)
1717 if t1 == t:
1718 # We found one solution, but it may not be the one we need.
1719 # Look for an earlier solution (if `fold` is 0), or a
1720 # later one (if `fold` is 1).
1721 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1722 b = local(u2) - u2
1723 if a == b:
1724 return u1
1725 else:
1726 b = t1 - u1
1727 assert a != b
1728 u2 = t - b
1729 t2 = local(u2)
1730 if t2 == t:
1731 return u2
1732 if t1 == t:
1733 return u1
1734 # We have found both offsets a and b, but neither t - a nor t - b is
1735 # a solution. This means t is in the gap.
1736 return (max, min)[self.fold](u1, u2)
1737
1738
Alexander Belopolskya4415142012-06-08 12:33:09 -04001739 def timestamp(self):
1740 "Return POSIX timestamp as float"
1741 if self._tzinfo is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001742 s = self._mktime()
1743 return s + self.microsecond / 1e6
Alexander Belopolskya4415142012-06-08 12:33:09 -04001744 else:
1745 return (self - _EPOCH).total_seconds()
1746
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001747 def utctimetuple(self):
1748 "Return UTC time tuple compatible with time.gmtime()."
1749 offset = self.utcoffset()
1750 if offset:
1751 self -= offset
1752 y, m, d = self.year, self.month, self.day
1753 hh, mm, ss = self.hour, self.minute, self.second
1754 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1755
1756 def date(self):
1757 "Return the date part."
1758 return date(self._year, self._month, self._day)
1759
1760 def time(self):
1761 "Return the time part, with tzinfo None."
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001762 return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001763
1764 def timetz(self):
1765 "Return the time part, with same tzinfo."
1766 return time(self.hour, self.minute, self.second, self.microsecond,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001767 self._tzinfo, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001768
1769 def replace(self, year=None, month=None, day=None, hour=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001770 minute=None, second=None, microsecond=None, tzinfo=True,
1771 *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001772 """Return a new datetime with new values for the specified fields."""
1773 if year is None:
1774 year = self.year
1775 if month is None:
1776 month = self.month
1777 if day is None:
1778 day = self.day
1779 if hour is None:
1780 hour = self.hour
1781 if minute is None:
1782 minute = self.minute
1783 if second is None:
1784 second = self.second
1785 if microsecond is None:
1786 microsecond = self.microsecond
1787 if tzinfo is True:
1788 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001789 if fold is None:
1790 fold = self.fold
Paul Ganssle191e9932017-11-09 16:34:29 -05001791 return type(self)(year, month, day, hour, minute, second,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001792 microsecond, tzinfo, fold=fold)
1793
1794 def _local_timezone(self):
1795 if self.tzinfo is None:
1796 ts = self._mktime()
1797 else:
1798 ts = (self - _EPOCH) // timedelta(seconds=1)
1799 localtm = _time.localtime(ts)
1800 local = datetime(*localtm[:6])
Alexander Belopolskybcb032e2018-06-08 19:22:33 -04001801 # Extract TZ data
1802 gmtoff = localtm.tm_gmtoff
1803 zone = localtm.tm_zone
1804 return timezone(timedelta(seconds=gmtoff), zone)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001805
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001806 def astimezone(self, tz=None):
1807 if tz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001808 tz = self._local_timezone()
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001809 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001810 raise TypeError("tz argument must be an instance of tzinfo")
1811
1812 mytz = self.tzinfo
1813 if mytz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001814 mytz = self._local_timezone()
Alexander Belopolsky877b2322018-06-10 17:02:58 -04001815 myoffset = mytz.utcoffset(self)
1816 else:
1817 myoffset = mytz.utcoffset(self)
1818 if myoffset is None:
1819 mytz = self.replace(tzinfo=None)._local_timezone()
1820 myoffset = mytz.utcoffset(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001821
1822 if tz is mytz:
1823 return self
1824
1825 # Convert self to UTC, and attach the new time zone object.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001826 utc = (self - myoffset).replace(tzinfo=tz)
1827
1828 # Convert from UTC to tz's local time.
1829 return tz.fromutc(utc)
1830
1831 # Ways to produce a string.
1832
1833 def ctime(self):
1834 "Return ctime() style string."
1835 weekday = self.toordinal() % 7 or 7
1836 return "%s %s %2d %02d:%02d:%02d %04d" % (
1837 _DAYNAMES[weekday],
1838 _MONTHNAMES[self._month],
1839 self._day,
1840 self._hour, self._minute, self._second,
1841 self._year)
1842
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001843 def isoformat(self, sep='T', timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001844 """Return the time formatted according to ISO.
1845
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001846 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1847 By default, the fractional part is omitted if self.microsecond == 0.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001848
1849 If self.tzinfo is not None, the UTC offset is also attached, giving
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001850 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001851
1852 Optional argument sep specifies the separator between date and
1853 time, default 'T'.
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001854
1855 The optional argument timespec specifies the number of additional
1856 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001857 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001858 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1859 _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001860 self._microsecond, timespec))
1861
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001862 off = self.utcoffset()
Paul Ganssle09dc2f52017-12-21 00:33:49 -05001863 tz = _format_offset(off)
1864 if tz:
1865 s += tz
1866
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001867 return s
1868
1869 def __repr__(self):
1870 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001871 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001872 self._hour, self._minute, self._second, self._microsecond]
1873 if L[-1] == 0:
1874 del L[-1]
1875 if L[-1] == 0:
1876 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001877 s = "%s.%s(%s)" % (self.__class__.__module__,
1878 self.__class__.__qualname__,
1879 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001880 if self._tzinfo is not None:
1881 assert s[-1:] == ")"
1882 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001883 if self._fold:
1884 assert s[-1:] == ")"
1885 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001886 return s
1887
1888 def __str__(self):
1889 "Convert to string, for str()."
1890 return self.isoformat(sep=' ')
1891
1892 @classmethod
1893 def strptime(cls, date_string, format):
1894 'string, format -> new datetime parsed from a string (like time.strptime()).'
1895 import _strptime
1896 return _strptime._strptime_datetime(cls, date_string, format)
1897
1898 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001899 """Return the timezone offset as timedelta positive east of UTC (negative west of
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001900 UTC)."""
1901 if self._tzinfo is None:
1902 return None
1903 offset = self._tzinfo.utcoffset(self)
1904 _check_utc_offset("utcoffset", offset)
1905 return offset
1906
1907 def tzname(self):
1908 """Return the timezone name.
1909
1910 Note that the name is 100% informational -- there's no requirement that
1911 it mean anything in particular. For example, "GMT", "UTC", "-500",
1912 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1913 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001914 if self._tzinfo is None:
1915 return None
1916 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001917 _check_tzname(name)
1918 return name
1919
1920 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001921 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1922 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001923
1924 This is purely informational; the DST offset has already been added to
1925 the UTC offset returned by utcoffset() if applicable, so there's no
1926 need to consult dst() unless you're interested in displaying the DST
1927 info.
1928 """
1929 if self._tzinfo is None:
1930 return None
1931 offset = self._tzinfo.dst(self)
1932 _check_utc_offset("dst", offset)
1933 return offset
1934
1935 # Comparisons of datetime objects with other.
1936
1937 def __eq__(self, other):
1938 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001939 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001940 elif not isinstance(other, date):
1941 return NotImplemented
1942 else:
1943 return False
1944
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001945 def __le__(self, other):
1946 if isinstance(other, datetime):
1947 return self._cmp(other) <= 0
1948 elif not isinstance(other, date):
1949 return NotImplemented
1950 else:
1951 _cmperror(self, other)
1952
1953 def __lt__(self, other):
1954 if isinstance(other, datetime):
1955 return self._cmp(other) < 0
1956 elif not isinstance(other, date):
1957 return NotImplemented
1958 else:
1959 _cmperror(self, other)
1960
1961 def __ge__(self, other):
1962 if isinstance(other, datetime):
1963 return self._cmp(other) >= 0
1964 elif not isinstance(other, date):
1965 return NotImplemented
1966 else:
1967 _cmperror(self, other)
1968
1969 def __gt__(self, other):
1970 if isinstance(other, datetime):
1971 return self._cmp(other) > 0
1972 elif not isinstance(other, date):
1973 return NotImplemented
1974 else:
1975 _cmperror(self, other)
1976
Alexander Belopolsky08313822012-06-15 20:19:47 -04001977 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001978 assert isinstance(other, datetime)
1979 mytz = self._tzinfo
1980 ottz = other._tzinfo
1981 myoff = otoff = None
1982
1983 if mytz is ottz:
1984 base_compare = True
1985 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04001986 myoff = self.utcoffset()
1987 otoff = other.utcoffset()
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001988 # Assume that allow_mixed means that we are called from __eq__
1989 if allow_mixed:
1990 if myoff != self.replace(fold=not self.fold).utcoffset():
1991 return 2
1992 if otoff != other.replace(fold=not other.fold).utcoffset():
1993 return 2
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001994 base_compare = myoff == otoff
1995
1996 if base_compare:
1997 return _cmp((self._year, self._month, self._day,
1998 self._hour, self._minute, self._second,
1999 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002000 (other._year, other._month, other._day,
2001 other._hour, other._minute, other._second,
2002 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002003 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04002004 if allow_mixed:
2005 return 2 # arbitrary non-zero value
2006 else:
2007 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002008 # XXX What follows could be done more efficiently...
2009 diff = self - other # this will take offsets into account
2010 if diff.days < 0:
2011 return -1
2012 return diff and 1 or 0
2013
2014 def __add__(self, other):
2015 "Add a datetime and a timedelta."
2016 if not isinstance(other, timedelta):
2017 return NotImplemented
2018 delta = timedelta(self.toordinal(),
2019 hours=self._hour,
2020 minutes=self._minute,
2021 seconds=self._second,
2022 microseconds=self._microsecond)
2023 delta += other
2024 hour, rem = divmod(delta.seconds, 3600)
2025 minute, second = divmod(rem, 60)
2026 if 0 < delta.days <= _MAXORDINAL:
Paul Ganssle89427cd2019-02-04 14:42:04 -05002027 return type(self).combine(date.fromordinal(delta.days),
2028 time(hour, minute, second,
2029 delta.microseconds,
2030 tzinfo=self._tzinfo))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002031 raise OverflowError("result out of range")
2032
2033 __radd__ = __add__
2034
2035 def __sub__(self, other):
2036 "Subtract two datetimes, or a datetime and a timedelta."
2037 if not isinstance(other, datetime):
2038 if isinstance(other, timedelta):
2039 return self + -other
2040 return NotImplemented
2041
2042 days1 = self.toordinal()
2043 days2 = other.toordinal()
2044 secs1 = self._second + self._minute * 60 + self._hour * 3600
2045 secs2 = other._second + other._minute * 60 + other._hour * 3600
2046 base = timedelta(days1 - days2,
2047 secs1 - secs2,
2048 self._microsecond - other._microsecond)
2049 if self._tzinfo is other._tzinfo:
2050 return base
2051 myoff = self.utcoffset()
2052 otoff = other.utcoffset()
2053 if myoff == otoff:
2054 return base
2055 if myoff is None or otoff is None:
2056 raise TypeError("cannot mix naive and timezone-aware time")
2057 return base + otoff - myoff
2058
2059 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002060 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002061 if self.fold:
2062 t = self.replace(fold=0)
2063 else:
2064 t = self
2065 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002066 if tzoff is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002067 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002068 else:
2069 days = _ymd2ord(self.year, self.month, self.day)
2070 seconds = self.hour * 3600 + self.minute * 60 + self.second
2071 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
2072 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002073
2074 # Pickle support.
2075
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002076 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002077 yhi, ylo = divmod(self._year, 256)
2078 us2, us3 = divmod(self._microsecond, 256)
2079 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002080 m = self._month
2081 if self._fold and protocol > 3:
2082 m += 128
2083 basestate = bytes([yhi, ylo, m, self._day,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002084 self._hour, self._minute, self._second,
2085 us1, us2, us3])
2086 if self._tzinfo is None:
2087 return (basestate,)
2088 else:
2089 return (basestate, self._tzinfo)
2090
2091 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002092 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
2093 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002094 (yhi, ylo, m, self._day, self._hour,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002095 self._minute, self._second, us1, us2, us3) = string
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002096 if m > 127:
2097 self._fold = 1
2098 self._month = m - 128
2099 else:
2100 self._fold = 0
2101 self._month = m
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002102 self._year = yhi * 256 + ylo
2103 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002104 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002105
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04002106 def __reduce_ex__(self, protocol):
2107 return (self.__class__, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002108
Serhiy Storchaka546ce652016-11-22 00:29:42 +02002109 def __reduce__(self):
2110 return self.__reduce_ex__(2)
2111
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002112
2113datetime.min = datetime(1, 1, 1)
2114datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
2115datetime.resolution = timedelta(microseconds=1)
2116
2117
2118def _isoweek1monday(year):
2119 # Helper to calculate the day number of the Monday starting week 1
2120 # XXX This could be done more efficiently
2121 THURSDAY = 3
2122 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002123 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002124 week1monday = firstday - firstweekday
2125 if firstweekday > THURSDAY:
2126 week1monday += 7
2127 return week1monday
2128
2129class timezone(tzinfo):
2130 __slots__ = '_offset', '_name'
2131
2132 # Sentinel value to disallow None
2133 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002134 def __new__(cls, offset, name=_Omitted):
2135 if not isinstance(offset, timedelta):
2136 raise TypeError("offset must be a timedelta")
2137 if name is cls._Omitted:
2138 if not offset:
2139 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002140 name = None
2141 elif not isinstance(name, str):
2142 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002143 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002144 raise ValueError("offset must be a timedelta "
2145 "strictly between -timedelta(hours=24) and "
2146 "timedelta(hours=24).")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002147 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002148
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002149 @classmethod
2150 def _create(cls, offset, name=None):
2151 self = tzinfo.__new__(cls)
2152 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002153 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002154 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002155
2156 def __getinitargs__(self):
2157 """pickle support"""
2158 if self._name is None:
2159 return (self._offset,)
2160 return (self._offset, self._name)
2161
2162 def __eq__(self, other):
Georg Brandl0085a242012-09-22 09:23:12 +02002163 if type(other) != timezone:
2164 return False
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002165 return self._offset == other._offset
2166
2167 def __hash__(self):
2168 return hash(self._offset)
2169
2170 def __repr__(self):
2171 """Convert to formal string, for repr().
2172
2173 >>> tz = timezone.utc
2174 >>> repr(tz)
2175 'datetime.timezone.utc'
2176 >>> tz = timezone(timedelta(hours=-5), 'EST')
2177 >>> repr(tz)
2178 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
2179 """
2180 if self is self.utc:
2181 return 'datetime.timezone.utc'
2182 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03002183 return "%s.%s(%r)" % (self.__class__.__module__,
2184 self.__class__.__qualname__,
2185 self._offset)
2186 return "%s.%s(%r, %r)" % (self.__class__.__module__,
2187 self.__class__.__qualname__,
2188 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002189
2190 def __str__(self):
2191 return self.tzname(None)
2192
2193 def utcoffset(self, dt):
2194 if isinstance(dt, datetime) or dt is None:
2195 return self._offset
2196 raise TypeError("utcoffset() argument must be a datetime instance"
2197 " or None")
2198
2199 def tzname(self, dt):
2200 if isinstance(dt, datetime) or dt is None:
2201 if self._name is None:
2202 return self._name_from_offset(self._offset)
2203 return self._name
2204 raise TypeError("tzname() argument must be a datetime instance"
2205 " or None")
2206
2207 def dst(self, dt):
2208 if isinstance(dt, datetime) or dt is None:
2209 return None
2210 raise TypeError("dst() argument must be a datetime instance"
2211 " or None")
2212
2213 def fromutc(self, dt):
2214 if isinstance(dt, datetime):
2215 if dt.tzinfo is not self:
2216 raise ValueError("fromutc: dt.tzinfo "
2217 "is not self")
2218 return dt + self._offset
2219 raise TypeError("fromutc() argument must be a datetime instance"
2220 " or None")
2221
2222 _maxoffset = timedelta(hours=23, minutes=59)
2223 _minoffset = -_maxoffset
2224
2225 @staticmethod
2226 def _name_from_offset(delta):
Alexander Belopolsky7827a5b2015-09-06 13:07:21 -04002227 if not delta:
2228 return 'UTC'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002229 if delta < timedelta(0):
2230 sign = '-'
2231 delta = -delta
2232 else:
2233 sign = '+'
2234 hours, rest = divmod(delta, timedelta(hours=1))
Alexander Belopolsky018d3532017-07-31 10:26:50 -04002235 minutes, rest = divmod(rest, timedelta(minutes=1))
2236 seconds = rest.seconds
2237 microseconds = rest.microseconds
2238 if microseconds:
2239 return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2240 f'.{microseconds:06d}')
2241 if seconds:
2242 return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2243 return f'UTC{sign}{hours:02d}:{minutes:02d}'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002244
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002245timezone.utc = timezone._create(timedelta(0))
2246timezone.min = timezone._create(timezone._minoffset)
2247timezone.max = timezone._create(timezone._maxoffset)
Alexander Belopolskya4415142012-06-08 12:33:09 -04002248_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002249
Victor Stinner765531d2013-03-26 01:11:54 +01002250# Some time zone algebra. For a datetime x, let
2251# x.n = x stripped of its timezone -- its naive time.
2252# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2253# return None
2254# x.d = x.dst(), and assuming that doesn't raise an exception or
2255# return None
2256# x.s = x's standard offset, x.o - x.d
2257#
2258# Now some derived rules, where k is a duration (timedelta).
2259#
2260# 1. x.o = x.s + x.d
2261# This follows from the definition of x.s.
2262#
2263# 2. If x and y have the same tzinfo member, x.s = y.s.
2264# This is actually a requirement, an assumption we need to make about
2265# sane tzinfo classes.
2266#
2267# 3. The naive UTC time corresponding to x is x.n - x.o.
2268# This is again a requirement for a sane tzinfo class.
2269#
2270# 4. (x+k).s = x.s
2271# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
2272#
2273# 5. (x+k).n = x.n + k
2274# Again follows from how arithmetic is defined.
2275#
2276# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
2277# (meaning that the various tzinfo methods exist, and don't blow up or return
2278# None when called).
2279#
2280# The function wants to return a datetime y with timezone tz, equivalent to x.
2281# x is already in UTC.
2282#
2283# By #3, we want
2284#
2285# y.n - y.o = x.n [1]
2286#
2287# The algorithm starts by attaching tz to x.n, and calling that y. So
2288# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
2289# becomes true; in effect, we want to solve [2] for k:
2290#
2291# (y+k).n - (y+k).o = x.n [2]
2292#
2293# By #1, this is the same as
2294#
2295# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
2296#
2297# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2298# Substituting that into [3],
2299#
2300# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2301# k - (y+k).s - (y+k).d = 0; rearranging,
2302# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2303# k = y.s - (y+k).d
2304#
2305# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2306# approximate k by ignoring the (y+k).d term at first. Note that k can't be
2307# very large, since all offset-returning methods return a duration of magnitude
2308# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
2309# be 0, so ignoring it has no consequence then.
2310#
2311# In any case, the new value is
2312#
2313# z = y + y.s [4]
2314#
2315# It's helpful to step back at look at [4] from a higher level: it's simply
2316# mapping from UTC to tz's standard time.
2317#
2318# At this point, if
2319#
2320# z.n - z.o = x.n [5]
2321#
2322# we have an equivalent time, and are almost done. The insecurity here is
2323# at the start of daylight time. Picture US Eastern for concreteness. The wall
2324# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2325# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2326# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2327# on the day DST starts. We want to return the 1:MM EST spelling because that's
2328# the only spelling that makes sense on the local wall clock.
2329#
2330# In fact, if [5] holds at this point, we do have the standard-time spelling,
2331# but that takes a bit of proof. We first prove a stronger result. What's the
2332# difference between the LHS and RHS of [5]? Let
2333#
2334# diff = x.n - (z.n - z.o) [6]
2335#
2336# Now
2337# z.n = by [4]
2338# (y + y.s).n = by #5
2339# y.n + y.s = since y.n = x.n
2340# x.n + y.s = since z and y are have the same tzinfo member,
2341# y.s = z.s by #2
2342# x.n + z.s
2343#
2344# Plugging that back into [6] gives
2345#
2346# diff =
2347# x.n - ((x.n + z.s) - z.o) = expanding
2348# x.n - x.n - z.s + z.o = cancelling
2349# - z.s + z.o = by #2
2350# z.d
2351#
2352# So diff = z.d.
2353#
2354# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2355# spelling we wanted in the endcase described above. We're done. Contrarily,
2356# if z.d = 0, then we have a UTC equivalent, and are also done.
2357#
2358# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2359# add to z (in effect, z is in tz's standard time, and we need to shift the
2360# local clock into tz's daylight time).
2361#
2362# Let
2363#
2364# z' = z + z.d = z + diff [7]
2365#
2366# and we can again ask whether
2367#
2368# z'.n - z'.o = x.n [8]
2369#
2370# If so, we're done. If not, the tzinfo class is insane, according to the
2371# assumptions we've made. This also requires a bit of proof. As before, let's
2372# compute the difference between the LHS and RHS of [8] (and skipping some of
2373# the justifications for the kinds of substitutions we've done several times
2374# already):
2375#
2376# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2377# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2378# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2379# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2380# - z.n + z.n - z.o + z'.o = cancel z.n
2381# - z.o + z'.o = #1 twice
2382# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2383# z'.d - z.d
2384#
2385# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2386# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2387# return z', not bothering to compute z'.d.
2388#
2389# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2390# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2391# would have to change the result dst() returns: we start in DST, and moving
2392# a little further into it takes us out of DST.
2393#
2394# There isn't a sane case where this can happen. The closest it gets is at
2395# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2396# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2397# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2398# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2399# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2400# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2401# standard time. Since that's what the local clock *does*, we want to map both
2402# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2403# in local time, but so it goes -- it's the way the local clock works.
2404#
2405# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2406# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2407# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2408# (correctly) concludes that z' is not UTC-equivalent to x.
2409#
2410# Because we know z.d said z was in daylight time (else [5] would have held and
2411# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2412# and we have stopped then), and there are only 2 possible values dst() can
2413# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2414# but the reasoning doesn't depend on the example -- it depends on there being
2415# two possible dst() outcomes, one zero and the other non-zero). Therefore
2416# z' must be in standard time, and is the spelling we want in this case.
2417#
2418# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2419# concerned (because it takes z' as being in standard time rather than the
2420# daylight time we intend here), but returning it gives the real-life "local
2421# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2422# tz.
2423#
2424# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2425# the 1:MM standard time spelling we want.
2426#
2427# So how can this break? One of the assumptions must be violated. Two
2428# possibilities:
2429#
2430# 1) [2] effectively says that y.s is invariant across all y belong to a given
2431# time zone. This isn't true if, for political reasons or continental drift,
2432# a region decides to change its base offset from UTC.
2433#
2434# 2) There may be versions of "double daylight" time where the tail end of
2435# the analysis gives up a step too early. I haven't thought about that
2436# enough to say.
2437#
2438# In any case, it's clear that the default fromutc() is strong enough to handle
2439# "almost all" time zones: so long as the standard offset is invariant, it
2440# doesn't matter if daylight time transition points change from year to year, or
2441# if daylight time is skipped in some years; it doesn't matter how large or
2442# small dst() may get within its bounds; and it doesn't even matter if some
2443# perverse time zone returns a negative dst()). So a breaking case must be
2444# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002445
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002446try:
2447 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002448except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002449 pass
2450else:
2451 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002452 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2453 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2454 _check_date_fields, _check_int_field, _check_time_fields,
2455 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2456 _date_class, _days_before_month, _days_before_year, _days_in_month,
Paul Ganssle09dc2f52017-12-21 00:33:49 -05002457 _format_time, _format_offset, _is_leap, _isoweek1monday, _math,
2458 _ord2ymd, _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord,
2459 _divide_and_round, _parse_isoformat_date, _parse_isoformat_time,
2460 _parse_hh_mm_ss_ff)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002461 # XXX Since import * above excludes names that start with _,
2462 # docstring does not get overwritten. In the future, it may be
2463 # appropriate to maintain a single module level docstring and
2464 # remove the following line.
2465 from _datetime import __doc__