blob: 9f942a207e888f18c968d2c905f895b6371c0bab [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
291def _check_time_fields(hour, minute, second, microsecond):
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 Belopolsky6c7a4182014-09-28 19:11:56 -0400304 return hour, minute, second, microsecond
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000305
306def _check_tzinfo_arg(tz):
307 if tz is not None and not isinstance(tz, tzinfo):
308 raise TypeError("tzinfo argument must be None or of a tzinfo subclass")
309
310def _cmperror(x, y):
311 raise TypeError("can't compare '%s' to '%s'" % (
312 type(x).__name__, type(y).__name__))
313
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500314def _divide_and_round(a, b):
315 """divide a by b and round result to the nearest integer
316
317 When the ratio is exactly half-way between two integers,
318 the even integer is returned.
319 """
320 # Based on the reference implementation for divmod_near
321 # in Objects/longobject.c.
322 q, r = divmod(a, b)
323 # round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
324 # The expression r / b > 0.5 is equivalent to 2 * r > b if b is
325 # positive, 2 * r < b if b negative.
326 r *= 2
327 greater_than_half = r > b if b > 0 else r < b
328 if greater_than_half or r == b and q % 2 == 1:
329 q += 1
330
331 return q
332
Victor Stinner2ec55872015-09-02 19:16:07 +0200333
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000334class timedelta:
335 """Represent the difference between two datetime objects.
336
337 Supported operators:
338
339 - add, subtract timedelta
340 - unary plus, minus, abs
341 - compare to timedelta
Serhiy Storchaka95949422013-08-27 19:40:23 +0300342 - multiply, divide by int
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000343
344 In addition, datetime supports subtraction of two datetime objects
345 returning a timedelta, and addition or subtraction of a datetime
346 and a timedelta giving a datetime.
347
348 Representation: (days, seconds, microseconds). Why? Because I
349 felt like it.
350 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400351 __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000352
353 def __new__(cls, days=0, seconds=0, microseconds=0,
354 milliseconds=0, minutes=0, hours=0, weeks=0):
355 # Doing this efficiently and accurately in C is going to be difficult
356 # and error-prone, due to ubiquitous overflow possibilities, and that
357 # C double doesn't have enough bits of precision to represent
358 # microseconds over 10K years faithfully. The code here tries to make
359 # explicit where go-fast assumptions can be relied on, in order to
360 # guide the C implementation; it's way more convoluted than speed-
361 # ignoring auto-overflow-to-long idiomatic Python could be.
362
363 # XXX Check that all inputs are ints or floats.
364
365 # Final values, all integer.
366 # s and us fit in 32-bit signed ints; d isn't bounded.
367 d = s = us = 0
368
369 # Normalize everything to days, seconds, microseconds.
370 days += weeks*7
371 seconds += minutes*60 + hours*3600
372 microseconds += milliseconds*1000
373
374 # Get rid of all fractions, and normalize s and us.
375 # Take a deep breath <wink>.
376 if isinstance(days, float):
377 dayfrac, days = _math.modf(days)
378 daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
379 assert daysecondswhole == int(daysecondswhole) # can't overflow
380 s = int(daysecondswhole)
381 assert days == int(days)
382 d = int(days)
383 else:
384 daysecondsfrac = 0.0
385 d = days
386 assert isinstance(daysecondsfrac, float)
387 assert abs(daysecondsfrac) <= 1.0
388 assert isinstance(d, int)
389 assert abs(s) <= 24 * 3600
390 # days isn't referenced again before redefinition
391
392 if isinstance(seconds, float):
393 secondsfrac, seconds = _math.modf(seconds)
394 assert seconds == int(seconds)
395 seconds = int(seconds)
396 secondsfrac += daysecondsfrac
397 assert abs(secondsfrac) <= 2.0
398 else:
399 secondsfrac = daysecondsfrac
400 # daysecondsfrac isn't referenced again
401 assert isinstance(secondsfrac, float)
402 assert abs(secondsfrac) <= 2.0
403
404 assert isinstance(seconds, int)
405 days, seconds = divmod(seconds, 24*3600)
406 d += days
407 s += int(seconds) # can't overflow
408 assert isinstance(s, int)
409 assert abs(s) <= 2 * 24 * 3600
410 # seconds isn't referenced again before redefinition
411
412 usdouble = secondsfrac * 1e6
413 assert abs(usdouble) < 2.1e6 # exact value not critical
414 # secondsfrac isn't referenced again
415
416 if isinstance(microseconds, float):
Victor Stinner69cc4872015-09-08 23:58:54 +0200417 microseconds = round(microseconds + usdouble)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000418 seconds, microseconds = divmod(microseconds, 1000000)
419 days, seconds = divmod(seconds, 24*3600)
420 d += days
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400421 s += seconds
422 else:
423 microseconds = int(microseconds)
424 seconds, microseconds = divmod(microseconds, 1000000)
425 days, seconds = divmod(seconds, 24*3600)
426 d += days
427 s += seconds
Victor Stinner69cc4872015-09-08 23:58:54 +0200428 microseconds = round(microseconds + usdouble)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400429 assert isinstance(s, int)
430 assert isinstance(microseconds, int)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000431 assert abs(s) <= 3 * 24 * 3600
432 assert abs(microseconds) < 3.1e6
433
434 # Just a little bit of carrying possible for microseconds and seconds.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400435 seconds, us = divmod(microseconds, 1000000)
436 s += seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000437 days, s = divmod(s, 24*3600)
438 d += days
439
440 assert isinstance(d, int)
441 assert isinstance(s, int) and 0 <= s < 24*3600
442 assert isinstance(us, int) and 0 <= us < 1000000
443
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000444 if abs(d) > 999999999:
445 raise OverflowError("timedelta # of days is too large: %d" % d)
446
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400447 self = object.__new__(cls)
448 self._days = d
449 self._seconds = s
450 self._microseconds = us
451 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000452 return self
453
454 def __repr__(self):
455 if self._microseconds:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300456 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
457 self.__class__.__qualname__,
458 self._days,
459 self._seconds,
460 self._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000461 if self._seconds:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300462 return "%s.%s(%d, %d)" % (self.__class__.__module__,
463 self.__class__.__qualname__,
464 self._days,
465 self._seconds)
466 return "%s.%s(%d)" % (self.__class__.__module__,
467 self.__class__.__qualname__,
468 self._days)
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
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -0400933 def _getstate(self, protocol=3):
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
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -0400941 def __reduce_ex__(self, protocol):
942 return (self.__class__, self._getstate(protocol))
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)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001054 fold (keyword only, default to True)
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 Belopolsky6c7a4182014-09-28 19:11:56 -04001062 hour, minute, second, microsecond = _check_time_fields(
1063 hour, minute, second, microsecond)
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
1349_time_class = time # so functions w/ args named "time" can get at the class
1350
1351time.min = time(0, 0, 0)
1352time.max = time(23, 59, 59, 999999)
1353time.resolution = timedelta(microseconds=1)
1354
1355class datetime(date):
1356 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1357
1358 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001359 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001360 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001361 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001362
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001363 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001364 microsecond=0, tzinfo=None, *, fold=0):
1365 if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2]&0x7F <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001366 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001367 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001368 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001369 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001370 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001371 year, month, day = _check_date_fields(year, month, day)
1372 hour, minute, second, microsecond = _check_time_fields(
1373 hour, minute, second, microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001374 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001375 self = object.__new__(cls)
1376 self._year = year
1377 self._month = month
1378 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001379 self._hour = hour
1380 self._minute = minute
1381 self._second = second
1382 self._microsecond = microsecond
1383 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001384 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001385 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001386 return self
1387
1388 # Read-only field accessors
1389 @property
1390 def hour(self):
1391 """hour (0-23)"""
1392 return self._hour
1393
1394 @property
1395 def minute(self):
1396 """minute (0-59)"""
1397 return self._minute
1398
1399 @property
1400 def second(self):
1401 """second (0-59)"""
1402 return self._second
1403
1404 @property
1405 def microsecond(self):
1406 """microsecond (0-999999)"""
1407 return self._microsecond
1408
1409 @property
1410 def tzinfo(self):
1411 """timezone info object"""
1412 return self._tzinfo
1413
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001414 @property
1415 def fold(self):
1416 return self._fold
1417
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001418 @classmethod
Victor Stinneradfefa52015-09-04 23:57:25 +02001419 def _fromtimestamp(cls, t, utc, tz):
1420 """Construct a datetime from a POSIX timestamp (like time.time()).
1421
1422 A timezone info object may be passed in as well.
1423 """
1424 frac, t = _math.modf(t)
Victor Stinner7667f582015-09-09 01:02:23 +02001425 us = round(frac * 1e6)
Victor Stinneradfefa52015-09-04 23:57:25 +02001426 if us >= 1000000:
1427 t += 1
1428 us -= 1000000
1429 elif us < 0:
1430 t -= 1
1431 us += 1000000
1432
1433 converter = _time.gmtime if utc else _time.localtime
1434 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1435 ss = min(ss, 59) # clamp out leap seconds if the platform has them
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001436 result = cls(y, m, d, hh, mm, ss, us, tz)
1437 if tz is None:
1438 # As of version 2015f max fold in IANA database is
1439 # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
1440 # Let's probe 24 hours in the past to detect a transition:
1441 max_fold_seconds = 24 * 3600
1442 y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1443 probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1444 trans = result - probe1 - timedelta(0, max_fold_seconds)
1445 if trans.days < 0:
1446 y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
1447 probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1448 if probe2 == result:
1449 result._fold = 1
1450 else:
1451 result = tz.fromutc(result)
1452 return result
Victor Stinneradfefa52015-09-04 23:57:25 +02001453
1454 @classmethod
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001455 def fromtimestamp(cls, t, tz=None):
1456 """Construct a datetime from a POSIX timestamp (like time.time()).
1457
1458 A timezone info object may be passed in as well.
1459 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001460 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001461
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001462 return cls._fromtimestamp(t, tz is not None, tz)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001463
1464 @classmethod
1465 def utcfromtimestamp(cls, t):
Alexander Belopolskye2e178e2015-03-01 14:52:07 -05001466 """Construct a naive UTC datetime from a POSIX timestamp."""
Victor Stinneradfefa52015-09-04 23:57:25 +02001467 return cls._fromtimestamp(t, True, None)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001468
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001469 @classmethod
1470 def now(cls, tz=None):
1471 "Construct a datetime from time.time() and optional time zone info."
1472 t = _time.time()
1473 return cls.fromtimestamp(t, tz)
1474
1475 @classmethod
1476 def utcnow(cls):
1477 "Construct a UTC datetime from time.time()."
1478 t = _time.time()
1479 return cls.utcfromtimestamp(t)
1480
1481 @classmethod
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001482 def combine(cls, date, time, tzinfo=True):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001483 "Construct a datetime from a given date and a given time."
1484 if not isinstance(date, _date_class):
1485 raise TypeError("date argument must be a date instance")
1486 if not isinstance(time, _time_class):
1487 raise TypeError("time argument must be a time instance")
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001488 if tzinfo is True:
1489 tzinfo = time.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001490 return cls(date.year, date.month, date.day,
1491 time.hour, time.minute, time.second, time.microsecond,
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001492 tzinfo, fold=time.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001493
1494 def timetuple(self):
1495 "Return local time tuple compatible with time.localtime()."
1496 dst = self.dst()
1497 if dst is None:
1498 dst = -1
1499 elif dst:
1500 dst = 1
1501 else:
1502 dst = 0
1503 return _build_struct_time(self.year, self.month, self.day,
1504 self.hour, self.minute, self.second,
1505 dst)
1506
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001507 def _mktime(self):
1508 """Return integer POSIX timestamp."""
1509 epoch = datetime(1970, 1, 1)
1510 max_fold_seconds = 24 * 3600
1511 t = (self - epoch) // timedelta(0, 1)
1512 def local(u):
1513 y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1514 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1515
1516 # Our goal is to solve t = local(u) for u.
1517 a = local(t) - t
1518 u1 = t - a
1519 t1 = local(u1)
1520 if t1 == t:
1521 # We found one solution, but it may not be the one we need.
1522 # Look for an earlier solution (if `fold` is 0), or a
1523 # later one (if `fold` is 1).
1524 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1525 b = local(u2) - u2
1526 if a == b:
1527 return u1
1528 else:
1529 b = t1 - u1
1530 assert a != b
1531 u2 = t - b
1532 t2 = local(u2)
1533 if t2 == t:
1534 return u2
1535 if t1 == t:
1536 return u1
1537 # We have found both offsets a and b, but neither t - a nor t - b is
1538 # a solution. This means t is in the gap.
1539 return (max, min)[self.fold](u1, u2)
1540
1541
Alexander Belopolskya4415142012-06-08 12:33:09 -04001542 def timestamp(self):
1543 "Return POSIX timestamp as float"
1544 if self._tzinfo is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001545 s = self._mktime()
1546 return s + self.microsecond / 1e6
Alexander Belopolskya4415142012-06-08 12:33:09 -04001547 else:
1548 return (self - _EPOCH).total_seconds()
1549
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001550 def utctimetuple(self):
1551 "Return UTC time tuple compatible with time.gmtime()."
1552 offset = self.utcoffset()
1553 if offset:
1554 self -= offset
1555 y, m, d = self.year, self.month, self.day
1556 hh, mm, ss = self.hour, self.minute, self.second
1557 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1558
1559 def date(self):
1560 "Return the date part."
1561 return date(self._year, self._month, self._day)
1562
1563 def time(self):
1564 "Return the time part, with tzinfo None."
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001565 return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001566
1567 def timetz(self):
1568 "Return the time part, with same tzinfo."
1569 return time(self.hour, self.minute, self.second, self.microsecond,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001570 self._tzinfo, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001571
1572 def replace(self, year=None, month=None, day=None, hour=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001573 minute=None, second=None, microsecond=None, tzinfo=True,
1574 *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001575 """Return a new datetime with new values for the specified fields."""
1576 if year is None:
1577 year = self.year
1578 if month is None:
1579 month = self.month
1580 if day is None:
1581 day = self.day
1582 if hour is None:
1583 hour = self.hour
1584 if minute is None:
1585 minute = self.minute
1586 if second is None:
1587 second = self.second
1588 if microsecond is None:
1589 microsecond = self.microsecond
1590 if tzinfo is True:
1591 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001592 if fold is None:
1593 fold = self.fold
1594 return datetime(year, month, day, hour, minute, second,
1595 microsecond, tzinfo, fold=fold)
1596
1597 def _local_timezone(self):
1598 if self.tzinfo is None:
1599 ts = self._mktime()
1600 else:
1601 ts = (self - _EPOCH) // timedelta(seconds=1)
1602 localtm = _time.localtime(ts)
1603 local = datetime(*localtm[:6])
1604 try:
1605 # Extract TZ data if available
1606 gmtoff = localtm.tm_gmtoff
1607 zone = localtm.tm_zone
1608 except AttributeError:
1609 delta = local - datetime(*_time.gmtime(ts)[:6])
1610 zone = _time.strftime('%Z', localtm)
1611 tz = timezone(delta, zone)
1612 else:
1613 tz = timezone(timedelta(seconds=gmtoff), zone)
1614 return tz
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001615
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001616 def astimezone(self, tz=None):
1617 if tz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001618 tz = self._local_timezone()
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001619 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001620 raise TypeError("tz argument must be an instance of tzinfo")
1621
1622 mytz = self.tzinfo
1623 if mytz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001624 mytz = self._local_timezone()
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001625
1626 if tz is mytz:
1627 return self
1628
1629 # Convert self to UTC, and attach the new time zone object.
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001630 myoffset = mytz.utcoffset(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001631 if myoffset is None:
1632 raise ValueError("astimezone() requires an aware datetime")
1633 utc = (self - myoffset).replace(tzinfo=tz)
1634
1635 # Convert from UTC to tz's local time.
1636 return tz.fromutc(utc)
1637
1638 # Ways to produce a string.
1639
1640 def ctime(self):
1641 "Return ctime() style string."
1642 weekday = self.toordinal() % 7 or 7
1643 return "%s %s %2d %02d:%02d:%02d %04d" % (
1644 _DAYNAMES[weekday],
1645 _MONTHNAMES[self._month],
1646 self._day,
1647 self._hour, self._minute, self._second,
1648 self._year)
1649
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001650 def isoformat(self, sep='T', timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001651 """Return the time formatted according to ISO.
1652
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001653 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1654 By default, the fractional part is omitted if self.microsecond == 0.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001655
1656 If self.tzinfo is not None, the UTC offset is also attached, giving
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001657 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001658
1659 Optional argument sep specifies the separator between date and
1660 time, default 'T'.
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001661
1662 The optional argument timespec specifies the number of additional
1663 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001664 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001665 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1666 _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001667 self._microsecond, timespec))
1668
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001669 off = self.utcoffset()
1670 if off is not None:
1671 if off.days < 0:
1672 sign = "-"
1673 off = -off
1674 else:
1675 sign = "+"
1676 hh, mm = divmod(off, timedelta(hours=1))
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001677 mm, ss = divmod(mm, timedelta(minutes=1))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001678 s += "%s%02d:%02d" % (sign, hh, mm)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001679 if ss:
1680 assert not ss.microseconds
1681 s += ":%02d" % ss.seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001682 return s
1683
1684 def __repr__(self):
1685 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001686 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001687 self._hour, self._minute, self._second, self._microsecond]
1688 if L[-1] == 0:
1689 del L[-1]
1690 if L[-1] == 0:
1691 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001692 s = "%s.%s(%s)" % (self.__class__.__module__,
1693 self.__class__.__qualname__,
1694 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001695 if self._tzinfo is not None:
1696 assert s[-1:] == ")"
1697 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001698 if self._fold:
1699 assert s[-1:] == ")"
1700 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001701 return s
1702
1703 def __str__(self):
1704 "Convert to string, for str()."
1705 return self.isoformat(sep=' ')
1706
1707 @classmethod
1708 def strptime(cls, date_string, format):
1709 'string, format -> new datetime parsed from a string (like time.strptime()).'
1710 import _strptime
1711 return _strptime._strptime_datetime(cls, date_string, format)
1712
1713 def utcoffset(self):
1714 """Return the timezone offset in minutes east of UTC (negative west of
1715 UTC)."""
1716 if self._tzinfo is None:
1717 return None
1718 offset = self._tzinfo.utcoffset(self)
1719 _check_utc_offset("utcoffset", offset)
1720 return offset
1721
1722 def tzname(self):
1723 """Return the timezone name.
1724
1725 Note that the name is 100% informational -- there's no requirement that
1726 it mean anything in particular. For example, "GMT", "UTC", "-500",
1727 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1728 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001729 if self._tzinfo is None:
1730 return None
1731 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001732 _check_tzname(name)
1733 return name
1734
1735 def dst(self):
1736 """Return 0 if DST is not in effect, or the DST offset (in minutes
1737 eastward) if DST is in effect.
1738
1739 This is purely informational; the DST offset has already been added to
1740 the UTC offset returned by utcoffset() if applicable, so there's no
1741 need to consult dst() unless you're interested in displaying the DST
1742 info.
1743 """
1744 if self._tzinfo is None:
1745 return None
1746 offset = self._tzinfo.dst(self)
1747 _check_utc_offset("dst", offset)
1748 return offset
1749
1750 # Comparisons of datetime objects with other.
1751
1752 def __eq__(self, other):
1753 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001754 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001755 elif not isinstance(other, date):
1756 return NotImplemented
1757 else:
1758 return False
1759
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001760 def __le__(self, other):
1761 if isinstance(other, datetime):
1762 return self._cmp(other) <= 0
1763 elif not isinstance(other, date):
1764 return NotImplemented
1765 else:
1766 _cmperror(self, other)
1767
1768 def __lt__(self, other):
1769 if isinstance(other, datetime):
1770 return self._cmp(other) < 0
1771 elif not isinstance(other, date):
1772 return NotImplemented
1773 else:
1774 _cmperror(self, other)
1775
1776 def __ge__(self, other):
1777 if isinstance(other, datetime):
1778 return self._cmp(other) >= 0
1779 elif not isinstance(other, date):
1780 return NotImplemented
1781 else:
1782 _cmperror(self, other)
1783
1784 def __gt__(self, other):
1785 if isinstance(other, datetime):
1786 return self._cmp(other) > 0
1787 elif not isinstance(other, date):
1788 return NotImplemented
1789 else:
1790 _cmperror(self, other)
1791
Alexander Belopolsky08313822012-06-15 20:19:47 -04001792 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001793 assert isinstance(other, datetime)
1794 mytz = self._tzinfo
1795 ottz = other._tzinfo
1796 myoff = otoff = None
1797
1798 if mytz is ottz:
1799 base_compare = True
1800 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04001801 myoff = self.utcoffset()
1802 otoff = other.utcoffset()
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001803 # Assume that allow_mixed means that we are called from __eq__
1804 if allow_mixed:
1805 if myoff != self.replace(fold=not self.fold).utcoffset():
1806 return 2
1807 if otoff != other.replace(fold=not other.fold).utcoffset():
1808 return 2
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001809 base_compare = myoff == otoff
1810
1811 if base_compare:
1812 return _cmp((self._year, self._month, self._day,
1813 self._hour, self._minute, self._second,
1814 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001815 (other._year, other._month, other._day,
1816 other._hour, other._minute, other._second,
1817 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001818 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001819 if allow_mixed:
1820 return 2 # arbitrary non-zero value
1821 else:
1822 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001823 # XXX What follows could be done more efficiently...
1824 diff = self - other # this will take offsets into account
1825 if diff.days < 0:
1826 return -1
1827 return diff and 1 or 0
1828
1829 def __add__(self, other):
1830 "Add a datetime and a timedelta."
1831 if not isinstance(other, timedelta):
1832 return NotImplemented
1833 delta = timedelta(self.toordinal(),
1834 hours=self._hour,
1835 minutes=self._minute,
1836 seconds=self._second,
1837 microseconds=self._microsecond)
1838 delta += other
1839 hour, rem = divmod(delta.seconds, 3600)
1840 minute, second = divmod(rem, 60)
1841 if 0 < delta.days <= _MAXORDINAL:
1842 return datetime.combine(date.fromordinal(delta.days),
1843 time(hour, minute, second,
1844 delta.microseconds,
1845 tzinfo=self._tzinfo))
1846 raise OverflowError("result out of range")
1847
1848 __radd__ = __add__
1849
1850 def __sub__(self, other):
1851 "Subtract two datetimes, or a datetime and a timedelta."
1852 if not isinstance(other, datetime):
1853 if isinstance(other, timedelta):
1854 return self + -other
1855 return NotImplemented
1856
1857 days1 = self.toordinal()
1858 days2 = other.toordinal()
1859 secs1 = self._second + self._minute * 60 + self._hour * 3600
1860 secs2 = other._second + other._minute * 60 + other._hour * 3600
1861 base = timedelta(days1 - days2,
1862 secs1 - secs2,
1863 self._microsecond - other._microsecond)
1864 if self._tzinfo is other._tzinfo:
1865 return base
1866 myoff = self.utcoffset()
1867 otoff = other.utcoffset()
1868 if myoff == otoff:
1869 return base
1870 if myoff is None or otoff is None:
1871 raise TypeError("cannot mix naive and timezone-aware time")
1872 return base + otoff - myoff
1873
1874 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001875 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001876 if self.fold:
1877 t = self.replace(fold=0)
1878 else:
1879 t = self
1880 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001881 if tzoff is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001882 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001883 else:
1884 days = _ymd2ord(self.year, self.month, self.day)
1885 seconds = self.hour * 3600 + self.minute * 60 + self.second
1886 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
1887 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001888
1889 # Pickle support.
1890
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001891 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001892 yhi, ylo = divmod(self._year, 256)
1893 us2, us3 = divmod(self._microsecond, 256)
1894 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001895 m = self._month
1896 if self._fold and protocol > 3:
1897 m += 128
1898 basestate = bytes([yhi, ylo, m, self._day,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001899 self._hour, self._minute, self._second,
1900 us1, us2, us3])
1901 if self._tzinfo is None:
1902 return (basestate,)
1903 else:
1904 return (basestate, self._tzinfo)
1905
1906 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001907 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1908 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001909 (yhi, ylo, m, self._day, self._hour,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001910 self._minute, self._second, us1, us2, us3) = string
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001911 if m > 127:
1912 self._fold = 1
1913 self._month = m - 128
1914 else:
1915 self._fold = 0
1916 self._month = m
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001917 self._year = yhi * 256 + ylo
1918 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001919 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001920
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001921 def __reduce_ex__(self, protocol):
1922 return (self.__class__, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001923
1924
1925datetime.min = datetime(1, 1, 1)
1926datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1927datetime.resolution = timedelta(microseconds=1)
1928
1929
1930def _isoweek1monday(year):
1931 # Helper to calculate the day number of the Monday starting week 1
1932 # XXX This could be done more efficiently
1933 THURSDAY = 3
1934 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001935 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001936 week1monday = firstday - firstweekday
1937 if firstweekday > THURSDAY:
1938 week1monday += 7
1939 return week1monday
1940
1941class timezone(tzinfo):
1942 __slots__ = '_offset', '_name'
1943
1944 # Sentinel value to disallow None
1945 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001946 def __new__(cls, offset, name=_Omitted):
1947 if not isinstance(offset, timedelta):
1948 raise TypeError("offset must be a timedelta")
1949 if name is cls._Omitted:
1950 if not offset:
1951 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001952 name = None
1953 elif not isinstance(name, str):
1954 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001955 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001956 raise ValueError("offset must be a timedelta "
1957 "strictly between -timedelta(hours=24) and "
1958 "timedelta(hours=24).")
1959 if (offset.microseconds != 0 or offset.seconds % 60 != 0):
1960 raise ValueError("offset must be a timedelta "
1961 "representing a whole number of minutes")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001962 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001963
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001964 @classmethod
1965 def _create(cls, offset, name=None):
1966 self = tzinfo.__new__(cls)
1967 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001968 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001969 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001970
1971 def __getinitargs__(self):
1972 """pickle support"""
1973 if self._name is None:
1974 return (self._offset,)
1975 return (self._offset, self._name)
1976
1977 def __eq__(self, other):
Georg Brandl0085a242012-09-22 09:23:12 +02001978 if type(other) != timezone:
1979 return False
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001980 return self._offset == other._offset
1981
1982 def __hash__(self):
1983 return hash(self._offset)
1984
1985 def __repr__(self):
1986 """Convert to formal string, for repr().
1987
1988 >>> tz = timezone.utc
1989 >>> repr(tz)
1990 'datetime.timezone.utc'
1991 >>> tz = timezone(timedelta(hours=-5), 'EST')
1992 >>> repr(tz)
1993 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
1994 """
1995 if self is self.utc:
1996 return 'datetime.timezone.utc'
1997 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001998 return "%s.%s(%r)" % (self.__class__.__module__,
1999 self.__class__.__qualname__,
2000 self._offset)
2001 return "%s.%s(%r, %r)" % (self.__class__.__module__,
2002 self.__class__.__qualname__,
2003 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002004
2005 def __str__(self):
2006 return self.tzname(None)
2007
2008 def utcoffset(self, dt):
2009 if isinstance(dt, datetime) or dt is None:
2010 return self._offset
2011 raise TypeError("utcoffset() argument must be a datetime instance"
2012 " or None")
2013
2014 def tzname(self, dt):
2015 if isinstance(dt, datetime) or dt is None:
2016 if self._name is None:
2017 return self._name_from_offset(self._offset)
2018 return self._name
2019 raise TypeError("tzname() argument must be a datetime instance"
2020 " or None")
2021
2022 def dst(self, dt):
2023 if isinstance(dt, datetime) or dt is None:
2024 return None
2025 raise TypeError("dst() argument must be a datetime instance"
2026 " or None")
2027
2028 def fromutc(self, dt):
2029 if isinstance(dt, datetime):
2030 if dt.tzinfo is not self:
2031 raise ValueError("fromutc: dt.tzinfo "
2032 "is not self")
2033 return dt + self._offset
2034 raise TypeError("fromutc() argument must be a datetime instance"
2035 " or None")
2036
2037 _maxoffset = timedelta(hours=23, minutes=59)
2038 _minoffset = -_maxoffset
2039
2040 @staticmethod
2041 def _name_from_offset(delta):
Alexander Belopolsky7827a5b2015-09-06 13:07:21 -04002042 if not delta:
2043 return 'UTC'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002044 if delta < timedelta(0):
2045 sign = '-'
2046 delta = -delta
2047 else:
2048 sign = '+'
2049 hours, rest = divmod(delta, timedelta(hours=1))
2050 minutes = rest // timedelta(minutes=1)
2051 return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes)
2052
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002053timezone.utc = timezone._create(timedelta(0))
2054timezone.min = timezone._create(timezone._minoffset)
2055timezone.max = timezone._create(timezone._maxoffset)
Alexander Belopolskya4415142012-06-08 12:33:09 -04002056_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002057
Victor Stinner765531d2013-03-26 01:11:54 +01002058# Some time zone algebra. For a datetime x, let
2059# x.n = x stripped of its timezone -- its naive time.
2060# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2061# return None
2062# x.d = x.dst(), and assuming that doesn't raise an exception or
2063# return None
2064# x.s = x's standard offset, x.o - x.d
2065#
2066# Now some derived rules, where k is a duration (timedelta).
2067#
2068# 1. x.o = x.s + x.d
2069# This follows from the definition of x.s.
2070#
2071# 2. If x and y have the same tzinfo member, x.s = y.s.
2072# This is actually a requirement, an assumption we need to make about
2073# sane tzinfo classes.
2074#
2075# 3. The naive UTC time corresponding to x is x.n - x.o.
2076# This is again a requirement for a sane tzinfo class.
2077#
2078# 4. (x+k).s = x.s
2079# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
2080#
2081# 5. (x+k).n = x.n + k
2082# Again follows from how arithmetic is defined.
2083#
2084# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
2085# (meaning that the various tzinfo methods exist, and don't blow up or return
2086# None when called).
2087#
2088# The function wants to return a datetime y with timezone tz, equivalent to x.
2089# x is already in UTC.
2090#
2091# By #3, we want
2092#
2093# y.n - y.o = x.n [1]
2094#
2095# The algorithm starts by attaching tz to x.n, and calling that y. So
2096# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
2097# becomes true; in effect, we want to solve [2] for k:
2098#
2099# (y+k).n - (y+k).o = x.n [2]
2100#
2101# By #1, this is the same as
2102#
2103# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
2104#
2105# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2106# Substituting that into [3],
2107#
2108# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2109# k - (y+k).s - (y+k).d = 0; rearranging,
2110# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2111# k = y.s - (y+k).d
2112#
2113# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2114# approximate k by ignoring the (y+k).d term at first. Note that k can't be
2115# very large, since all offset-returning methods return a duration of magnitude
2116# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
2117# be 0, so ignoring it has no consequence then.
2118#
2119# In any case, the new value is
2120#
2121# z = y + y.s [4]
2122#
2123# It's helpful to step back at look at [4] from a higher level: it's simply
2124# mapping from UTC to tz's standard time.
2125#
2126# At this point, if
2127#
2128# z.n - z.o = x.n [5]
2129#
2130# we have an equivalent time, and are almost done. The insecurity here is
2131# at the start of daylight time. Picture US Eastern for concreteness. The wall
2132# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2133# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2134# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2135# on the day DST starts. We want to return the 1:MM EST spelling because that's
2136# the only spelling that makes sense on the local wall clock.
2137#
2138# In fact, if [5] holds at this point, we do have the standard-time spelling,
2139# but that takes a bit of proof. We first prove a stronger result. What's the
2140# difference between the LHS and RHS of [5]? Let
2141#
2142# diff = x.n - (z.n - z.o) [6]
2143#
2144# Now
2145# z.n = by [4]
2146# (y + y.s).n = by #5
2147# y.n + y.s = since y.n = x.n
2148# x.n + y.s = since z and y are have the same tzinfo member,
2149# y.s = z.s by #2
2150# x.n + z.s
2151#
2152# Plugging that back into [6] gives
2153#
2154# diff =
2155# x.n - ((x.n + z.s) - z.o) = expanding
2156# x.n - x.n - z.s + z.o = cancelling
2157# - z.s + z.o = by #2
2158# z.d
2159#
2160# So diff = z.d.
2161#
2162# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2163# spelling we wanted in the endcase described above. We're done. Contrarily,
2164# if z.d = 0, then we have a UTC equivalent, and are also done.
2165#
2166# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2167# add to z (in effect, z is in tz's standard time, and we need to shift the
2168# local clock into tz's daylight time).
2169#
2170# Let
2171#
2172# z' = z + z.d = z + diff [7]
2173#
2174# and we can again ask whether
2175#
2176# z'.n - z'.o = x.n [8]
2177#
2178# If so, we're done. If not, the tzinfo class is insane, according to the
2179# assumptions we've made. This also requires a bit of proof. As before, let's
2180# compute the difference between the LHS and RHS of [8] (and skipping some of
2181# the justifications for the kinds of substitutions we've done several times
2182# already):
2183#
2184# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2185# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2186# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2187# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2188# - z.n + z.n - z.o + z'.o = cancel z.n
2189# - z.o + z'.o = #1 twice
2190# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2191# z'.d - z.d
2192#
2193# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2194# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2195# return z', not bothering to compute z'.d.
2196#
2197# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2198# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2199# would have to change the result dst() returns: we start in DST, and moving
2200# a little further into it takes us out of DST.
2201#
2202# There isn't a sane case where this can happen. The closest it gets is at
2203# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2204# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2205# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2206# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2207# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2208# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2209# standard time. Since that's what the local clock *does*, we want to map both
2210# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2211# in local time, but so it goes -- it's the way the local clock works.
2212#
2213# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2214# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2215# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2216# (correctly) concludes that z' is not UTC-equivalent to x.
2217#
2218# Because we know z.d said z was in daylight time (else [5] would have held and
2219# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2220# and we have stopped then), and there are only 2 possible values dst() can
2221# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2222# but the reasoning doesn't depend on the example -- it depends on there being
2223# two possible dst() outcomes, one zero and the other non-zero). Therefore
2224# z' must be in standard time, and is the spelling we want in this case.
2225#
2226# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2227# concerned (because it takes z' as being in standard time rather than the
2228# daylight time we intend here), but returning it gives the real-life "local
2229# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2230# tz.
2231#
2232# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2233# the 1:MM standard time spelling we want.
2234#
2235# So how can this break? One of the assumptions must be violated. Two
2236# possibilities:
2237#
2238# 1) [2] effectively says that y.s is invariant across all y belong to a given
2239# time zone. This isn't true if, for political reasons or continental drift,
2240# a region decides to change its base offset from UTC.
2241#
2242# 2) There may be versions of "double daylight" time where the tail end of
2243# the analysis gives up a step too early. I haven't thought about that
2244# enough to say.
2245#
2246# In any case, it's clear that the default fromutc() is strong enough to handle
2247# "almost all" time zones: so long as the standard offset is invariant, it
2248# doesn't matter if daylight time transition points change from year to year, or
2249# if daylight time is skipped in some years; it doesn't matter how large or
2250# small dst() may get within its bounds; and it doesn't even matter if some
2251# perverse time zone returns a negative dst()). So a breaking case must be
2252# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002253
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002254try:
2255 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002256except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002257 pass
2258else:
2259 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002260 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2261 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2262 _check_date_fields, _check_int_field, _check_time_fields,
2263 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2264 _date_class, _days_before_month, _days_before_year, _days_in_month,
2265 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd,
2266 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002267 # XXX Since import * above excludes names that start with _,
2268 # docstring does not get overwritten. In the future, it may be
2269 # appropriate to maintain a single module level docstring and
2270 # remove the following line.
2271 from _datetime import __doc__