blob: 2f03847be0a0794c14aa1a67d150ad4ad381faf3 [file] [log] [blame]
Ezio Melottif756f942013-04-13 20:12:38 +03001"""Concrete date/time and related types.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002
Ezio Melottif756f942013-04-13 20:12:38 +03003See http://www.iana.org/time-zones/repository/tz-link.html for
4time zone and DST data sources.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00005"""
6
7import time as _time
8import math as _math
9
10def _cmp(x, y):
11 return 0 if x == y else 1 if x > y else -1
12
13MINYEAR = 1
14MAXYEAR = 9999
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -040015_MAXORDINAL = 3652059 # date.max.toordinal()
Alexander Belopolskycf86e362010-07-23 19:25:47 +000016
17# Utility functions, adapted from Python's Demo/classes/Dates.py, which
18# also assumes the current Gregorian calendar indefinitely extended in
19# both directions. Difference: Dates.py calls January 1 of year 0 day
20# number 1. The code here calls January 1 of year 1 day number 1. This is
21# to match the definition of the "proleptic Gregorian" calendar in Dershowitz
22# and Reingold's "Calendrical Calculations", where it's the base calendar
23# for all computations. See the book for algorithms for converting between
24# proleptic Gregorian ordinals and many other calendar systems.
25
Benjamin Petersonda0bea22013-08-29 17:29:30 -040026# -1 is a placeholder for indexing purposes.
Benjamin Petersonf908efb2013-08-29 17:27:57 -040027_DAYS_IN_MONTH = [-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
Alexander Belopolskycf86e362010-07-23 19:25:47 +000028
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -040029_DAYS_BEFORE_MONTH = [-1] # -1 is a placeholder for indexing purposes.
Alexander Belopolskycf86e362010-07-23 19:25:47 +000030dbm = 0
31for dim in _DAYS_IN_MONTH[1:]:
32 _DAYS_BEFORE_MONTH.append(dbm)
33 dbm += dim
34del dbm, dim
35
36def _is_leap(year):
37 "year -> 1 if leap year, else 0."
38 return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
39
40def _days_before_year(year):
41 "year -> number of days before January 1st of year."
42 y = year - 1
43 return y*365 + y//4 - y//100 + y//400
44
45def _days_in_month(year, month):
46 "year, month -> number of days in that month in that year."
47 assert 1 <= month <= 12, month
48 if month == 2 and _is_leap(year):
49 return 29
50 return _DAYS_IN_MONTH[month]
51
52def _days_before_month(year, month):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +030053 "year, month -> number of days in year preceding first day of month."
Alexander Belopolskycf86e362010-07-23 19:25:47 +000054 assert 1 <= month <= 12, 'month must be in 1..12'
55 return _DAYS_BEFORE_MONTH[month] + (month > 2 and _is_leap(year))
56
57def _ymd2ord(year, month, day):
58 "year, month, day -> ordinal, considering 01-Jan-0001 as day 1."
59 assert 1 <= month <= 12, 'month must be in 1..12'
60 dim = _days_in_month(year, month)
61 assert 1 <= day <= dim, ('day must be in 1..%d' % dim)
62 return (_days_before_year(year) +
63 _days_before_month(year, month) +
64 day)
65
66_DI400Y = _days_before_year(401) # number of days in 400 years
67_DI100Y = _days_before_year(101) # " " " " 100 "
68_DI4Y = _days_before_year(5) # " " " " 4 "
69
70# A 4-year cycle has an extra leap day over what we'd get from pasting
71# together 4 single years.
72assert _DI4Y == 4 * 365 + 1
73
74# Similarly, a 400-year cycle has an extra leap day over what we'd get from
75# pasting together 4 100-year cycles.
76assert _DI400Y == 4 * _DI100Y + 1
77
78# OTOH, a 100-year cycle has one fewer leap day than we'd get from
79# pasting together 25 4-year cycles.
80assert _DI100Y == 25 * _DI4Y - 1
81
82def _ord2ymd(n):
83 "ordinal -> (year, month, day), considering 01-Jan-0001 as day 1."
84
85 # n is a 1-based index, starting at 1-Jan-1. The pattern of leap years
86 # repeats exactly every 400 years. The basic strategy is to find the
87 # closest 400-year boundary at or before n, then work with the offset
88 # from that boundary to n. Life is much clearer if we subtract 1 from
89 # n first -- then the values of n at 400-year boundaries are exactly
90 # those divisible by _DI400Y:
91 #
92 # D M Y n n-1
93 # -- --- ---- ---------- ----------------
94 # 31 Dec -400 -_DI400Y -_DI400Y -1
95 # 1 Jan -399 -_DI400Y +1 -_DI400Y 400-year boundary
96 # ...
97 # 30 Dec 000 -1 -2
98 # 31 Dec 000 0 -1
99 # 1 Jan 001 1 0 400-year boundary
100 # 2 Jan 001 2 1
101 # 3 Jan 001 3 2
102 # ...
103 # 31 Dec 400 _DI400Y _DI400Y -1
104 # 1 Jan 401 _DI400Y +1 _DI400Y 400-year boundary
105 n -= 1
106 n400, n = divmod(n, _DI400Y)
107 year = n400 * 400 + 1 # ..., -399, 1, 401, ...
108
109 # Now n is the (non-negative) offset, in days, from January 1 of year, to
110 # the desired date. Now compute how many 100-year cycles precede n.
111 # Note that it's possible for n100 to equal 4! In that case 4 full
112 # 100-year cycles precede the desired day, which implies the desired
113 # day is December 31 at the end of a 400-year cycle.
114 n100, n = divmod(n, _DI100Y)
115
116 # Now compute how many 4-year cycles precede it.
117 n4, n = divmod(n, _DI4Y)
118
119 # And now how many single years. Again n1 can be 4, and again meaning
120 # that the desired day is December 31 at the end of the 4-year cycle.
121 n1, n = divmod(n, 365)
122
123 year += n100 * 100 + n4 * 4 + n1
124 if n1 == 4 or n100 == 4:
125 assert n == 0
126 return year-1, 12, 31
127
128 # Now the year is correct, and n is the offset from January 1. We find
129 # the month via an estimate that's either exact or one too large.
130 leapyear = n1 == 3 and (n4 != 24 or n100 == 3)
131 assert leapyear == _is_leap(year)
132 month = (n + 50) >> 5
133 preceding = _DAYS_BEFORE_MONTH[month] + (month > 2 and leapyear)
134 if preceding > n: # estimate is too large
135 month -= 1
136 preceding -= _DAYS_IN_MONTH[month] + (month == 2 and leapyear)
137 n -= preceding
138 assert 0 <= n < _days_in_month(year, month)
139
140 # Now the year and month are correct, and n is the offset from the
141 # start of that month: we're done!
142 return year, month, n+1
143
144# Month and day names. For localized versions, see the calendar module.
145_MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
146 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
147_DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
148
149
150def _build_struct_time(y, m, d, hh, mm, ss, dstflag):
151 wday = (_ymd2ord(y, m, d) + 6) % 7
152 dnum = _days_before_month(y, m) + d
153 return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag))
154
Alexander Belopolskya2998a62016-03-06 14:58:43 -0500155def _format_time(hh, mm, ss, us, timespec='auto'):
156 specs = {
157 'hours': '{:02d}',
158 'minutes': '{:02d}:{:02d}',
159 'seconds': '{:02d}:{:02d}:{:02d}',
160 'milliseconds': '{:02d}:{:02d}:{:02d}.{:03d}',
161 'microseconds': '{:02d}:{:02d}:{:02d}.{:06d}'
162 }
163
164 if timespec == 'auto':
165 # Skip trailing microseconds when us==0.
166 timespec = 'microseconds' if us else 'seconds'
167 elif timespec == 'milliseconds':
168 us //= 1000
169 try:
170 fmt = specs[timespec]
171 except KeyError:
172 raise ValueError('Unknown timespec value')
173 else:
174 return fmt.format(hh, mm, ss, us)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000175
176# Correctly substitute for %z and %Z escapes in strftime formats.
177def _wrap_strftime(object, format, timetuple):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000178 # Don't call utcoffset() or tzname() unless actually needed.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400179 freplace = None # the string to use for %f
180 zreplace = None # the string to use for %z
181 Zreplace = None # the string to use for %Z
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000182
183 # Scan format for %z and %Z escapes, replacing as needed.
184 newformat = []
185 push = newformat.append
186 i, n = 0, len(format)
187 while i < n:
188 ch = format[i]
189 i += 1
190 if ch == '%':
191 if i < n:
192 ch = format[i]
193 i += 1
194 if ch == 'f':
195 if freplace is None:
196 freplace = '%06d' % getattr(object,
197 'microsecond', 0)
198 newformat.append(freplace)
199 elif ch == 'z':
200 if zreplace is None:
201 zreplace = ""
202 if hasattr(object, "utcoffset"):
203 offset = object.utcoffset()
204 if offset is not None:
205 sign = '+'
206 if offset.days < 0:
207 offset = -offset
208 sign = '-'
Alexander Belopolsky018d3532017-07-31 10:26:50 -0400209 h, rest = divmod(offset, timedelta(hours=1))
210 m, rest = divmod(rest, timedelta(minutes=1))
211 s = rest.seconds
212 u = offset.microseconds
213 if u:
214 zreplace = '%c%02d%02d%02d.%06d' % (sign, h, m, s, u)
215 elif s:
216 zreplace = '%c%02d%02d%02d' % (sign, h, m, s)
217 else:
218 zreplace = '%c%02d%02d' % (sign, h, m)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000219 assert '%' not in zreplace
220 newformat.append(zreplace)
221 elif ch == 'Z':
222 if Zreplace is None:
223 Zreplace = ""
224 if hasattr(object, "tzname"):
225 s = object.tzname()
226 if s is not None:
227 # strftime is going to have at this: escape %
228 Zreplace = s.replace('%', '%%')
229 newformat.append(Zreplace)
230 else:
231 push('%')
232 push(ch)
233 else:
234 push('%')
235 else:
236 push(ch)
237 newformat = "".join(newformat)
238 return _time.strftime(newformat, timetuple)
239
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000240# Just raise TypeError if the arg isn't None or a string.
241def _check_tzname(name):
242 if name is not None and not isinstance(name, str):
243 raise TypeError("tzinfo.tzname() must return None or string, "
244 "not '%s'" % type(name))
245
246# name is the offset-producing method, "utcoffset" or "dst".
247# offset is what it returned.
248# If offset isn't None or timedelta, raises TypeError.
249# If offset is None, returns None.
Alexander Belopolsky018d3532017-07-31 10:26:50 -0400250# Else offset is checked for being in range.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000251# If it is, its integer value is returned. Else ValueError is raised.
252def _check_utc_offset(name, offset):
253 assert name in ("utcoffset", "dst")
254 if offset is None:
255 return
256 if not isinstance(offset, timedelta):
257 raise TypeError("tzinfo.%s() must return None "
258 "or timedelta, not '%s'" % (name, type(offset)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000259 if not -timedelta(1) < offset < timedelta(1):
Martin Panterdd780e42016-05-30 04:08:23 +0000260 raise ValueError("%s()=%s, must be strictly between "
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400261 "-timedelta(hours=24) and timedelta(hours=24)" %
262 (name, offset))
263
264def _check_int_field(value):
265 if isinstance(value, int):
266 return value
267 if not isinstance(value, float):
268 try:
269 value = value.__int__()
270 except AttributeError:
271 pass
272 else:
273 if isinstance(value, int):
274 return value
275 raise TypeError('__int__ returned non-int (type %s)' %
276 type(value).__name__)
277 raise TypeError('an integer is required (got type %s)' %
278 type(value).__name__)
279 raise TypeError('integer argument expected, got float')
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000280
281def _check_date_fields(year, month, day):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400282 year = _check_int_field(year)
283 month = _check_int_field(month)
284 day = _check_int_field(day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000285 if not MINYEAR <= year <= MAXYEAR:
286 raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year)
287 if not 1 <= month <= 12:
288 raise ValueError('month must be in 1..12', month)
289 dim = _days_in_month(year, month)
290 if not 1 <= day <= dim:
291 raise ValueError('day must be in 1..%d' % dim, day)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400292 return year, month, day
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000293
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400294def _check_time_fields(hour, minute, second, microsecond, fold):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400295 hour = _check_int_field(hour)
296 minute = _check_int_field(minute)
297 second = _check_int_field(second)
298 microsecond = _check_int_field(microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000299 if not 0 <= hour <= 23:
300 raise ValueError('hour must be in 0..23', hour)
301 if not 0 <= minute <= 59:
302 raise ValueError('minute must be in 0..59', minute)
303 if not 0 <= second <= 59:
304 raise ValueError('second must be in 0..59', second)
305 if not 0 <= microsecond <= 999999:
306 raise ValueError('microsecond must be in 0..999999', microsecond)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400307 if fold not in (0, 1):
308 raise ValueError('fold must be either 0 or 1', fold)
309 return hour, minute, second, microsecond, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000310
311def _check_tzinfo_arg(tz):
312 if tz is not None and not isinstance(tz, tzinfo):
313 raise TypeError("tzinfo argument must be None or of a tzinfo subclass")
314
315def _cmperror(x, y):
316 raise TypeError("can't compare '%s' to '%s'" % (
317 type(x).__name__, type(y).__name__))
318
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500319def _divide_and_round(a, b):
320 """divide a by b and round result to the nearest integer
321
322 When the ratio is exactly half-way between two integers,
323 the even integer is returned.
324 """
325 # Based on the reference implementation for divmod_near
326 # in Objects/longobject.c.
327 q, r = divmod(a, b)
328 # round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
329 # The expression r / b > 0.5 is equivalent to 2 * r > b if b is
330 # positive, 2 * r < b if b negative.
331 r *= 2
332 greater_than_half = r > b if b > 0 else r < b
333 if greater_than_half or r == b and q % 2 == 1:
334 q += 1
335
336 return q
337
Victor Stinner2ec55872015-09-02 19:16:07 +0200338
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000339class timedelta:
340 """Represent the difference between two datetime objects.
341
342 Supported operators:
343
344 - add, subtract timedelta
345 - unary plus, minus, abs
346 - compare to timedelta
Serhiy Storchaka95949422013-08-27 19:40:23 +0300347 - multiply, divide by int
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000348
349 In addition, datetime supports subtraction of two datetime objects
350 returning a timedelta, and addition or subtraction of a datetime
351 and a timedelta giving a datetime.
352
353 Representation: (days, seconds, microseconds). Why? Because I
354 felt like it.
355 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400356 __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000357
358 def __new__(cls, days=0, seconds=0, microseconds=0,
359 milliseconds=0, minutes=0, hours=0, weeks=0):
360 # Doing this efficiently and accurately in C is going to be difficult
361 # and error-prone, due to ubiquitous overflow possibilities, and that
362 # C double doesn't have enough bits of precision to represent
363 # microseconds over 10K years faithfully. The code here tries to make
364 # explicit where go-fast assumptions can be relied on, in order to
365 # guide the C implementation; it's way more convoluted than speed-
366 # ignoring auto-overflow-to-long idiomatic Python could be.
367
368 # XXX Check that all inputs are ints or floats.
369
370 # Final values, all integer.
371 # s and us fit in 32-bit signed ints; d isn't bounded.
372 d = s = us = 0
373
374 # Normalize everything to days, seconds, microseconds.
375 days += weeks*7
376 seconds += minutes*60 + hours*3600
377 microseconds += milliseconds*1000
378
379 # Get rid of all fractions, and normalize s and us.
380 # Take a deep breath <wink>.
381 if isinstance(days, float):
382 dayfrac, days = _math.modf(days)
383 daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
384 assert daysecondswhole == int(daysecondswhole) # can't overflow
385 s = int(daysecondswhole)
386 assert days == int(days)
387 d = int(days)
388 else:
389 daysecondsfrac = 0.0
390 d = days
391 assert isinstance(daysecondsfrac, float)
392 assert abs(daysecondsfrac) <= 1.0
393 assert isinstance(d, int)
394 assert abs(s) <= 24 * 3600
395 # days isn't referenced again before redefinition
396
397 if isinstance(seconds, float):
398 secondsfrac, seconds = _math.modf(seconds)
399 assert seconds == int(seconds)
400 seconds = int(seconds)
401 secondsfrac += daysecondsfrac
402 assert abs(secondsfrac) <= 2.0
403 else:
404 secondsfrac = daysecondsfrac
405 # daysecondsfrac isn't referenced again
406 assert isinstance(secondsfrac, float)
407 assert abs(secondsfrac) <= 2.0
408
409 assert isinstance(seconds, int)
410 days, seconds = divmod(seconds, 24*3600)
411 d += days
412 s += int(seconds) # can't overflow
413 assert isinstance(s, int)
414 assert abs(s) <= 2 * 24 * 3600
415 # seconds isn't referenced again before redefinition
416
417 usdouble = secondsfrac * 1e6
418 assert abs(usdouble) < 2.1e6 # exact value not critical
419 # secondsfrac isn't referenced again
420
421 if isinstance(microseconds, float):
Victor Stinner69cc4872015-09-08 23:58:54 +0200422 microseconds = round(microseconds + usdouble)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000423 seconds, microseconds = divmod(microseconds, 1000000)
424 days, seconds = divmod(seconds, 24*3600)
425 d += days
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400426 s += seconds
427 else:
428 microseconds = int(microseconds)
429 seconds, microseconds = divmod(microseconds, 1000000)
430 days, seconds = divmod(seconds, 24*3600)
431 d += days
432 s += seconds
Victor Stinner69cc4872015-09-08 23:58:54 +0200433 microseconds = round(microseconds + usdouble)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400434 assert isinstance(s, int)
435 assert isinstance(microseconds, int)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000436 assert abs(s) <= 3 * 24 * 3600
437 assert abs(microseconds) < 3.1e6
438
439 # Just a little bit of carrying possible for microseconds and seconds.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400440 seconds, us = divmod(microseconds, 1000000)
441 s += seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000442 days, s = divmod(s, 24*3600)
443 d += days
444
445 assert isinstance(d, int)
446 assert isinstance(s, int) and 0 <= s < 24*3600
447 assert isinstance(us, int) and 0 <= us < 1000000
448
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000449 if abs(d) > 999999999:
450 raise OverflowError("timedelta # of days is too large: %d" % d)
451
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400452 self = object.__new__(cls)
453 self._days = d
454 self._seconds = s
455 self._microseconds = us
456 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000457 return self
458
459 def __repr__(self):
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200460 args = []
461 if self._days:
462 args.append("days=%d" % self._days)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000463 if self._seconds:
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200464 args.append("seconds=%d" % self._seconds)
465 if self._microseconds:
466 args.append("microseconds=%d" % self._microseconds)
467 if not args:
468 args.append('0')
469 return "%s.%s(%s)" % (self.__class__.__module__,
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300470 self.__class__.__qualname__,
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200471 ', '.join(args))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000472
473 def __str__(self):
474 mm, ss = divmod(self._seconds, 60)
475 hh, mm = divmod(mm, 60)
476 s = "%d:%02d:%02d" % (hh, mm, ss)
477 if self._days:
478 def plural(n):
479 return n, abs(n) != 1 and "s" or ""
480 s = ("%d day%s, " % plural(self._days)) + s
481 if self._microseconds:
482 s = s + ".%06d" % self._microseconds
483 return s
484
485 def total_seconds(self):
486 """Total seconds in the duration."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400487 return ((self.days * 86400 + self.seconds) * 10**6 +
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000488 self.microseconds) / 10**6
489
490 # Read-only field accessors
491 @property
492 def days(self):
493 """days"""
494 return self._days
495
496 @property
497 def seconds(self):
498 """seconds"""
499 return self._seconds
500
501 @property
502 def microseconds(self):
503 """microseconds"""
504 return self._microseconds
505
506 def __add__(self, other):
507 if isinstance(other, timedelta):
508 # for CPython compatibility, we cannot use
509 # our __class__ here, but need a real timedelta
510 return timedelta(self._days + other._days,
511 self._seconds + other._seconds,
512 self._microseconds + other._microseconds)
513 return NotImplemented
514
515 __radd__ = __add__
516
517 def __sub__(self, other):
518 if isinstance(other, timedelta):
Alexander Belopolskyb6f5ec72011-04-05 20:07:38 -0400519 # for CPython compatibility, we cannot use
520 # our __class__ here, but need a real timedelta
521 return timedelta(self._days - other._days,
522 self._seconds - other._seconds,
523 self._microseconds - other._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000524 return NotImplemented
525
526 def __rsub__(self, other):
527 if isinstance(other, timedelta):
528 return -self + other
529 return NotImplemented
530
531 def __neg__(self):
532 # for CPython compatibility, we cannot use
533 # our __class__ here, but need a real timedelta
534 return timedelta(-self._days,
535 -self._seconds,
536 -self._microseconds)
537
538 def __pos__(self):
539 return self
540
541 def __abs__(self):
542 if self._days < 0:
543 return -self
544 else:
545 return self
546
547 def __mul__(self, other):
548 if isinstance(other, int):
549 # for CPython compatibility, we cannot use
550 # our __class__ here, but need a real timedelta
551 return timedelta(self._days * other,
552 self._seconds * other,
553 self._microseconds * other)
554 if isinstance(other, float):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500555 usec = self._to_microseconds()
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000556 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500557 return timedelta(0, 0, _divide_and_round(usec * a, b))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000558 return NotImplemented
559
560 __rmul__ = __mul__
561
562 def _to_microseconds(self):
563 return ((self._days * (24*3600) + self._seconds) * 1000000 +
564 self._microseconds)
565
566 def __floordiv__(self, other):
567 if not isinstance(other, (int, timedelta)):
568 return NotImplemented
569 usec = self._to_microseconds()
570 if isinstance(other, timedelta):
571 return usec // other._to_microseconds()
572 if isinstance(other, int):
573 return timedelta(0, 0, usec // other)
574
575 def __truediv__(self, other):
576 if not isinstance(other, (int, float, timedelta)):
577 return NotImplemented
578 usec = self._to_microseconds()
579 if isinstance(other, timedelta):
580 return usec / other._to_microseconds()
581 if isinstance(other, int):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500582 return timedelta(0, 0, _divide_and_round(usec, other))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000583 if isinstance(other, float):
584 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500585 return timedelta(0, 0, _divide_and_round(b * usec, a))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000586
587 def __mod__(self, other):
588 if isinstance(other, timedelta):
589 r = self._to_microseconds() % other._to_microseconds()
590 return timedelta(0, 0, r)
591 return NotImplemented
592
593 def __divmod__(self, other):
594 if isinstance(other, timedelta):
595 q, r = divmod(self._to_microseconds(),
596 other._to_microseconds())
597 return q, timedelta(0, 0, r)
598 return NotImplemented
599
600 # Comparisons of timedelta objects with other.
601
602 def __eq__(self, other):
603 if isinstance(other, timedelta):
604 return self._cmp(other) == 0
605 else:
606 return False
607
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000608 def __le__(self, other):
609 if isinstance(other, timedelta):
610 return self._cmp(other) <= 0
611 else:
612 _cmperror(self, other)
613
614 def __lt__(self, other):
615 if isinstance(other, timedelta):
616 return self._cmp(other) < 0
617 else:
618 _cmperror(self, other)
619
620 def __ge__(self, other):
621 if isinstance(other, timedelta):
622 return self._cmp(other) >= 0
623 else:
624 _cmperror(self, other)
625
626 def __gt__(self, other):
627 if isinstance(other, timedelta):
628 return self._cmp(other) > 0
629 else:
630 _cmperror(self, other)
631
632 def _cmp(self, other):
633 assert isinstance(other, timedelta)
634 return _cmp(self._getstate(), other._getstate())
635
636 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400637 if self._hashcode == -1:
638 self._hashcode = hash(self._getstate())
639 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000640
641 def __bool__(self):
642 return (self._days != 0 or
643 self._seconds != 0 or
644 self._microseconds != 0)
645
646 # Pickle support.
647
648 def _getstate(self):
649 return (self._days, self._seconds, self._microseconds)
650
651 def __reduce__(self):
652 return (self.__class__, self._getstate())
653
654timedelta.min = timedelta(-999999999)
655timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
656 microseconds=999999)
657timedelta.resolution = timedelta(microseconds=1)
658
659class date:
660 """Concrete date type.
661
662 Constructors:
663
664 __new__()
665 fromtimestamp()
666 today()
667 fromordinal()
668
669 Operators:
670
671 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200672 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000673 __add__, __radd__, __sub__ (add/radd only with timedelta arg)
674
675 Methods:
676
677 timetuple()
678 toordinal()
679 weekday()
680 isoweekday(), isocalendar(), isoformat()
681 ctime()
682 strftime()
683
684 Properties (readonly):
685 year, month, day
686 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400687 __slots__ = '_year', '_month', '_day', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000688
689 def __new__(cls, year, month=None, day=None):
690 """Constructor.
691
692 Arguments:
693
694 year, month, day (required, base 1)
695 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400696 if month is None and isinstance(year, bytes) and len(year) == 4 and \
697 1 <= year[2] <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000698 # Pickle support
699 self = object.__new__(cls)
700 self.__setstate(year)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400701 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000702 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400703 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000704 self = object.__new__(cls)
705 self._year = year
706 self._month = month
707 self._day = day
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400708 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000709 return self
710
711 # Additional constructors
712
713 @classmethod
714 def fromtimestamp(cls, t):
715 "Construct a date from a POSIX timestamp (like time.time())."
716 y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
717 return cls(y, m, d)
718
719 @classmethod
720 def today(cls):
721 "Construct a date from time.time()."
722 t = _time.time()
723 return cls.fromtimestamp(t)
724
725 @classmethod
726 def fromordinal(cls, n):
Martin Pantereb995702016-07-28 01:11:04 +0000727 """Construct a date from a proleptic Gregorian ordinal.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000728
729 January 1 of year 1 is day 1. Only the year, month and day are
730 non-zero in the result.
731 """
732 y, m, d = _ord2ymd(n)
733 return cls(y, m, d)
734
735 # Conversions to string
736
737 def __repr__(self):
738 """Convert to formal string, for repr().
739
740 >>> dt = datetime(2010, 1, 1)
741 >>> repr(dt)
742 'datetime.datetime(2010, 1, 1, 0, 0)'
743
744 >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
745 >>> repr(dt)
746 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
747 """
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300748 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
749 self.__class__.__qualname__,
750 self._year,
751 self._month,
752 self._day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000753 # XXX These shouldn't depend on time.localtime(), because that
754 # clips the usable dates to [1970 .. 2038). At least ctime() is
755 # easily done without using strftime() -- that's better too because
756 # strftime("%c", ...) is locale specific.
757
758
759 def ctime(self):
760 "Return ctime() style string."
761 weekday = self.toordinal() % 7 or 7
762 return "%s %s %2d 00:00:00 %04d" % (
763 _DAYNAMES[weekday],
764 _MONTHNAMES[self._month],
765 self._day, self._year)
766
767 def strftime(self, fmt):
768 "Format using strftime()."
769 return _wrap_strftime(self, fmt, self.timetuple())
770
771 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400772 if not isinstance(fmt, str):
773 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000774 if len(fmt) != 0:
775 return self.strftime(fmt)
776 return str(self)
777
778 def isoformat(self):
779 """Return the date formatted according to ISO.
780
781 This is 'YYYY-MM-DD'.
782
783 References:
784 - http://www.w3.org/TR/NOTE-datetime
785 - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
786 """
787 return "%04d-%02d-%02d" % (self._year, self._month, self._day)
788
789 __str__ = isoformat
790
791 # Read-only field accessors
792 @property
793 def year(self):
794 """year (1-9999)"""
795 return self._year
796
797 @property
798 def month(self):
799 """month (1-12)"""
800 return self._month
801
802 @property
803 def day(self):
804 """day (1-31)"""
805 return self._day
806
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200807 # Standard conversions, __eq__, __le__, __lt__, __ge__, __gt__,
808 # __hash__ (and helpers)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000809
810 def timetuple(self):
811 "Return local time tuple compatible with time.localtime()."
812 return _build_struct_time(self._year, self._month, self._day,
813 0, 0, 0, -1)
814
815 def toordinal(self):
816 """Return proleptic Gregorian ordinal for the year, month and day.
817
818 January 1 of year 1 is day 1. Only the year, month and day values
819 contribute to the result.
820 """
821 return _ymd2ord(self._year, self._month, self._day)
822
823 def replace(self, year=None, month=None, day=None):
824 """Return a new date with new values for the specified fields."""
825 if year is None:
826 year = self._year
827 if month is None:
828 month = self._month
829 if day is None:
830 day = self._day
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000831 return date(year, month, day)
832
833 # Comparisons of date objects with other.
834
835 def __eq__(self, other):
836 if isinstance(other, date):
837 return self._cmp(other) == 0
838 return NotImplemented
839
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000840 def __le__(self, other):
841 if isinstance(other, date):
842 return self._cmp(other) <= 0
843 return NotImplemented
844
845 def __lt__(self, other):
846 if isinstance(other, date):
847 return self._cmp(other) < 0
848 return NotImplemented
849
850 def __ge__(self, other):
851 if isinstance(other, date):
852 return self._cmp(other) >= 0
853 return NotImplemented
854
855 def __gt__(self, other):
856 if isinstance(other, date):
857 return self._cmp(other) > 0
858 return NotImplemented
859
860 def _cmp(self, other):
861 assert isinstance(other, date)
862 y, m, d = self._year, self._month, self._day
863 y2, m2, d2 = other._year, other._month, other._day
864 return _cmp((y, m, d), (y2, m2, d2))
865
866 def __hash__(self):
867 "Hash."
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400868 if self._hashcode == -1:
869 self._hashcode = hash(self._getstate())
870 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000871
872 # Computations
873
874 def __add__(self, other):
875 "Add a date to a timedelta."
876 if isinstance(other, timedelta):
877 o = self.toordinal() + other.days
878 if 0 < o <= _MAXORDINAL:
879 return date.fromordinal(o)
880 raise OverflowError("result out of range")
881 return NotImplemented
882
883 __radd__ = __add__
884
885 def __sub__(self, other):
886 """Subtract two dates, or a date and a timedelta."""
887 if isinstance(other, timedelta):
888 return self + timedelta(-other.days)
889 if isinstance(other, date):
890 days1 = self.toordinal()
891 days2 = other.toordinal()
892 return timedelta(days1 - days2)
893 return NotImplemented
894
895 def weekday(self):
896 "Return day of the week, where Monday == 0 ... Sunday == 6."
897 return (self.toordinal() + 6) % 7
898
899 # Day-of-the-week and week-of-the-year, according to ISO
900
901 def isoweekday(self):
902 "Return day of the week, where Monday == 1 ... Sunday == 7."
903 # 1-Jan-0001 is a Monday
904 return self.toordinal() % 7 or 7
905
906 def isocalendar(self):
907 """Return a 3-tuple containing ISO year, week number, and weekday.
908
909 The first ISO week of the year is the (Mon-Sun) week
910 containing the year's first Thursday; everything else derives
911 from that.
912
913 The first week is 1; Monday is 1 ... Sunday is 7.
914
915 ISO calendar algorithm taken from
916 http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
Brett Cannon07b954d2016-01-15 09:53:51 -0800917 (used with permission)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000918 """
919 year = self._year
920 week1monday = _isoweek1monday(year)
921 today = _ymd2ord(self._year, self._month, self._day)
922 # Internally, week and day have origin 0
923 week, day = divmod(today - week1monday, 7)
924 if week < 0:
925 year -= 1
926 week1monday = _isoweek1monday(year)
927 week, day = divmod(today - week1monday, 7)
928 elif week >= 52:
929 if today >= _isoweek1monday(year+1):
930 year += 1
931 week = 0
932 return year, week+1, day+1
933
934 # Pickle support.
935
Serhiy Storchaka546ce652016-11-22 00:29:42 +0200936 def _getstate(self):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000937 yhi, ylo = divmod(self._year, 256)
938 return bytes([yhi, ylo, self._month, self._day]),
939
940 def __setstate(self, string):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000941 yhi, ylo, self._month, self._day = string
942 self._year = yhi * 256 + ylo
943
Serhiy Storchaka546ce652016-11-22 00:29:42 +0200944 def __reduce__(self):
945 return (self.__class__, self._getstate())
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000946
947_date_class = date # so functions w/ args named "date" can get at the class
948
949date.min = date(1, 1, 1)
950date.max = date(9999, 12, 31)
951date.resolution = timedelta(days=1)
952
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -0400953
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000954class tzinfo:
955 """Abstract base class for time zone info classes.
956
957 Subclasses must override the name(), utcoffset() and dst() methods.
958 """
959 __slots__ = ()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400960
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000961 def tzname(self, dt):
962 "datetime -> string name of time zone."
963 raise NotImplementedError("tzinfo subclass must override tzname()")
964
965 def utcoffset(self, dt):
Alexander Belopolsky018d3532017-07-31 10:26:50 -0400966 "datetime -> timedelta, positive for east of UTC, negative for west of UTC"
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000967 raise NotImplementedError("tzinfo subclass must override utcoffset()")
968
969 def dst(self, dt):
Alexander Belopolsky018d3532017-07-31 10:26:50 -0400970 """datetime -> DST offset as timedelta, positive for east of UTC.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000971
972 Return 0 if DST not in effect. utcoffset() must include the DST
973 offset.
974 """
975 raise NotImplementedError("tzinfo subclass must override dst()")
976
977 def fromutc(self, dt):
978 "datetime in UTC -> datetime in local time."
979
980 if not isinstance(dt, datetime):
981 raise TypeError("fromutc() requires a datetime argument")
982 if dt.tzinfo is not self:
983 raise ValueError("dt.tzinfo is not self")
984
985 dtoff = dt.utcoffset()
986 if dtoff is None:
987 raise ValueError("fromutc() requires a non-None utcoffset() "
988 "result")
989
990 # See the long comment block at the end of this file for an
991 # explanation of this algorithm.
992 dtdst = dt.dst()
993 if dtdst is None:
994 raise ValueError("fromutc() requires a non-None dst() result")
995 delta = dtoff - dtdst
996 if delta:
997 dt += delta
998 dtdst = dt.dst()
999 if dtdst is None:
1000 raise ValueError("fromutc(): dt.dst gave inconsistent "
1001 "results; cannot convert")
1002 return dt + dtdst
1003
1004 # Pickle support.
1005
1006 def __reduce__(self):
1007 getinitargs = getattr(self, "__getinitargs__", None)
1008 if getinitargs:
1009 args = getinitargs()
1010 else:
1011 args = ()
1012 getstate = getattr(self, "__getstate__", None)
1013 if getstate:
1014 state = getstate()
1015 else:
1016 state = getattr(self, "__dict__", None) or None
1017 if state is None:
1018 return (self.__class__, args)
1019 else:
1020 return (self.__class__, args, state)
1021
1022_tzinfo_class = tzinfo
1023
1024class time:
1025 """Time with time zone.
1026
1027 Constructors:
1028
1029 __new__()
1030
1031 Operators:
1032
1033 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +02001034 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001035
1036 Methods:
1037
1038 strftime()
1039 isoformat()
1040 utcoffset()
1041 tzname()
1042 dst()
1043
1044 Properties (readonly):
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001045 hour, minute, second, microsecond, tzinfo, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001046 """
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001047 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode', '_fold'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001048
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001049 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001050 """Constructor.
1051
1052 Arguments:
1053
1054 hour, minute (required)
1055 second, microsecond (default to zero)
1056 tzinfo (default to None)
Victor Stinner51b90d22017-01-04 12:01:16 +01001057 fold (keyword only, default to zero)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001058 """
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001059 if isinstance(hour, bytes) and len(hour) == 6 and hour[0]&0x7F < 24:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001060 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001061 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001062 self.__setstate(hour, minute or None)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001063 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001064 return self
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001065 hour, minute, second, microsecond, fold = _check_time_fields(
1066 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001067 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001068 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001069 self._hour = hour
1070 self._minute = minute
1071 self._second = second
1072 self._microsecond = microsecond
1073 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001074 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001075 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001076 return self
1077
1078 # Read-only field accessors
1079 @property
1080 def hour(self):
1081 """hour (0-23)"""
1082 return self._hour
1083
1084 @property
1085 def minute(self):
1086 """minute (0-59)"""
1087 return self._minute
1088
1089 @property
1090 def second(self):
1091 """second (0-59)"""
1092 return self._second
1093
1094 @property
1095 def microsecond(self):
1096 """microsecond (0-999999)"""
1097 return self._microsecond
1098
1099 @property
1100 def tzinfo(self):
1101 """timezone info object"""
1102 return self._tzinfo
1103
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001104 @property
1105 def fold(self):
1106 return self._fold
1107
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001108 # Standard conversions, __hash__ (and helpers)
1109
1110 # Comparisons of time objects with other.
1111
1112 def __eq__(self, other):
1113 if isinstance(other, time):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001114 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001115 else:
1116 return False
1117
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001118 def __le__(self, other):
1119 if isinstance(other, time):
1120 return self._cmp(other) <= 0
1121 else:
1122 _cmperror(self, other)
1123
1124 def __lt__(self, other):
1125 if isinstance(other, time):
1126 return self._cmp(other) < 0
1127 else:
1128 _cmperror(self, other)
1129
1130 def __ge__(self, other):
1131 if isinstance(other, time):
1132 return self._cmp(other) >= 0
1133 else:
1134 _cmperror(self, other)
1135
1136 def __gt__(self, other):
1137 if isinstance(other, time):
1138 return self._cmp(other) > 0
1139 else:
1140 _cmperror(self, other)
1141
Alexander Belopolsky08313822012-06-15 20:19:47 -04001142 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001143 assert isinstance(other, time)
1144 mytz = self._tzinfo
1145 ottz = other._tzinfo
1146 myoff = otoff = None
1147
1148 if mytz is ottz:
1149 base_compare = True
1150 else:
1151 myoff = self.utcoffset()
1152 otoff = other.utcoffset()
1153 base_compare = myoff == otoff
1154
1155 if base_compare:
1156 return _cmp((self._hour, self._minute, self._second,
1157 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001158 (other._hour, other._minute, other._second,
1159 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001160 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001161 if allow_mixed:
1162 return 2 # arbitrary non-zero value
1163 else:
1164 raise TypeError("cannot compare naive and aware times")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001165 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1166 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1167 return _cmp((myhhmm, self._second, self._microsecond),
1168 (othhmm, other._second, other._microsecond))
1169
1170 def __hash__(self):
1171 """Hash."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001172 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001173 if self.fold:
1174 t = self.replace(fold=0)
1175 else:
1176 t = self
1177 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001178 if not tzoff: # zero or None
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001179 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001180 else:
1181 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1182 timedelta(hours=1))
1183 assert not m % timedelta(minutes=1), "whole minute"
1184 m //= timedelta(minutes=1)
1185 if 0 <= h < 24:
1186 self._hashcode = hash(time(h, m, self.second, self.microsecond))
1187 else:
1188 self._hashcode = hash((h, m, self.second, self.microsecond))
1189 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001190
1191 # Conversion to string
1192
1193 def _tzstr(self, sep=":"):
1194 """Return formatted timezone offset (+xx:xx) or None."""
1195 off = self.utcoffset()
1196 if off is not None:
1197 if off.days < 0:
1198 sign = "-"
1199 off = -off
1200 else:
1201 sign = "+"
1202 hh, mm = divmod(off, timedelta(hours=1))
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001203 mm, ss = divmod(mm, timedelta(minutes=1))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001204 assert 0 <= hh < 24
1205 off = "%s%02d%s%02d" % (sign, hh, sep, mm)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001206 if ss:
1207 off += ':%02d' % ss.seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001208 return off
1209
1210 def __repr__(self):
1211 """Convert to formal string, for repr()."""
1212 if self._microsecond != 0:
1213 s = ", %d, %d" % (self._second, self._microsecond)
1214 elif self._second != 0:
1215 s = ", %d" % self._second
1216 else:
1217 s = ""
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001218 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1219 self.__class__.__qualname__,
1220 self._hour, self._minute, s)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001221 if self._tzinfo is not None:
1222 assert s[-1:] == ")"
1223 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001224 if self._fold:
1225 assert s[-1:] == ")"
1226 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001227 return s
1228
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001229 def isoformat(self, timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001230 """Return the time formatted according to ISO.
1231
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001232 The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional
1233 part is omitted if self.microsecond == 0.
1234
1235 The optional argument timespec specifies the number of additional
1236 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001237 """
1238 s = _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001239 self._microsecond, timespec)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001240 tz = self._tzstr()
1241 if tz:
1242 s += tz
1243 return s
1244
1245 __str__ = isoformat
1246
1247 def strftime(self, fmt):
1248 """Format using strftime(). The date part of the timestamp passed
1249 to underlying strftime should not be used.
1250 """
Alexander Belopolskyb8bb4662011-01-08 00:13:34 +00001251 # The year must be >= 1000 else Python's strftime implementation
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001252 # can raise a bogus exception.
1253 timetuple = (1900, 1, 1,
1254 self._hour, self._minute, self._second,
1255 0, 1, -1)
1256 return _wrap_strftime(self, fmt, timetuple)
1257
1258 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001259 if not isinstance(fmt, str):
1260 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001261 if len(fmt) != 0:
1262 return self.strftime(fmt)
1263 return str(self)
1264
1265 # Timezone functions
1266
1267 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001268 """Return the timezone offset as timedelta, positive east of UTC
1269 (negative west of UTC)."""
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001270 if self._tzinfo is None:
1271 return None
1272 offset = self._tzinfo.utcoffset(None)
1273 _check_utc_offset("utcoffset", offset)
1274 return offset
1275
1276 def tzname(self):
1277 """Return the timezone name.
1278
1279 Note that the name is 100% informational -- there's no requirement that
1280 it mean anything in particular. For example, "GMT", "UTC", "-500",
1281 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1282 """
1283 if self._tzinfo is None:
1284 return None
1285 name = self._tzinfo.tzname(None)
1286 _check_tzname(name)
1287 return name
1288
1289 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001290 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1291 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001292
1293 This is purely informational; the DST offset has already been added to
1294 the UTC offset returned by utcoffset() if applicable, so there's no
1295 need to consult dst() unless you're interested in displaying the DST
1296 info.
1297 """
1298 if self._tzinfo is None:
1299 return None
1300 offset = self._tzinfo.dst(None)
1301 _check_utc_offset("dst", offset)
1302 return offset
1303
1304 def replace(self, hour=None, minute=None, second=None, microsecond=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001305 tzinfo=True, *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001306 """Return a new time with new values for the specified fields."""
1307 if hour is None:
1308 hour = self.hour
1309 if minute is None:
1310 minute = self.minute
1311 if second is None:
1312 second = self.second
1313 if microsecond is None:
1314 microsecond = self.microsecond
1315 if tzinfo is True:
1316 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001317 if fold is None:
1318 fold = self._fold
1319 return time(hour, minute, second, microsecond, tzinfo, fold=fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001320
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001321 # Pickle support.
1322
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001323 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001324 us2, us3 = divmod(self._microsecond, 256)
1325 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001326 h = self._hour
1327 if self._fold and protocol > 3:
1328 h += 128
1329 basestate = bytes([h, self._minute, self._second,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001330 us1, us2, us3])
1331 if self._tzinfo is None:
1332 return (basestate,)
1333 else:
1334 return (basestate, self._tzinfo)
1335
1336 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001337 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1338 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001339 h, self._minute, self._second, us1, us2, us3 = string
1340 if h > 127:
1341 self._fold = 1
1342 self._hour = h - 128
1343 else:
1344 self._fold = 0
1345 self._hour = h
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001346 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001347 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001348
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001349 def __reduce_ex__(self, protocol):
1350 return (time, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001351
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001352 def __reduce__(self):
1353 return self.__reduce_ex__(2)
1354
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001355_time_class = time # so functions w/ args named "time" can get at the class
1356
1357time.min = time(0, 0, 0)
1358time.max = time(23, 59, 59, 999999)
1359time.resolution = timedelta(microseconds=1)
1360
1361class datetime(date):
1362 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1363
1364 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001365 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001366 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001367 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001368
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001369 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001370 microsecond=0, tzinfo=None, *, fold=0):
1371 if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2]&0x7F <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001372 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001373 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001374 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001375 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001376 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001377 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001378 hour, minute, second, microsecond, fold = _check_time_fields(
1379 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001380 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001381 self = object.__new__(cls)
1382 self._year = year
1383 self._month = month
1384 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001385 self._hour = hour
1386 self._minute = minute
1387 self._second = second
1388 self._microsecond = microsecond
1389 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001390 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001391 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001392 return self
1393
1394 # Read-only field accessors
1395 @property
1396 def hour(self):
1397 """hour (0-23)"""
1398 return self._hour
1399
1400 @property
1401 def minute(self):
1402 """minute (0-59)"""
1403 return self._minute
1404
1405 @property
1406 def second(self):
1407 """second (0-59)"""
1408 return self._second
1409
1410 @property
1411 def microsecond(self):
1412 """microsecond (0-999999)"""
1413 return self._microsecond
1414
1415 @property
1416 def tzinfo(self):
1417 """timezone info object"""
1418 return self._tzinfo
1419
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001420 @property
1421 def fold(self):
1422 return self._fold
1423
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001424 @classmethod
Victor Stinneradfefa52015-09-04 23:57:25 +02001425 def _fromtimestamp(cls, t, utc, tz):
1426 """Construct a datetime from a POSIX timestamp (like time.time()).
1427
1428 A timezone info object may be passed in as well.
1429 """
1430 frac, t = _math.modf(t)
Victor Stinner7667f582015-09-09 01:02:23 +02001431 us = round(frac * 1e6)
Victor Stinneradfefa52015-09-04 23:57:25 +02001432 if us >= 1000000:
1433 t += 1
1434 us -= 1000000
1435 elif us < 0:
1436 t -= 1
1437 us += 1000000
1438
1439 converter = _time.gmtime if utc else _time.localtime
1440 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1441 ss = min(ss, 59) # clamp out leap seconds if the platform has them
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001442 result = cls(y, m, d, hh, mm, ss, us, tz)
1443 if tz is None:
1444 # As of version 2015f max fold in IANA database is
1445 # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
1446 # Let's probe 24 hours in the past to detect a transition:
1447 max_fold_seconds = 24 * 3600
1448 y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1449 probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1450 trans = result - probe1 - timedelta(0, max_fold_seconds)
1451 if trans.days < 0:
1452 y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
1453 probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1454 if probe2 == result:
1455 result._fold = 1
1456 else:
1457 result = tz.fromutc(result)
1458 return result
Victor Stinneradfefa52015-09-04 23:57:25 +02001459
1460 @classmethod
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001461 def fromtimestamp(cls, t, tz=None):
1462 """Construct a datetime from a POSIX timestamp (like time.time()).
1463
1464 A timezone info object may be passed in as well.
1465 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001466 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001467
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001468 return cls._fromtimestamp(t, tz is not None, tz)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001469
1470 @classmethod
1471 def utcfromtimestamp(cls, t):
Alexander Belopolskye2e178e2015-03-01 14:52:07 -05001472 """Construct a naive UTC datetime from a POSIX timestamp."""
Victor Stinneradfefa52015-09-04 23:57:25 +02001473 return cls._fromtimestamp(t, True, None)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001474
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001475 @classmethod
1476 def now(cls, tz=None):
1477 "Construct a datetime from time.time() and optional time zone info."
1478 t = _time.time()
1479 return cls.fromtimestamp(t, tz)
1480
1481 @classmethod
1482 def utcnow(cls):
1483 "Construct a UTC datetime from time.time()."
1484 t = _time.time()
1485 return cls.utcfromtimestamp(t)
1486
1487 @classmethod
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001488 def combine(cls, date, time, tzinfo=True):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001489 "Construct a datetime from a given date and a given time."
1490 if not isinstance(date, _date_class):
1491 raise TypeError("date argument must be a date instance")
1492 if not isinstance(time, _time_class):
1493 raise TypeError("time argument must be a time instance")
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001494 if tzinfo is True:
1495 tzinfo = time.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001496 return cls(date.year, date.month, date.day,
1497 time.hour, time.minute, time.second, time.microsecond,
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001498 tzinfo, fold=time.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001499
1500 def timetuple(self):
1501 "Return local time tuple compatible with time.localtime()."
1502 dst = self.dst()
1503 if dst is None:
1504 dst = -1
1505 elif dst:
1506 dst = 1
1507 else:
1508 dst = 0
1509 return _build_struct_time(self.year, self.month, self.day,
1510 self.hour, self.minute, self.second,
1511 dst)
1512
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001513 def _mktime(self):
1514 """Return integer POSIX timestamp."""
1515 epoch = datetime(1970, 1, 1)
1516 max_fold_seconds = 24 * 3600
1517 t = (self - epoch) // timedelta(0, 1)
1518 def local(u):
1519 y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1520 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1521
1522 # Our goal is to solve t = local(u) for u.
1523 a = local(t) - t
1524 u1 = t - a
1525 t1 = local(u1)
1526 if t1 == t:
1527 # We found one solution, but it may not be the one we need.
1528 # Look for an earlier solution (if `fold` is 0), or a
1529 # later one (if `fold` is 1).
1530 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1531 b = local(u2) - u2
1532 if a == b:
1533 return u1
1534 else:
1535 b = t1 - u1
1536 assert a != b
1537 u2 = t - b
1538 t2 = local(u2)
1539 if t2 == t:
1540 return u2
1541 if t1 == t:
1542 return u1
1543 # We have found both offsets a and b, but neither t - a nor t - b is
1544 # a solution. This means t is in the gap.
1545 return (max, min)[self.fold](u1, u2)
1546
1547
Alexander Belopolskya4415142012-06-08 12:33:09 -04001548 def timestamp(self):
1549 "Return POSIX timestamp as float"
1550 if self._tzinfo is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001551 s = self._mktime()
1552 return s + self.microsecond / 1e6
Alexander Belopolskya4415142012-06-08 12:33:09 -04001553 else:
1554 return (self - _EPOCH).total_seconds()
1555
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001556 def utctimetuple(self):
1557 "Return UTC time tuple compatible with time.gmtime()."
1558 offset = self.utcoffset()
1559 if offset:
1560 self -= offset
1561 y, m, d = self.year, self.month, self.day
1562 hh, mm, ss = self.hour, self.minute, self.second
1563 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1564
1565 def date(self):
1566 "Return the date part."
1567 return date(self._year, self._month, self._day)
1568
1569 def time(self):
1570 "Return the time part, with tzinfo None."
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001571 return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001572
1573 def timetz(self):
1574 "Return the time part, with same tzinfo."
1575 return time(self.hour, self.minute, self.second, self.microsecond,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001576 self._tzinfo, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001577
1578 def replace(self, year=None, month=None, day=None, hour=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001579 minute=None, second=None, microsecond=None, tzinfo=True,
1580 *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001581 """Return a new datetime with new values for the specified fields."""
1582 if year is None:
1583 year = self.year
1584 if month is None:
1585 month = self.month
1586 if day is None:
1587 day = self.day
1588 if hour is None:
1589 hour = self.hour
1590 if minute is None:
1591 minute = self.minute
1592 if second is None:
1593 second = self.second
1594 if microsecond is None:
1595 microsecond = self.microsecond
1596 if tzinfo is True:
1597 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001598 if fold is None:
1599 fold = self.fold
1600 return datetime(year, month, day, hour, minute, second,
1601 microsecond, tzinfo, fold=fold)
1602
1603 def _local_timezone(self):
1604 if self.tzinfo is None:
1605 ts = self._mktime()
1606 else:
1607 ts = (self - _EPOCH) // timedelta(seconds=1)
1608 localtm = _time.localtime(ts)
1609 local = datetime(*localtm[:6])
1610 try:
1611 # Extract TZ data if available
1612 gmtoff = localtm.tm_gmtoff
1613 zone = localtm.tm_zone
1614 except AttributeError:
1615 delta = local - datetime(*_time.gmtime(ts)[:6])
1616 zone = _time.strftime('%Z', localtm)
1617 tz = timezone(delta, zone)
1618 else:
1619 tz = timezone(timedelta(seconds=gmtoff), zone)
1620 return tz
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001621
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001622 def astimezone(self, tz=None):
1623 if tz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001624 tz = self._local_timezone()
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001625 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001626 raise TypeError("tz argument must be an instance of tzinfo")
1627
1628 mytz = self.tzinfo
1629 if mytz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001630 mytz = self._local_timezone()
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001631
1632 if tz is mytz:
1633 return self
1634
1635 # Convert self to UTC, and attach the new time zone object.
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001636 myoffset = mytz.utcoffset(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001637 if myoffset is None:
1638 raise ValueError("astimezone() requires an aware datetime")
1639 utc = (self - myoffset).replace(tzinfo=tz)
1640
1641 # Convert from UTC to tz's local time.
1642 return tz.fromutc(utc)
1643
1644 # Ways to produce a string.
1645
1646 def ctime(self):
1647 "Return ctime() style string."
1648 weekday = self.toordinal() % 7 or 7
1649 return "%s %s %2d %02d:%02d:%02d %04d" % (
1650 _DAYNAMES[weekday],
1651 _MONTHNAMES[self._month],
1652 self._day,
1653 self._hour, self._minute, self._second,
1654 self._year)
1655
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001656 def isoformat(self, sep='T', timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001657 """Return the time formatted according to ISO.
1658
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001659 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1660 By default, the fractional part is omitted if self.microsecond == 0.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001661
1662 If self.tzinfo is not None, the UTC offset is also attached, giving
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001663 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001664
1665 Optional argument sep specifies the separator between date and
1666 time, default 'T'.
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001667
1668 The optional argument timespec specifies the number of additional
1669 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001670 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001671 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1672 _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001673 self._microsecond, timespec))
1674
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001675 off = self.utcoffset()
1676 if off is not None:
1677 if off.days < 0:
1678 sign = "-"
1679 off = -off
1680 else:
1681 sign = "+"
1682 hh, mm = divmod(off, timedelta(hours=1))
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001683 mm, ss = divmod(mm, timedelta(minutes=1))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001684 s += "%s%02d:%02d" % (sign, hh, mm)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001685 if ss:
1686 assert not ss.microseconds
1687 s += ":%02d" % ss.seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001688 return s
1689
1690 def __repr__(self):
1691 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001692 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001693 self._hour, self._minute, self._second, self._microsecond]
1694 if L[-1] == 0:
1695 del L[-1]
1696 if L[-1] == 0:
1697 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001698 s = "%s.%s(%s)" % (self.__class__.__module__,
1699 self.__class__.__qualname__,
1700 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001701 if self._tzinfo is not None:
1702 assert s[-1:] == ")"
1703 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001704 if self._fold:
1705 assert s[-1:] == ")"
1706 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001707 return s
1708
1709 def __str__(self):
1710 "Convert to string, for str()."
1711 return self.isoformat(sep=' ')
1712
1713 @classmethod
1714 def strptime(cls, date_string, format):
1715 'string, format -> new datetime parsed from a string (like time.strptime()).'
1716 import _strptime
1717 return _strptime._strptime_datetime(cls, date_string, format)
1718
1719 def utcoffset(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001720 """Return the timezone offset as timedelta positive east of UTC (negative west of
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001721 UTC)."""
1722 if self._tzinfo is None:
1723 return None
1724 offset = self._tzinfo.utcoffset(self)
1725 _check_utc_offset("utcoffset", offset)
1726 return offset
1727
1728 def tzname(self):
1729 """Return the timezone name.
1730
1731 Note that the name is 100% informational -- there's no requirement that
1732 it mean anything in particular. For example, "GMT", "UTC", "-500",
1733 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1734 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001735 if self._tzinfo is None:
1736 return None
1737 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001738 _check_tzname(name)
1739 return name
1740
1741 def dst(self):
Alexander Belopolsky018d3532017-07-31 10:26:50 -04001742 """Return 0 if DST is not in effect, or the DST offset (as timedelta
1743 positive eastward) if DST is in effect.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001744
1745 This is purely informational; the DST offset has already been added to
1746 the UTC offset returned by utcoffset() if applicable, so there's no
1747 need to consult dst() unless you're interested in displaying the DST
1748 info.
1749 """
1750 if self._tzinfo is None:
1751 return None
1752 offset = self._tzinfo.dst(self)
1753 _check_utc_offset("dst", offset)
1754 return offset
1755
1756 # Comparisons of datetime objects with other.
1757
1758 def __eq__(self, other):
1759 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001760 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001761 elif not isinstance(other, date):
1762 return NotImplemented
1763 else:
1764 return False
1765
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001766 def __le__(self, other):
1767 if isinstance(other, datetime):
1768 return self._cmp(other) <= 0
1769 elif not isinstance(other, date):
1770 return NotImplemented
1771 else:
1772 _cmperror(self, other)
1773
1774 def __lt__(self, other):
1775 if isinstance(other, datetime):
1776 return self._cmp(other) < 0
1777 elif not isinstance(other, date):
1778 return NotImplemented
1779 else:
1780 _cmperror(self, other)
1781
1782 def __ge__(self, other):
1783 if isinstance(other, datetime):
1784 return self._cmp(other) >= 0
1785 elif not isinstance(other, date):
1786 return NotImplemented
1787 else:
1788 _cmperror(self, other)
1789
1790 def __gt__(self, other):
1791 if isinstance(other, datetime):
1792 return self._cmp(other) > 0
1793 elif not isinstance(other, date):
1794 return NotImplemented
1795 else:
1796 _cmperror(self, other)
1797
Alexander Belopolsky08313822012-06-15 20:19:47 -04001798 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001799 assert isinstance(other, datetime)
1800 mytz = self._tzinfo
1801 ottz = other._tzinfo
1802 myoff = otoff = None
1803
1804 if mytz is ottz:
1805 base_compare = True
1806 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04001807 myoff = self.utcoffset()
1808 otoff = other.utcoffset()
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001809 # Assume that allow_mixed means that we are called from __eq__
1810 if allow_mixed:
1811 if myoff != self.replace(fold=not self.fold).utcoffset():
1812 return 2
1813 if otoff != other.replace(fold=not other.fold).utcoffset():
1814 return 2
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001815 base_compare = myoff == otoff
1816
1817 if base_compare:
1818 return _cmp((self._year, self._month, self._day,
1819 self._hour, self._minute, self._second,
1820 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001821 (other._year, other._month, other._day,
1822 other._hour, other._minute, other._second,
1823 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001824 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001825 if allow_mixed:
1826 return 2 # arbitrary non-zero value
1827 else:
1828 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001829 # XXX What follows could be done more efficiently...
1830 diff = self - other # this will take offsets into account
1831 if diff.days < 0:
1832 return -1
1833 return diff and 1 or 0
1834
1835 def __add__(self, other):
1836 "Add a datetime and a timedelta."
1837 if not isinstance(other, timedelta):
1838 return NotImplemented
1839 delta = timedelta(self.toordinal(),
1840 hours=self._hour,
1841 minutes=self._minute,
1842 seconds=self._second,
1843 microseconds=self._microsecond)
1844 delta += other
1845 hour, rem = divmod(delta.seconds, 3600)
1846 minute, second = divmod(rem, 60)
1847 if 0 < delta.days <= _MAXORDINAL:
1848 return datetime.combine(date.fromordinal(delta.days),
1849 time(hour, minute, second,
1850 delta.microseconds,
1851 tzinfo=self._tzinfo))
1852 raise OverflowError("result out of range")
1853
1854 __radd__ = __add__
1855
1856 def __sub__(self, other):
1857 "Subtract two datetimes, or a datetime and a timedelta."
1858 if not isinstance(other, datetime):
1859 if isinstance(other, timedelta):
1860 return self + -other
1861 return NotImplemented
1862
1863 days1 = self.toordinal()
1864 days2 = other.toordinal()
1865 secs1 = self._second + self._minute * 60 + self._hour * 3600
1866 secs2 = other._second + other._minute * 60 + other._hour * 3600
1867 base = timedelta(days1 - days2,
1868 secs1 - secs2,
1869 self._microsecond - other._microsecond)
1870 if self._tzinfo is other._tzinfo:
1871 return base
1872 myoff = self.utcoffset()
1873 otoff = other.utcoffset()
1874 if myoff == otoff:
1875 return base
1876 if myoff is None or otoff is None:
1877 raise TypeError("cannot mix naive and timezone-aware time")
1878 return base + otoff - myoff
1879
1880 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001881 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001882 if self.fold:
1883 t = self.replace(fold=0)
1884 else:
1885 t = self
1886 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001887 if tzoff is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001888 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001889 else:
1890 days = _ymd2ord(self.year, self.month, self.day)
1891 seconds = self.hour * 3600 + self.minute * 60 + self.second
1892 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
1893 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001894
1895 # Pickle support.
1896
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001897 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001898 yhi, ylo = divmod(self._year, 256)
1899 us2, us3 = divmod(self._microsecond, 256)
1900 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001901 m = self._month
1902 if self._fold and protocol > 3:
1903 m += 128
1904 basestate = bytes([yhi, ylo, m, self._day,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001905 self._hour, self._minute, self._second,
1906 us1, us2, us3])
1907 if self._tzinfo is None:
1908 return (basestate,)
1909 else:
1910 return (basestate, self._tzinfo)
1911
1912 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001913 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1914 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001915 (yhi, ylo, m, self._day, self._hour,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001916 self._minute, self._second, us1, us2, us3) = string
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001917 if m > 127:
1918 self._fold = 1
1919 self._month = m - 128
1920 else:
1921 self._fold = 0
1922 self._month = m
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001923 self._year = yhi * 256 + ylo
1924 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001925 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001926
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001927 def __reduce_ex__(self, protocol):
1928 return (self.__class__, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001929
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001930 def __reduce__(self):
1931 return self.__reduce_ex__(2)
1932
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001933
1934datetime.min = datetime(1, 1, 1)
1935datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1936datetime.resolution = timedelta(microseconds=1)
1937
1938
1939def _isoweek1monday(year):
1940 # Helper to calculate the day number of the Monday starting week 1
1941 # XXX This could be done more efficiently
1942 THURSDAY = 3
1943 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001944 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001945 week1monday = firstday - firstweekday
1946 if firstweekday > THURSDAY:
1947 week1monday += 7
1948 return week1monday
1949
1950class timezone(tzinfo):
1951 __slots__ = '_offset', '_name'
1952
1953 # Sentinel value to disallow None
1954 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001955 def __new__(cls, offset, name=_Omitted):
1956 if not isinstance(offset, timedelta):
1957 raise TypeError("offset must be a timedelta")
1958 if name is cls._Omitted:
1959 if not offset:
1960 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001961 name = None
1962 elif not isinstance(name, str):
1963 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001964 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001965 raise ValueError("offset must be a timedelta "
1966 "strictly between -timedelta(hours=24) and "
1967 "timedelta(hours=24).")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001968 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001969
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001970 @classmethod
1971 def _create(cls, offset, name=None):
1972 self = tzinfo.__new__(cls)
1973 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001974 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001975 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001976
1977 def __getinitargs__(self):
1978 """pickle support"""
1979 if self._name is None:
1980 return (self._offset,)
1981 return (self._offset, self._name)
1982
1983 def __eq__(self, other):
Georg Brandl0085a242012-09-22 09:23:12 +02001984 if type(other) != timezone:
1985 return False
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001986 return self._offset == other._offset
1987
1988 def __hash__(self):
1989 return hash(self._offset)
1990
1991 def __repr__(self):
1992 """Convert to formal string, for repr().
1993
1994 >>> tz = timezone.utc
1995 >>> repr(tz)
1996 'datetime.timezone.utc'
1997 >>> tz = timezone(timedelta(hours=-5), 'EST')
1998 >>> repr(tz)
1999 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
2000 """
2001 if self is self.utc:
2002 return 'datetime.timezone.utc'
2003 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03002004 return "%s.%s(%r)" % (self.__class__.__module__,
2005 self.__class__.__qualname__,
2006 self._offset)
2007 return "%s.%s(%r, %r)" % (self.__class__.__module__,
2008 self.__class__.__qualname__,
2009 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002010
2011 def __str__(self):
2012 return self.tzname(None)
2013
2014 def utcoffset(self, dt):
2015 if isinstance(dt, datetime) or dt is None:
2016 return self._offset
2017 raise TypeError("utcoffset() argument must be a datetime instance"
2018 " or None")
2019
2020 def tzname(self, dt):
2021 if isinstance(dt, datetime) or dt is None:
2022 if self._name is None:
2023 return self._name_from_offset(self._offset)
2024 return self._name
2025 raise TypeError("tzname() argument must be a datetime instance"
2026 " or None")
2027
2028 def dst(self, dt):
2029 if isinstance(dt, datetime) or dt is None:
2030 return None
2031 raise TypeError("dst() argument must be a datetime instance"
2032 " or None")
2033
2034 def fromutc(self, dt):
2035 if isinstance(dt, datetime):
2036 if dt.tzinfo is not self:
2037 raise ValueError("fromutc: dt.tzinfo "
2038 "is not self")
2039 return dt + self._offset
2040 raise TypeError("fromutc() argument must be a datetime instance"
2041 " or None")
2042
2043 _maxoffset = timedelta(hours=23, minutes=59)
2044 _minoffset = -_maxoffset
2045
2046 @staticmethod
2047 def _name_from_offset(delta):
Alexander Belopolsky7827a5b2015-09-06 13:07:21 -04002048 if not delta:
2049 return 'UTC'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002050 if delta < timedelta(0):
2051 sign = '-'
2052 delta = -delta
2053 else:
2054 sign = '+'
2055 hours, rest = divmod(delta, timedelta(hours=1))
Alexander Belopolsky018d3532017-07-31 10:26:50 -04002056 minutes, rest = divmod(rest, timedelta(minutes=1))
2057 seconds = rest.seconds
2058 microseconds = rest.microseconds
2059 if microseconds:
2060 return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2061 f'.{microseconds:06d}')
2062 if seconds:
2063 return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
2064 return f'UTC{sign}{hours:02d}:{minutes:02d}'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002065
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002066timezone.utc = timezone._create(timedelta(0))
2067timezone.min = timezone._create(timezone._minoffset)
2068timezone.max = timezone._create(timezone._maxoffset)
Alexander Belopolskya4415142012-06-08 12:33:09 -04002069_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002070
Victor Stinner765531d2013-03-26 01:11:54 +01002071# Some time zone algebra. For a datetime x, let
2072# x.n = x stripped of its timezone -- its naive time.
2073# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2074# return None
2075# x.d = x.dst(), and assuming that doesn't raise an exception or
2076# return None
2077# x.s = x's standard offset, x.o - x.d
2078#
2079# Now some derived rules, where k is a duration (timedelta).
2080#
2081# 1. x.o = x.s + x.d
2082# This follows from the definition of x.s.
2083#
2084# 2. If x and y have the same tzinfo member, x.s = y.s.
2085# This is actually a requirement, an assumption we need to make about
2086# sane tzinfo classes.
2087#
2088# 3. The naive UTC time corresponding to x is x.n - x.o.
2089# This is again a requirement for a sane tzinfo class.
2090#
2091# 4. (x+k).s = x.s
2092# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
2093#
2094# 5. (x+k).n = x.n + k
2095# Again follows from how arithmetic is defined.
2096#
2097# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
2098# (meaning that the various tzinfo methods exist, and don't blow up or return
2099# None when called).
2100#
2101# The function wants to return a datetime y with timezone tz, equivalent to x.
2102# x is already in UTC.
2103#
2104# By #3, we want
2105#
2106# y.n - y.o = x.n [1]
2107#
2108# The algorithm starts by attaching tz to x.n, and calling that y. So
2109# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
2110# becomes true; in effect, we want to solve [2] for k:
2111#
2112# (y+k).n - (y+k).o = x.n [2]
2113#
2114# By #1, this is the same as
2115#
2116# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
2117#
2118# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2119# Substituting that into [3],
2120#
2121# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2122# k - (y+k).s - (y+k).d = 0; rearranging,
2123# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2124# k = y.s - (y+k).d
2125#
2126# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2127# approximate k by ignoring the (y+k).d term at first. Note that k can't be
2128# very large, since all offset-returning methods return a duration of magnitude
2129# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
2130# be 0, so ignoring it has no consequence then.
2131#
2132# In any case, the new value is
2133#
2134# z = y + y.s [4]
2135#
2136# It's helpful to step back at look at [4] from a higher level: it's simply
2137# mapping from UTC to tz's standard time.
2138#
2139# At this point, if
2140#
2141# z.n - z.o = x.n [5]
2142#
2143# we have an equivalent time, and are almost done. The insecurity here is
2144# at the start of daylight time. Picture US Eastern for concreteness. The wall
2145# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2146# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2147# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2148# on the day DST starts. We want to return the 1:MM EST spelling because that's
2149# the only spelling that makes sense on the local wall clock.
2150#
2151# In fact, if [5] holds at this point, we do have the standard-time spelling,
2152# but that takes a bit of proof. We first prove a stronger result. What's the
2153# difference between the LHS and RHS of [5]? Let
2154#
2155# diff = x.n - (z.n - z.o) [6]
2156#
2157# Now
2158# z.n = by [4]
2159# (y + y.s).n = by #5
2160# y.n + y.s = since y.n = x.n
2161# x.n + y.s = since z and y are have the same tzinfo member,
2162# y.s = z.s by #2
2163# x.n + z.s
2164#
2165# Plugging that back into [6] gives
2166#
2167# diff =
2168# x.n - ((x.n + z.s) - z.o) = expanding
2169# x.n - x.n - z.s + z.o = cancelling
2170# - z.s + z.o = by #2
2171# z.d
2172#
2173# So diff = z.d.
2174#
2175# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2176# spelling we wanted in the endcase described above. We're done. Contrarily,
2177# if z.d = 0, then we have a UTC equivalent, and are also done.
2178#
2179# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2180# add to z (in effect, z is in tz's standard time, and we need to shift the
2181# local clock into tz's daylight time).
2182#
2183# Let
2184#
2185# z' = z + z.d = z + diff [7]
2186#
2187# and we can again ask whether
2188#
2189# z'.n - z'.o = x.n [8]
2190#
2191# If so, we're done. If not, the tzinfo class is insane, according to the
2192# assumptions we've made. This also requires a bit of proof. As before, let's
2193# compute the difference between the LHS and RHS of [8] (and skipping some of
2194# the justifications for the kinds of substitutions we've done several times
2195# already):
2196#
2197# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2198# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2199# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2200# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2201# - z.n + z.n - z.o + z'.o = cancel z.n
2202# - z.o + z'.o = #1 twice
2203# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2204# z'.d - z.d
2205#
2206# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2207# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2208# return z', not bothering to compute z'.d.
2209#
2210# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2211# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2212# would have to change the result dst() returns: we start in DST, and moving
2213# a little further into it takes us out of DST.
2214#
2215# There isn't a sane case where this can happen. The closest it gets is at
2216# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2217# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2218# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2219# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2220# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2221# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2222# standard time. Since that's what the local clock *does*, we want to map both
2223# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2224# in local time, but so it goes -- it's the way the local clock works.
2225#
2226# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2227# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2228# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2229# (correctly) concludes that z' is not UTC-equivalent to x.
2230#
2231# Because we know z.d said z was in daylight time (else [5] would have held and
2232# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2233# and we have stopped then), and there are only 2 possible values dst() can
2234# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2235# but the reasoning doesn't depend on the example -- it depends on there being
2236# two possible dst() outcomes, one zero and the other non-zero). Therefore
2237# z' must be in standard time, and is the spelling we want in this case.
2238#
2239# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2240# concerned (because it takes z' as being in standard time rather than the
2241# daylight time we intend here), but returning it gives the real-life "local
2242# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2243# tz.
2244#
2245# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2246# the 1:MM standard time spelling we want.
2247#
2248# So how can this break? One of the assumptions must be violated. Two
2249# possibilities:
2250#
2251# 1) [2] effectively says that y.s is invariant across all y belong to a given
2252# time zone. This isn't true if, for political reasons or continental drift,
2253# a region decides to change its base offset from UTC.
2254#
2255# 2) There may be versions of "double daylight" time where the tail end of
2256# the analysis gives up a step too early. I haven't thought about that
2257# enough to say.
2258#
2259# In any case, it's clear that the default fromutc() is strong enough to handle
2260# "almost all" time zones: so long as the standard offset is invariant, it
2261# doesn't matter if daylight time transition points change from year to year, or
2262# if daylight time is skipped in some years; it doesn't matter how large or
2263# small dst() may get within its bounds; and it doesn't even matter if some
2264# perverse time zone returns a negative dst()). So a breaking case must be
2265# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002266
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002267try:
2268 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002269except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002270 pass
2271else:
2272 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002273 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2274 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2275 _check_date_fields, _check_int_field, _check_time_fields,
2276 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2277 _date_class, _days_before_month, _days_before_year, _days_in_month,
2278 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd,
Utkarsh Upadhyay287c5592017-07-21 02:14:54 +02002279 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord,
2280 _divide_and_round)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002281 # XXX Since import * above excludes names that start with _,
2282 # docstring does not get overwritten. In the future, it may be
2283 # appropriate to maintain a single module level docstring and
2284 # remove the following line.
2285 from _datetime import __doc__