blob: 36374aa94c871a7b658c3a2bcc42060d8a6e6e2d [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
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -0400935 def _getstate(self, protocol=3):
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
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -0400943 def __reduce_ex__(self, protocol):
944 return (self.__class__, self._getstate(protocol))
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)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001056 fold (keyword only, default to True)
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
1351_time_class = time # so functions w/ args named "time" can get at the class
1352
1353time.min = time(0, 0, 0)
1354time.max = time(23, 59, 59, 999999)
1355time.resolution = timedelta(microseconds=1)
1356
1357class datetime(date):
1358 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1359
1360 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001361 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001362 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001363 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001364
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001365 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001366 microsecond=0, tzinfo=None, *, fold=0):
1367 if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2]&0x7F <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001368 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001369 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001370 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001371 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001372 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001373 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolsky47649ab2016-08-08 17:05:40 -04001374 hour, minute, second, microsecond, fold = _check_time_fields(
1375 hour, minute, second, microsecond, fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001376 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001377 self = object.__new__(cls)
1378 self._year = year
1379 self._month = month
1380 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001381 self._hour = hour
1382 self._minute = minute
1383 self._second = second
1384 self._microsecond = microsecond
1385 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001386 self._hashcode = -1
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001387 self._fold = fold
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001388 return self
1389
1390 # Read-only field accessors
1391 @property
1392 def hour(self):
1393 """hour (0-23)"""
1394 return self._hour
1395
1396 @property
1397 def minute(self):
1398 """minute (0-59)"""
1399 return self._minute
1400
1401 @property
1402 def second(self):
1403 """second (0-59)"""
1404 return self._second
1405
1406 @property
1407 def microsecond(self):
1408 """microsecond (0-999999)"""
1409 return self._microsecond
1410
1411 @property
1412 def tzinfo(self):
1413 """timezone info object"""
1414 return self._tzinfo
1415
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001416 @property
1417 def fold(self):
1418 return self._fold
1419
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001420 @classmethod
Victor Stinneradfefa52015-09-04 23:57:25 +02001421 def _fromtimestamp(cls, t, utc, tz):
1422 """Construct a datetime from a POSIX timestamp (like time.time()).
1423
1424 A timezone info object may be passed in as well.
1425 """
1426 frac, t = _math.modf(t)
Victor Stinner7667f582015-09-09 01:02:23 +02001427 us = round(frac * 1e6)
Victor Stinneradfefa52015-09-04 23:57:25 +02001428 if us >= 1000000:
1429 t += 1
1430 us -= 1000000
1431 elif us < 0:
1432 t -= 1
1433 us += 1000000
1434
1435 converter = _time.gmtime if utc else _time.localtime
1436 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1437 ss = min(ss, 59) # clamp out leap seconds if the platform has them
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001438 result = cls(y, m, d, hh, mm, ss, us, tz)
1439 if tz is None:
1440 # As of version 2015f max fold in IANA database is
1441 # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
1442 # Let's probe 24 hours in the past to detect a transition:
1443 max_fold_seconds = 24 * 3600
1444 y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1445 probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1446 trans = result - probe1 - timedelta(0, max_fold_seconds)
1447 if trans.days < 0:
1448 y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
1449 probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1450 if probe2 == result:
1451 result._fold = 1
1452 else:
1453 result = tz.fromutc(result)
1454 return result
Victor Stinneradfefa52015-09-04 23:57:25 +02001455
1456 @classmethod
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001457 def fromtimestamp(cls, t, tz=None):
1458 """Construct a datetime from a POSIX timestamp (like time.time()).
1459
1460 A timezone info object may be passed in as well.
1461 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001462 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001463
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001464 return cls._fromtimestamp(t, tz is not None, tz)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001465
1466 @classmethod
1467 def utcfromtimestamp(cls, t):
Alexander Belopolskye2e178e2015-03-01 14:52:07 -05001468 """Construct a naive UTC datetime from a POSIX timestamp."""
Victor Stinneradfefa52015-09-04 23:57:25 +02001469 return cls._fromtimestamp(t, True, None)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001470
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001471 @classmethod
1472 def now(cls, tz=None):
1473 "Construct a datetime from time.time() and optional time zone info."
1474 t = _time.time()
1475 return cls.fromtimestamp(t, tz)
1476
1477 @classmethod
1478 def utcnow(cls):
1479 "Construct a UTC datetime from time.time()."
1480 t = _time.time()
1481 return cls.utcfromtimestamp(t)
1482
1483 @classmethod
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001484 def combine(cls, date, time, tzinfo=True):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001485 "Construct a datetime from a given date and a given time."
1486 if not isinstance(date, _date_class):
1487 raise TypeError("date argument must be a date instance")
1488 if not isinstance(time, _time_class):
1489 raise TypeError("time argument must be a time instance")
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001490 if tzinfo is True:
1491 tzinfo = time.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001492 return cls(date.year, date.month, date.day,
1493 time.hour, time.minute, time.second, time.microsecond,
Alexander Belopolsky43746c32016-08-02 17:49:30 -04001494 tzinfo, fold=time.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001495
1496 def timetuple(self):
1497 "Return local time tuple compatible with time.localtime()."
1498 dst = self.dst()
1499 if dst is None:
1500 dst = -1
1501 elif dst:
1502 dst = 1
1503 else:
1504 dst = 0
1505 return _build_struct_time(self.year, self.month, self.day,
1506 self.hour, self.minute, self.second,
1507 dst)
1508
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001509 def _mktime(self):
1510 """Return integer POSIX timestamp."""
1511 epoch = datetime(1970, 1, 1)
1512 max_fold_seconds = 24 * 3600
1513 t = (self - epoch) // timedelta(0, 1)
1514 def local(u):
1515 y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1516 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1517
1518 # Our goal is to solve t = local(u) for u.
1519 a = local(t) - t
1520 u1 = t - a
1521 t1 = local(u1)
1522 if t1 == t:
1523 # We found one solution, but it may not be the one we need.
1524 # Look for an earlier solution (if `fold` is 0), or a
1525 # later one (if `fold` is 1).
1526 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1527 b = local(u2) - u2
1528 if a == b:
1529 return u1
1530 else:
1531 b = t1 - u1
1532 assert a != b
1533 u2 = t - b
1534 t2 = local(u2)
1535 if t2 == t:
1536 return u2
1537 if t1 == t:
1538 return u1
1539 # We have found both offsets a and b, but neither t - a nor t - b is
1540 # a solution. This means t is in the gap.
1541 return (max, min)[self.fold](u1, u2)
1542
1543
Alexander Belopolskya4415142012-06-08 12:33:09 -04001544 def timestamp(self):
1545 "Return POSIX timestamp as float"
1546 if self._tzinfo is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001547 s = self._mktime()
1548 return s + self.microsecond / 1e6
Alexander Belopolskya4415142012-06-08 12:33:09 -04001549 else:
1550 return (self - _EPOCH).total_seconds()
1551
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001552 def utctimetuple(self):
1553 "Return UTC time tuple compatible with time.gmtime()."
1554 offset = self.utcoffset()
1555 if offset:
1556 self -= offset
1557 y, m, d = self.year, self.month, self.day
1558 hh, mm, ss = self.hour, self.minute, self.second
1559 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1560
1561 def date(self):
1562 "Return the date part."
1563 return date(self._year, self._month, self._day)
1564
1565 def time(self):
1566 "Return the time part, with tzinfo None."
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001567 return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001568
1569 def timetz(self):
1570 "Return the time part, with same tzinfo."
1571 return time(self.hour, self.minute, self.second, self.microsecond,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001572 self._tzinfo, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001573
1574 def replace(self, year=None, month=None, day=None, hour=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001575 minute=None, second=None, microsecond=None, tzinfo=True,
1576 *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001577 """Return a new datetime with new values for the specified fields."""
1578 if year is None:
1579 year = self.year
1580 if month is None:
1581 month = self.month
1582 if day is None:
1583 day = self.day
1584 if hour is None:
1585 hour = self.hour
1586 if minute is None:
1587 minute = self.minute
1588 if second is None:
1589 second = self.second
1590 if microsecond is None:
1591 microsecond = self.microsecond
1592 if tzinfo is True:
1593 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001594 if fold is None:
1595 fold = self.fold
1596 return datetime(year, month, day, hour, minute, second,
1597 microsecond, tzinfo, fold=fold)
1598
1599 def _local_timezone(self):
1600 if self.tzinfo is None:
1601 ts = self._mktime()
1602 else:
1603 ts = (self - _EPOCH) // timedelta(seconds=1)
1604 localtm = _time.localtime(ts)
1605 local = datetime(*localtm[:6])
1606 try:
1607 # Extract TZ data if available
1608 gmtoff = localtm.tm_gmtoff
1609 zone = localtm.tm_zone
1610 except AttributeError:
1611 delta = local - datetime(*_time.gmtime(ts)[:6])
1612 zone = _time.strftime('%Z', localtm)
1613 tz = timezone(delta, zone)
1614 else:
1615 tz = timezone(timedelta(seconds=gmtoff), zone)
1616 return tz
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001617
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001618 def astimezone(self, tz=None):
1619 if tz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001620 tz = self._local_timezone()
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001621 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001622 raise TypeError("tz argument must be an instance of tzinfo")
1623
1624 mytz = self.tzinfo
1625 if mytz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001626 mytz = self._local_timezone()
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001627
1628 if tz is mytz:
1629 return self
1630
1631 # Convert self to UTC, and attach the new time zone object.
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001632 myoffset = mytz.utcoffset(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001633 if myoffset is None:
1634 raise ValueError("astimezone() requires an aware datetime")
1635 utc = (self - myoffset).replace(tzinfo=tz)
1636
1637 # Convert from UTC to tz's local time.
1638 return tz.fromutc(utc)
1639
1640 # Ways to produce a string.
1641
1642 def ctime(self):
1643 "Return ctime() style string."
1644 weekday = self.toordinal() % 7 or 7
1645 return "%s %s %2d %02d:%02d:%02d %04d" % (
1646 _DAYNAMES[weekday],
1647 _MONTHNAMES[self._month],
1648 self._day,
1649 self._hour, self._minute, self._second,
1650 self._year)
1651
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001652 def isoformat(self, sep='T', timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001653 """Return the time formatted according to ISO.
1654
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001655 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1656 By default, the fractional part is omitted if self.microsecond == 0.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001657
1658 If self.tzinfo is not None, the UTC offset is also attached, giving
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001659 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001660
1661 Optional argument sep specifies the separator between date and
1662 time, default 'T'.
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001663
1664 The optional argument timespec specifies the number of additional
1665 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001666 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001667 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1668 _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001669 self._microsecond, timespec))
1670
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001671 off = self.utcoffset()
1672 if off is not None:
1673 if off.days < 0:
1674 sign = "-"
1675 off = -off
1676 else:
1677 sign = "+"
1678 hh, mm = divmod(off, timedelta(hours=1))
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001679 mm, ss = divmod(mm, timedelta(minutes=1))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001680 s += "%s%02d:%02d" % (sign, hh, mm)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001681 if ss:
1682 assert not ss.microseconds
1683 s += ":%02d" % ss.seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001684 return s
1685
1686 def __repr__(self):
1687 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001688 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001689 self._hour, self._minute, self._second, self._microsecond]
1690 if L[-1] == 0:
1691 del L[-1]
1692 if L[-1] == 0:
1693 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001694 s = "%s.%s(%s)" % (self.__class__.__module__,
1695 self.__class__.__qualname__,
1696 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001697 if self._tzinfo is not None:
1698 assert s[-1:] == ")"
1699 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001700 if self._fold:
1701 assert s[-1:] == ")"
1702 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001703 return s
1704
1705 def __str__(self):
1706 "Convert to string, for str()."
1707 return self.isoformat(sep=' ')
1708
1709 @classmethod
1710 def strptime(cls, date_string, format):
1711 'string, format -> new datetime parsed from a string (like time.strptime()).'
1712 import _strptime
1713 return _strptime._strptime_datetime(cls, date_string, format)
1714
1715 def utcoffset(self):
1716 """Return the timezone offset in minutes east of UTC (negative west of
1717 UTC)."""
1718 if self._tzinfo is None:
1719 return None
1720 offset = self._tzinfo.utcoffset(self)
1721 _check_utc_offset("utcoffset", offset)
1722 return offset
1723
1724 def tzname(self):
1725 """Return the timezone name.
1726
1727 Note that the name is 100% informational -- there's no requirement that
1728 it mean anything in particular. For example, "GMT", "UTC", "-500",
1729 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1730 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001731 if self._tzinfo is None:
1732 return None
1733 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001734 _check_tzname(name)
1735 return name
1736
1737 def dst(self):
1738 """Return 0 if DST is not in effect, or the DST offset (in minutes
1739 eastward) if DST is in effect.
1740
1741 This is purely informational; the DST offset has already been added to
1742 the UTC offset returned by utcoffset() if applicable, so there's no
1743 need to consult dst() unless you're interested in displaying the DST
1744 info.
1745 """
1746 if self._tzinfo is None:
1747 return None
1748 offset = self._tzinfo.dst(self)
1749 _check_utc_offset("dst", offset)
1750 return offset
1751
1752 # Comparisons of datetime objects with other.
1753
1754 def __eq__(self, other):
1755 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001756 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001757 elif not isinstance(other, date):
1758 return NotImplemented
1759 else:
1760 return False
1761
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001762 def __le__(self, other):
1763 if isinstance(other, datetime):
1764 return self._cmp(other) <= 0
1765 elif not isinstance(other, date):
1766 return NotImplemented
1767 else:
1768 _cmperror(self, other)
1769
1770 def __lt__(self, other):
1771 if isinstance(other, datetime):
1772 return self._cmp(other) < 0
1773 elif not isinstance(other, date):
1774 return NotImplemented
1775 else:
1776 _cmperror(self, other)
1777
1778 def __ge__(self, other):
1779 if isinstance(other, datetime):
1780 return self._cmp(other) >= 0
1781 elif not isinstance(other, date):
1782 return NotImplemented
1783 else:
1784 _cmperror(self, other)
1785
1786 def __gt__(self, other):
1787 if isinstance(other, datetime):
1788 return self._cmp(other) > 0
1789 elif not isinstance(other, date):
1790 return NotImplemented
1791 else:
1792 _cmperror(self, other)
1793
Alexander Belopolsky08313822012-06-15 20:19:47 -04001794 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001795 assert isinstance(other, datetime)
1796 mytz = self._tzinfo
1797 ottz = other._tzinfo
1798 myoff = otoff = None
1799
1800 if mytz is ottz:
1801 base_compare = True
1802 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04001803 myoff = self.utcoffset()
1804 otoff = other.utcoffset()
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001805 # Assume that allow_mixed means that we are called from __eq__
1806 if allow_mixed:
1807 if myoff != self.replace(fold=not self.fold).utcoffset():
1808 return 2
1809 if otoff != other.replace(fold=not other.fold).utcoffset():
1810 return 2
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001811 base_compare = myoff == otoff
1812
1813 if base_compare:
1814 return _cmp((self._year, self._month, self._day,
1815 self._hour, self._minute, self._second,
1816 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001817 (other._year, other._month, other._day,
1818 other._hour, other._minute, other._second,
1819 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001820 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001821 if allow_mixed:
1822 return 2 # arbitrary non-zero value
1823 else:
1824 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001825 # XXX What follows could be done more efficiently...
1826 diff = self - other # this will take offsets into account
1827 if diff.days < 0:
1828 return -1
1829 return diff and 1 or 0
1830
1831 def __add__(self, other):
1832 "Add a datetime and a timedelta."
1833 if not isinstance(other, timedelta):
1834 return NotImplemented
1835 delta = timedelta(self.toordinal(),
1836 hours=self._hour,
1837 minutes=self._minute,
1838 seconds=self._second,
1839 microseconds=self._microsecond)
1840 delta += other
1841 hour, rem = divmod(delta.seconds, 3600)
1842 minute, second = divmod(rem, 60)
1843 if 0 < delta.days <= _MAXORDINAL:
1844 return datetime.combine(date.fromordinal(delta.days),
1845 time(hour, minute, second,
1846 delta.microseconds,
1847 tzinfo=self._tzinfo))
1848 raise OverflowError("result out of range")
1849
1850 __radd__ = __add__
1851
1852 def __sub__(self, other):
1853 "Subtract two datetimes, or a datetime and a timedelta."
1854 if not isinstance(other, datetime):
1855 if isinstance(other, timedelta):
1856 return self + -other
1857 return NotImplemented
1858
1859 days1 = self.toordinal()
1860 days2 = other.toordinal()
1861 secs1 = self._second + self._minute * 60 + self._hour * 3600
1862 secs2 = other._second + other._minute * 60 + other._hour * 3600
1863 base = timedelta(days1 - days2,
1864 secs1 - secs2,
1865 self._microsecond - other._microsecond)
1866 if self._tzinfo is other._tzinfo:
1867 return base
1868 myoff = self.utcoffset()
1869 otoff = other.utcoffset()
1870 if myoff == otoff:
1871 return base
1872 if myoff is None or otoff is None:
1873 raise TypeError("cannot mix naive and timezone-aware time")
1874 return base + otoff - myoff
1875
1876 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001877 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001878 if self.fold:
1879 t = self.replace(fold=0)
1880 else:
1881 t = self
1882 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001883 if tzoff is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001884 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001885 else:
1886 days = _ymd2ord(self.year, self.month, self.day)
1887 seconds = self.hour * 3600 + self.minute * 60 + self.second
1888 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
1889 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001890
1891 # Pickle support.
1892
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001893 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001894 yhi, ylo = divmod(self._year, 256)
1895 us2, us3 = divmod(self._microsecond, 256)
1896 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001897 m = self._month
1898 if self._fold and protocol > 3:
1899 m += 128
1900 basestate = bytes([yhi, ylo, m, self._day,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001901 self._hour, self._minute, self._second,
1902 us1, us2, us3])
1903 if self._tzinfo is None:
1904 return (basestate,)
1905 else:
1906 return (basestate, self._tzinfo)
1907
1908 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001909 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1910 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001911 (yhi, ylo, m, self._day, self._hour,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001912 self._minute, self._second, us1, us2, us3) = string
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001913 if m > 127:
1914 self._fold = 1
1915 self._month = m - 128
1916 else:
1917 self._fold = 0
1918 self._month = m
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001919 self._year = yhi * 256 + ylo
1920 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001921 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001922
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001923 def __reduce_ex__(self, protocol):
1924 return (self.__class__, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001925
1926
1927datetime.min = datetime(1, 1, 1)
1928datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1929datetime.resolution = timedelta(microseconds=1)
1930
1931
1932def _isoweek1monday(year):
1933 # Helper to calculate the day number of the Monday starting week 1
1934 # XXX This could be done more efficiently
1935 THURSDAY = 3
1936 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001937 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001938 week1monday = firstday - firstweekday
1939 if firstweekday > THURSDAY:
1940 week1monday += 7
1941 return week1monday
1942
1943class timezone(tzinfo):
1944 __slots__ = '_offset', '_name'
1945
1946 # Sentinel value to disallow None
1947 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001948 def __new__(cls, offset, name=_Omitted):
1949 if not isinstance(offset, timedelta):
1950 raise TypeError("offset must be a timedelta")
1951 if name is cls._Omitted:
1952 if not offset:
1953 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001954 name = None
1955 elif not isinstance(name, str):
1956 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001957 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001958 raise ValueError("offset must be a timedelta "
1959 "strictly between -timedelta(hours=24) and "
1960 "timedelta(hours=24).")
1961 if (offset.microseconds != 0 or offset.seconds % 60 != 0):
1962 raise ValueError("offset must be a timedelta "
1963 "representing a whole number of minutes")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001964 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001965
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001966 @classmethod
1967 def _create(cls, offset, name=None):
1968 self = tzinfo.__new__(cls)
1969 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001970 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001971 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001972
1973 def __getinitargs__(self):
1974 """pickle support"""
1975 if self._name is None:
1976 return (self._offset,)
1977 return (self._offset, self._name)
1978
1979 def __eq__(self, other):
Georg Brandl0085a242012-09-22 09:23:12 +02001980 if type(other) != timezone:
1981 return False
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001982 return self._offset == other._offset
1983
1984 def __hash__(self):
1985 return hash(self._offset)
1986
1987 def __repr__(self):
1988 """Convert to formal string, for repr().
1989
1990 >>> tz = timezone.utc
1991 >>> repr(tz)
1992 'datetime.timezone.utc'
1993 >>> tz = timezone(timedelta(hours=-5), 'EST')
1994 >>> repr(tz)
1995 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
1996 """
1997 if self is self.utc:
1998 return 'datetime.timezone.utc'
1999 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03002000 return "%s.%s(%r)" % (self.__class__.__module__,
2001 self.__class__.__qualname__,
2002 self._offset)
2003 return "%s.%s(%r, %r)" % (self.__class__.__module__,
2004 self.__class__.__qualname__,
2005 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002006
2007 def __str__(self):
2008 return self.tzname(None)
2009
2010 def utcoffset(self, dt):
2011 if isinstance(dt, datetime) or dt is None:
2012 return self._offset
2013 raise TypeError("utcoffset() argument must be a datetime instance"
2014 " or None")
2015
2016 def tzname(self, dt):
2017 if isinstance(dt, datetime) or dt is None:
2018 if self._name is None:
2019 return self._name_from_offset(self._offset)
2020 return self._name
2021 raise TypeError("tzname() argument must be a datetime instance"
2022 " or None")
2023
2024 def dst(self, dt):
2025 if isinstance(dt, datetime) or dt is None:
2026 return None
2027 raise TypeError("dst() argument must be a datetime instance"
2028 " or None")
2029
2030 def fromutc(self, dt):
2031 if isinstance(dt, datetime):
2032 if dt.tzinfo is not self:
2033 raise ValueError("fromutc: dt.tzinfo "
2034 "is not self")
2035 return dt + self._offset
2036 raise TypeError("fromutc() argument must be a datetime instance"
2037 " or None")
2038
2039 _maxoffset = timedelta(hours=23, minutes=59)
2040 _minoffset = -_maxoffset
2041
2042 @staticmethod
2043 def _name_from_offset(delta):
Alexander Belopolsky7827a5b2015-09-06 13:07:21 -04002044 if not delta:
2045 return 'UTC'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002046 if delta < timedelta(0):
2047 sign = '-'
2048 delta = -delta
2049 else:
2050 sign = '+'
2051 hours, rest = divmod(delta, timedelta(hours=1))
2052 minutes = rest // timedelta(minutes=1)
2053 return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes)
2054
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002055timezone.utc = timezone._create(timedelta(0))
2056timezone.min = timezone._create(timezone._minoffset)
2057timezone.max = timezone._create(timezone._maxoffset)
Alexander Belopolskya4415142012-06-08 12:33:09 -04002058_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002059
Victor Stinner765531d2013-03-26 01:11:54 +01002060# Some time zone algebra. For a datetime x, let
2061# x.n = x stripped of its timezone -- its naive time.
2062# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2063# return None
2064# x.d = x.dst(), and assuming that doesn't raise an exception or
2065# return None
2066# x.s = x's standard offset, x.o - x.d
2067#
2068# Now some derived rules, where k is a duration (timedelta).
2069#
2070# 1. x.o = x.s + x.d
2071# This follows from the definition of x.s.
2072#
2073# 2. If x and y have the same tzinfo member, x.s = y.s.
2074# This is actually a requirement, an assumption we need to make about
2075# sane tzinfo classes.
2076#
2077# 3. The naive UTC time corresponding to x is x.n - x.o.
2078# This is again a requirement for a sane tzinfo class.
2079#
2080# 4. (x+k).s = x.s
2081# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
2082#
2083# 5. (x+k).n = x.n + k
2084# Again follows from how arithmetic is defined.
2085#
2086# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
2087# (meaning that the various tzinfo methods exist, and don't blow up or return
2088# None when called).
2089#
2090# The function wants to return a datetime y with timezone tz, equivalent to x.
2091# x is already in UTC.
2092#
2093# By #3, we want
2094#
2095# y.n - y.o = x.n [1]
2096#
2097# The algorithm starts by attaching tz to x.n, and calling that y. So
2098# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
2099# becomes true; in effect, we want to solve [2] for k:
2100#
2101# (y+k).n - (y+k).o = x.n [2]
2102#
2103# By #1, this is the same as
2104#
2105# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
2106#
2107# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2108# Substituting that into [3],
2109#
2110# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2111# k - (y+k).s - (y+k).d = 0; rearranging,
2112# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2113# k = y.s - (y+k).d
2114#
2115# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2116# approximate k by ignoring the (y+k).d term at first. Note that k can't be
2117# very large, since all offset-returning methods return a duration of magnitude
2118# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
2119# be 0, so ignoring it has no consequence then.
2120#
2121# In any case, the new value is
2122#
2123# z = y + y.s [4]
2124#
2125# It's helpful to step back at look at [4] from a higher level: it's simply
2126# mapping from UTC to tz's standard time.
2127#
2128# At this point, if
2129#
2130# z.n - z.o = x.n [5]
2131#
2132# we have an equivalent time, and are almost done. The insecurity here is
2133# at the start of daylight time. Picture US Eastern for concreteness. The wall
2134# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2135# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2136# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2137# on the day DST starts. We want to return the 1:MM EST spelling because that's
2138# the only spelling that makes sense on the local wall clock.
2139#
2140# In fact, if [5] holds at this point, we do have the standard-time spelling,
2141# but that takes a bit of proof. We first prove a stronger result. What's the
2142# difference between the LHS and RHS of [5]? Let
2143#
2144# diff = x.n - (z.n - z.o) [6]
2145#
2146# Now
2147# z.n = by [4]
2148# (y + y.s).n = by #5
2149# y.n + y.s = since y.n = x.n
2150# x.n + y.s = since z and y are have the same tzinfo member,
2151# y.s = z.s by #2
2152# x.n + z.s
2153#
2154# Plugging that back into [6] gives
2155#
2156# diff =
2157# x.n - ((x.n + z.s) - z.o) = expanding
2158# x.n - x.n - z.s + z.o = cancelling
2159# - z.s + z.o = by #2
2160# z.d
2161#
2162# So diff = z.d.
2163#
2164# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2165# spelling we wanted in the endcase described above. We're done. Contrarily,
2166# if z.d = 0, then we have a UTC equivalent, and are also done.
2167#
2168# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2169# add to z (in effect, z is in tz's standard time, and we need to shift the
2170# local clock into tz's daylight time).
2171#
2172# Let
2173#
2174# z' = z + z.d = z + diff [7]
2175#
2176# and we can again ask whether
2177#
2178# z'.n - z'.o = x.n [8]
2179#
2180# If so, we're done. If not, the tzinfo class is insane, according to the
2181# assumptions we've made. This also requires a bit of proof. As before, let's
2182# compute the difference between the LHS and RHS of [8] (and skipping some of
2183# the justifications for the kinds of substitutions we've done several times
2184# already):
2185#
2186# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2187# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2188# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2189# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2190# - z.n + z.n - z.o + z'.o = cancel z.n
2191# - z.o + z'.o = #1 twice
2192# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2193# z'.d - z.d
2194#
2195# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2196# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2197# return z', not bothering to compute z'.d.
2198#
2199# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2200# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2201# would have to change the result dst() returns: we start in DST, and moving
2202# a little further into it takes us out of DST.
2203#
2204# There isn't a sane case where this can happen. The closest it gets is at
2205# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2206# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2207# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2208# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2209# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2210# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2211# standard time. Since that's what the local clock *does*, we want to map both
2212# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2213# in local time, but so it goes -- it's the way the local clock works.
2214#
2215# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2216# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2217# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2218# (correctly) concludes that z' is not UTC-equivalent to x.
2219#
2220# Because we know z.d said z was in daylight time (else [5] would have held and
2221# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2222# and we have stopped then), and there are only 2 possible values dst() can
2223# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2224# but the reasoning doesn't depend on the example -- it depends on there being
2225# two possible dst() outcomes, one zero and the other non-zero). Therefore
2226# z' must be in standard time, and is the spelling we want in this case.
2227#
2228# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2229# concerned (because it takes z' as being in standard time rather than the
2230# daylight time we intend here), but returning it gives the real-life "local
2231# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2232# tz.
2233#
2234# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2235# the 1:MM standard time spelling we want.
2236#
2237# So how can this break? One of the assumptions must be violated. Two
2238# possibilities:
2239#
2240# 1) [2] effectively says that y.s is invariant across all y belong to a given
2241# time zone. This isn't true if, for political reasons or continental drift,
2242# a region decides to change its base offset from UTC.
2243#
2244# 2) There may be versions of "double daylight" time where the tail end of
2245# the analysis gives up a step too early. I haven't thought about that
2246# enough to say.
2247#
2248# In any case, it's clear that the default fromutc() is strong enough to handle
2249# "almost all" time zones: so long as the standard offset is invariant, it
2250# doesn't matter if daylight time transition points change from year to year, or
2251# if daylight time is skipped in some years; it doesn't matter how large or
2252# small dst() may get within its bounds; and it doesn't even matter if some
2253# perverse time zone returns a negative dst()). So a breaking case must be
2254# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002255
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002256try:
2257 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002258except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002259 pass
2260else:
2261 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002262 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2263 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2264 _check_date_fields, _check_int_field, _check_time_fields,
2265 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2266 _date_class, _days_before_month, _days_before_year, _days_in_month,
2267 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd,
2268 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002269 # XXX Since import * above excludes names that start with _,
2270 # docstring does not get overwritten. In the future, it may be
2271 # appropriate to maintain a single module level docstring and
2272 # remove the following line.
2273 from _datetime import __doc__