blob: 76a6f957e08c37e8ce476536712ff074c3f05bf7 [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 = '-'
209 h, m = divmod(offset, timedelta(hours=1))
210 assert not m % timedelta(minutes=1), "whole minute"
211 m //= timedelta(minutes=1)
212 zreplace = '%c%02d%02d' % (sign, h, m)
213 assert '%' not in zreplace
214 newformat.append(zreplace)
215 elif ch == 'Z':
216 if Zreplace is None:
217 Zreplace = ""
218 if hasattr(object, "tzname"):
219 s = object.tzname()
220 if s is not None:
221 # strftime is going to have at this: escape %
222 Zreplace = s.replace('%', '%%')
223 newformat.append(Zreplace)
224 else:
225 push('%')
226 push(ch)
227 else:
228 push('%')
229 else:
230 push(ch)
231 newformat = "".join(newformat)
232 return _time.strftime(newformat, timetuple)
233
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000234# Just raise TypeError if the arg isn't None or a string.
235def _check_tzname(name):
236 if name is not None and not isinstance(name, str):
237 raise TypeError("tzinfo.tzname() must return None or string, "
238 "not '%s'" % type(name))
239
240# name is the offset-producing method, "utcoffset" or "dst".
241# offset is what it returned.
242# If offset isn't None or timedelta, raises TypeError.
243# If offset is None, returns None.
244# Else offset is checked for being in range, and a whole # of minutes.
245# If it is, its integer value is returned. Else ValueError is raised.
246def _check_utc_offset(name, offset):
247 assert name in ("utcoffset", "dst")
248 if offset is None:
249 return
250 if not isinstance(offset, timedelta):
251 raise TypeError("tzinfo.%s() must return None "
252 "or timedelta, not '%s'" % (name, type(offset)))
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -0400253 if offset.microseconds:
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000254 raise ValueError("tzinfo.%s() must return a whole number "
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -0400255 "of seconds, got %s" % (name, offset))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000256 if not -timedelta(1) < offset < timedelta(1):
Martin Panterdd780e42016-05-30 04:08:23 +0000257 raise ValueError("%s()=%s, must be strictly between "
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400258 "-timedelta(hours=24) and timedelta(hours=24)" %
259 (name, offset))
260
261def _check_int_field(value):
262 if isinstance(value, int):
263 return value
264 if not isinstance(value, float):
265 try:
266 value = value.__int__()
267 except AttributeError:
268 pass
269 else:
270 if isinstance(value, int):
271 return value
272 raise TypeError('__int__ returned non-int (type %s)' %
273 type(value).__name__)
274 raise TypeError('an integer is required (got type %s)' %
275 type(value).__name__)
276 raise TypeError('integer argument expected, got float')
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000277
278def _check_date_fields(year, month, day):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400279 year = _check_int_field(year)
280 month = _check_int_field(month)
281 day = _check_int_field(day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000282 if not MINYEAR <= year <= MAXYEAR:
283 raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year)
284 if not 1 <= month <= 12:
285 raise ValueError('month must be in 1..12', month)
286 dim = _days_in_month(year, month)
287 if not 1 <= day <= dim:
288 raise ValueError('day must be in 1..%d' % dim, day)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400289 return year, month, day
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000290
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400291def _check_time_fields(hour, minute, second, microsecond, fold):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400292 hour = _check_int_field(hour)
293 minute = _check_int_field(minute)
294 second = _check_int_field(second)
295 microsecond = _check_int_field(microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000296 if not 0 <= hour <= 23:
297 raise ValueError('hour must be in 0..23', hour)
298 if not 0 <= minute <= 59:
299 raise ValueError('minute must be in 0..59', minute)
300 if not 0 <= second <= 59:
301 raise ValueError('second must be in 0..59', second)
302 if not 0 <= microsecond <= 999999:
303 raise ValueError('microsecond must be in 0..999999', microsecond)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -0400304 if fold not in (0, 1):
305 raise ValueError('fold must be either 0 or 1', fold)
306 return hour, minute, second, microsecond, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000307
308def _check_tzinfo_arg(tz):
309 if tz is not None and not isinstance(tz, tzinfo):
310 raise TypeError("tzinfo argument must be None or of a tzinfo subclass")
311
312def _cmperror(x, y):
313 raise TypeError("can't compare '%s' to '%s'" % (
314 type(x).__name__, type(y).__name__))
315
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500316def _divide_and_round(a, b):
317 """divide a by b and round result to the nearest integer
318
319 When the ratio is exactly half-way between two integers,
320 the even integer is returned.
321 """
322 # Based on the reference implementation for divmod_near
323 # in Objects/longobject.c.
324 q, r = divmod(a, b)
325 # round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
326 # The expression r / b > 0.5 is equivalent to 2 * r > b if b is
327 # positive, 2 * r < b if b negative.
328 r *= 2
329 greater_than_half = r > b if b > 0 else r < b
330 if greater_than_half or r == b and q % 2 == 1:
331 q += 1
332
333 return q
334
Victor Stinner2ec55872015-09-02 19:16:07 +0200335
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000336class timedelta:
337 """Represent the difference between two datetime objects.
338
339 Supported operators:
340
341 - add, subtract timedelta
342 - unary plus, minus, abs
343 - compare to timedelta
Serhiy Storchaka95949422013-08-27 19:40:23 +0300344 - multiply, divide by int
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000345
346 In addition, datetime supports subtraction of two datetime objects
347 returning a timedelta, and addition or subtraction of a datetime
348 and a timedelta giving a datetime.
349
350 Representation: (days, seconds, microseconds). Why? Because I
351 felt like it.
352 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400353 __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000354
355 def __new__(cls, days=0, seconds=0, microseconds=0,
356 milliseconds=0, minutes=0, hours=0, weeks=0):
357 # Doing this efficiently and accurately in C is going to be difficult
358 # and error-prone, due to ubiquitous overflow possibilities, and that
359 # C double doesn't have enough bits of precision to represent
360 # microseconds over 10K years faithfully. The code here tries to make
361 # explicit where go-fast assumptions can be relied on, in order to
362 # guide the C implementation; it's way more convoluted than speed-
363 # ignoring auto-overflow-to-long idiomatic Python could be.
364
365 # XXX Check that all inputs are ints or floats.
366
367 # Final values, all integer.
368 # s and us fit in 32-bit signed ints; d isn't bounded.
369 d = s = us = 0
370
371 # Normalize everything to days, seconds, microseconds.
372 days += weeks*7
373 seconds += minutes*60 + hours*3600
374 microseconds += milliseconds*1000
375
376 # Get rid of all fractions, and normalize s and us.
377 # Take a deep breath <wink>.
378 if isinstance(days, float):
379 dayfrac, days = _math.modf(days)
380 daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
381 assert daysecondswhole == int(daysecondswhole) # can't overflow
382 s = int(daysecondswhole)
383 assert days == int(days)
384 d = int(days)
385 else:
386 daysecondsfrac = 0.0
387 d = days
388 assert isinstance(daysecondsfrac, float)
389 assert abs(daysecondsfrac) <= 1.0
390 assert isinstance(d, int)
391 assert abs(s) <= 24 * 3600
392 # days isn't referenced again before redefinition
393
394 if isinstance(seconds, float):
395 secondsfrac, seconds = _math.modf(seconds)
396 assert seconds == int(seconds)
397 seconds = int(seconds)
398 secondsfrac += daysecondsfrac
399 assert abs(secondsfrac) <= 2.0
400 else:
401 secondsfrac = daysecondsfrac
402 # daysecondsfrac isn't referenced again
403 assert isinstance(secondsfrac, float)
404 assert abs(secondsfrac) <= 2.0
405
406 assert isinstance(seconds, int)
407 days, seconds = divmod(seconds, 24*3600)
408 d += days
409 s += int(seconds) # can't overflow
410 assert isinstance(s, int)
411 assert abs(s) <= 2 * 24 * 3600
412 # seconds isn't referenced again before redefinition
413
414 usdouble = secondsfrac * 1e6
415 assert abs(usdouble) < 2.1e6 # exact value not critical
416 # secondsfrac isn't referenced again
417
418 if isinstance(microseconds, float):
Victor Stinner69cc4872015-09-08 23:58:54 +0200419 microseconds = round(microseconds + usdouble)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000420 seconds, microseconds = divmod(microseconds, 1000000)
421 days, seconds = divmod(seconds, 24*3600)
422 d += days
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400423 s += seconds
424 else:
425 microseconds = int(microseconds)
426 seconds, microseconds = divmod(microseconds, 1000000)
427 days, seconds = divmod(seconds, 24*3600)
428 d += days
429 s += seconds
Victor Stinner69cc4872015-09-08 23:58:54 +0200430 microseconds = round(microseconds + usdouble)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400431 assert isinstance(s, int)
432 assert isinstance(microseconds, int)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000433 assert abs(s) <= 3 * 24 * 3600
434 assert abs(microseconds) < 3.1e6
435
436 # Just a little bit of carrying possible for microseconds and seconds.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400437 seconds, us = divmod(microseconds, 1000000)
438 s += seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000439 days, s = divmod(s, 24*3600)
440 d += days
441
442 assert isinstance(d, int)
443 assert isinstance(s, int) and 0 <= s < 24*3600
444 assert isinstance(us, int) and 0 <= us < 1000000
445
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000446 if abs(d) > 999999999:
447 raise OverflowError("timedelta # of days is too large: %d" % d)
448
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400449 self = object.__new__(cls)
450 self._days = d
451 self._seconds = s
452 self._microseconds = us
453 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000454 return self
455
456 def __repr__(self):
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200457 args = []
458 if self._days:
459 args.append("days=%d" % self._days)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000460 if self._seconds:
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200461 args.append("seconds=%d" % self._seconds)
462 if self._microseconds:
463 args.append("microseconds=%d" % self._microseconds)
464 if not args:
465 args.append('0')
466 return "%s.%s(%s)" % (self.__class__.__module__,
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300467 self.__class__.__qualname__,
Utkarsh Upadhyaycc5a65c2017-07-25 23:51:33 +0200468 ', '.join(args))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000469
470 def __str__(self):
471 mm, ss = divmod(self._seconds, 60)
472 hh, mm = divmod(mm, 60)
473 s = "%d:%02d:%02d" % (hh, mm, ss)
474 if self._days:
475 def plural(n):
476 return n, abs(n) != 1 and "s" or ""
477 s = ("%d day%s, " % plural(self._days)) + s
478 if self._microseconds:
479 s = s + ".%06d" % self._microseconds
480 return s
481
482 def total_seconds(self):
483 """Total seconds in the duration."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400484 return ((self.days * 86400 + self.seconds) * 10**6 +
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000485 self.microseconds) / 10**6
486
487 # Read-only field accessors
488 @property
489 def days(self):
490 """days"""
491 return self._days
492
493 @property
494 def seconds(self):
495 """seconds"""
496 return self._seconds
497
498 @property
499 def microseconds(self):
500 """microseconds"""
501 return self._microseconds
502
503 def __add__(self, other):
504 if isinstance(other, timedelta):
505 # for CPython compatibility, we cannot use
506 # our __class__ here, but need a real timedelta
507 return timedelta(self._days + other._days,
508 self._seconds + other._seconds,
509 self._microseconds + other._microseconds)
510 return NotImplemented
511
512 __radd__ = __add__
513
514 def __sub__(self, other):
515 if isinstance(other, timedelta):
Alexander Belopolskyb6f5ec72011-04-05 20:07:38 -0400516 # for CPython compatibility, we cannot use
517 # our __class__ here, but need a real timedelta
518 return timedelta(self._days - other._days,
519 self._seconds - other._seconds,
520 self._microseconds - other._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000521 return NotImplemented
522
523 def __rsub__(self, other):
524 if isinstance(other, timedelta):
525 return -self + other
526 return NotImplemented
527
528 def __neg__(self):
529 # for CPython compatibility, we cannot use
530 # our __class__ here, but need a real timedelta
531 return timedelta(-self._days,
532 -self._seconds,
533 -self._microseconds)
534
535 def __pos__(self):
536 return self
537
538 def __abs__(self):
539 if self._days < 0:
540 return -self
541 else:
542 return self
543
544 def __mul__(self, other):
545 if isinstance(other, int):
546 # for CPython compatibility, we cannot use
547 # our __class__ here, but need a real timedelta
548 return timedelta(self._days * other,
549 self._seconds * other,
550 self._microseconds * other)
551 if isinstance(other, float):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500552 usec = self._to_microseconds()
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000553 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500554 return timedelta(0, 0, _divide_and_round(usec * a, b))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000555 return NotImplemented
556
557 __rmul__ = __mul__
558
559 def _to_microseconds(self):
560 return ((self._days * (24*3600) + self._seconds) * 1000000 +
561 self._microseconds)
562
563 def __floordiv__(self, other):
564 if not isinstance(other, (int, timedelta)):
565 return NotImplemented
566 usec = self._to_microseconds()
567 if isinstance(other, timedelta):
568 return usec // other._to_microseconds()
569 if isinstance(other, int):
570 return timedelta(0, 0, usec // other)
571
572 def __truediv__(self, other):
573 if not isinstance(other, (int, float, timedelta)):
574 return NotImplemented
575 usec = self._to_microseconds()
576 if isinstance(other, timedelta):
577 return usec / other._to_microseconds()
578 if isinstance(other, int):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500579 return timedelta(0, 0, _divide_and_round(usec, other))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000580 if isinstance(other, float):
581 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500582 return timedelta(0, 0, _divide_and_round(b * usec, a))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000583
584 def __mod__(self, other):
585 if isinstance(other, timedelta):
586 r = self._to_microseconds() % other._to_microseconds()
587 return timedelta(0, 0, r)
588 return NotImplemented
589
590 def __divmod__(self, other):
591 if isinstance(other, timedelta):
592 q, r = divmod(self._to_microseconds(),
593 other._to_microseconds())
594 return q, timedelta(0, 0, r)
595 return NotImplemented
596
597 # Comparisons of timedelta objects with other.
598
599 def __eq__(self, other):
600 if isinstance(other, timedelta):
601 return self._cmp(other) == 0
602 else:
603 return False
604
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000605 def __le__(self, other):
606 if isinstance(other, timedelta):
607 return self._cmp(other) <= 0
608 else:
609 _cmperror(self, other)
610
611 def __lt__(self, other):
612 if isinstance(other, timedelta):
613 return self._cmp(other) < 0
614 else:
615 _cmperror(self, other)
616
617 def __ge__(self, other):
618 if isinstance(other, timedelta):
619 return self._cmp(other) >= 0
620 else:
621 _cmperror(self, other)
622
623 def __gt__(self, other):
624 if isinstance(other, timedelta):
625 return self._cmp(other) > 0
626 else:
627 _cmperror(self, other)
628
629 def _cmp(self, other):
630 assert isinstance(other, timedelta)
631 return _cmp(self._getstate(), other._getstate())
632
633 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400634 if self._hashcode == -1:
635 self._hashcode = hash(self._getstate())
636 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000637
638 def __bool__(self):
639 return (self._days != 0 or
640 self._seconds != 0 or
641 self._microseconds != 0)
642
643 # Pickle support.
644
645 def _getstate(self):
646 return (self._days, self._seconds, self._microseconds)
647
648 def __reduce__(self):
649 return (self.__class__, self._getstate())
650
651timedelta.min = timedelta(-999999999)
652timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
653 microseconds=999999)
654timedelta.resolution = timedelta(microseconds=1)
655
656class date:
657 """Concrete date type.
658
659 Constructors:
660
661 __new__()
662 fromtimestamp()
663 today()
664 fromordinal()
665
666 Operators:
667
668 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200669 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000670 __add__, __radd__, __sub__ (add/radd only with timedelta arg)
671
672 Methods:
673
674 timetuple()
675 toordinal()
676 weekday()
677 isoweekday(), isocalendar(), isoformat()
678 ctime()
679 strftime()
680
681 Properties (readonly):
682 year, month, day
683 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400684 __slots__ = '_year', '_month', '_day', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000685
686 def __new__(cls, year, month=None, day=None):
687 """Constructor.
688
689 Arguments:
690
691 year, month, day (required, base 1)
692 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400693 if month is None and isinstance(year, bytes) and len(year) == 4 and \
694 1 <= year[2] <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000695 # Pickle support
696 self = object.__new__(cls)
697 self.__setstate(year)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400698 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000699 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400700 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000701 self = object.__new__(cls)
702 self._year = year
703 self._month = month
704 self._day = day
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400705 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000706 return self
707
708 # Additional constructors
709
710 @classmethod
711 def fromtimestamp(cls, t):
712 "Construct a date from a POSIX timestamp (like time.time())."
713 y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
714 return cls(y, m, d)
715
716 @classmethod
717 def today(cls):
718 "Construct a date from time.time()."
719 t = _time.time()
720 return cls.fromtimestamp(t)
721
722 @classmethod
723 def fromordinal(cls, n):
Martin Pantereb995702016-07-28 01:11:04 +0000724 """Construct a date from a proleptic Gregorian ordinal.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000725
726 January 1 of year 1 is day 1. Only the year, month and day are
727 non-zero in the result.
728 """
729 y, m, d = _ord2ymd(n)
730 return cls(y, m, d)
731
732 # Conversions to string
733
734 def __repr__(self):
735 """Convert to formal string, for repr().
736
737 >>> dt = datetime(2010, 1, 1)
738 >>> repr(dt)
739 'datetime.datetime(2010, 1, 1, 0, 0)'
740
741 >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
742 >>> repr(dt)
743 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
744 """
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300745 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
746 self.__class__.__qualname__,
747 self._year,
748 self._month,
749 self._day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000750 # XXX These shouldn't depend on time.localtime(), because that
751 # clips the usable dates to [1970 .. 2038). At least ctime() is
752 # easily done without using strftime() -- that's better too because
753 # strftime("%c", ...) is locale specific.
754
755
756 def ctime(self):
757 "Return ctime() style string."
758 weekday = self.toordinal() % 7 or 7
759 return "%s %s %2d 00:00:00 %04d" % (
760 _DAYNAMES[weekday],
761 _MONTHNAMES[self._month],
762 self._day, self._year)
763
764 def strftime(self, fmt):
765 "Format using strftime()."
766 return _wrap_strftime(self, fmt, self.timetuple())
767
768 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400769 if not isinstance(fmt, str):
770 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000771 if len(fmt) != 0:
772 return self.strftime(fmt)
773 return str(self)
774
775 def isoformat(self):
776 """Return the date formatted according to ISO.
777
778 This is 'YYYY-MM-DD'.
779
780 References:
781 - http://www.w3.org/TR/NOTE-datetime
782 - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
783 """
784 return "%04d-%02d-%02d" % (self._year, self._month, self._day)
785
786 __str__ = isoformat
787
788 # Read-only field accessors
789 @property
790 def year(self):
791 """year (1-9999)"""
792 return self._year
793
794 @property
795 def month(self):
796 """month (1-12)"""
797 return self._month
798
799 @property
800 def day(self):
801 """day (1-31)"""
802 return self._day
803
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200804 # Standard conversions, __eq__, __le__, __lt__, __ge__, __gt__,
805 # __hash__ (and helpers)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000806
807 def timetuple(self):
808 "Return local time tuple compatible with time.localtime()."
809 return _build_struct_time(self._year, self._month, self._day,
810 0, 0, 0, -1)
811
812 def toordinal(self):
813 """Return proleptic Gregorian ordinal for the year, month and day.
814
815 January 1 of year 1 is day 1. Only the year, month and day values
816 contribute to the result.
817 """
818 return _ymd2ord(self._year, self._month, self._day)
819
820 def replace(self, year=None, month=None, day=None):
821 """Return a new date with new values for the specified fields."""
822 if year is None:
823 year = self._year
824 if month is None:
825 month = self._month
826 if day is None:
827 day = self._day
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000828 return date(year, month, day)
829
830 # Comparisons of date objects with other.
831
832 def __eq__(self, other):
833 if isinstance(other, date):
834 return self._cmp(other) == 0
835 return NotImplemented
836
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000837 def __le__(self, other):
838 if isinstance(other, date):
839 return self._cmp(other) <= 0
840 return NotImplemented
841
842 def __lt__(self, other):
843 if isinstance(other, date):
844 return self._cmp(other) < 0
845 return NotImplemented
846
847 def __ge__(self, other):
848 if isinstance(other, date):
849 return self._cmp(other) >= 0
850 return NotImplemented
851
852 def __gt__(self, other):
853 if isinstance(other, date):
854 return self._cmp(other) > 0
855 return NotImplemented
856
857 def _cmp(self, other):
858 assert isinstance(other, date)
859 y, m, d = self._year, self._month, self._day
860 y2, m2, d2 = other._year, other._month, other._day
861 return _cmp((y, m, d), (y2, m2, d2))
862
863 def __hash__(self):
864 "Hash."
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400865 if self._hashcode == -1:
866 self._hashcode = hash(self._getstate())
867 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000868
869 # Computations
870
871 def __add__(self, other):
872 "Add a date to a timedelta."
873 if isinstance(other, timedelta):
874 o = self.toordinal() + other.days
875 if 0 < o <= _MAXORDINAL:
876 return date.fromordinal(o)
877 raise OverflowError("result out of range")
878 return NotImplemented
879
880 __radd__ = __add__
881
882 def __sub__(self, other):
883 """Subtract two dates, or a date and a timedelta."""
884 if isinstance(other, timedelta):
885 return self + timedelta(-other.days)
886 if isinstance(other, date):
887 days1 = self.toordinal()
888 days2 = other.toordinal()
889 return timedelta(days1 - days2)
890 return NotImplemented
891
892 def weekday(self):
893 "Return day of the week, where Monday == 0 ... Sunday == 6."
894 return (self.toordinal() + 6) % 7
895
896 # Day-of-the-week and week-of-the-year, according to ISO
897
898 def isoweekday(self):
899 "Return day of the week, where Monday == 1 ... Sunday == 7."
900 # 1-Jan-0001 is a Monday
901 return self.toordinal() % 7 or 7
902
903 def isocalendar(self):
904 """Return a 3-tuple containing ISO year, week number, and weekday.
905
906 The first ISO week of the year is the (Mon-Sun) week
907 containing the year's first Thursday; everything else derives
908 from that.
909
910 The first week is 1; Monday is 1 ... Sunday is 7.
911
912 ISO calendar algorithm taken from
913 http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
Brett Cannon07b954d2016-01-15 09:53:51 -0800914 (used with permission)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000915 """
916 year = self._year
917 week1monday = _isoweek1monday(year)
918 today = _ymd2ord(self._year, self._month, self._day)
919 # Internally, week and day have origin 0
920 week, day = divmod(today - week1monday, 7)
921 if week < 0:
922 year -= 1
923 week1monday = _isoweek1monday(year)
924 week, day = divmod(today - week1monday, 7)
925 elif week >= 52:
926 if today >= _isoweek1monday(year+1):
927 year += 1
928 week = 0
929 return year, week+1, day+1
930
931 # Pickle support.
932
Serhiy Storchaka546ce652016-11-22 00:29:42 +0200933 def _getstate(self):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000934 yhi, ylo = divmod(self._year, 256)
935 return bytes([yhi, ylo, self._month, self._day]),
936
937 def __setstate(self, string):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000938 yhi, ylo, self._month, self._day = string
939 self._year = yhi * 256 + ylo
940
Serhiy Storchaka546ce652016-11-22 00:29:42 +0200941 def __reduce__(self):
942 return (self.__class__, self._getstate())
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000943
944_date_class = date # so functions w/ args named "date" can get at the class
945
946date.min = date(1, 1, 1)
947date.max = date(9999, 12, 31)
948date.resolution = timedelta(days=1)
949
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -0400950
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000951class tzinfo:
952 """Abstract base class for time zone info classes.
953
954 Subclasses must override the name(), utcoffset() and dst() methods.
955 """
956 __slots__ = ()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400957
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000958 def tzname(self, dt):
959 "datetime -> string name of time zone."
960 raise NotImplementedError("tzinfo subclass must override tzname()")
961
962 def utcoffset(self, dt):
963 "datetime -> minutes east of UTC (negative for west of UTC)"
964 raise NotImplementedError("tzinfo subclass must override utcoffset()")
965
966 def dst(self, dt):
967 """datetime -> DST offset in minutes east of UTC.
968
969 Return 0 if DST not in effect. utcoffset() must include the DST
970 offset.
971 """
972 raise NotImplementedError("tzinfo subclass must override dst()")
973
974 def fromutc(self, dt):
975 "datetime in UTC -> datetime in local time."
976
977 if not isinstance(dt, datetime):
978 raise TypeError("fromutc() requires a datetime argument")
979 if dt.tzinfo is not self:
980 raise ValueError("dt.tzinfo is not self")
981
982 dtoff = dt.utcoffset()
983 if dtoff is None:
984 raise ValueError("fromutc() requires a non-None utcoffset() "
985 "result")
986
987 # See the long comment block at the end of this file for an
988 # explanation of this algorithm.
989 dtdst = dt.dst()
990 if dtdst is None:
991 raise ValueError("fromutc() requires a non-None dst() result")
992 delta = dtoff - dtdst
993 if delta:
994 dt += delta
995 dtdst = dt.dst()
996 if dtdst is None:
997 raise ValueError("fromutc(): dt.dst gave inconsistent "
998 "results; cannot convert")
999 return dt + dtdst
1000
1001 # Pickle support.
1002
1003 def __reduce__(self):
1004 getinitargs = getattr(self, "__getinitargs__", None)
1005 if getinitargs:
1006 args = getinitargs()
1007 else:
1008 args = ()
1009 getstate = getattr(self, "__getstate__", None)
1010 if getstate:
1011 state = getstate()
1012 else:
1013 state = getattr(self, "__dict__", None) or None
1014 if state is None:
1015 return (self.__class__, args)
1016 else:
1017 return (self.__class__, args, state)
1018
1019_tzinfo_class = tzinfo
1020
1021class time:
1022 """Time with time zone.
1023
1024 Constructors:
1025
1026 __new__()
1027
1028 Operators:
1029
1030 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +02001031 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001032
1033 Methods:
1034
1035 strftime()
1036 isoformat()
1037 utcoffset()
1038 tzname()
1039 dst()
1040
1041 Properties (readonly):
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001042 hour, minute, second, microsecond, tzinfo, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001043 """
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001044 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode', '_fold'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001045
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001046 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001047 """Constructor.
1048
1049 Arguments:
1050
1051 hour, minute (required)
1052 second, microsecond (default to zero)
1053 tzinfo (default to None)
Victor Stinner51b90d22017-01-04 12:01:16 +01001054 fold (keyword only, default to zero)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001055 """
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001056 if isinstance(hour, bytes) and len(hour) == 6 and hour[0]&0x7F < 24:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001057 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001058 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001059 self.__setstate(hour, minute or None)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001060 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001061 return self
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001062 hour, minute, second, microsecond, fold = _check_time_fields(
1063 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001064 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001065 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001066 self._hour = hour
1067 self._minute = minute
1068 self._second = second
1069 self._microsecond = microsecond
1070 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001071 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001072 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001073 return self
1074
1075 # Read-only field accessors
1076 @property
1077 def hour(self):
1078 """hour (0-23)"""
1079 return self._hour
1080
1081 @property
1082 def minute(self):
1083 """minute (0-59)"""
1084 return self._minute
1085
1086 @property
1087 def second(self):
1088 """second (0-59)"""
1089 return self._second
1090
1091 @property
1092 def microsecond(self):
1093 """microsecond (0-999999)"""
1094 return self._microsecond
1095
1096 @property
1097 def tzinfo(self):
1098 """timezone info object"""
1099 return self._tzinfo
1100
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001101 @property
1102 def fold(self):
1103 return self._fold
1104
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001105 # Standard conversions, __hash__ (and helpers)
1106
1107 # Comparisons of time objects with other.
1108
1109 def __eq__(self, other):
1110 if isinstance(other, time):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001111 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001112 else:
1113 return False
1114
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001115 def __le__(self, other):
1116 if isinstance(other, time):
1117 return self._cmp(other) <= 0
1118 else:
1119 _cmperror(self, other)
1120
1121 def __lt__(self, other):
1122 if isinstance(other, time):
1123 return self._cmp(other) < 0
1124 else:
1125 _cmperror(self, other)
1126
1127 def __ge__(self, other):
1128 if isinstance(other, time):
1129 return self._cmp(other) >= 0
1130 else:
1131 _cmperror(self, other)
1132
1133 def __gt__(self, other):
1134 if isinstance(other, time):
1135 return self._cmp(other) > 0
1136 else:
1137 _cmperror(self, other)
1138
Alexander Belopolsky08313822012-06-15 20:19:47 -04001139 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001140 assert isinstance(other, time)
1141 mytz = self._tzinfo
1142 ottz = other._tzinfo
1143 myoff = otoff = None
1144
1145 if mytz is ottz:
1146 base_compare = True
1147 else:
1148 myoff = self.utcoffset()
1149 otoff = other.utcoffset()
1150 base_compare = myoff == otoff
1151
1152 if base_compare:
1153 return _cmp((self._hour, self._minute, self._second,
1154 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001155 (other._hour, other._minute, other._second,
1156 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001157 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001158 if allow_mixed:
1159 return 2 # arbitrary non-zero value
1160 else:
1161 raise TypeError("cannot compare naive and aware times")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001162 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1163 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1164 return _cmp((myhhmm, self._second, self._microsecond),
1165 (othhmm, other._second, other._microsecond))
1166
1167 def __hash__(self):
1168 """Hash."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001169 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001170 if self.fold:
1171 t = self.replace(fold=0)
1172 else:
1173 t = self
1174 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001175 if not tzoff: # zero or None
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001176 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001177 else:
1178 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1179 timedelta(hours=1))
1180 assert not m % timedelta(minutes=1), "whole minute"
1181 m //= timedelta(minutes=1)
1182 if 0 <= h < 24:
1183 self._hashcode = hash(time(h, m, self.second, self.microsecond))
1184 else:
1185 self._hashcode = hash((h, m, self.second, self.microsecond))
1186 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001187
1188 # Conversion to string
1189
1190 def _tzstr(self, sep=":"):
1191 """Return formatted timezone offset (+xx:xx) or None."""
1192 off = self.utcoffset()
1193 if off is not None:
1194 if off.days < 0:
1195 sign = "-"
1196 off = -off
1197 else:
1198 sign = "+"
1199 hh, mm = divmod(off, timedelta(hours=1))
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001200 mm, ss = divmod(mm, timedelta(minutes=1))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001201 assert 0 <= hh < 24
1202 off = "%s%02d%s%02d" % (sign, hh, sep, mm)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001203 if ss:
1204 off += ':%02d' % ss.seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001205 return off
1206
1207 def __repr__(self):
1208 """Convert to formal string, for repr()."""
1209 if self._microsecond != 0:
1210 s = ", %d, %d" % (self._second, self._microsecond)
1211 elif self._second != 0:
1212 s = ", %d" % self._second
1213 else:
1214 s = ""
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001215 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1216 self.__class__.__qualname__,
1217 self._hour, self._minute, s)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001218 if self._tzinfo is not None:
1219 assert s[-1:] == ")"
1220 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001221 if self._fold:
1222 assert s[-1:] == ")"
1223 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001224 return s
1225
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001226 def isoformat(self, timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001227 """Return the time formatted according to ISO.
1228
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001229 The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional
1230 part is omitted if self.microsecond == 0.
1231
1232 The optional argument timespec specifies the number of additional
1233 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001234 """
1235 s = _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001236 self._microsecond, timespec)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001237 tz = self._tzstr()
1238 if tz:
1239 s += tz
1240 return s
1241
1242 __str__ = isoformat
1243
1244 def strftime(self, fmt):
1245 """Format using strftime(). The date part of the timestamp passed
1246 to underlying strftime should not be used.
1247 """
Alexander Belopolskyb8bb4662011-01-08 00:13:34 +00001248 # The year must be >= 1000 else Python's strftime implementation
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001249 # can raise a bogus exception.
1250 timetuple = (1900, 1, 1,
1251 self._hour, self._minute, self._second,
1252 0, 1, -1)
1253 return _wrap_strftime(self, fmt, timetuple)
1254
1255 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001256 if not isinstance(fmt, str):
1257 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001258 if len(fmt) != 0:
1259 return self.strftime(fmt)
1260 return str(self)
1261
1262 # Timezone functions
1263
1264 def utcoffset(self):
1265 """Return the timezone offset in minutes east of UTC (negative west of
1266 UTC)."""
1267 if self._tzinfo is None:
1268 return None
1269 offset = self._tzinfo.utcoffset(None)
1270 _check_utc_offset("utcoffset", offset)
1271 return offset
1272
1273 def tzname(self):
1274 """Return the timezone name.
1275
1276 Note that the name is 100% informational -- there's no requirement that
1277 it mean anything in particular. For example, "GMT", "UTC", "-500",
1278 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1279 """
1280 if self._tzinfo is None:
1281 return None
1282 name = self._tzinfo.tzname(None)
1283 _check_tzname(name)
1284 return name
1285
1286 def dst(self):
1287 """Return 0 if DST is not in effect, or the DST offset (in minutes
1288 eastward) if DST is in effect.
1289
1290 This is purely informational; the DST offset has already been added to
1291 the UTC offset returned by utcoffset() if applicable, so there's no
1292 need to consult dst() unless you're interested in displaying the DST
1293 info.
1294 """
1295 if self._tzinfo is None:
1296 return None
1297 offset = self._tzinfo.dst(None)
1298 _check_utc_offset("dst", offset)
1299 return offset
1300
1301 def replace(self, hour=None, minute=None, second=None, microsecond=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001302 tzinfo=True, *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001303 """Return a new time with new values for the specified fields."""
1304 if hour is None:
1305 hour = self.hour
1306 if minute is None:
1307 minute = self.minute
1308 if second is None:
1309 second = self.second
1310 if microsecond is None:
1311 microsecond = self.microsecond
1312 if tzinfo is True:
1313 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001314 if fold is None:
1315 fold = self._fold
1316 return time(hour, minute, second, microsecond, tzinfo, fold=fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001317
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001318 # Pickle support.
1319
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001320 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001321 us2, us3 = divmod(self._microsecond, 256)
1322 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001323 h = self._hour
1324 if self._fold and protocol > 3:
1325 h += 128
1326 basestate = bytes([h, self._minute, self._second,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001327 us1, us2, us3])
1328 if self._tzinfo is None:
1329 return (basestate,)
1330 else:
1331 return (basestate, self._tzinfo)
1332
1333 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001334 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1335 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001336 h, self._minute, self._second, us1, us2, us3 = string
1337 if h > 127:
1338 self._fold = 1
1339 self._hour = h - 128
1340 else:
1341 self._fold = 0
1342 self._hour = h
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001343 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001344 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001345
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001346 def __reduce_ex__(self, protocol):
1347 return (time, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001348
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001349 def __reduce__(self):
1350 return self.__reduce_ex__(2)
1351
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001352_time_class = time # so functions w/ args named "time" can get at the class
1353
1354time.min = time(0, 0, 0)
1355time.max = time(23, 59, 59, 999999)
1356time.resolution = timedelta(microseconds=1)
1357
1358class datetime(date):
1359 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1360
1361 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001362 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001363 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001364 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001365
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001366 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001367 microsecond=0, tzinfo=None, *, fold=0):
1368 if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2]&0x7F <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001369 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001370 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001371 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001372 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001373 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001374 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001375 hour, minute, second, microsecond, fold = _check_time_fields(
1376 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001377 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001378 self = object.__new__(cls)
1379 self._year = year
1380 self._month = month
1381 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001382 self._hour = hour
1383 self._minute = minute
1384 self._second = second
1385 self._microsecond = microsecond
1386 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001387 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001388 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001389 return self
1390
1391 # Read-only field accessors
1392 @property
1393 def hour(self):
1394 """hour (0-23)"""
1395 return self._hour
1396
1397 @property
1398 def minute(self):
1399 """minute (0-59)"""
1400 return self._minute
1401
1402 @property
1403 def second(self):
1404 """second (0-59)"""
1405 return self._second
1406
1407 @property
1408 def microsecond(self):
1409 """microsecond (0-999999)"""
1410 return self._microsecond
1411
1412 @property
1413 def tzinfo(self):
1414 """timezone info object"""
1415 return self._tzinfo
1416
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001417 @property
1418 def fold(self):
1419 return self._fold
1420
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001421 @classmethod
Victor Stinneradfefa52015-09-04 23:57:25 +02001422 def _fromtimestamp(cls, t, utc, tz):
1423 """Construct a datetime from a POSIX timestamp (like time.time()).
1424
1425 A timezone info object may be passed in as well.
1426 """
1427 frac, t = _math.modf(t)
Victor Stinner7667f582015-09-09 01:02:23 +02001428 us = round(frac * 1e6)
Victor Stinneradfefa52015-09-04 23:57:25 +02001429 if us >= 1000000:
1430 t += 1
1431 us -= 1000000
1432 elif us < 0:
1433 t -= 1
1434 us += 1000000
1435
1436 converter = _time.gmtime if utc else _time.localtime
1437 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1438 ss = min(ss, 59) # clamp out leap seconds if the platform has them
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001439 result = cls(y, m, d, hh, mm, ss, us, tz)
1440 if tz is None:
1441 # As of version 2015f max fold in IANA database is
1442 # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
1443 # Let's probe 24 hours in the past to detect a transition:
1444 max_fold_seconds = 24 * 3600
1445 y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1446 probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1447 trans = result - probe1 - timedelta(0, max_fold_seconds)
1448 if trans.days < 0:
1449 y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
1450 probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1451 if probe2 == result:
1452 result._fold = 1
1453 else:
1454 result = tz.fromutc(result)
1455 return result
Victor Stinneradfefa52015-09-04 23:57:25 +02001456
1457 @classmethod
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001458 def fromtimestamp(cls, t, tz=None):
1459 """Construct a datetime from a POSIX timestamp (like time.time()).
1460
1461 A timezone info object may be passed in as well.
1462 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001463 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001464
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001465 return cls._fromtimestamp(t, tz is not None, tz)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001466
1467 @classmethod
1468 def utcfromtimestamp(cls, t):
Alexander Belopolskye2e178e2015-03-01 14:52:07 -05001469 """Construct a naive UTC datetime from a POSIX timestamp."""
Victor Stinneradfefa52015-09-04 23:57:25 +02001470 return cls._fromtimestamp(t, True, None)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001471
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001472 @classmethod
1473 def now(cls, tz=None):
1474 "Construct a datetime from time.time() and optional time zone info."
1475 t = _time.time()
1476 return cls.fromtimestamp(t, tz)
1477
1478 @classmethod
1479 def utcnow(cls):
1480 "Construct a UTC datetime from time.time()."
1481 t = _time.time()
1482 return cls.utcfromtimestamp(t)
1483
1484 @classmethod
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001485 def combine(cls, date, time, tzinfo=True):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001486 "Construct a datetime from a given date and a given time."
1487 if not isinstance(date, _date_class):
1488 raise TypeError("date argument must be a date instance")
1489 if not isinstance(time, _time_class):
1490 raise TypeError("time argument must be a time instance")
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001491 if tzinfo is True:
1492 tzinfo = time.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001493 return cls(date.year, date.month, date.day,
1494 time.hour, time.minute, time.second, time.microsecond,
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001495 tzinfo, fold=time.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001496
1497 def timetuple(self):
1498 "Return local time tuple compatible with time.localtime()."
1499 dst = self.dst()
1500 if dst is None:
1501 dst = -1
1502 elif dst:
1503 dst = 1
1504 else:
1505 dst = 0
1506 return _build_struct_time(self.year, self.month, self.day,
1507 self.hour, self.minute, self.second,
1508 dst)
1509
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001510 def _mktime(self):
1511 """Return integer POSIX timestamp."""
1512 epoch = datetime(1970, 1, 1)
1513 max_fold_seconds = 24 * 3600
1514 t = (self - epoch) // timedelta(0, 1)
1515 def local(u):
1516 y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1517 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1518
1519 # Our goal is to solve t = local(u) for u.
1520 a = local(t) - t
1521 u1 = t - a
1522 t1 = local(u1)
1523 if t1 == t:
1524 # We found one solution, but it may not be the one we need.
1525 # Look for an earlier solution (if `fold` is 0), or a
1526 # later one (if `fold` is 1).
1527 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1528 b = local(u2) - u2
1529 if a == b:
1530 return u1
1531 else:
1532 b = t1 - u1
1533 assert a != b
1534 u2 = t - b
1535 t2 = local(u2)
1536 if t2 == t:
1537 return u2
1538 if t1 == t:
1539 return u1
1540 # We have found both offsets a and b, but neither t - a nor t - b is
1541 # a solution. This means t is in the gap.
1542 return (max, min)[self.fold](u1, u2)
1543
1544
Alexander Belopolskya4415142012-06-08 12:33:09 -04001545 def timestamp(self):
1546 "Return POSIX timestamp as float"
1547 if self._tzinfo is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001548 s = self._mktime()
1549 return s + self.microsecond / 1e6
Alexander Belopolskya4415142012-06-08 12:33:09 -04001550 else:
1551 return (self - _EPOCH).total_seconds()
1552
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001553 def utctimetuple(self):
1554 "Return UTC time tuple compatible with time.gmtime()."
1555 offset = self.utcoffset()
1556 if offset:
1557 self -= offset
1558 y, m, d = self.year, self.month, self.day
1559 hh, mm, ss = self.hour, self.minute, self.second
1560 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1561
1562 def date(self):
1563 "Return the date part."
1564 return date(self._year, self._month, self._day)
1565
1566 def time(self):
1567 "Return the time part, with tzinfo None."
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001568 return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001569
1570 def timetz(self):
1571 "Return the time part, with same tzinfo."
1572 return time(self.hour, self.minute, self.second, self.microsecond,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001573 self._tzinfo, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001574
1575 def replace(self, year=None, month=None, day=None, hour=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001576 minute=None, second=None, microsecond=None, tzinfo=True,
1577 *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001578 """Return a new datetime with new values for the specified fields."""
1579 if year is None:
1580 year = self.year
1581 if month is None:
1582 month = self.month
1583 if day is None:
1584 day = self.day
1585 if hour is None:
1586 hour = self.hour
1587 if minute is None:
1588 minute = self.minute
1589 if second is None:
1590 second = self.second
1591 if microsecond is None:
1592 microsecond = self.microsecond
1593 if tzinfo is True:
1594 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001595 if fold is None:
1596 fold = self.fold
1597 return datetime(year, month, day, hour, minute, second,
1598 microsecond, tzinfo, fold=fold)
1599
1600 def _local_timezone(self):
1601 if self.tzinfo is None:
1602 ts = self._mktime()
1603 else:
1604 ts = (self - _EPOCH) // timedelta(seconds=1)
1605 localtm = _time.localtime(ts)
1606 local = datetime(*localtm[:6])
1607 try:
1608 # Extract TZ data if available
1609 gmtoff = localtm.tm_gmtoff
1610 zone = localtm.tm_zone
1611 except AttributeError:
1612 delta = local - datetime(*_time.gmtime(ts)[:6])
1613 zone = _time.strftime('%Z', localtm)
1614 tz = timezone(delta, zone)
1615 else:
1616 tz = timezone(timedelta(seconds=gmtoff), zone)
1617 return tz
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001618
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001619 def astimezone(self, tz=None):
1620 if tz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001621 tz = self._local_timezone()
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001622 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001623 raise TypeError("tz argument must be an instance of tzinfo")
1624
1625 mytz = self.tzinfo
1626 if mytz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001627 mytz = self._local_timezone()
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001628
1629 if tz is mytz:
1630 return self
1631
1632 # Convert self to UTC, and attach the new time zone object.
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001633 myoffset = mytz.utcoffset(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001634 if myoffset is None:
1635 raise ValueError("astimezone() requires an aware datetime")
1636 utc = (self - myoffset).replace(tzinfo=tz)
1637
1638 # Convert from UTC to tz's local time.
1639 return tz.fromutc(utc)
1640
1641 # Ways to produce a string.
1642
1643 def ctime(self):
1644 "Return ctime() style string."
1645 weekday = self.toordinal() % 7 or 7
1646 return "%s %s %2d %02d:%02d:%02d %04d" % (
1647 _DAYNAMES[weekday],
1648 _MONTHNAMES[self._month],
1649 self._day,
1650 self._hour, self._minute, self._second,
1651 self._year)
1652
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001653 def isoformat(self, sep='T', timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001654 """Return the time formatted according to ISO.
1655
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001656 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1657 By default, the fractional part is omitted if self.microsecond == 0.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001658
1659 If self.tzinfo is not None, the UTC offset is also attached, giving
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001660 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001661
1662 Optional argument sep specifies the separator between date and
1663 time, default 'T'.
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001664
1665 The optional argument timespec specifies the number of additional
1666 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001667 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001668 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1669 _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001670 self._microsecond, timespec))
1671
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001672 off = self.utcoffset()
1673 if off is not None:
1674 if off.days < 0:
1675 sign = "-"
1676 off = -off
1677 else:
1678 sign = "+"
1679 hh, mm = divmod(off, timedelta(hours=1))
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001680 mm, ss = divmod(mm, timedelta(minutes=1))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001681 s += "%s%02d:%02d" % (sign, hh, mm)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001682 if ss:
1683 assert not ss.microseconds
1684 s += ":%02d" % ss.seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001685 return s
1686
1687 def __repr__(self):
1688 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001689 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001690 self._hour, self._minute, self._second, self._microsecond]
1691 if L[-1] == 0:
1692 del L[-1]
1693 if L[-1] == 0:
1694 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001695 s = "%s.%s(%s)" % (self.__class__.__module__,
1696 self.__class__.__qualname__,
1697 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001698 if self._tzinfo is not None:
1699 assert s[-1:] == ")"
1700 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001701 if self._fold:
1702 assert s[-1:] == ")"
1703 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001704 return s
1705
1706 def __str__(self):
1707 "Convert to string, for str()."
1708 return self.isoformat(sep=' ')
1709
1710 @classmethod
1711 def strptime(cls, date_string, format):
1712 'string, format -> new datetime parsed from a string (like time.strptime()).'
1713 import _strptime
1714 return _strptime._strptime_datetime(cls, date_string, format)
1715
1716 def utcoffset(self):
1717 """Return the timezone offset in minutes east of UTC (negative west of
1718 UTC)."""
1719 if self._tzinfo is None:
1720 return None
1721 offset = self._tzinfo.utcoffset(self)
1722 _check_utc_offset("utcoffset", offset)
1723 return offset
1724
1725 def tzname(self):
1726 """Return the timezone name.
1727
1728 Note that the name is 100% informational -- there's no requirement that
1729 it mean anything in particular. For example, "GMT", "UTC", "-500",
1730 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1731 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001732 if self._tzinfo is None:
1733 return None
1734 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001735 _check_tzname(name)
1736 return name
1737
1738 def dst(self):
1739 """Return 0 if DST is not in effect, or the DST offset (in minutes
1740 eastward) if DST is in effect.
1741
1742 This is purely informational; the DST offset has already been added to
1743 the UTC offset returned by utcoffset() if applicable, so there's no
1744 need to consult dst() unless you're interested in displaying the DST
1745 info.
1746 """
1747 if self._tzinfo is None:
1748 return None
1749 offset = self._tzinfo.dst(self)
1750 _check_utc_offset("dst", offset)
1751 return offset
1752
1753 # Comparisons of datetime objects with other.
1754
1755 def __eq__(self, other):
1756 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001757 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001758 elif not isinstance(other, date):
1759 return NotImplemented
1760 else:
1761 return False
1762
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001763 def __le__(self, other):
1764 if isinstance(other, datetime):
1765 return self._cmp(other) <= 0
1766 elif not isinstance(other, date):
1767 return NotImplemented
1768 else:
1769 _cmperror(self, other)
1770
1771 def __lt__(self, other):
1772 if isinstance(other, datetime):
1773 return self._cmp(other) < 0
1774 elif not isinstance(other, date):
1775 return NotImplemented
1776 else:
1777 _cmperror(self, other)
1778
1779 def __ge__(self, other):
1780 if isinstance(other, datetime):
1781 return self._cmp(other) >= 0
1782 elif not isinstance(other, date):
1783 return NotImplemented
1784 else:
1785 _cmperror(self, other)
1786
1787 def __gt__(self, other):
1788 if isinstance(other, datetime):
1789 return self._cmp(other) > 0
1790 elif not isinstance(other, date):
1791 return NotImplemented
1792 else:
1793 _cmperror(self, other)
1794
Alexander Belopolsky08313822012-06-15 20:19:47 -04001795 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001796 assert isinstance(other, datetime)
1797 mytz = self._tzinfo
1798 ottz = other._tzinfo
1799 myoff = otoff = None
1800
1801 if mytz is ottz:
1802 base_compare = True
1803 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04001804 myoff = self.utcoffset()
1805 otoff = other.utcoffset()
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001806 # Assume that allow_mixed means that we are called from __eq__
1807 if allow_mixed:
1808 if myoff != self.replace(fold=not self.fold).utcoffset():
1809 return 2
1810 if otoff != other.replace(fold=not other.fold).utcoffset():
1811 return 2
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001812 base_compare = myoff == otoff
1813
1814 if base_compare:
1815 return _cmp((self._year, self._month, self._day,
1816 self._hour, self._minute, self._second,
1817 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001818 (other._year, other._month, other._day,
1819 other._hour, other._minute, other._second,
1820 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001821 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001822 if allow_mixed:
1823 return 2 # arbitrary non-zero value
1824 else:
1825 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001826 # XXX What follows could be done more efficiently...
1827 diff = self - other # this will take offsets into account
1828 if diff.days < 0:
1829 return -1
1830 return diff and 1 or 0
1831
1832 def __add__(self, other):
1833 "Add a datetime and a timedelta."
1834 if not isinstance(other, timedelta):
1835 return NotImplemented
1836 delta = timedelta(self.toordinal(),
1837 hours=self._hour,
1838 minutes=self._minute,
1839 seconds=self._second,
1840 microseconds=self._microsecond)
1841 delta += other
1842 hour, rem = divmod(delta.seconds, 3600)
1843 minute, second = divmod(rem, 60)
1844 if 0 < delta.days <= _MAXORDINAL:
1845 return datetime.combine(date.fromordinal(delta.days),
1846 time(hour, minute, second,
1847 delta.microseconds,
1848 tzinfo=self._tzinfo))
1849 raise OverflowError("result out of range")
1850
1851 __radd__ = __add__
1852
1853 def __sub__(self, other):
1854 "Subtract two datetimes, or a datetime and a timedelta."
1855 if not isinstance(other, datetime):
1856 if isinstance(other, timedelta):
1857 return self + -other
1858 return NotImplemented
1859
1860 days1 = self.toordinal()
1861 days2 = other.toordinal()
1862 secs1 = self._second + self._minute * 60 + self._hour * 3600
1863 secs2 = other._second + other._minute * 60 + other._hour * 3600
1864 base = timedelta(days1 - days2,
1865 secs1 - secs2,
1866 self._microsecond - other._microsecond)
1867 if self._tzinfo is other._tzinfo:
1868 return base
1869 myoff = self.utcoffset()
1870 otoff = other.utcoffset()
1871 if myoff == otoff:
1872 return base
1873 if myoff is None or otoff is None:
1874 raise TypeError("cannot mix naive and timezone-aware time")
1875 return base + otoff - myoff
1876
1877 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001878 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001879 if self.fold:
1880 t = self.replace(fold=0)
1881 else:
1882 t = self
1883 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001884 if tzoff is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001885 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001886 else:
1887 days = _ymd2ord(self.year, self.month, self.day)
1888 seconds = self.hour * 3600 + self.minute * 60 + self.second
1889 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
1890 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001891
1892 # Pickle support.
1893
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001894 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001895 yhi, ylo = divmod(self._year, 256)
1896 us2, us3 = divmod(self._microsecond, 256)
1897 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001898 m = self._month
1899 if self._fold and protocol > 3:
1900 m += 128
1901 basestate = bytes([yhi, ylo, m, self._day,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001902 self._hour, self._minute, self._second,
1903 us1, us2, us3])
1904 if self._tzinfo is None:
1905 return (basestate,)
1906 else:
1907 return (basestate, self._tzinfo)
1908
1909 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001910 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1911 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001912 (yhi, ylo, m, self._day, self._hour,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001913 self._minute, self._second, us1, us2, us3) = string
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001914 if m > 127:
1915 self._fold = 1
1916 self._month = m - 128
1917 else:
1918 self._fold = 0
1919 self._month = m
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001920 self._year = yhi * 256 + ylo
1921 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001922 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001923
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001924 def __reduce_ex__(self, protocol):
1925 return (self.__class__, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001926
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001927 def __reduce__(self):
1928 return self.__reduce_ex__(2)
1929
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001930
1931datetime.min = datetime(1, 1, 1)
1932datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1933datetime.resolution = timedelta(microseconds=1)
1934
1935
1936def _isoweek1monday(year):
1937 # Helper to calculate the day number of the Monday starting week 1
1938 # XXX This could be done more efficiently
1939 THURSDAY = 3
1940 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001941 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001942 week1monday = firstday - firstweekday
1943 if firstweekday > THURSDAY:
1944 week1monday += 7
1945 return week1monday
1946
1947class timezone(tzinfo):
1948 __slots__ = '_offset', '_name'
1949
1950 # Sentinel value to disallow None
1951 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001952 def __new__(cls, offset, name=_Omitted):
1953 if not isinstance(offset, timedelta):
1954 raise TypeError("offset must be a timedelta")
1955 if name is cls._Omitted:
1956 if not offset:
1957 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001958 name = None
1959 elif not isinstance(name, str):
1960 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001961 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001962 raise ValueError("offset must be a timedelta "
1963 "strictly between -timedelta(hours=24) and "
1964 "timedelta(hours=24).")
1965 if (offset.microseconds != 0 or offset.seconds % 60 != 0):
1966 raise ValueError("offset must be a timedelta "
1967 "representing a whole number of minutes")
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))
2056 minutes = rest // timedelta(minutes=1)
2057 return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes)
2058
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002059timezone.utc = timezone._create(timedelta(0))
2060timezone.min = timezone._create(timezone._minoffset)
2061timezone.max = timezone._create(timezone._maxoffset)
Alexander Belopolskya4415142012-06-08 12:33:09 -04002062_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002063
Victor Stinner765531d2013-03-26 01:11:54 +01002064# Some time zone algebra. For a datetime x, let
2065# x.n = x stripped of its timezone -- its naive time.
2066# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2067# return None
2068# x.d = x.dst(), and assuming that doesn't raise an exception or
2069# return None
2070# x.s = x's standard offset, x.o - x.d
2071#
2072# Now some derived rules, where k is a duration (timedelta).
2073#
2074# 1. x.o = x.s + x.d
2075# This follows from the definition of x.s.
2076#
2077# 2. If x and y have the same tzinfo member, x.s = y.s.
2078# This is actually a requirement, an assumption we need to make about
2079# sane tzinfo classes.
2080#
2081# 3. The naive UTC time corresponding to x is x.n - x.o.
2082# This is again a requirement for a sane tzinfo class.
2083#
2084# 4. (x+k).s = x.s
2085# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
2086#
2087# 5. (x+k).n = x.n + k
2088# Again follows from how arithmetic is defined.
2089#
2090# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
2091# (meaning that the various tzinfo methods exist, and don't blow up or return
2092# None when called).
2093#
2094# The function wants to return a datetime y with timezone tz, equivalent to x.
2095# x is already in UTC.
2096#
2097# By #3, we want
2098#
2099# y.n - y.o = x.n [1]
2100#
2101# The algorithm starts by attaching tz to x.n, and calling that y. So
2102# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
2103# becomes true; in effect, we want to solve [2] for k:
2104#
2105# (y+k).n - (y+k).o = x.n [2]
2106#
2107# By #1, this is the same as
2108#
2109# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
2110#
2111# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2112# Substituting that into [3],
2113#
2114# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2115# k - (y+k).s - (y+k).d = 0; rearranging,
2116# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2117# k = y.s - (y+k).d
2118#
2119# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2120# approximate k by ignoring the (y+k).d term at first. Note that k can't be
2121# very large, since all offset-returning methods return a duration of magnitude
2122# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
2123# be 0, so ignoring it has no consequence then.
2124#
2125# In any case, the new value is
2126#
2127# z = y + y.s [4]
2128#
2129# It's helpful to step back at look at [4] from a higher level: it's simply
2130# mapping from UTC to tz's standard time.
2131#
2132# At this point, if
2133#
2134# z.n - z.o = x.n [5]
2135#
2136# we have an equivalent time, and are almost done. The insecurity here is
2137# at the start of daylight time. Picture US Eastern for concreteness. The wall
2138# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2139# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2140# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2141# on the day DST starts. We want to return the 1:MM EST spelling because that's
2142# the only spelling that makes sense on the local wall clock.
2143#
2144# In fact, if [5] holds at this point, we do have the standard-time spelling,
2145# but that takes a bit of proof. We first prove a stronger result. What's the
2146# difference between the LHS and RHS of [5]? Let
2147#
2148# diff = x.n - (z.n - z.o) [6]
2149#
2150# Now
2151# z.n = by [4]
2152# (y + y.s).n = by #5
2153# y.n + y.s = since y.n = x.n
2154# x.n + y.s = since z and y are have the same tzinfo member,
2155# y.s = z.s by #2
2156# x.n + z.s
2157#
2158# Plugging that back into [6] gives
2159#
2160# diff =
2161# x.n - ((x.n + z.s) - z.o) = expanding
2162# x.n - x.n - z.s + z.o = cancelling
2163# - z.s + z.o = by #2
2164# z.d
2165#
2166# So diff = z.d.
2167#
2168# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2169# spelling we wanted in the endcase described above. We're done. Contrarily,
2170# if z.d = 0, then we have a UTC equivalent, and are also done.
2171#
2172# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2173# add to z (in effect, z is in tz's standard time, and we need to shift the
2174# local clock into tz's daylight time).
2175#
2176# Let
2177#
2178# z' = z + z.d = z + diff [7]
2179#
2180# and we can again ask whether
2181#
2182# z'.n - z'.o = x.n [8]
2183#
2184# If so, we're done. If not, the tzinfo class is insane, according to the
2185# assumptions we've made. This also requires a bit of proof. As before, let's
2186# compute the difference between the LHS and RHS of [8] (and skipping some of
2187# the justifications for the kinds of substitutions we've done several times
2188# already):
2189#
2190# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2191# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2192# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2193# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2194# - z.n + z.n - z.o + z'.o = cancel z.n
2195# - z.o + z'.o = #1 twice
2196# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2197# z'.d - z.d
2198#
2199# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2200# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2201# return z', not bothering to compute z'.d.
2202#
2203# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2204# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2205# would have to change the result dst() returns: we start in DST, and moving
2206# a little further into it takes us out of DST.
2207#
2208# There isn't a sane case where this can happen. The closest it gets is at
2209# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2210# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2211# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2212# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2213# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2214# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2215# standard time. Since that's what the local clock *does*, we want to map both
2216# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2217# in local time, but so it goes -- it's the way the local clock works.
2218#
2219# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2220# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2221# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2222# (correctly) concludes that z' is not UTC-equivalent to x.
2223#
2224# Because we know z.d said z was in daylight time (else [5] would have held and
2225# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2226# and we have stopped then), and there are only 2 possible values dst() can
2227# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2228# but the reasoning doesn't depend on the example -- it depends on there being
2229# two possible dst() outcomes, one zero and the other non-zero). Therefore
2230# z' must be in standard time, and is the spelling we want in this case.
2231#
2232# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2233# concerned (because it takes z' as being in standard time rather than the
2234# daylight time we intend here), but returning it gives the real-life "local
2235# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2236# tz.
2237#
2238# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2239# the 1:MM standard time spelling we want.
2240#
2241# So how can this break? One of the assumptions must be violated. Two
2242# possibilities:
2243#
2244# 1) [2] effectively says that y.s is invariant across all y belong to a given
2245# time zone. This isn't true if, for political reasons or continental drift,
2246# a region decides to change its base offset from UTC.
2247#
2248# 2) There may be versions of "double daylight" time where the tail end of
2249# the analysis gives up a step too early. I haven't thought about that
2250# enough to say.
2251#
2252# In any case, it's clear that the default fromutc() is strong enough to handle
2253# "almost all" time zones: so long as the standard offset is invariant, it
2254# doesn't matter if daylight time transition points change from year to year, or
2255# if daylight time is skipped in some years; it doesn't matter how large or
2256# small dst() may get within its bounds; and it doesn't even matter if some
2257# perverse time zone returns a negative dst()). So a breaking case must be
2258# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002259
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002260try:
2261 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002262except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002263 pass
2264else:
2265 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002266 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2267 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2268 _check_date_fields, _check_int_field, _check_time_fields,
2269 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2270 _date_class, _days_before_month, _days_before_year, _days_in_month,
2271 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd,
Utkarsh Upadhyay287c5592017-07-21 02:14:54 +02002272 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord,
2273 _divide_and_round)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002274 # XXX Since import * above excludes names that start with _,
2275 # docstring does not get overwritten. In the future, it may be
2276 # appropriate to maintain a single module level docstring and
2277 # remove the following line.
2278 from _datetime import __doc__