blob: 5d5579c1c6f4be483d36057bbd08abfb79c8e6b5 [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):
457 if self._microseconds:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300458 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
459 self.__class__.__qualname__,
460 self._days,
461 self._seconds,
462 self._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000463 if self._seconds:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300464 return "%s.%s(%d, %d)" % (self.__class__.__module__,
465 self.__class__.__qualname__,
466 self._days,
467 self._seconds)
468 return "%s.%s(%d)" % (self.__class__.__module__,
469 self.__class__.__qualname__,
470 self._days)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000471
472 def __str__(self):
473 mm, ss = divmod(self._seconds, 60)
474 hh, mm = divmod(mm, 60)
475 s = "%d:%02d:%02d" % (hh, mm, ss)
476 if self._days:
477 def plural(n):
478 return n, abs(n) != 1 and "s" or ""
479 s = ("%d day%s, " % plural(self._days)) + s
480 if self._microseconds:
481 s = s + ".%06d" % self._microseconds
482 return s
483
484 def total_seconds(self):
485 """Total seconds in the duration."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400486 return ((self.days * 86400 + self.seconds) * 10**6 +
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000487 self.microseconds) / 10**6
488
489 # Read-only field accessors
490 @property
491 def days(self):
492 """days"""
493 return self._days
494
495 @property
496 def seconds(self):
497 """seconds"""
498 return self._seconds
499
500 @property
501 def microseconds(self):
502 """microseconds"""
503 return self._microseconds
504
505 def __add__(self, other):
506 if isinstance(other, timedelta):
507 # for CPython compatibility, we cannot use
508 # our __class__ here, but need a real timedelta
509 return timedelta(self._days + other._days,
510 self._seconds + other._seconds,
511 self._microseconds + other._microseconds)
512 return NotImplemented
513
514 __radd__ = __add__
515
516 def __sub__(self, other):
517 if isinstance(other, timedelta):
Alexander Belopolskyb6f5ec72011-04-05 20:07:38 -0400518 # for CPython compatibility, we cannot use
519 # our __class__ here, but need a real timedelta
520 return timedelta(self._days - other._days,
521 self._seconds - other._seconds,
522 self._microseconds - other._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000523 return NotImplemented
524
525 def __rsub__(self, other):
526 if isinstance(other, timedelta):
527 return -self + other
528 return NotImplemented
529
530 def __neg__(self):
531 # for CPython compatibility, we cannot use
532 # our __class__ here, but need a real timedelta
533 return timedelta(-self._days,
534 -self._seconds,
535 -self._microseconds)
536
537 def __pos__(self):
538 return self
539
540 def __abs__(self):
541 if self._days < 0:
542 return -self
543 else:
544 return self
545
546 def __mul__(self, other):
547 if isinstance(other, int):
548 # for CPython compatibility, we cannot use
549 # our __class__ here, but need a real timedelta
550 return timedelta(self._days * other,
551 self._seconds * other,
552 self._microseconds * other)
553 if isinstance(other, float):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500554 usec = self._to_microseconds()
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000555 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500556 return timedelta(0, 0, _divide_and_round(usec * a, b))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000557 return NotImplemented
558
559 __rmul__ = __mul__
560
561 def _to_microseconds(self):
562 return ((self._days * (24*3600) + self._seconds) * 1000000 +
563 self._microseconds)
564
565 def __floordiv__(self, other):
566 if not isinstance(other, (int, timedelta)):
567 return NotImplemented
568 usec = self._to_microseconds()
569 if isinstance(other, timedelta):
570 return usec // other._to_microseconds()
571 if isinstance(other, int):
572 return timedelta(0, 0, usec // other)
573
574 def __truediv__(self, other):
575 if not isinstance(other, (int, float, timedelta)):
576 return NotImplemented
577 usec = self._to_microseconds()
578 if isinstance(other, timedelta):
579 return usec / other._to_microseconds()
580 if isinstance(other, int):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500581 return timedelta(0, 0, _divide_and_round(usec, other))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000582 if isinstance(other, float):
583 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500584 return timedelta(0, 0, _divide_and_round(b * usec, a))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000585
586 def __mod__(self, other):
587 if isinstance(other, timedelta):
588 r = self._to_microseconds() % other._to_microseconds()
589 return timedelta(0, 0, r)
590 return NotImplemented
591
592 def __divmod__(self, other):
593 if isinstance(other, timedelta):
594 q, r = divmod(self._to_microseconds(),
595 other._to_microseconds())
596 return q, timedelta(0, 0, r)
597 return NotImplemented
598
599 # Comparisons of timedelta objects with other.
600
601 def __eq__(self, other):
602 if isinstance(other, timedelta):
603 return self._cmp(other) == 0
604 else:
605 return False
606
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000607 def __le__(self, other):
608 if isinstance(other, timedelta):
609 return self._cmp(other) <= 0
610 else:
611 _cmperror(self, other)
612
613 def __lt__(self, other):
614 if isinstance(other, timedelta):
615 return self._cmp(other) < 0
616 else:
617 _cmperror(self, other)
618
619 def __ge__(self, other):
620 if isinstance(other, timedelta):
621 return self._cmp(other) >= 0
622 else:
623 _cmperror(self, other)
624
625 def __gt__(self, other):
626 if isinstance(other, timedelta):
627 return self._cmp(other) > 0
628 else:
629 _cmperror(self, other)
630
631 def _cmp(self, other):
632 assert isinstance(other, timedelta)
633 return _cmp(self._getstate(), other._getstate())
634
635 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400636 if self._hashcode == -1:
637 self._hashcode = hash(self._getstate())
638 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000639
640 def __bool__(self):
641 return (self._days != 0 or
642 self._seconds != 0 or
643 self._microseconds != 0)
644
645 # Pickle support.
646
647 def _getstate(self):
648 return (self._days, self._seconds, self._microseconds)
649
650 def __reduce__(self):
651 return (self.__class__, self._getstate())
652
653timedelta.min = timedelta(-999999999)
654timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
655 microseconds=999999)
656timedelta.resolution = timedelta(microseconds=1)
657
658class date:
659 """Concrete date type.
660
661 Constructors:
662
663 __new__()
664 fromtimestamp()
665 today()
666 fromordinal()
667
668 Operators:
669
670 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200671 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000672 __add__, __radd__, __sub__ (add/radd only with timedelta arg)
673
674 Methods:
675
676 timetuple()
677 toordinal()
678 weekday()
679 isoweekday(), isocalendar(), isoformat()
680 ctime()
681 strftime()
682
683 Properties (readonly):
684 year, month, day
685 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400686 __slots__ = '_year', '_month', '_day', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000687
688 def __new__(cls, year, month=None, day=None):
689 """Constructor.
690
691 Arguments:
692
693 year, month, day (required, base 1)
694 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400695 if month is None and isinstance(year, bytes) and len(year) == 4 and \
696 1 <= year[2] <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000697 # Pickle support
698 self = object.__new__(cls)
699 self.__setstate(year)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400700 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000701 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400702 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000703 self = object.__new__(cls)
704 self._year = year
705 self._month = month
706 self._day = day
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400707 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000708 return self
709
710 # Additional constructors
711
712 @classmethod
713 def fromtimestamp(cls, t):
714 "Construct a date from a POSIX timestamp (like time.time())."
715 y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
716 return cls(y, m, d)
717
718 @classmethod
719 def today(cls):
720 "Construct a date from time.time()."
721 t = _time.time()
722 return cls.fromtimestamp(t)
723
724 @classmethod
725 def fromordinal(cls, n):
Martin Pantereb995702016-07-28 01:11:04 +0000726 """Construct a date from a proleptic Gregorian ordinal.
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000727
728 January 1 of year 1 is day 1. Only the year, month and day are
729 non-zero in the result.
730 """
731 y, m, d = _ord2ymd(n)
732 return cls(y, m, d)
733
734 # Conversions to string
735
736 def __repr__(self):
737 """Convert to formal string, for repr().
738
739 >>> dt = datetime(2010, 1, 1)
740 >>> repr(dt)
741 'datetime.datetime(2010, 1, 1, 0, 0)'
742
743 >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
744 >>> repr(dt)
745 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
746 """
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300747 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
748 self.__class__.__qualname__,
749 self._year,
750 self._month,
751 self._day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000752 # XXX These shouldn't depend on time.localtime(), because that
753 # clips the usable dates to [1970 .. 2038). At least ctime() is
754 # easily done without using strftime() -- that's better too because
755 # strftime("%c", ...) is locale specific.
756
757
758 def ctime(self):
759 "Return ctime() style string."
760 weekday = self.toordinal() % 7 or 7
761 return "%s %s %2d 00:00:00 %04d" % (
762 _DAYNAMES[weekday],
763 _MONTHNAMES[self._month],
764 self._day, self._year)
765
766 def strftime(self, fmt):
767 "Format using strftime()."
768 return _wrap_strftime(self, fmt, self.timetuple())
769
770 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400771 if not isinstance(fmt, str):
772 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000773 if len(fmt) != 0:
774 return self.strftime(fmt)
775 return str(self)
776
777 def isoformat(self):
778 """Return the date formatted according to ISO.
779
780 This is 'YYYY-MM-DD'.
781
782 References:
783 - http://www.w3.org/TR/NOTE-datetime
784 - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
785 """
786 return "%04d-%02d-%02d" % (self._year, self._month, self._day)
787
788 __str__ = isoformat
789
790 # Read-only field accessors
791 @property
792 def year(self):
793 """year (1-9999)"""
794 return self._year
795
796 @property
797 def month(self):
798 """month (1-12)"""
799 return self._month
800
801 @property
802 def day(self):
803 """day (1-31)"""
804 return self._day
805
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200806 # Standard conversions, __eq__, __le__, __lt__, __ge__, __gt__,
807 # __hash__ (and helpers)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000808
809 def timetuple(self):
810 "Return local time tuple compatible with time.localtime()."
811 return _build_struct_time(self._year, self._month, self._day,
812 0, 0, 0, -1)
813
814 def toordinal(self):
815 """Return proleptic Gregorian ordinal for the year, month and day.
816
817 January 1 of year 1 is day 1. Only the year, month and day values
818 contribute to the result.
819 """
820 return _ymd2ord(self._year, self._month, self._day)
821
822 def replace(self, year=None, month=None, day=None):
823 """Return a new date with new values for the specified fields."""
824 if year is None:
825 year = self._year
826 if month is None:
827 month = self._month
828 if day is None:
829 day = self._day
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000830 return date(year, month, day)
831
832 # Comparisons of date objects with other.
833
834 def __eq__(self, other):
835 if isinstance(other, date):
836 return self._cmp(other) == 0
837 return NotImplemented
838
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000839 def __le__(self, other):
840 if isinstance(other, date):
841 return self._cmp(other) <= 0
842 return NotImplemented
843
844 def __lt__(self, other):
845 if isinstance(other, date):
846 return self._cmp(other) < 0
847 return NotImplemented
848
849 def __ge__(self, other):
850 if isinstance(other, date):
851 return self._cmp(other) >= 0
852 return NotImplemented
853
854 def __gt__(self, other):
855 if isinstance(other, date):
856 return self._cmp(other) > 0
857 return NotImplemented
858
859 def _cmp(self, other):
860 assert isinstance(other, date)
861 y, m, d = self._year, self._month, self._day
862 y2, m2, d2 = other._year, other._month, other._day
863 return _cmp((y, m, d), (y2, m2, d2))
864
865 def __hash__(self):
866 "Hash."
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400867 if self._hashcode == -1:
868 self._hashcode = hash(self._getstate())
869 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000870
871 # Computations
872
873 def __add__(self, other):
874 "Add a date to a timedelta."
875 if isinstance(other, timedelta):
876 o = self.toordinal() + other.days
877 if 0 < o <= _MAXORDINAL:
878 return date.fromordinal(o)
879 raise OverflowError("result out of range")
880 return NotImplemented
881
882 __radd__ = __add__
883
884 def __sub__(self, other):
885 """Subtract two dates, or a date and a timedelta."""
886 if isinstance(other, timedelta):
887 return self + timedelta(-other.days)
888 if isinstance(other, date):
889 days1 = self.toordinal()
890 days2 = other.toordinal()
891 return timedelta(days1 - days2)
892 return NotImplemented
893
894 def weekday(self):
895 "Return day of the week, where Monday == 0 ... Sunday == 6."
896 return (self.toordinal() + 6) % 7
897
898 # Day-of-the-week and week-of-the-year, according to ISO
899
900 def isoweekday(self):
901 "Return day of the week, where Monday == 1 ... Sunday == 7."
902 # 1-Jan-0001 is a Monday
903 return self.toordinal() % 7 or 7
904
905 def isocalendar(self):
906 """Return a 3-tuple containing ISO year, week number, and weekday.
907
908 The first ISO week of the year is the (Mon-Sun) week
909 containing the year's first Thursday; everything else derives
910 from that.
911
912 The first week is 1; Monday is 1 ... Sunday is 7.
913
914 ISO calendar algorithm taken from
915 http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
Brett Cannon07b954d2016-01-15 09:53:51 -0800916 (used with permission)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000917 """
918 year = self._year
919 week1monday = _isoweek1monday(year)
920 today = _ymd2ord(self._year, self._month, self._day)
921 # Internally, week and day have origin 0
922 week, day = divmod(today - week1monday, 7)
923 if week < 0:
924 year -= 1
925 week1monday = _isoweek1monday(year)
926 week, day = divmod(today - week1monday, 7)
927 elif week >= 52:
928 if today >= _isoweek1monday(year+1):
929 year += 1
930 week = 0
931 return year, week+1, day+1
932
933 # Pickle support.
934
Serhiy Storchaka546ce652016-11-22 00:29:42 +0200935 def _getstate(self):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000936 yhi, ylo = divmod(self._year, 256)
937 return bytes([yhi, ylo, self._month, self._day]),
938
939 def __setstate(self, string):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000940 yhi, ylo, self._month, self._day = string
941 self._year = yhi * 256 + ylo
942
Serhiy Storchaka546ce652016-11-22 00:29:42 +0200943 def __reduce__(self):
944 return (self.__class__, self._getstate())
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000945
946_date_class = date # so functions w/ args named "date" can get at the class
947
948date.min = date(1, 1, 1)
949date.max = date(9999, 12, 31)
950date.resolution = timedelta(days=1)
951
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -0400952
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000953class tzinfo:
954 """Abstract base class for time zone info classes.
955
956 Subclasses must override the name(), utcoffset() and dst() methods.
957 """
958 __slots__ = ()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400959
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000960 def tzname(self, dt):
961 "datetime -> string name of time zone."
962 raise NotImplementedError("tzinfo subclass must override tzname()")
963
964 def utcoffset(self, dt):
965 "datetime -> minutes east of UTC (negative for west of UTC)"
966 raise NotImplementedError("tzinfo subclass must override utcoffset()")
967
968 def dst(self, dt):
969 """datetime -> DST offset in minutes east of UTC.
970
971 Return 0 if DST not in effect. utcoffset() must include the DST
972 offset.
973 """
974 raise NotImplementedError("tzinfo subclass must override dst()")
975
976 def fromutc(self, dt):
977 "datetime in UTC -> datetime in local time."
978
979 if not isinstance(dt, datetime):
980 raise TypeError("fromutc() requires a datetime argument")
981 if dt.tzinfo is not self:
982 raise ValueError("dt.tzinfo is not self")
983
984 dtoff = dt.utcoffset()
985 if dtoff is None:
986 raise ValueError("fromutc() requires a non-None utcoffset() "
987 "result")
988
989 # See the long comment block at the end of this file for an
990 # explanation of this algorithm.
991 dtdst = dt.dst()
992 if dtdst is None:
993 raise ValueError("fromutc() requires a non-None dst() result")
994 delta = dtoff - dtdst
995 if delta:
996 dt += delta
997 dtdst = dt.dst()
998 if dtdst is None:
999 raise ValueError("fromutc(): dt.dst gave inconsistent "
1000 "results; cannot convert")
1001 return dt + dtdst
1002
1003 # Pickle support.
1004
1005 def __reduce__(self):
1006 getinitargs = getattr(self, "__getinitargs__", None)
1007 if getinitargs:
1008 args = getinitargs()
1009 else:
1010 args = ()
1011 getstate = getattr(self, "__getstate__", None)
1012 if getstate:
1013 state = getstate()
1014 else:
1015 state = getattr(self, "__dict__", None) or None
1016 if state is None:
1017 return (self.__class__, args)
1018 else:
1019 return (self.__class__, args, state)
1020
1021_tzinfo_class = tzinfo
1022
1023class time:
1024 """Time with time zone.
1025
1026 Constructors:
1027
1028 __new__()
1029
1030 Operators:
1031
1032 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +02001033 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001034
1035 Methods:
1036
1037 strftime()
1038 isoformat()
1039 utcoffset()
1040 tzname()
1041 dst()
1042
1043 Properties (readonly):
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001044 hour, minute, second, microsecond, tzinfo, fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001045 """
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001046 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode', '_fold'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001047
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001048 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001049 """Constructor.
1050
1051 Arguments:
1052
1053 hour, minute (required)
1054 second, microsecond (default to zero)
1055 tzinfo (default to None)
Victor Stinner51b90d22017-01-04 12:01:16 +01001056 fold (keyword only, default to zero)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001057 """
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001058 if isinstance(hour, bytes) and len(hour) == 6 and hour[0]&0x7F < 24:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001059 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001060 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001061 self.__setstate(hour, minute or None)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001062 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001063 return self
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001064 hour, minute, second, microsecond, fold = _check_time_fields(
1065 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001066 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001067 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001068 self._hour = hour
1069 self._minute = minute
1070 self._second = second
1071 self._microsecond = microsecond
1072 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001073 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001074 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001075 return self
1076
1077 # Read-only field accessors
1078 @property
1079 def hour(self):
1080 """hour (0-23)"""
1081 return self._hour
1082
1083 @property
1084 def minute(self):
1085 """minute (0-59)"""
1086 return self._minute
1087
1088 @property
1089 def second(self):
1090 """second (0-59)"""
1091 return self._second
1092
1093 @property
1094 def microsecond(self):
1095 """microsecond (0-999999)"""
1096 return self._microsecond
1097
1098 @property
1099 def tzinfo(self):
1100 """timezone info object"""
1101 return self._tzinfo
1102
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001103 @property
1104 def fold(self):
1105 return self._fold
1106
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001107 # Standard conversions, __hash__ (and helpers)
1108
1109 # Comparisons of time objects with other.
1110
1111 def __eq__(self, other):
1112 if isinstance(other, time):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001113 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001114 else:
1115 return False
1116
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001117 def __le__(self, other):
1118 if isinstance(other, time):
1119 return self._cmp(other) <= 0
1120 else:
1121 _cmperror(self, other)
1122
1123 def __lt__(self, other):
1124 if isinstance(other, time):
1125 return self._cmp(other) < 0
1126 else:
1127 _cmperror(self, other)
1128
1129 def __ge__(self, other):
1130 if isinstance(other, time):
1131 return self._cmp(other) >= 0
1132 else:
1133 _cmperror(self, other)
1134
1135 def __gt__(self, other):
1136 if isinstance(other, time):
1137 return self._cmp(other) > 0
1138 else:
1139 _cmperror(self, other)
1140
Alexander Belopolsky08313822012-06-15 20:19:47 -04001141 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001142 assert isinstance(other, time)
1143 mytz = self._tzinfo
1144 ottz = other._tzinfo
1145 myoff = otoff = None
1146
1147 if mytz is ottz:
1148 base_compare = True
1149 else:
1150 myoff = self.utcoffset()
1151 otoff = other.utcoffset()
1152 base_compare = myoff == otoff
1153
1154 if base_compare:
1155 return _cmp((self._hour, self._minute, self._second,
1156 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001157 (other._hour, other._minute, other._second,
1158 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001159 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001160 if allow_mixed:
1161 return 2 # arbitrary non-zero value
1162 else:
1163 raise TypeError("cannot compare naive and aware times")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001164 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1165 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1166 return _cmp((myhhmm, self._second, self._microsecond),
1167 (othhmm, other._second, other._microsecond))
1168
1169 def __hash__(self):
1170 """Hash."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001171 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001172 if self.fold:
1173 t = self.replace(fold=0)
1174 else:
1175 t = self
1176 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001177 if not tzoff: # zero or None
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001178 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001179 else:
1180 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1181 timedelta(hours=1))
1182 assert not m % timedelta(minutes=1), "whole minute"
1183 m //= timedelta(minutes=1)
1184 if 0 <= h < 24:
1185 self._hashcode = hash(time(h, m, self.second, self.microsecond))
1186 else:
1187 self._hashcode = hash((h, m, self.second, self.microsecond))
1188 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001189
1190 # Conversion to string
1191
1192 def _tzstr(self, sep=":"):
1193 """Return formatted timezone offset (+xx:xx) or None."""
1194 off = self.utcoffset()
1195 if off is not None:
1196 if off.days < 0:
1197 sign = "-"
1198 off = -off
1199 else:
1200 sign = "+"
1201 hh, mm = divmod(off, timedelta(hours=1))
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001202 mm, ss = divmod(mm, timedelta(minutes=1))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001203 assert 0 <= hh < 24
1204 off = "%s%02d%s%02d" % (sign, hh, sep, mm)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001205 if ss:
1206 off += ':%02d' % ss.seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001207 return off
1208
1209 def __repr__(self):
1210 """Convert to formal string, for repr()."""
1211 if self._microsecond != 0:
1212 s = ", %d, %d" % (self._second, self._microsecond)
1213 elif self._second != 0:
1214 s = ", %d" % self._second
1215 else:
1216 s = ""
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001217 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1218 self.__class__.__qualname__,
1219 self._hour, self._minute, s)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001220 if self._tzinfo is not None:
1221 assert s[-1:] == ")"
1222 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001223 if self._fold:
1224 assert s[-1:] == ")"
1225 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001226 return s
1227
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001228 def isoformat(self, timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001229 """Return the time formatted according to ISO.
1230
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001231 The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional
1232 part is omitted if self.microsecond == 0.
1233
1234 The optional argument timespec specifies the number of additional
1235 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001236 """
1237 s = _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001238 self._microsecond, timespec)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001239 tz = self._tzstr()
1240 if tz:
1241 s += tz
1242 return s
1243
1244 __str__ = isoformat
1245
1246 def strftime(self, fmt):
1247 """Format using strftime(). The date part of the timestamp passed
1248 to underlying strftime should not be used.
1249 """
Alexander Belopolskyb8bb4662011-01-08 00:13:34 +00001250 # The year must be >= 1000 else Python's strftime implementation
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001251 # can raise a bogus exception.
1252 timetuple = (1900, 1, 1,
1253 self._hour, self._minute, self._second,
1254 0, 1, -1)
1255 return _wrap_strftime(self, fmt, timetuple)
1256
1257 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001258 if not isinstance(fmt, str):
1259 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001260 if len(fmt) != 0:
1261 return self.strftime(fmt)
1262 return str(self)
1263
1264 # Timezone functions
1265
1266 def utcoffset(self):
1267 """Return the timezone offset in minutes east of UTC (negative west of
1268 UTC)."""
1269 if self._tzinfo is None:
1270 return None
1271 offset = self._tzinfo.utcoffset(None)
1272 _check_utc_offset("utcoffset", offset)
1273 return offset
1274
1275 def tzname(self):
1276 """Return the timezone name.
1277
1278 Note that the name is 100% informational -- there's no requirement that
1279 it mean anything in particular. For example, "GMT", "UTC", "-500",
1280 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1281 """
1282 if self._tzinfo is None:
1283 return None
1284 name = self._tzinfo.tzname(None)
1285 _check_tzname(name)
1286 return name
1287
1288 def dst(self):
1289 """Return 0 if DST is not in effect, or the DST offset (in minutes
1290 eastward) if DST is in effect.
1291
1292 This is purely informational; the DST offset has already been added to
1293 the UTC offset returned by utcoffset() if applicable, so there's no
1294 need to consult dst() unless you're interested in displaying the DST
1295 info.
1296 """
1297 if self._tzinfo is None:
1298 return None
1299 offset = self._tzinfo.dst(None)
1300 _check_utc_offset("dst", offset)
1301 return offset
1302
1303 def replace(self, hour=None, minute=None, second=None, microsecond=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001304 tzinfo=True, *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001305 """Return a new time with new values for the specified fields."""
1306 if hour is None:
1307 hour = self.hour
1308 if minute is None:
1309 minute = self.minute
1310 if second is None:
1311 second = self.second
1312 if microsecond is None:
1313 microsecond = self.microsecond
1314 if tzinfo is True:
1315 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001316 if fold is None:
1317 fold = self._fold
1318 return time(hour, minute, second, microsecond, tzinfo, fold=fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001319
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001320 # Pickle support.
1321
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001322 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001323 us2, us3 = divmod(self._microsecond, 256)
1324 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001325 h = self._hour
1326 if self._fold and protocol > 3:
1327 h += 128
1328 basestate = bytes([h, self._minute, self._second,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001329 us1, us2, us3])
1330 if self._tzinfo is None:
1331 return (basestate,)
1332 else:
1333 return (basestate, self._tzinfo)
1334
1335 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001336 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1337 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001338 h, self._minute, self._second, us1, us2, us3 = string
1339 if h > 127:
1340 self._fold = 1
1341 self._hour = h - 128
1342 else:
1343 self._fold = 0
1344 self._hour = h
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001345 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001346 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001347
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001348 def __reduce_ex__(self, protocol):
1349 return (time, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001350
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001351 def __reduce__(self):
1352 return self.__reduce_ex__(2)
1353
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001354_time_class = time # so functions w/ args named "time" can get at the class
1355
1356time.min = time(0, 0, 0)
1357time.max = time(23, 59, 59, 999999)
1358time.resolution = timedelta(microseconds=1)
1359
1360class datetime(date):
1361 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1362
1363 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001364 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001365 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001366 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001367
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001368 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001369 microsecond=0, tzinfo=None, *, fold=0):
1370 if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2]&0x7F <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001371 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001372 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001373 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001374 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001375 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001376 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001377 hour, minute, second, microsecond, fold = _check_time_fields(
1378 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001379 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001380 self = object.__new__(cls)
1381 self._year = year
1382 self._month = month
1383 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001384 self._hour = hour
1385 self._minute = minute
1386 self._second = second
1387 self._microsecond = microsecond
1388 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001389 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001390 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001391 return self
1392
1393 # Read-only field accessors
1394 @property
1395 def hour(self):
1396 """hour (0-23)"""
1397 return self._hour
1398
1399 @property
1400 def minute(self):
1401 """minute (0-59)"""
1402 return self._minute
1403
1404 @property
1405 def second(self):
1406 """second (0-59)"""
1407 return self._second
1408
1409 @property
1410 def microsecond(self):
1411 """microsecond (0-999999)"""
1412 return self._microsecond
1413
1414 @property
1415 def tzinfo(self):
1416 """timezone info object"""
1417 return self._tzinfo
1418
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001419 @property
1420 def fold(self):
1421 return self._fold
1422
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001423 @classmethod
Victor Stinneradfefa52015-09-04 23:57:25 +02001424 def _fromtimestamp(cls, t, utc, tz):
1425 """Construct a datetime from a POSIX timestamp (like time.time()).
1426
1427 A timezone info object may be passed in as well.
1428 """
1429 frac, t = _math.modf(t)
Victor Stinner7667f582015-09-09 01:02:23 +02001430 us = round(frac * 1e6)
Victor Stinneradfefa52015-09-04 23:57:25 +02001431 if us >= 1000000:
1432 t += 1
1433 us -= 1000000
1434 elif us < 0:
1435 t -= 1
1436 us += 1000000
1437
1438 converter = _time.gmtime if utc else _time.localtime
1439 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1440 ss = min(ss, 59) # clamp out leap seconds if the platform has them
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001441 result = cls(y, m, d, hh, mm, ss, us, tz)
1442 if tz is None:
1443 # As of version 2015f max fold in IANA database is
1444 # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
1445 # Let's probe 24 hours in the past to detect a transition:
1446 max_fold_seconds = 24 * 3600
1447 y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1448 probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1449 trans = result - probe1 - timedelta(0, max_fold_seconds)
1450 if trans.days < 0:
1451 y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
1452 probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1453 if probe2 == result:
1454 result._fold = 1
1455 else:
1456 result = tz.fromutc(result)
1457 return result
Victor Stinneradfefa52015-09-04 23:57:25 +02001458
1459 @classmethod
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001460 def fromtimestamp(cls, t, tz=None):
1461 """Construct a datetime from a POSIX timestamp (like time.time()).
1462
1463 A timezone info object may be passed in as well.
1464 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001465 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001466
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001467 return cls._fromtimestamp(t, tz is not None, tz)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001468
1469 @classmethod
1470 def utcfromtimestamp(cls, t):
Alexander Belopolskye2e178e2015-03-01 14:52:07 -05001471 """Construct a naive UTC datetime from a POSIX timestamp."""
Victor Stinneradfefa52015-09-04 23:57:25 +02001472 return cls._fromtimestamp(t, True, None)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001473
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001474 @classmethod
1475 def now(cls, tz=None):
1476 "Construct a datetime from time.time() and optional time zone info."
1477 t = _time.time()
1478 return cls.fromtimestamp(t, tz)
1479
1480 @classmethod
1481 def utcnow(cls):
1482 "Construct a UTC datetime from time.time()."
1483 t = _time.time()
1484 return cls.utcfromtimestamp(t)
1485
1486 @classmethod
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001487 def combine(cls, date, time, tzinfo=True):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001488 "Construct a datetime from a given date and a given time."
1489 if not isinstance(date, _date_class):
1490 raise TypeError("date argument must be a date instance")
1491 if not isinstance(time, _time_class):
1492 raise TypeError("time argument must be a time instance")
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001493 if tzinfo is True:
1494 tzinfo = time.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001495 return cls(date.year, date.month, date.day,
1496 time.hour, time.minute, time.second, time.microsecond,
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001497 tzinfo, fold=time.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001498
1499 def timetuple(self):
1500 "Return local time tuple compatible with time.localtime()."
1501 dst = self.dst()
1502 if dst is None:
1503 dst = -1
1504 elif dst:
1505 dst = 1
1506 else:
1507 dst = 0
1508 return _build_struct_time(self.year, self.month, self.day,
1509 self.hour, self.minute, self.second,
1510 dst)
1511
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001512 def _mktime(self):
1513 """Return integer POSIX timestamp."""
1514 epoch = datetime(1970, 1, 1)
1515 max_fold_seconds = 24 * 3600
1516 t = (self - epoch) // timedelta(0, 1)
1517 def local(u):
1518 y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1519 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1520
1521 # Our goal is to solve t = local(u) for u.
1522 a = local(t) - t
1523 u1 = t - a
1524 t1 = local(u1)
1525 if t1 == t:
1526 # We found one solution, but it may not be the one we need.
1527 # Look for an earlier solution (if `fold` is 0), or a
1528 # later one (if `fold` is 1).
1529 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1530 b = local(u2) - u2
1531 if a == b:
1532 return u1
1533 else:
1534 b = t1 - u1
1535 assert a != b
1536 u2 = t - b
1537 t2 = local(u2)
1538 if t2 == t:
1539 return u2
1540 if t1 == t:
1541 return u1
1542 # We have found both offsets a and b, but neither t - a nor t - b is
1543 # a solution. This means t is in the gap.
1544 return (max, min)[self.fold](u1, u2)
1545
1546
Alexander Belopolskya4415142012-06-08 12:33:09 -04001547 def timestamp(self):
1548 "Return POSIX timestamp as float"
1549 if self._tzinfo is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001550 s = self._mktime()
1551 return s + self.microsecond / 1e6
Alexander Belopolskya4415142012-06-08 12:33:09 -04001552 else:
1553 return (self - _EPOCH).total_seconds()
1554
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001555 def utctimetuple(self):
1556 "Return UTC time tuple compatible with time.gmtime()."
1557 offset = self.utcoffset()
1558 if offset:
1559 self -= offset
1560 y, m, d = self.year, self.month, self.day
1561 hh, mm, ss = self.hour, self.minute, self.second
1562 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1563
1564 def date(self):
1565 "Return the date part."
1566 return date(self._year, self._month, self._day)
1567
1568 def time(self):
1569 "Return the time part, with tzinfo None."
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001570 return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001571
1572 def timetz(self):
1573 "Return the time part, with same tzinfo."
1574 return time(self.hour, self.minute, self.second, self.microsecond,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001575 self._tzinfo, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001576
1577 def replace(self, year=None, month=None, day=None, hour=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001578 minute=None, second=None, microsecond=None, tzinfo=True,
1579 *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001580 """Return a new datetime with new values for the specified fields."""
1581 if year is None:
1582 year = self.year
1583 if month is None:
1584 month = self.month
1585 if day is None:
1586 day = self.day
1587 if hour is None:
1588 hour = self.hour
1589 if minute is None:
1590 minute = self.minute
1591 if second is None:
1592 second = self.second
1593 if microsecond is None:
1594 microsecond = self.microsecond
1595 if tzinfo is True:
1596 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001597 if fold is None:
1598 fold = self.fold
1599 return datetime(year, month, day, hour, minute, second,
1600 microsecond, tzinfo, fold=fold)
1601
1602 def _local_timezone(self):
1603 if self.tzinfo is None:
1604 ts = self._mktime()
1605 else:
1606 ts = (self - _EPOCH) // timedelta(seconds=1)
1607 localtm = _time.localtime(ts)
1608 local = datetime(*localtm[:6])
1609 try:
1610 # Extract TZ data if available
1611 gmtoff = localtm.tm_gmtoff
1612 zone = localtm.tm_zone
1613 except AttributeError:
1614 delta = local - datetime(*_time.gmtime(ts)[:6])
1615 zone = _time.strftime('%Z', localtm)
1616 tz = timezone(delta, zone)
1617 else:
1618 tz = timezone(timedelta(seconds=gmtoff), zone)
1619 return tz
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001620
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001621 def astimezone(self, tz=None):
1622 if tz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001623 tz = self._local_timezone()
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001624 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001625 raise TypeError("tz argument must be an instance of tzinfo")
1626
1627 mytz = self.tzinfo
1628 if mytz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001629 mytz = self._local_timezone()
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001630
1631 if tz is mytz:
1632 return self
1633
1634 # Convert self to UTC, and attach the new time zone object.
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001635 myoffset = mytz.utcoffset(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001636 if myoffset is None:
1637 raise ValueError("astimezone() requires an aware datetime")
1638 utc = (self - myoffset).replace(tzinfo=tz)
1639
1640 # Convert from UTC to tz's local time.
1641 return tz.fromutc(utc)
1642
1643 # Ways to produce a string.
1644
1645 def ctime(self):
1646 "Return ctime() style string."
1647 weekday = self.toordinal() % 7 or 7
1648 return "%s %s %2d %02d:%02d:%02d %04d" % (
1649 _DAYNAMES[weekday],
1650 _MONTHNAMES[self._month],
1651 self._day,
1652 self._hour, self._minute, self._second,
1653 self._year)
1654
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001655 def isoformat(self, sep='T', timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001656 """Return the time formatted according to ISO.
1657
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001658 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1659 By default, the fractional part is omitted if self.microsecond == 0.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001660
1661 If self.tzinfo is not None, the UTC offset is also attached, giving
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001662 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001663
1664 Optional argument sep specifies the separator between date and
1665 time, default 'T'.
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001666
1667 The optional argument timespec specifies the number of additional
1668 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001669 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001670 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1671 _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001672 self._microsecond, timespec))
1673
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001674 off = self.utcoffset()
1675 if off is not None:
1676 if off.days < 0:
1677 sign = "-"
1678 off = -off
1679 else:
1680 sign = "+"
1681 hh, mm = divmod(off, timedelta(hours=1))
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001682 mm, ss = divmod(mm, timedelta(minutes=1))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001683 s += "%s%02d:%02d" % (sign, hh, mm)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001684 if ss:
1685 assert not ss.microseconds
1686 s += ":%02d" % ss.seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001687 return s
1688
1689 def __repr__(self):
1690 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001691 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001692 self._hour, self._minute, self._second, self._microsecond]
1693 if L[-1] == 0:
1694 del L[-1]
1695 if L[-1] == 0:
1696 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001697 s = "%s.%s(%s)" % (self.__class__.__module__,
1698 self.__class__.__qualname__,
1699 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001700 if self._tzinfo is not None:
1701 assert s[-1:] == ")"
1702 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001703 if self._fold:
1704 assert s[-1:] == ")"
1705 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001706 return s
1707
1708 def __str__(self):
1709 "Convert to string, for str()."
1710 return self.isoformat(sep=' ')
1711
1712 @classmethod
1713 def strptime(cls, date_string, format):
1714 'string, format -> new datetime parsed from a string (like time.strptime()).'
1715 import _strptime
1716 return _strptime._strptime_datetime(cls, date_string, format)
1717
1718 def utcoffset(self):
1719 """Return the timezone offset in minutes east of UTC (negative west of
1720 UTC)."""
1721 if self._tzinfo is None:
1722 return None
1723 offset = self._tzinfo.utcoffset(self)
1724 _check_utc_offset("utcoffset", offset)
1725 return offset
1726
1727 def tzname(self):
1728 """Return the timezone name.
1729
1730 Note that the name is 100% informational -- there's no requirement that
1731 it mean anything in particular. For example, "GMT", "UTC", "-500",
1732 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1733 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001734 if self._tzinfo is None:
1735 return None
1736 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001737 _check_tzname(name)
1738 return name
1739
1740 def dst(self):
1741 """Return 0 if DST is not in effect, or the DST offset (in minutes
1742 eastward) if DST is in effect.
1743
1744 This is purely informational; the DST offset has already been added to
1745 the UTC offset returned by utcoffset() if applicable, so there's no
1746 need to consult dst() unless you're interested in displaying the DST
1747 info.
1748 """
1749 if self._tzinfo is None:
1750 return None
1751 offset = self._tzinfo.dst(self)
1752 _check_utc_offset("dst", offset)
1753 return offset
1754
1755 # Comparisons of datetime objects with other.
1756
1757 def __eq__(self, other):
1758 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001759 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001760 elif not isinstance(other, date):
1761 return NotImplemented
1762 else:
1763 return False
1764
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001765 def __le__(self, other):
1766 if isinstance(other, datetime):
1767 return self._cmp(other) <= 0
1768 elif not isinstance(other, date):
1769 return NotImplemented
1770 else:
1771 _cmperror(self, other)
1772
1773 def __lt__(self, other):
1774 if isinstance(other, datetime):
1775 return self._cmp(other) < 0
1776 elif not isinstance(other, date):
1777 return NotImplemented
1778 else:
1779 _cmperror(self, other)
1780
1781 def __ge__(self, other):
1782 if isinstance(other, datetime):
1783 return self._cmp(other) >= 0
1784 elif not isinstance(other, date):
1785 return NotImplemented
1786 else:
1787 _cmperror(self, other)
1788
1789 def __gt__(self, other):
1790 if isinstance(other, datetime):
1791 return self._cmp(other) > 0
1792 elif not isinstance(other, date):
1793 return NotImplemented
1794 else:
1795 _cmperror(self, other)
1796
Alexander Belopolsky08313822012-06-15 20:19:47 -04001797 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001798 assert isinstance(other, datetime)
1799 mytz = self._tzinfo
1800 ottz = other._tzinfo
1801 myoff = otoff = None
1802
1803 if mytz is ottz:
1804 base_compare = True
1805 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04001806 myoff = self.utcoffset()
1807 otoff = other.utcoffset()
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001808 # Assume that allow_mixed means that we are called from __eq__
1809 if allow_mixed:
1810 if myoff != self.replace(fold=not self.fold).utcoffset():
1811 return 2
1812 if otoff != other.replace(fold=not other.fold).utcoffset():
1813 return 2
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001814 base_compare = myoff == otoff
1815
1816 if base_compare:
1817 return _cmp((self._year, self._month, self._day,
1818 self._hour, self._minute, self._second,
1819 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001820 (other._year, other._month, other._day,
1821 other._hour, other._minute, other._second,
1822 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001823 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001824 if allow_mixed:
1825 return 2 # arbitrary non-zero value
1826 else:
1827 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001828 # XXX What follows could be done more efficiently...
1829 diff = self - other # this will take offsets into account
1830 if diff.days < 0:
1831 return -1
1832 return diff and 1 or 0
1833
1834 def __add__(self, other):
1835 "Add a datetime and a timedelta."
1836 if not isinstance(other, timedelta):
1837 return NotImplemented
1838 delta = timedelta(self.toordinal(),
1839 hours=self._hour,
1840 minutes=self._minute,
1841 seconds=self._second,
1842 microseconds=self._microsecond)
1843 delta += other
1844 hour, rem = divmod(delta.seconds, 3600)
1845 minute, second = divmod(rem, 60)
1846 if 0 < delta.days <= _MAXORDINAL:
1847 return datetime.combine(date.fromordinal(delta.days),
1848 time(hour, minute, second,
1849 delta.microseconds,
1850 tzinfo=self._tzinfo))
1851 raise OverflowError("result out of range")
1852
1853 __radd__ = __add__
1854
1855 def __sub__(self, other):
1856 "Subtract two datetimes, or a datetime and a timedelta."
1857 if not isinstance(other, datetime):
1858 if isinstance(other, timedelta):
1859 return self + -other
1860 return NotImplemented
1861
1862 days1 = self.toordinal()
1863 days2 = other.toordinal()
1864 secs1 = self._second + self._minute * 60 + self._hour * 3600
1865 secs2 = other._second + other._minute * 60 + other._hour * 3600
1866 base = timedelta(days1 - days2,
1867 secs1 - secs2,
1868 self._microsecond - other._microsecond)
1869 if self._tzinfo is other._tzinfo:
1870 return base
1871 myoff = self.utcoffset()
1872 otoff = other.utcoffset()
1873 if myoff == otoff:
1874 return base
1875 if myoff is None or otoff is None:
1876 raise TypeError("cannot mix naive and timezone-aware time")
1877 return base + otoff - myoff
1878
1879 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001880 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001881 if self.fold:
1882 t = self.replace(fold=0)
1883 else:
1884 t = self
1885 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001886 if tzoff is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001887 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001888 else:
1889 days = _ymd2ord(self.year, self.month, self.day)
1890 seconds = self.hour * 3600 + self.minute * 60 + self.second
1891 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
1892 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001893
1894 # Pickle support.
1895
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001896 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001897 yhi, ylo = divmod(self._year, 256)
1898 us2, us3 = divmod(self._microsecond, 256)
1899 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001900 m = self._month
1901 if self._fold and protocol > 3:
1902 m += 128
1903 basestate = bytes([yhi, ylo, m, self._day,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001904 self._hour, self._minute, self._second,
1905 us1, us2, us3])
1906 if self._tzinfo is None:
1907 return (basestate,)
1908 else:
1909 return (basestate, self._tzinfo)
1910
1911 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001912 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1913 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001914 (yhi, ylo, m, self._day, self._hour,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001915 self._minute, self._second, us1, us2, us3) = string
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001916 if m > 127:
1917 self._fold = 1
1918 self._month = m - 128
1919 else:
1920 self._fold = 0
1921 self._month = m
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001922 self._year = yhi * 256 + ylo
1923 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001924 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001925
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001926 def __reduce_ex__(self, protocol):
1927 return (self.__class__, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001928
Serhiy Storchaka546ce652016-11-22 00:29:42 +02001929 def __reduce__(self):
1930 return self.__reduce_ex__(2)
1931
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001932
1933datetime.min = datetime(1, 1, 1)
1934datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1935datetime.resolution = timedelta(microseconds=1)
1936
1937
1938def _isoweek1monday(year):
1939 # Helper to calculate the day number of the Monday starting week 1
1940 # XXX This could be done more efficiently
1941 THURSDAY = 3
1942 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001943 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001944 week1monday = firstday - firstweekday
1945 if firstweekday > THURSDAY:
1946 week1monday += 7
1947 return week1monday
1948
1949class timezone(tzinfo):
1950 __slots__ = '_offset', '_name'
1951
1952 # Sentinel value to disallow None
1953 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001954 def __new__(cls, offset, name=_Omitted):
1955 if not isinstance(offset, timedelta):
1956 raise TypeError("offset must be a timedelta")
1957 if name is cls._Omitted:
1958 if not offset:
1959 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001960 name = None
1961 elif not isinstance(name, str):
1962 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001963 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001964 raise ValueError("offset must be a timedelta "
1965 "strictly between -timedelta(hours=24) and "
1966 "timedelta(hours=24).")
1967 if (offset.microseconds != 0 or offset.seconds % 60 != 0):
1968 raise ValueError("offset must be a timedelta "
1969 "representing a whole number of minutes")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001970 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001971
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001972 @classmethod
1973 def _create(cls, offset, name=None):
1974 self = tzinfo.__new__(cls)
1975 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001976 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001977 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001978
1979 def __getinitargs__(self):
1980 """pickle support"""
1981 if self._name is None:
1982 return (self._offset,)
1983 return (self._offset, self._name)
1984
1985 def __eq__(self, other):
Georg Brandl0085a242012-09-22 09:23:12 +02001986 if type(other) != timezone:
1987 return False
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001988 return self._offset == other._offset
1989
1990 def __hash__(self):
1991 return hash(self._offset)
1992
1993 def __repr__(self):
1994 """Convert to formal string, for repr().
1995
1996 >>> tz = timezone.utc
1997 >>> repr(tz)
1998 'datetime.timezone.utc'
1999 >>> tz = timezone(timedelta(hours=-5), 'EST')
2000 >>> repr(tz)
2001 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
2002 """
2003 if self is self.utc:
2004 return 'datetime.timezone.utc'
2005 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03002006 return "%s.%s(%r)" % (self.__class__.__module__,
2007 self.__class__.__qualname__,
2008 self._offset)
2009 return "%s.%s(%r, %r)" % (self.__class__.__module__,
2010 self.__class__.__qualname__,
2011 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002012
2013 def __str__(self):
2014 return self.tzname(None)
2015
2016 def utcoffset(self, dt):
2017 if isinstance(dt, datetime) or dt is None:
2018 return self._offset
2019 raise TypeError("utcoffset() argument must be a datetime instance"
2020 " or None")
2021
2022 def tzname(self, dt):
2023 if isinstance(dt, datetime) or dt is None:
2024 if self._name is None:
2025 return self._name_from_offset(self._offset)
2026 return self._name
2027 raise TypeError("tzname() argument must be a datetime instance"
2028 " or None")
2029
2030 def dst(self, dt):
2031 if isinstance(dt, datetime) or dt is None:
2032 return None
2033 raise TypeError("dst() argument must be a datetime instance"
2034 " or None")
2035
2036 def fromutc(self, dt):
2037 if isinstance(dt, datetime):
2038 if dt.tzinfo is not self:
2039 raise ValueError("fromutc: dt.tzinfo "
2040 "is not self")
2041 return dt + self._offset
2042 raise TypeError("fromutc() argument must be a datetime instance"
2043 " or None")
2044
2045 _maxoffset = timedelta(hours=23, minutes=59)
2046 _minoffset = -_maxoffset
2047
2048 @staticmethod
2049 def _name_from_offset(delta):
Alexander Belopolsky7827a5b2015-09-06 13:07:21 -04002050 if not delta:
2051 return 'UTC'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002052 if delta < timedelta(0):
2053 sign = '-'
2054 delta = -delta
2055 else:
2056 sign = '+'
2057 hours, rest = divmod(delta, timedelta(hours=1))
2058 minutes = rest // timedelta(minutes=1)
2059 return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes)
2060
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002061timezone.utc = timezone._create(timedelta(0))
2062timezone.min = timezone._create(timezone._minoffset)
2063timezone.max = timezone._create(timezone._maxoffset)
Alexander Belopolskya4415142012-06-08 12:33:09 -04002064_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002065
Victor Stinner765531d2013-03-26 01:11:54 +01002066# Some time zone algebra. For a datetime x, let
2067# x.n = x stripped of its timezone -- its naive time.
2068# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2069# return None
2070# x.d = x.dst(), and assuming that doesn't raise an exception or
2071# return None
2072# x.s = x's standard offset, x.o - x.d
2073#
2074# Now some derived rules, where k is a duration (timedelta).
2075#
2076# 1. x.o = x.s + x.d
2077# This follows from the definition of x.s.
2078#
2079# 2. If x and y have the same tzinfo member, x.s = y.s.
2080# This is actually a requirement, an assumption we need to make about
2081# sane tzinfo classes.
2082#
2083# 3. The naive UTC time corresponding to x is x.n - x.o.
2084# This is again a requirement for a sane tzinfo class.
2085#
2086# 4. (x+k).s = x.s
2087# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
2088#
2089# 5. (x+k).n = x.n + k
2090# Again follows from how arithmetic is defined.
2091#
2092# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
2093# (meaning that the various tzinfo methods exist, and don't blow up or return
2094# None when called).
2095#
2096# The function wants to return a datetime y with timezone tz, equivalent to x.
2097# x is already in UTC.
2098#
2099# By #3, we want
2100#
2101# y.n - y.o = x.n [1]
2102#
2103# The algorithm starts by attaching tz to x.n, and calling that y. So
2104# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
2105# becomes true; in effect, we want to solve [2] for k:
2106#
2107# (y+k).n - (y+k).o = x.n [2]
2108#
2109# By #1, this is the same as
2110#
2111# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
2112#
2113# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2114# Substituting that into [3],
2115#
2116# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2117# k - (y+k).s - (y+k).d = 0; rearranging,
2118# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2119# k = y.s - (y+k).d
2120#
2121# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2122# approximate k by ignoring the (y+k).d term at first. Note that k can't be
2123# very large, since all offset-returning methods return a duration of magnitude
2124# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
2125# be 0, so ignoring it has no consequence then.
2126#
2127# In any case, the new value is
2128#
2129# z = y + y.s [4]
2130#
2131# It's helpful to step back at look at [4] from a higher level: it's simply
2132# mapping from UTC to tz's standard time.
2133#
2134# At this point, if
2135#
2136# z.n - z.o = x.n [5]
2137#
2138# we have an equivalent time, and are almost done. The insecurity here is
2139# at the start of daylight time. Picture US Eastern for concreteness. The wall
2140# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2141# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2142# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2143# on the day DST starts. We want to return the 1:MM EST spelling because that's
2144# the only spelling that makes sense on the local wall clock.
2145#
2146# In fact, if [5] holds at this point, we do have the standard-time spelling,
2147# but that takes a bit of proof. We first prove a stronger result. What's the
2148# difference between the LHS and RHS of [5]? Let
2149#
2150# diff = x.n - (z.n - z.o) [6]
2151#
2152# Now
2153# z.n = by [4]
2154# (y + y.s).n = by #5
2155# y.n + y.s = since y.n = x.n
2156# x.n + y.s = since z and y are have the same tzinfo member,
2157# y.s = z.s by #2
2158# x.n + z.s
2159#
2160# Plugging that back into [6] gives
2161#
2162# diff =
2163# x.n - ((x.n + z.s) - z.o) = expanding
2164# x.n - x.n - z.s + z.o = cancelling
2165# - z.s + z.o = by #2
2166# z.d
2167#
2168# So diff = z.d.
2169#
2170# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2171# spelling we wanted in the endcase described above. We're done. Contrarily,
2172# if z.d = 0, then we have a UTC equivalent, and are also done.
2173#
2174# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2175# add to z (in effect, z is in tz's standard time, and we need to shift the
2176# local clock into tz's daylight time).
2177#
2178# Let
2179#
2180# z' = z + z.d = z + diff [7]
2181#
2182# and we can again ask whether
2183#
2184# z'.n - z'.o = x.n [8]
2185#
2186# If so, we're done. If not, the tzinfo class is insane, according to the
2187# assumptions we've made. This also requires a bit of proof. As before, let's
2188# compute the difference between the LHS and RHS of [8] (and skipping some of
2189# the justifications for the kinds of substitutions we've done several times
2190# already):
2191#
2192# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2193# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2194# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2195# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2196# - z.n + z.n - z.o + z'.o = cancel z.n
2197# - z.o + z'.o = #1 twice
2198# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2199# z'.d - z.d
2200#
2201# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2202# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2203# return z', not bothering to compute z'.d.
2204#
2205# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2206# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2207# would have to change the result dst() returns: we start in DST, and moving
2208# a little further into it takes us out of DST.
2209#
2210# There isn't a sane case where this can happen. The closest it gets is at
2211# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2212# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2213# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2214# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2215# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2216# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2217# standard time. Since that's what the local clock *does*, we want to map both
2218# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2219# in local time, but so it goes -- it's the way the local clock works.
2220#
2221# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2222# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2223# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2224# (correctly) concludes that z' is not UTC-equivalent to x.
2225#
2226# Because we know z.d said z was in daylight time (else [5] would have held and
2227# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2228# and we have stopped then), and there are only 2 possible values dst() can
2229# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2230# but the reasoning doesn't depend on the example -- it depends on there being
2231# two possible dst() outcomes, one zero and the other non-zero). Therefore
2232# z' must be in standard time, and is the spelling we want in this case.
2233#
2234# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2235# concerned (because it takes z' as being in standard time rather than the
2236# daylight time we intend here), but returning it gives the real-life "local
2237# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2238# tz.
2239#
2240# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2241# the 1:MM standard time spelling we want.
2242#
2243# So how can this break? One of the assumptions must be violated. Two
2244# possibilities:
2245#
2246# 1) [2] effectively says that y.s is invariant across all y belong to a given
2247# time zone. This isn't true if, for political reasons or continental drift,
2248# a region decides to change its base offset from UTC.
2249#
2250# 2) There may be versions of "double daylight" time where the tail end of
2251# the analysis gives up a step too early. I haven't thought about that
2252# enough to say.
2253#
2254# In any case, it's clear that the default fromutc() is strong enough to handle
2255# "almost all" time zones: so long as the standard offset is invariant, it
2256# doesn't matter if daylight time transition points change from year to year, or
2257# if daylight time is skipped in some years; it doesn't matter how large or
2258# small dst() may get within its bounds; and it doesn't even matter if some
2259# perverse time zone returns a negative dst()). So a breaking case must be
2260# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002261
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002262try:
2263 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002264except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002265 pass
2266else:
2267 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002268 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2269 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2270 _check_date_fields, _check_int_field, _check_time_fields,
2271 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2272 _date_class, _days_before_month, _days_before_year, _days_in_month,
2273 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd,
2274 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002275 # XXX Since import * above excludes names that start with _,
2276 # docstring does not get overwritten. In the future, it may be
2277 # appropriate to maintain a single module level docstring and
2278 # remove the following line.
2279 from _datetime import __doc__