blob: 19d2f676e550ce860a2bf242d27cafacac8028aa [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):
724 """Contruct a date from a proleptic Gregorian ordinal.
725
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
1482 def combine(cls, date, time):
1483 "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")
1488 return cls(date.year, date.month, date.day,
1489 time.hour, time.minute, time.second, time.microsecond,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001490 time.tzinfo, fold=time.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001491
1492 def timetuple(self):
1493 "Return local time tuple compatible with time.localtime()."
1494 dst = self.dst()
1495 if dst is None:
1496 dst = -1
1497 elif dst:
1498 dst = 1
1499 else:
1500 dst = 0
1501 return _build_struct_time(self.year, self.month, self.day,
1502 self.hour, self.minute, self.second,
1503 dst)
1504
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001505 def _mktime(self):
1506 """Return integer POSIX timestamp."""
1507 epoch = datetime(1970, 1, 1)
1508 max_fold_seconds = 24 * 3600
1509 t = (self - epoch) // timedelta(0, 1)
1510 def local(u):
1511 y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1512 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1513
1514 # Our goal is to solve t = local(u) for u.
1515 a = local(t) - t
1516 u1 = t - a
1517 t1 = local(u1)
1518 if t1 == t:
1519 # We found one solution, but it may not be the one we need.
1520 # Look for an earlier solution (if `fold` is 0), or a
1521 # later one (if `fold` is 1).
1522 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1523 b = local(u2) - u2
1524 if a == b:
1525 return u1
1526 else:
1527 b = t1 - u1
1528 assert a != b
1529 u2 = t - b
1530 t2 = local(u2)
1531 if t2 == t:
1532 return u2
1533 if t1 == t:
1534 return u1
1535 # We have found both offsets a and b, but neither t - a nor t - b is
1536 # a solution. This means t is in the gap.
1537 return (max, min)[self.fold](u1, u2)
1538
1539
Alexander Belopolskya4415142012-06-08 12:33:09 -04001540 def timestamp(self):
1541 "Return POSIX timestamp as float"
1542 if self._tzinfo is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001543 s = self._mktime()
1544 return s + self.microsecond / 1e6
Alexander Belopolskya4415142012-06-08 12:33:09 -04001545 else:
1546 return (self - _EPOCH).total_seconds()
1547
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001548 def utctimetuple(self):
1549 "Return UTC time tuple compatible with time.gmtime()."
1550 offset = self.utcoffset()
1551 if offset:
1552 self -= offset
1553 y, m, d = self.year, self.month, self.day
1554 hh, mm, ss = self.hour, self.minute, self.second
1555 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1556
1557 def date(self):
1558 "Return the date part."
1559 return date(self._year, self._month, self._day)
1560
1561 def time(self):
1562 "Return the time part, with tzinfo None."
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001563 return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001564
1565 def timetz(self):
1566 "Return the time part, with same tzinfo."
1567 return time(self.hour, self.minute, self.second, self.microsecond,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001568 self._tzinfo, fold=self.fold)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001569
1570 def replace(self, year=None, month=None, day=None, hour=None,
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001571 minute=None, second=None, microsecond=None, tzinfo=True,
1572 *, fold=None):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001573 """Return a new datetime with new values for the specified fields."""
1574 if year is None:
1575 year = self.year
1576 if month is None:
1577 month = self.month
1578 if day is None:
1579 day = self.day
1580 if hour is None:
1581 hour = self.hour
1582 if minute is None:
1583 minute = self.minute
1584 if second is None:
1585 second = self.second
1586 if microsecond is None:
1587 microsecond = self.microsecond
1588 if tzinfo is True:
1589 tzinfo = self.tzinfo
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001590 if fold is None:
1591 fold = self.fold
1592 return datetime(year, month, day, hour, minute, second,
1593 microsecond, tzinfo, fold=fold)
1594
1595 def _local_timezone(self):
1596 if self.tzinfo is None:
1597 ts = self._mktime()
1598 else:
1599 ts = (self - _EPOCH) // timedelta(seconds=1)
1600 localtm = _time.localtime(ts)
1601 local = datetime(*localtm[:6])
1602 try:
1603 # Extract TZ data if available
1604 gmtoff = localtm.tm_gmtoff
1605 zone = localtm.tm_zone
1606 except AttributeError:
1607 delta = local - datetime(*_time.gmtime(ts)[:6])
1608 zone = _time.strftime('%Z', localtm)
1609 tz = timezone(delta, zone)
1610 else:
1611 tz = timezone(timedelta(seconds=gmtoff), zone)
1612 return tz
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001613
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001614 def astimezone(self, tz=None):
1615 if tz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001616 tz = self._local_timezone()
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001617 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001618 raise TypeError("tz argument must be an instance of tzinfo")
1619
1620 mytz = self.tzinfo
1621 if mytz is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001622 mytz = self._local_timezone()
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001623
1624 if tz is mytz:
1625 return self
1626
1627 # Convert self to UTC, and attach the new time zone object.
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001628 myoffset = mytz.utcoffset(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001629 if myoffset is None:
1630 raise ValueError("astimezone() requires an aware datetime")
1631 utc = (self - myoffset).replace(tzinfo=tz)
1632
1633 # Convert from UTC to tz's local time.
1634 return tz.fromutc(utc)
1635
1636 # Ways to produce a string.
1637
1638 def ctime(self):
1639 "Return ctime() style string."
1640 weekday = self.toordinal() % 7 or 7
1641 return "%s %s %2d %02d:%02d:%02d %04d" % (
1642 _DAYNAMES[weekday],
1643 _MONTHNAMES[self._month],
1644 self._day,
1645 self._hour, self._minute, self._second,
1646 self._year)
1647
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001648 def isoformat(self, sep='T', timespec='auto'):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001649 """Return the time formatted according to ISO.
1650
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001651 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1652 By default, the fractional part is omitted if self.microsecond == 0.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001653
1654 If self.tzinfo is not None, the UTC offset is also attached, giving
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001655 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001656
1657 Optional argument sep specifies the separator between date and
1658 time, default 'T'.
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001659
1660 The optional argument timespec specifies the number of additional
1661 terms of the time to include.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001662 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001663 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1664 _format_time(self._hour, self._minute, self._second,
Alexander Belopolskya2998a62016-03-06 14:58:43 -05001665 self._microsecond, timespec))
1666
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001667 off = self.utcoffset()
1668 if off is not None:
1669 if off.days < 0:
1670 sign = "-"
1671 off = -off
1672 else:
1673 sign = "+"
1674 hh, mm = divmod(off, timedelta(hours=1))
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001675 mm, ss = divmod(mm, timedelta(minutes=1))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001676 s += "%s%02d:%02d" % (sign, hh, mm)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001677 if ss:
1678 assert not ss.microseconds
1679 s += ":%02d" % ss.seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001680 return s
1681
1682 def __repr__(self):
1683 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001684 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001685 self._hour, self._minute, self._second, self._microsecond]
1686 if L[-1] == 0:
1687 del L[-1]
1688 if L[-1] == 0:
1689 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001690 s = "%s.%s(%s)" % (self.__class__.__module__,
1691 self.__class__.__qualname__,
1692 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001693 if self._tzinfo is not None:
1694 assert s[-1:] == ")"
1695 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001696 if self._fold:
1697 assert s[-1:] == ")"
1698 s = s[:-1] + ", fold=1)"
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001699 return s
1700
1701 def __str__(self):
1702 "Convert to string, for str()."
1703 return self.isoformat(sep=' ')
1704
1705 @classmethod
1706 def strptime(cls, date_string, format):
1707 'string, format -> new datetime parsed from a string (like time.strptime()).'
1708 import _strptime
1709 return _strptime._strptime_datetime(cls, date_string, format)
1710
1711 def utcoffset(self):
1712 """Return the timezone offset in minutes east of UTC (negative west of
1713 UTC)."""
1714 if self._tzinfo is None:
1715 return None
1716 offset = self._tzinfo.utcoffset(self)
1717 _check_utc_offset("utcoffset", offset)
1718 return offset
1719
1720 def tzname(self):
1721 """Return the timezone name.
1722
1723 Note that the name is 100% informational -- there's no requirement that
1724 it mean anything in particular. For example, "GMT", "UTC", "-500",
1725 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1726 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001727 if self._tzinfo is None:
1728 return None
1729 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001730 _check_tzname(name)
1731 return name
1732
1733 def dst(self):
1734 """Return 0 if DST is not in effect, or the DST offset (in minutes
1735 eastward) if DST is in effect.
1736
1737 This is purely informational; the DST offset has already been added to
1738 the UTC offset returned by utcoffset() if applicable, so there's no
1739 need to consult dst() unless you're interested in displaying the DST
1740 info.
1741 """
1742 if self._tzinfo is None:
1743 return None
1744 offset = self._tzinfo.dst(self)
1745 _check_utc_offset("dst", offset)
1746 return offset
1747
1748 # Comparisons of datetime objects with other.
1749
1750 def __eq__(self, other):
1751 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001752 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001753 elif not isinstance(other, date):
1754 return NotImplemented
1755 else:
1756 return False
1757
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001758 def __le__(self, other):
1759 if isinstance(other, datetime):
1760 return self._cmp(other) <= 0
1761 elif not isinstance(other, date):
1762 return NotImplemented
1763 else:
1764 _cmperror(self, other)
1765
1766 def __lt__(self, other):
1767 if isinstance(other, datetime):
1768 return self._cmp(other) < 0
1769 elif not isinstance(other, date):
1770 return NotImplemented
1771 else:
1772 _cmperror(self, other)
1773
1774 def __ge__(self, other):
1775 if isinstance(other, datetime):
1776 return self._cmp(other) >= 0
1777 elif not isinstance(other, date):
1778 return NotImplemented
1779 else:
1780 _cmperror(self, other)
1781
1782 def __gt__(self, other):
1783 if isinstance(other, datetime):
1784 return self._cmp(other) > 0
1785 elif not isinstance(other, date):
1786 return NotImplemented
1787 else:
1788 _cmperror(self, other)
1789
Alexander Belopolsky08313822012-06-15 20:19:47 -04001790 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001791 assert isinstance(other, datetime)
1792 mytz = self._tzinfo
1793 ottz = other._tzinfo
1794 myoff = otoff = None
1795
1796 if mytz is ottz:
1797 base_compare = True
1798 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04001799 myoff = self.utcoffset()
1800 otoff = other.utcoffset()
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001801 # Assume that allow_mixed means that we are called from __eq__
1802 if allow_mixed:
1803 if myoff != self.replace(fold=not self.fold).utcoffset():
1804 return 2
1805 if otoff != other.replace(fold=not other.fold).utcoffset():
1806 return 2
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001807 base_compare = myoff == otoff
1808
1809 if base_compare:
1810 return _cmp((self._year, self._month, self._day,
1811 self._hour, self._minute, self._second,
1812 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001813 (other._year, other._month, other._day,
1814 other._hour, other._minute, other._second,
1815 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001816 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001817 if allow_mixed:
1818 return 2 # arbitrary non-zero value
1819 else:
1820 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001821 # XXX What follows could be done more efficiently...
1822 diff = self - other # this will take offsets into account
1823 if diff.days < 0:
1824 return -1
1825 return diff and 1 or 0
1826
1827 def __add__(self, other):
1828 "Add a datetime and a timedelta."
1829 if not isinstance(other, timedelta):
1830 return NotImplemented
1831 delta = timedelta(self.toordinal(),
1832 hours=self._hour,
1833 minutes=self._minute,
1834 seconds=self._second,
1835 microseconds=self._microsecond)
1836 delta += other
1837 hour, rem = divmod(delta.seconds, 3600)
1838 minute, second = divmod(rem, 60)
1839 if 0 < delta.days <= _MAXORDINAL:
1840 return datetime.combine(date.fromordinal(delta.days),
1841 time(hour, minute, second,
1842 delta.microseconds,
1843 tzinfo=self._tzinfo))
1844 raise OverflowError("result out of range")
1845
1846 __radd__ = __add__
1847
1848 def __sub__(self, other):
1849 "Subtract two datetimes, or a datetime and a timedelta."
1850 if not isinstance(other, datetime):
1851 if isinstance(other, timedelta):
1852 return self + -other
1853 return NotImplemented
1854
1855 days1 = self.toordinal()
1856 days2 = other.toordinal()
1857 secs1 = self._second + self._minute * 60 + self._hour * 3600
1858 secs2 = other._second + other._minute * 60 + other._hour * 3600
1859 base = timedelta(days1 - days2,
1860 secs1 - secs2,
1861 self._microsecond - other._microsecond)
1862 if self._tzinfo is other._tzinfo:
1863 return base
1864 myoff = self.utcoffset()
1865 otoff = other.utcoffset()
1866 if myoff == otoff:
1867 return base
1868 if myoff is None or otoff is None:
1869 raise TypeError("cannot mix naive and timezone-aware time")
1870 return base + otoff - myoff
1871
1872 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001873 if self._hashcode == -1:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001874 if self.fold:
1875 t = self.replace(fold=0)
1876 else:
1877 t = self
1878 tzoff = t.utcoffset()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001879 if tzoff is None:
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001880 self._hashcode = hash(t._getstate()[0])
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001881 else:
1882 days = _ymd2ord(self.year, self.month, self.day)
1883 seconds = self.hour * 3600 + self.minute * 60 + self.second
1884 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
1885 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001886
1887 # Pickle support.
1888
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001889 def _getstate(self, protocol=3):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001890 yhi, ylo = divmod(self._year, 256)
1891 us2, us3 = divmod(self._microsecond, 256)
1892 us1, us2 = divmod(us2, 256)
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001893 m = self._month
1894 if self._fold and protocol > 3:
1895 m += 128
1896 basestate = bytes([yhi, ylo, m, self._day,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001897 self._hour, self._minute, self._second,
1898 us1, us2, us3])
1899 if self._tzinfo is None:
1900 return (basestate,)
1901 else:
1902 return (basestate, self._tzinfo)
1903
1904 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001905 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1906 raise TypeError("bad tzinfo state arg")
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001907 (yhi, ylo, m, self._day, self._hour,
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001908 self._minute, self._second, us1, us2, us3) = string
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001909 if m > 127:
1910 self._fold = 1
1911 self._month = m - 128
1912 else:
1913 self._fold = 0
1914 self._month = m
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001915 self._year = yhi * 256 + ylo
1916 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001917 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001918
Alexander Belopolsky5d0c5982016-07-22 18:47:04 -04001919 def __reduce_ex__(self, protocol):
1920 return (self.__class__, self._getstate(protocol))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001921
1922
1923datetime.min = datetime(1, 1, 1)
1924datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1925datetime.resolution = timedelta(microseconds=1)
1926
1927
1928def _isoweek1monday(year):
1929 # Helper to calculate the day number of the Monday starting week 1
1930 # XXX This could be done more efficiently
1931 THURSDAY = 3
1932 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001933 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001934 week1monday = firstday - firstweekday
1935 if firstweekday > THURSDAY:
1936 week1monday += 7
1937 return week1monday
1938
1939class timezone(tzinfo):
1940 __slots__ = '_offset', '_name'
1941
1942 # Sentinel value to disallow None
1943 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001944 def __new__(cls, offset, name=_Omitted):
1945 if not isinstance(offset, timedelta):
1946 raise TypeError("offset must be a timedelta")
1947 if name is cls._Omitted:
1948 if not offset:
1949 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001950 name = None
1951 elif not isinstance(name, str):
1952 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001953 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001954 raise ValueError("offset must be a timedelta "
1955 "strictly between -timedelta(hours=24) and "
1956 "timedelta(hours=24).")
1957 if (offset.microseconds != 0 or offset.seconds % 60 != 0):
1958 raise ValueError("offset must be a timedelta "
1959 "representing a whole number of minutes")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001960 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001961
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001962 @classmethod
1963 def _create(cls, offset, name=None):
1964 self = tzinfo.__new__(cls)
1965 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001966 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001967 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001968
1969 def __getinitargs__(self):
1970 """pickle support"""
1971 if self._name is None:
1972 return (self._offset,)
1973 return (self._offset, self._name)
1974
1975 def __eq__(self, other):
Georg Brandl0085a242012-09-22 09:23:12 +02001976 if type(other) != timezone:
1977 return False
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001978 return self._offset == other._offset
1979
1980 def __hash__(self):
1981 return hash(self._offset)
1982
1983 def __repr__(self):
1984 """Convert to formal string, for repr().
1985
1986 >>> tz = timezone.utc
1987 >>> repr(tz)
1988 'datetime.timezone.utc'
1989 >>> tz = timezone(timedelta(hours=-5), 'EST')
1990 >>> repr(tz)
1991 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
1992 """
1993 if self is self.utc:
1994 return 'datetime.timezone.utc'
1995 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001996 return "%s.%s(%r)" % (self.__class__.__module__,
1997 self.__class__.__qualname__,
1998 self._offset)
1999 return "%s.%s(%r, %r)" % (self.__class__.__module__,
2000 self.__class__.__qualname__,
2001 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002002
2003 def __str__(self):
2004 return self.tzname(None)
2005
2006 def utcoffset(self, dt):
2007 if isinstance(dt, datetime) or dt is None:
2008 return self._offset
2009 raise TypeError("utcoffset() argument must be a datetime instance"
2010 " or None")
2011
2012 def tzname(self, dt):
2013 if isinstance(dt, datetime) or dt is None:
2014 if self._name is None:
2015 return self._name_from_offset(self._offset)
2016 return self._name
2017 raise TypeError("tzname() argument must be a datetime instance"
2018 " or None")
2019
2020 def dst(self, dt):
2021 if isinstance(dt, datetime) or dt is None:
2022 return None
2023 raise TypeError("dst() argument must be a datetime instance"
2024 " or None")
2025
2026 def fromutc(self, dt):
2027 if isinstance(dt, datetime):
2028 if dt.tzinfo is not self:
2029 raise ValueError("fromutc: dt.tzinfo "
2030 "is not self")
2031 return dt + self._offset
2032 raise TypeError("fromutc() argument must be a datetime instance"
2033 " or None")
2034
2035 _maxoffset = timedelta(hours=23, minutes=59)
2036 _minoffset = -_maxoffset
2037
2038 @staticmethod
2039 def _name_from_offset(delta):
Alexander Belopolsky7827a5b2015-09-06 13:07:21 -04002040 if not delta:
2041 return 'UTC'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002042 if delta < timedelta(0):
2043 sign = '-'
2044 delta = -delta
2045 else:
2046 sign = '+'
2047 hours, rest = divmod(delta, timedelta(hours=1))
2048 minutes = rest // timedelta(minutes=1)
2049 return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes)
2050
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00002051timezone.utc = timezone._create(timedelta(0))
2052timezone.min = timezone._create(timezone._minoffset)
2053timezone.max = timezone._create(timezone._maxoffset)
Alexander Belopolskya4415142012-06-08 12:33:09 -04002054_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002055
Victor Stinner765531d2013-03-26 01:11:54 +01002056# Some time zone algebra. For a datetime x, let
2057# x.n = x stripped of its timezone -- its naive time.
2058# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
2059# return None
2060# x.d = x.dst(), and assuming that doesn't raise an exception or
2061# return None
2062# x.s = x's standard offset, x.o - x.d
2063#
2064# Now some derived rules, where k is a duration (timedelta).
2065#
2066# 1. x.o = x.s + x.d
2067# This follows from the definition of x.s.
2068#
2069# 2. If x and y have the same tzinfo member, x.s = y.s.
2070# This is actually a requirement, an assumption we need to make about
2071# sane tzinfo classes.
2072#
2073# 3. The naive UTC time corresponding to x is x.n - x.o.
2074# This is again a requirement for a sane tzinfo class.
2075#
2076# 4. (x+k).s = x.s
2077# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
2078#
2079# 5. (x+k).n = x.n + k
2080# Again follows from how arithmetic is defined.
2081#
2082# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
2083# (meaning that the various tzinfo methods exist, and don't blow up or return
2084# None when called).
2085#
2086# The function wants to return a datetime y with timezone tz, equivalent to x.
2087# x is already in UTC.
2088#
2089# By #3, we want
2090#
2091# y.n - y.o = x.n [1]
2092#
2093# The algorithm starts by attaching tz to x.n, and calling that y. So
2094# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
2095# becomes true; in effect, we want to solve [2] for k:
2096#
2097# (y+k).n - (y+k).o = x.n [2]
2098#
2099# By #1, this is the same as
2100#
2101# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
2102#
2103# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
2104# Substituting that into [3],
2105#
2106# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
2107# k - (y+k).s - (y+k).d = 0; rearranging,
2108# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
2109# k = y.s - (y+k).d
2110#
2111# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
2112# approximate k by ignoring the (y+k).d term at first. Note that k can't be
2113# very large, since all offset-returning methods return a duration of magnitude
2114# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
2115# be 0, so ignoring it has no consequence then.
2116#
2117# In any case, the new value is
2118#
2119# z = y + y.s [4]
2120#
2121# It's helpful to step back at look at [4] from a higher level: it's simply
2122# mapping from UTC to tz's standard time.
2123#
2124# At this point, if
2125#
2126# z.n - z.o = x.n [5]
2127#
2128# we have an equivalent time, and are almost done. The insecurity here is
2129# at the start of daylight time. Picture US Eastern for concreteness. The wall
2130# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2131# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2132# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2133# on the day DST starts. We want to return the 1:MM EST spelling because that's
2134# the only spelling that makes sense on the local wall clock.
2135#
2136# In fact, if [5] holds at this point, we do have the standard-time spelling,
2137# but that takes a bit of proof. We first prove a stronger result. What's the
2138# difference between the LHS and RHS of [5]? Let
2139#
2140# diff = x.n - (z.n - z.o) [6]
2141#
2142# Now
2143# z.n = by [4]
2144# (y + y.s).n = by #5
2145# y.n + y.s = since y.n = x.n
2146# x.n + y.s = since z and y are have the same tzinfo member,
2147# y.s = z.s by #2
2148# x.n + z.s
2149#
2150# Plugging that back into [6] gives
2151#
2152# diff =
2153# x.n - ((x.n + z.s) - z.o) = expanding
2154# x.n - x.n - z.s + z.o = cancelling
2155# - z.s + z.o = by #2
2156# z.d
2157#
2158# So diff = z.d.
2159#
2160# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2161# spelling we wanted in the endcase described above. We're done. Contrarily,
2162# if z.d = 0, then we have a UTC equivalent, and are also done.
2163#
2164# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2165# add to z (in effect, z is in tz's standard time, and we need to shift the
2166# local clock into tz's daylight time).
2167#
2168# Let
2169#
2170# z' = z + z.d = z + diff [7]
2171#
2172# and we can again ask whether
2173#
2174# z'.n - z'.o = x.n [8]
2175#
2176# If so, we're done. If not, the tzinfo class is insane, according to the
2177# assumptions we've made. This also requires a bit of proof. As before, let's
2178# compute the difference between the LHS and RHS of [8] (and skipping some of
2179# the justifications for the kinds of substitutions we've done several times
2180# already):
2181#
2182# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2183# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2184# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2185# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2186# - z.n + z.n - z.o + z'.o = cancel z.n
2187# - z.o + z'.o = #1 twice
2188# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2189# z'.d - z.d
2190#
2191# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2192# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2193# return z', not bothering to compute z'.d.
2194#
2195# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2196# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2197# would have to change the result dst() returns: we start in DST, and moving
2198# a little further into it takes us out of DST.
2199#
2200# There isn't a sane case where this can happen. The closest it gets is at
2201# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2202# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2203# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2204# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2205# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2206# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2207# standard time. Since that's what the local clock *does*, we want to map both
2208# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2209# in local time, but so it goes -- it's the way the local clock works.
2210#
2211# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2212# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2213# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2214# (correctly) concludes that z' is not UTC-equivalent to x.
2215#
2216# Because we know z.d said z was in daylight time (else [5] would have held and
2217# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2218# and we have stopped then), and there are only 2 possible values dst() can
2219# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2220# but the reasoning doesn't depend on the example -- it depends on there being
2221# two possible dst() outcomes, one zero and the other non-zero). Therefore
2222# z' must be in standard time, and is the spelling we want in this case.
2223#
2224# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2225# concerned (because it takes z' as being in standard time rather than the
2226# daylight time we intend here), but returning it gives the real-life "local
2227# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2228# tz.
2229#
2230# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2231# the 1:MM standard time spelling we want.
2232#
2233# So how can this break? One of the assumptions must be violated. Two
2234# possibilities:
2235#
2236# 1) [2] effectively says that y.s is invariant across all y belong to a given
2237# time zone. This isn't true if, for political reasons or continental drift,
2238# a region decides to change its base offset from UTC.
2239#
2240# 2) There may be versions of "double daylight" time where the tail end of
2241# the analysis gives up a step too early. I haven't thought about that
2242# enough to say.
2243#
2244# In any case, it's clear that the default fromutc() is strong enough to handle
2245# "almost all" time zones: so long as the standard offset is invariant, it
2246# doesn't matter if daylight time transition points change from year to year, or
2247# if daylight time is skipped in some years; it doesn't matter how large or
2248# small dst() may get within its bounds; and it doesn't even matter if some
2249# perverse time zone returns a negative dst()). So a breaking case must be
2250# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002251
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002252try:
2253 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002254except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002255 pass
2256else:
2257 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002258 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2259 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2260 _check_date_fields, _check_int_field, _check_time_fields,
2261 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2262 _date_class, _days_before_month, _days_before_year, _days_in_month,
2263 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd,
2264 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002265 # XXX Since import * above excludes names that start with _,
2266 # docstring does not get overwritten. In the future, it may be
2267 # appropriate to maintain a single module level docstring and
2268 # remove the following line.
2269 from _datetime import __doc__