blob: db13b12ef3d0c4251429e3864d94c8f1f2d3a73f [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
155def _format_time(hh, mm, ss, us):
156 # Skip trailing microseconds when us==0.
157 result = "%02d:%02d:%02d" % (hh, mm, ss)
158 if us:
159 result += ".%06d" % us
160 return result
161
162# Correctly substitute for %z and %Z escapes in strftime formats.
163def _wrap_strftime(object, format, timetuple):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000164 # Don't call utcoffset() or tzname() unless actually needed.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400165 freplace = None # the string to use for %f
166 zreplace = None # the string to use for %z
167 Zreplace = None # the string to use for %Z
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000168
169 # Scan format for %z and %Z escapes, replacing as needed.
170 newformat = []
171 push = newformat.append
172 i, n = 0, len(format)
173 while i < n:
174 ch = format[i]
175 i += 1
176 if ch == '%':
177 if i < n:
178 ch = format[i]
179 i += 1
180 if ch == 'f':
181 if freplace is None:
182 freplace = '%06d' % getattr(object,
183 'microsecond', 0)
184 newformat.append(freplace)
185 elif ch == 'z':
186 if zreplace is None:
187 zreplace = ""
188 if hasattr(object, "utcoffset"):
189 offset = object.utcoffset()
190 if offset is not None:
191 sign = '+'
192 if offset.days < 0:
193 offset = -offset
194 sign = '-'
195 h, m = divmod(offset, timedelta(hours=1))
196 assert not m % timedelta(minutes=1), "whole minute"
197 m //= timedelta(minutes=1)
198 zreplace = '%c%02d%02d' % (sign, h, m)
199 assert '%' not in zreplace
200 newformat.append(zreplace)
201 elif ch == 'Z':
202 if Zreplace is None:
203 Zreplace = ""
204 if hasattr(object, "tzname"):
205 s = object.tzname()
206 if s is not None:
207 # strftime is going to have at this: escape %
208 Zreplace = s.replace('%', '%%')
209 newformat.append(Zreplace)
210 else:
211 push('%')
212 push(ch)
213 else:
214 push('%')
215 else:
216 push(ch)
217 newformat = "".join(newformat)
218 return _time.strftime(newformat, timetuple)
219
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000220# Just raise TypeError if the arg isn't None or a string.
221def _check_tzname(name):
222 if name is not None and not isinstance(name, str):
223 raise TypeError("tzinfo.tzname() must return None or string, "
224 "not '%s'" % type(name))
225
226# name is the offset-producing method, "utcoffset" or "dst".
227# offset is what it returned.
228# If offset isn't None or timedelta, raises TypeError.
229# If offset is None, returns None.
230# Else offset is checked for being in range, and a whole # of minutes.
231# If it is, its integer value is returned. Else ValueError is raised.
232def _check_utc_offset(name, offset):
233 assert name in ("utcoffset", "dst")
234 if offset is None:
235 return
236 if not isinstance(offset, timedelta):
237 raise TypeError("tzinfo.%s() must return None "
238 "or timedelta, not '%s'" % (name, type(offset)))
239 if offset % timedelta(minutes=1) or offset.microseconds:
240 raise ValueError("tzinfo.%s() must return a whole number "
241 "of minutes, got %s" % (name, offset))
242 if not -timedelta(1) < offset < timedelta(1):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400243 raise ValueError("%s()=%s, must be must be strictly between "
244 "-timedelta(hours=24) and timedelta(hours=24)" %
245 (name, offset))
246
247def _check_int_field(value):
248 if isinstance(value, int):
249 return value
250 if not isinstance(value, float):
251 try:
252 value = value.__int__()
253 except AttributeError:
254 pass
255 else:
256 if isinstance(value, int):
257 return value
258 raise TypeError('__int__ returned non-int (type %s)' %
259 type(value).__name__)
260 raise TypeError('an integer is required (got type %s)' %
261 type(value).__name__)
262 raise TypeError('integer argument expected, got float')
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000263
264def _check_date_fields(year, month, day):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400265 year = _check_int_field(year)
266 month = _check_int_field(month)
267 day = _check_int_field(day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000268 if not MINYEAR <= year <= MAXYEAR:
269 raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year)
270 if not 1 <= month <= 12:
271 raise ValueError('month must be in 1..12', month)
272 dim = _days_in_month(year, month)
273 if not 1 <= day <= dim:
274 raise ValueError('day must be in 1..%d' % dim, day)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400275 return year, month, day
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000276
277def _check_time_fields(hour, minute, second, microsecond):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400278 hour = _check_int_field(hour)
279 minute = _check_int_field(minute)
280 second = _check_int_field(second)
281 microsecond = _check_int_field(microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000282 if not 0 <= hour <= 23:
283 raise ValueError('hour must be in 0..23', hour)
284 if not 0 <= minute <= 59:
285 raise ValueError('minute must be in 0..59', minute)
286 if not 0 <= second <= 59:
287 raise ValueError('second must be in 0..59', second)
288 if not 0 <= microsecond <= 999999:
289 raise ValueError('microsecond must be in 0..999999', microsecond)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400290 return hour, minute, second, microsecond
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000291
292def _check_tzinfo_arg(tz):
293 if tz is not None and not isinstance(tz, tzinfo):
294 raise TypeError("tzinfo argument must be None or of a tzinfo subclass")
295
296def _cmperror(x, y):
297 raise TypeError("can't compare '%s' to '%s'" % (
298 type(x).__name__, type(y).__name__))
299
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500300def _divide_and_round(a, b):
301 """divide a by b and round result to the nearest integer
302
303 When the ratio is exactly half-way between two integers,
304 the even integer is returned.
305 """
306 # Based on the reference implementation for divmod_near
307 # in Objects/longobject.c.
308 q, r = divmod(a, b)
309 # round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
310 # The expression r / b > 0.5 is equivalent to 2 * r > b if b is
311 # positive, 2 * r < b if b negative.
312 r *= 2
313 greater_than_half = r > b if b > 0 else r < b
314 if greater_than_half or r == b and q % 2 == 1:
315 q += 1
316
317 return q
318
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000319class timedelta:
320 """Represent the difference between two datetime objects.
321
322 Supported operators:
323
324 - add, subtract timedelta
325 - unary plus, minus, abs
326 - compare to timedelta
Serhiy Storchaka95949422013-08-27 19:40:23 +0300327 - multiply, divide by int
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000328
329 In addition, datetime supports subtraction of two datetime objects
330 returning a timedelta, and addition or subtraction of a datetime
331 and a timedelta giving a datetime.
332
333 Representation: (days, seconds, microseconds). Why? Because I
334 felt like it.
335 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400336 __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000337
338 def __new__(cls, days=0, seconds=0, microseconds=0,
339 milliseconds=0, minutes=0, hours=0, weeks=0):
340 # Doing this efficiently and accurately in C is going to be difficult
341 # and error-prone, due to ubiquitous overflow possibilities, and that
342 # C double doesn't have enough bits of precision to represent
343 # microseconds over 10K years faithfully. The code here tries to make
344 # explicit where go-fast assumptions can be relied on, in order to
345 # guide the C implementation; it's way more convoluted than speed-
346 # ignoring auto-overflow-to-long idiomatic Python could be.
347
348 # XXX Check that all inputs are ints or floats.
349
350 # Final values, all integer.
351 # s and us fit in 32-bit signed ints; d isn't bounded.
352 d = s = us = 0
353
354 # Normalize everything to days, seconds, microseconds.
355 days += weeks*7
356 seconds += minutes*60 + hours*3600
357 microseconds += milliseconds*1000
358
359 # Get rid of all fractions, and normalize s and us.
360 # Take a deep breath <wink>.
361 if isinstance(days, float):
362 dayfrac, days = _math.modf(days)
363 daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
364 assert daysecondswhole == int(daysecondswhole) # can't overflow
365 s = int(daysecondswhole)
366 assert days == int(days)
367 d = int(days)
368 else:
369 daysecondsfrac = 0.0
370 d = days
371 assert isinstance(daysecondsfrac, float)
372 assert abs(daysecondsfrac) <= 1.0
373 assert isinstance(d, int)
374 assert abs(s) <= 24 * 3600
375 # days isn't referenced again before redefinition
376
377 if isinstance(seconds, float):
378 secondsfrac, seconds = _math.modf(seconds)
379 assert seconds == int(seconds)
380 seconds = int(seconds)
381 secondsfrac += daysecondsfrac
382 assert abs(secondsfrac) <= 2.0
383 else:
384 secondsfrac = daysecondsfrac
385 # daysecondsfrac isn't referenced again
386 assert isinstance(secondsfrac, float)
387 assert abs(secondsfrac) <= 2.0
388
389 assert isinstance(seconds, int)
390 days, seconds = divmod(seconds, 24*3600)
391 d += days
392 s += int(seconds) # can't overflow
393 assert isinstance(s, int)
394 assert abs(s) <= 2 * 24 * 3600
395 # seconds isn't referenced again before redefinition
396
397 usdouble = secondsfrac * 1e6
398 assert abs(usdouble) < 2.1e6 # exact value not critical
399 # secondsfrac isn't referenced again
400
401 if isinstance(microseconds, float):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400402 microseconds = round(microseconds + usdouble)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000403 seconds, microseconds = divmod(microseconds, 1000000)
404 days, seconds = divmod(seconds, 24*3600)
405 d += days
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400406 s += seconds
407 else:
408 microseconds = int(microseconds)
409 seconds, microseconds = divmod(microseconds, 1000000)
410 days, seconds = divmod(seconds, 24*3600)
411 d += days
412 s += seconds
413 microseconds = round(microseconds + usdouble)
414 assert isinstance(s, int)
415 assert isinstance(microseconds, int)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000416 assert abs(s) <= 3 * 24 * 3600
417 assert abs(microseconds) < 3.1e6
418
419 # Just a little bit of carrying possible for microseconds and seconds.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400420 seconds, us = divmod(microseconds, 1000000)
421 s += seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000422 days, s = divmod(s, 24*3600)
423 d += days
424
425 assert isinstance(d, int)
426 assert isinstance(s, int) and 0 <= s < 24*3600
427 assert isinstance(us, int) and 0 <= us < 1000000
428
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000429 if abs(d) > 999999999:
430 raise OverflowError("timedelta # of days is too large: %d" % d)
431
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400432 self = object.__new__(cls)
433 self._days = d
434 self._seconds = s
435 self._microseconds = us
436 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000437 return self
438
439 def __repr__(self):
440 if self._microseconds:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300441 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
442 self.__class__.__qualname__,
443 self._days,
444 self._seconds,
445 self._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000446 if self._seconds:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300447 return "%s.%s(%d, %d)" % (self.__class__.__module__,
448 self.__class__.__qualname__,
449 self._days,
450 self._seconds)
451 return "%s.%s(%d)" % (self.__class__.__module__,
452 self.__class__.__qualname__,
453 self._days)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000454
455 def __str__(self):
456 mm, ss = divmod(self._seconds, 60)
457 hh, mm = divmod(mm, 60)
458 s = "%d:%02d:%02d" % (hh, mm, ss)
459 if self._days:
460 def plural(n):
461 return n, abs(n) != 1 and "s" or ""
462 s = ("%d day%s, " % plural(self._days)) + s
463 if self._microseconds:
464 s = s + ".%06d" % self._microseconds
465 return s
466
467 def total_seconds(self):
468 """Total seconds in the duration."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400469 return ((self.days * 86400 + self.seconds) * 10**6 +
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000470 self.microseconds) / 10**6
471
472 # Read-only field accessors
473 @property
474 def days(self):
475 """days"""
476 return self._days
477
478 @property
479 def seconds(self):
480 """seconds"""
481 return self._seconds
482
483 @property
484 def microseconds(self):
485 """microseconds"""
486 return self._microseconds
487
488 def __add__(self, other):
489 if isinstance(other, timedelta):
490 # for CPython compatibility, we cannot use
491 # our __class__ here, but need a real timedelta
492 return timedelta(self._days + other._days,
493 self._seconds + other._seconds,
494 self._microseconds + other._microseconds)
495 return NotImplemented
496
497 __radd__ = __add__
498
499 def __sub__(self, other):
500 if isinstance(other, timedelta):
Alexander Belopolskyb6f5ec72011-04-05 20:07:38 -0400501 # for CPython compatibility, we cannot use
502 # our __class__ here, but need a real timedelta
503 return timedelta(self._days - other._days,
504 self._seconds - other._seconds,
505 self._microseconds - other._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000506 return NotImplemented
507
508 def __rsub__(self, other):
509 if isinstance(other, timedelta):
510 return -self + other
511 return NotImplemented
512
513 def __neg__(self):
514 # for CPython compatibility, we cannot use
515 # our __class__ here, but need a real timedelta
516 return timedelta(-self._days,
517 -self._seconds,
518 -self._microseconds)
519
520 def __pos__(self):
521 return self
522
523 def __abs__(self):
524 if self._days < 0:
525 return -self
526 else:
527 return self
528
529 def __mul__(self, other):
530 if isinstance(other, int):
531 # for CPython compatibility, we cannot use
532 # our __class__ here, but need a real timedelta
533 return timedelta(self._days * other,
534 self._seconds * other,
535 self._microseconds * other)
536 if isinstance(other, float):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500537 usec = self._to_microseconds()
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000538 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500539 return timedelta(0, 0, _divide_and_round(usec * a, b))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000540 return NotImplemented
541
542 __rmul__ = __mul__
543
544 def _to_microseconds(self):
545 return ((self._days * (24*3600) + self._seconds) * 1000000 +
546 self._microseconds)
547
548 def __floordiv__(self, other):
549 if not isinstance(other, (int, timedelta)):
550 return NotImplemented
551 usec = self._to_microseconds()
552 if isinstance(other, timedelta):
553 return usec // other._to_microseconds()
554 if isinstance(other, int):
555 return timedelta(0, 0, usec // other)
556
557 def __truediv__(self, other):
558 if not isinstance(other, (int, float, timedelta)):
559 return NotImplemented
560 usec = self._to_microseconds()
561 if isinstance(other, timedelta):
562 return usec / other._to_microseconds()
563 if isinstance(other, int):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500564 return timedelta(0, 0, _divide_and_round(usec, other))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000565 if isinstance(other, float):
566 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500567 return timedelta(0, 0, _divide_and_round(b * usec, a))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000568
569 def __mod__(self, other):
570 if isinstance(other, timedelta):
571 r = self._to_microseconds() % other._to_microseconds()
572 return timedelta(0, 0, r)
573 return NotImplemented
574
575 def __divmod__(self, other):
576 if isinstance(other, timedelta):
577 q, r = divmod(self._to_microseconds(),
578 other._to_microseconds())
579 return q, timedelta(0, 0, r)
580 return NotImplemented
581
582 # Comparisons of timedelta objects with other.
583
584 def __eq__(self, other):
585 if isinstance(other, timedelta):
586 return self._cmp(other) == 0
587 else:
588 return False
589
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000590 def __le__(self, other):
591 if isinstance(other, timedelta):
592 return self._cmp(other) <= 0
593 else:
594 _cmperror(self, other)
595
596 def __lt__(self, other):
597 if isinstance(other, timedelta):
598 return self._cmp(other) < 0
599 else:
600 _cmperror(self, other)
601
602 def __ge__(self, other):
603 if isinstance(other, timedelta):
604 return self._cmp(other) >= 0
605 else:
606 _cmperror(self, other)
607
608 def __gt__(self, other):
609 if isinstance(other, timedelta):
610 return self._cmp(other) > 0
611 else:
612 _cmperror(self, other)
613
614 def _cmp(self, other):
615 assert isinstance(other, timedelta)
616 return _cmp(self._getstate(), other._getstate())
617
618 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400619 if self._hashcode == -1:
620 self._hashcode = hash(self._getstate())
621 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000622
623 def __bool__(self):
624 return (self._days != 0 or
625 self._seconds != 0 or
626 self._microseconds != 0)
627
628 # Pickle support.
629
630 def _getstate(self):
631 return (self._days, self._seconds, self._microseconds)
632
633 def __reduce__(self):
634 return (self.__class__, self._getstate())
635
636timedelta.min = timedelta(-999999999)
637timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
638 microseconds=999999)
639timedelta.resolution = timedelta(microseconds=1)
640
641class date:
642 """Concrete date type.
643
644 Constructors:
645
646 __new__()
647 fromtimestamp()
648 today()
649 fromordinal()
650
651 Operators:
652
653 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200654 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000655 __add__, __radd__, __sub__ (add/radd only with timedelta arg)
656
657 Methods:
658
659 timetuple()
660 toordinal()
661 weekday()
662 isoweekday(), isocalendar(), isoformat()
663 ctime()
664 strftime()
665
666 Properties (readonly):
667 year, month, day
668 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400669 __slots__ = '_year', '_month', '_day', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000670
671 def __new__(cls, year, month=None, day=None):
672 """Constructor.
673
674 Arguments:
675
676 year, month, day (required, base 1)
677 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400678 if month is None and isinstance(year, bytes) and len(year) == 4 and \
679 1 <= year[2] <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000680 # Pickle support
681 self = object.__new__(cls)
682 self.__setstate(year)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400683 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000684 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400685 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000686 self = object.__new__(cls)
687 self._year = year
688 self._month = month
689 self._day = day
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400690 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000691 return self
692
693 # Additional constructors
694
695 @classmethod
696 def fromtimestamp(cls, t):
697 "Construct a date from a POSIX timestamp (like time.time())."
698 y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
699 return cls(y, m, d)
700
701 @classmethod
702 def today(cls):
703 "Construct a date from time.time()."
704 t = _time.time()
705 return cls.fromtimestamp(t)
706
707 @classmethod
708 def fromordinal(cls, n):
709 """Contruct a date from a proleptic Gregorian ordinal.
710
711 January 1 of year 1 is day 1. Only the year, month and day are
712 non-zero in the result.
713 """
714 y, m, d = _ord2ymd(n)
715 return cls(y, m, d)
716
717 # Conversions to string
718
719 def __repr__(self):
720 """Convert to formal string, for repr().
721
722 >>> dt = datetime(2010, 1, 1)
723 >>> repr(dt)
724 'datetime.datetime(2010, 1, 1, 0, 0)'
725
726 >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
727 >>> repr(dt)
728 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
729 """
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300730 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
731 self.__class__.__qualname__,
732 self._year,
733 self._month,
734 self._day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000735 # XXX These shouldn't depend on time.localtime(), because that
736 # clips the usable dates to [1970 .. 2038). At least ctime() is
737 # easily done without using strftime() -- that's better too because
738 # strftime("%c", ...) is locale specific.
739
740
741 def ctime(self):
742 "Return ctime() style string."
743 weekday = self.toordinal() % 7 or 7
744 return "%s %s %2d 00:00:00 %04d" % (
745 _DAYNAMES[weekday],
746 _MONTHNAMES[self._month],
747 self._day, self._year)
748
749 def strftime(self, fmt):
750 "Format using strftime()."
751 return _wrap_strftime(self, fmt, self.timetuple())
752
753 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400754 if not isinstance(fmt, str):
755 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000756 if len(fmt) != 0:
757 return self.strftime(fmt)
758 return str(self)
759
760 def isoformat(self):
761 """Return the date formatted according to ISO.
762
763 This is 'YYYY-MM-DD'.
764
765 References:
766 - http://www.w3.org/TR/NOTE-datetime
767 - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
768 """
769 return "%04d-%02d-%02d" % (self._year, self._month, self._day)
770
771 __str__ = isoformat
772
773 # Read-only field accessors
774 @property
775 def year(self):
776 """year (1-9999)"""
777 return self._year
778
779 @property
780 def month(self):
781 """month (1-12)"""
782 return self._month
783
784 @property
785 def day(self):
786 """day (1-31)"""
787 return self._day
788
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200789 # Standard conversions, __eq__, __le__, __lt__, __ge__, __gt__,
790 # __hash__ (and helpers)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000791
792 def timetuple(self):
793 "Return local time tuple compatible with time.localtime()."
794 return _build_struct_time(self._year, self._month, self._day,
795 0, 0, 0, -1)
796
797 def toordinal(self):
798 """Return proleptic Gregorian ordinal for the year, month and day.
799
800 January 1 of year 1 is day 1. Only the year, month and day values
801 contribute to the result.
802 """
803 return _ymd2ord(self._year, self._month, self._day)
804
805 def replace(self, year=None, month=None, day=None):
806 """Return a new date with new values for the specified fields."""
807 if year is None:
808 year = self._year
809 if month is None:
810 month = self._month
811 if day is None:
812 day = self._day
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000813 return date(year, month, day)
814
815 # Comparisons of date objects with other.
816
817 def __eq__(self, other):
818 if isinstance(other, date):
819 return self._cmp(other) == 0
820 return NotImplemented
821
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000822 def __le__(self, other):
823 if isinstance(other, date):
824 return self._cmp(other) <= 0
825 return NotImplemented
826
827 def __lt__(self, other):
828 if isinstance(other, date):
829 return self._cmp(other) < 0
830 return NotImplemented
831
832 def __ge__(self, other):
833 if isinstance(other, date):
834 return self._cmp(other) >= 0
835 return NotImplemented
836
837 def __gt__(self, other):
838 if isinstance(other, date):
839 return self._cmp(other) > 0
840 return NotImplemented
841
842 def _cmp(self, other):
843 assert isinstance(other, date)
844 y, m, d = self._year, self._month, self._day
845 y2, m2, d2 = other._year, other._month, other._day
846 return _cmp((y, m, d), (y2, m2, d2))
847
848 def __hash__(self):
849 "Hash."
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400850 if self._hashcode == -1:
851 self._hashcode = hash(self._getstate())
852 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000853
854 # Computations
855
856 def __add__(self, other):
857 "Add a date to a timedelta."
858 if isinstance(other, timedelta):
859 o = self.toordinal() + other.days
860 if 0 < o <= _MAXORDINAL:
861 return date.fromordinal(o)
862 raise OverflowError("result out of range")
863 return NotImplemented
864
865 __radd__ = __add__
866
867 def __sub__(self, other):
868 """Subtract two dates, or a date and a timedelta."""
869 if isinstance(other, timedelta):
870 return self + timedelta(-other.days)
871 if isinstance(other, date):
872 days1 = self.toordinal()
873 days2 = other.toordinal()
874 return timedelta(days1 - days2)
875 return NotImplemented
876
877 def weekday(self):
878 "Return day of the week, where Monday == 0 ... Sunday == 6."
879 return (self.toordinal() + 6) % 7
880
881 # Day-of-the-week and week-of-the-year, according to ISO
882
883 def isoweekday(self):
884 "Return day of the week, where Monday == 1 ... Sunday == 7."
885 # 1-Jan-0001 is a Monday
886 return self.toordinal() % 7 or 7
887
888 def isocalendar(self):
889 """Return a 3-tuple containing ISO year, week number, and weekday.
890
891 The first ISO week of the year is the (Mon-Sun) week
892 containing the year's first Thursday; everything else derives
893 from that.
894
895 The first week is 1; Monday is 1 ... Sunday is 7.
896
897 ISO calendar algorithm taken from
898 http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
899 """
900 year = self._year
901 week1monday = _isoweek1monday(year)
902 today = _ymd2ord(self._year, self._month, self._day)
903 # Internally, week and day have origin 0
904 week, day = divmod(today - week1monday, 7)
905 if week < 0:
906 year -= 1
907 week1monday = _isoweek1monday(year)
908 week, day = divmod(today - week1monday, 7)
909 elif week >= 52:
910 if today >= _isoweek1monday(year+1):
911 year += 1
912 week = 0
913 return year, week+1, day+1
914
915 # Pickle support.
916
917 def _getstate(self):
918 yhi, ylo = divmod(self._year, 256)
919 return bytes([yhi, ylo, self._month, self._day]),
920
921 def __setstate(self, string):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000922 yhi, ylo, self._month, self._day = string
923 self._year = yhi * 256 + ylo
924
925 def __reduce__(self):
926 return (self.__class__, self._getstate())
927
928_date_class = date # so functions w/ args named "date" can get at the class
929
930date.min = date(1, 1, 1)
931date.max = date(9999, 12, 31)
932date.resolution = timedelta(days=1)
933
934class tzinfo:
935 """Abstract base class for time zone info classes.
936
937 Subclasses must override the name(), utcoffset() and dst() methods.
938 """
939 __slots__ = ()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400940
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000941 def tzname(self, dt):
942 "datetime -> string name of time zone."
943 raise NotImplementedError("tzinfo subclass must override tzname()")
944
945 def utcoffset(self, dt):
946 "datetime -> minutes east of UTC (negative for west of UTC)"
947 raise NotImplementedError("tzinfo subclass must override utcoffset()")
948
949 def dst(self, dt):
950 """datetime -> DST offset in minutes east of UTC.
951
952 Return 0 if DST not in effect. utcoffset() must include the DST
953 offset.
954 """
955 raise NotImplementedError("tzinfo subclass must override dst()")
956
957 def fromutc(self, dt):
958 "datetime in UTC -> datetime in local time."
959
960 if not isinstance(dt, datetime):
961 raise TypeError("fromutc() requires a datetime argument")
962 if dt.tzinfo is not self:
963 raise ValueError("dt.tzinfo is not self")
964
965 dtoff = dt.utcoffset()
966 if dtoff is None:
967 raise ValueError("fromutc() requires a non-None utcoffset() "
968 "result")
969
970 # See the long comment block at the end of this file for an
971 # explanation of this algorithm.
972 dtdst = dt.dst()
973 if dtdst is None:
974 raise ValueError("fromutc() requires a non-None dst() result")
975 delta = dtoff - dtdst
976 if delta:
977 dt += delta
978 dtdst = dt.dst()
979 if dtdst is None:
980 raise ValueError("fromutc(): dt.dst gave inconsistent "
981 "results; cannot convert")
982 return dt + dtdst
983
984 # Pickle support.
985
986 def __reduce__(self):
987 getinitargs = getattr(self, "__getinitargs__", None)
988 if getinitargs:
989 args = getinitargs()
990 else:
991 args = ()
992 getstate = getattr(self, "__getstate__", None)
993 if getstate:
994 state = getstate()
995 else:
996 state = getattr(self, "__dict__", None) or None
997 if state is None:
998 return (self.__class__, args)
999 else:
1000 return (self.__class__, args, state)
1001
1002_tzinfo_class = tzinfo
1003
1004class time:
1005 """Time with time zone.
1006
1007 Constructors:
1008
1009 __new__()
1010
1011 Operators:
1012
1013 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +02001014 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001015
1016 Methods:
1017
1018 strftime()
1019 isoformat()
1020 utcoffset()
1021 tzname()
1022 dst()
1023
1024 Properties (readonly):
1025 hour, minute, second, microsecond, tzinfo
1026 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001027 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001028
1029 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None):
1030 """Constructor.
1031
1032 Arguments:
1033
1034 hour, minute (required)
1035 second, microsecond (default to zero)
1036 tzinfo (default to None)
1037 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001038 if isinstance(hour, bytes) and len(hour) == 6 and hour[0] < 24:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001039 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001040 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001041 self.__setstate(hour, minute or None)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001042 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001043 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001044 hour, minute, second, microsecond = _check_time_fields(
1045 hour, minute, second, microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001046 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001047 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001048 self._hour = hour
1049 self._minute = minute
1050 self._second = second
1051 self._microsecond = microsecond
1052 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001053 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001054 return self
1055
1056 # Read-only field accessors
1057 @property
1058 def hour(self):
1059 """hour (0-23)"""
1060 return self._hour
1061
1062 @property
1063 def minute(self):
1064 """minute (0-59)"""
1065 return self._minute
1066
1067 @property
1068 def second(self):
1069 """second (0-59)"""
1070 return self._second
1071
1072 @property
1073 def microsecond(self):
1074 """microsecond (0-999999)"""
1075 return self._microsecond
1076
1077 @property
1078 def tzinfo(self):
1079 """timezone info object"""
1080 return self._tzinfo
1081
1082 # Standard conversions, __hash__ (and helpers)
1083
1084 # Comparisons of time objects with other.
1085
1086 def __eq__(self, other):
1087 if isinstance(other, time):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001088 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001089 else:
1090 return False
1091
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001092 def __le__(self, other):
1093 if isinstance(other, time):
1094 return self._cmp(other) <= 0
1095 else:
1096 _cmperror(self, other)
1097
1098 def __lt__(self, other):
1099 if isinstance(other, time):
1100 return self._cmp(other) < 0
1101 else:
1102 _cmperror(self, other)
1103
1104 def __ge__(self, other):
1105 if isinstance(other, time):
1106 return self._cmp(other) >= 0
1107 else:
1108 _cmperror(self, other)
1109
1110 def __gt__(self, other):
1111 if isinstance(other, time):
1112 return self._cmp(other) > 0
1113 else:
1114 _cmperror(self, other)
1115
Alexander Belopolsky08313822012-06-15 20:19:47 -04001116 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001117 assert isinstance(other, time)
1118 mytz = self._tzinfo
1119 ottz = other._tzinfo
1120 myoff = otoff = None
1121
1122 if mytz is ottz:
1123 base_compare = True
1124 else:
1125 myoff = self.utcoffset()
1126 otoff = other.utcoffset()
1127 base_compare = myoff == otoff
1128
1129 if base_compare:
1130 return _cmp((self._hour, self._minute, self._second,
1131 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001132 (other._hour, other._minute, other._second,
1133 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001134 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001135 if allow_mixed:
1136 return 2 # arbitrary non-zero value
1137 else:
1138 raise TypeError("cannot compare naive and aware times")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001139 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1140 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1141 return _cmp((myhhmm, self._second, self._microsecond),
1142 (othhmm, other._second, other._microsecond))
1143
1144 def __hash__(self):
1145 """Hash."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001146 if self._hashcode == -1:
1147 tzoff = self.utcoffset()
1148 if not tzoff: # zero or None
1149 self._hashcode = hash(self._getstate()[0])
1150 else:
1151 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1152 timedelta(hours=1))
1153 assert not m % timedelta(minutes=1), "whole minute"
1154 m //= timedelta(minutes=1)
1155 if 0 <= h < 24:
1156 self._hashcode = hash(time(h, m, self.second, self.microsecond))
1157 else:
1158 self._hashcode = hash((h, m, self.second, self.microsecond))
1159 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001160
1161 # Conversion to string
1162
1163 def _tzstr(self, sep=":"):
1164 """Return formatted timezone offset (+xx:xx) or None."""
1165 off = self.utcoffset()
1166 if off is not None:
1167 if off.days < 0:
1168 sign = "-"
1169 off = -off
1170 else:
1171 sign = "+"
1172 hh, mm = divmod(off, timedelta(hours=1))
1173 assert not mm % timedelta(minutes=1), "whole minute"
1174 mm //= timedelta(minutes=1)
1175 assert 0 <= hh < 24
1176 off = "%s%02d%s%02d" % (sign, hh, sep, mm)
1177 return off
1178
1179 def __repr__(self):
1180 """Convert to formal string, for repr()."""
1181 if self._microsecond != 0:
1182 s = ", %d, %d" % (self._second, self._microsecond)
1183 elif self._second != 0:
1184 s = ", %d" % self._second
1185 else:
1186 s = ""
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001187 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1188 self.__class__.__qualname__,
1189 self._hour, self._minute, s)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001190 if self._tzinfo is not None:
1191 assert s[-1:] == ")"
1192 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
1193 return s
1194
1195 def isoformat(self):
1196 """Return the time formatted according to ISO.
1197
1198 This is 'HH:MM:SS.mmmmmm+zz:zz', or 'HH:MM:SS+zz:zz' if
1199 self.microsecond == 0.
1200 """
1201 s = _format_time(self._hour, self._minute, self._second,
1202 self._microsecond)
1203 tz = self._tzstr()
1204 if tz:
1205 s += tz
1206 return s
1207
1208 __str__ = isoformat
1209
1210 def strftime(self, fmt):
1211 """Format using strftime(). The date part of the timestamp passed
1212 to underlying strftime should not be used.
1213 """
Alexander Belopolskyb8bb4662011-01-08 00:13:34 +00001214 # The year must be >= 1000 else Python's strftime implementation
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001215 # can raise a bogus exception.
1216 timetuple = (1900, 1, 1,
1217 self._hour, self._minute, self._second,
1218 0, 1, -1)
1219 return _wrap_strftime(self, fmt, timetuple)
1220
1221 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001222 if not isinstance(fmt, str):
1223 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001224 if len(fmt) != 0:
1225 return self.strftime(fmt)
1226 return str(self)
1227
1228 # Timezone functions
1229
1230 def utcoffset(self):
1231 """Return the timezone offset in minutes east of UTC (negative west of
1232 UTC)."""
1233 if self._tzinfo is None:
1234 return None
1235 offset = self._tzinfo.utcoffset(None)
1236 _check_utc_offset("utcoffset", offset)
1237 return offset
1238
1239 def tzname(self):
1240 """Return the timezone name.
1241
1242 Note that the name is 100% informational -- there's no requirement that
1243 it mean anything in particular. For example, "GMT", "UTC", "-500",
1244 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1245 """
1246 if self._tzinfo is None:
1247 return None
1248 name = self._tzinfo.tzname(None)
1249 _check_tzname(name)
1250 return name
1251
1252 def dst(self):
1253 """Return 0 if DST is not in effect, or the DST offset (in minutes
1254 eastward) if DST is in effect.
1255
1256 This is purely informational; the DST offset has already been added to
1257 the UTC offset returned by utcoffset() if applicable, so there's no
1258 need to consult dst() unless you're interested in displaying the DST
1259 info.
1260 """
1261 if self._tzinfo is None:
1262 return None
1263 offset = self._tzinfo.dst(None)
1264 _check_utc_offset("dst", offset)
1265 return offset
1266
1267 def replace(self, hour=None, minute=None, second=None, microsecond=None,
1268 tzinfo=True):
1269 """Return a new time with new values for the specified fields."""
1270 if hour is None:
1271 hour = self.hour
1272 if minute is None:
1273 minute = self.minute
1274 if second is None:
1275 second = self.second
1276 if microsecond is None:
1277 microsecond = self.microsecond
1278 if tzinfo is True:
1279 tzinfo = self.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001280 return time(hour, minute, second, microsecond, tzinfo)
1281
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001282 # Pickle support.
1283
1284 def _getstate(self):
1285 us2, us3 = divmod(self._microsecond, 256)
1286 us1, us2 = divmod(us2, 256)
1287 basestate = bytes([self._hour, self._minute, self._second,
1288 us1, us2, us3])
1289 if self._tzinfo is None:
1290 return (basestate,)
1291 else:
1292 return (basestate, self._tzinfo)
1293
1294 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001295 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1296 raise TypeError("bad tzinfo state arg")
1297 self._hour, self._minute, self._second, us1, us2, us3 = string
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001298 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001299 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001300
1301 def __reduce__(self):
1302 return (time, self._getstate())
1303
1304_time_class = time # so functions w/ args named "time" can get at the class
1305
1306time.min = time(0, 0, 0)
1307time.max = time(23, 59, 59, 999999)
1308time.resolution = timedelta(microseconds=1)
1309
1310class datetime(date):
1311 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1312
1313 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001314 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001315 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001316 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001317
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001318 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
1319 microsecond=0, tzinfo=None):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001320 if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2] <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001321 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001322 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001323 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001324 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001325 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001326 year, month, day = _check_date_fields(year, month, day)
1327 hour, minute, second, microsecond = _check_time_fields(
1328 hour, minute, second, microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001329 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001330 self = object.__new__(cls)
1331 self._year = year
1332 self._month = month
1333 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001334 self._hour = hour
1335 self._minute = minute
1336 self._second = second
1337 self._microsecond = microsecond
1338 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001339 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001340 return self
1341
1342 # Read-only field accessors
1343 @property
1344 def hour(self):
1345 """hour (0-23)"""
1346 return self._hour
1347
1348 @property
1349 def minute(self):
1350 """minute (0-59)"""
1351 return self._minute
1352
1353 @property
1354 def second(self):
1355 """second (0-59)"""
1356 return self._second
1357
1358 @property
1359 def microsecond(self):
1360 """microsecond (0-999999)"""
1361 return self._microsecond
1362
1363 @property
1364 def tzinfo(self):
1365 """timezone info object"""
1366 return self._tzinfo
1367
1368 @classmethod
1369 def fromtimestamp(cls, t, tz=None):
1370 """Construct a datetime from a POSIX timestamp (like time.time()).
1371
1372 A timezone info object may be passed in as well.
1373 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001374 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001375
1376 converter = _time.localtime if tz is None else _time.gmtime
1377
1378 t, frac = divmod(t, 1.0)
Victor Stinner5d272cc2012-03-13 13:35:55 +01001379 us = int(frac * 1e6)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001380
1381 # If timestamp is less than one microsecond smaller than a
1382 # full second, us can be rounded up to 1000000. In this case,
1383 # roll over to seconds, otherwise, ValueError is raised
1384 # by the constructor.
1385 if us == 1000000:
1386 t += 1
1387 us = 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001388 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001389 ss = min(ss, 59) # clamp out leap seconds if the platform has them
1390 result = cls(y, m, d, hh, mm, ss, us, tz)
1391 if tz is not None:
1392 result = tz.fromutc(result)
1393 return result
1394
1395 @classmethod
1396 def utcfromtimestamp(cls, t):
Alexander Belopolskye2e178e2015-03-01 14:52:07 -05001397 """Construct a naive UTC datetime from a POSIX timestamp."""
Alexander Belopolsky3e62f782010-09-21 16:30:56 +00001398 t, frac = divmod(t, 1.0)
Victor Stinner5d272cc2012-03-13 13:35:55 +01001399 us = int(frac * 1e6)
Alexander Belopolsky3e62f782010-09-21 16:30:56 +00001400
1401 # If timestamp is less than one microsecond smaller than a
1402 # full second, us can be rounded up to 1000000. In this case,
1403 # roll over to seconds, otherwise, ValueError is raised
1404 # by the constructor.
1405 if us == 1000000:
1406 t += 1
1407 us = 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001408 y, m, d, hh, mm, ss, weekday, jday, dst = _time.gmtime(t)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001409 ss = min(ss, 59) # clamp out leap seconds if the platform has them
1410 return cls(y, m, d, hh, mm, ss, us)
1411
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001412 @classmethod
1413 def now(cls, tz=None):
1414 "Construct a datetime from time.time() and optional time zone info."
1415 t = _time.time()
1416 return cls.fromtimestamp(t, tz)
1417
1418 @classmethod
1419 def utcnow(cls):
1420 "Construct a UTC datetime from time.time()."
1421 t = _time.time()
1422 return cls.utcfromtimestamp(t)
1423
1424 @classmethod
1425 def combine(cls, date, time):
1426 "Construct a datetime from a given date and a given time."
1427 if not isinstance(date, _date_class):
1428 raise TypeError("date argument must be a date instance")
1429 if not isinstance(time, _time_class):
1430 raise TypeError("time argument must be a time instance")
1431 return cls(date.year, date.month, date.day,
1432 time.hour, time.minute, time.second, time.microsecond,
1433 time.tzinfo)
1434
1435 def timetuple(self):
1436 "Return local time tuple compatible with time.localtime()."
1437 dst = self.dst()
1438 if dst is None:
1439 dst = -1
1440 elif dst:
1441 dst = 1
1442 else:
1443 dst = 0
1444 return _build_struct_time(self.year, self.month, self.day,
1445 self.hour, self.minute, self.second,
1446 dst)
1447
Alexander Belopolskya4415142012-06-08 12:33:09 -04001448 def timestamp(self):
1449 "Return POSIX timestamp as float"
1450 if self._tzinfo is None:
1451 return _time.mktime((self.year, self.month, self.day,
1452 self.hour, self.minute, self.second,
1453 -1, -1, -1)) + self.microsecond / 1e6
1454 else:
1455 return (self - _EPOCH).total_seconds()
1456
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001457 def utctimetuple(self):
1458 "Return UTC time tuple compatible with time.gmtime()."
1459 offset = self.utcoffset()
1460 if offset:
1461 self -= offset
1462 y, m, d = self.year, self.month, self.day
1463 hh, mm, ss = self.hour, self.minute, self.second
1464 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1465
1466 def date(self):
1467 "Return the date part."
1468 return date(self._year, self._month, self._day)
1469
1470 def time(self):
1471 "Return the time part, with tzinfo None."
1472 return time(self.hour, self.minute, self.second, self.microsecond)
1473
1474 def timetz(self):
1475 "Return the time part, with same tzinfo."
1476 return time(self.hour, self.minute, self.second, self.microsecond,
1477 self._tzinfo)
1478
1479 def replace(self, year=None, month=None, day=None, hour=None,
1480 minute=None, second=None, microsecond=None, tzinfo=True):
1481 """Return a new datetime with new values for the specified fields."""
1482 if year is None:
1483 year = self.year
1484 if month is None:
1485 month = self.month
1486 if day is None:
1487 day = self.day
1488 if hour is None:
1489 hour = self.hour
1490 if minute is None:
1491 minute = self.minute
1492 if second is None:
1493 second = self.second
1494 if microsecond is None:
1495 microsecond = self.microsecond
1496 if tzinfo is True:
1497 tzinfo = self.tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001498 return datetime(year, month, day, hour, minute, second, microsecond,
1499 tzinfo)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001500
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001501 def astimezone(self, tz=None):
1502 if tz is None:
1503 if self.tzinfo is None:
1504 raise ValueError("astimezone() requires an aware datetime")
1505 ts = (self - _EPOCH) // timedelta(seconds=1)
1506 localtm = _time.localtime(ts)
1507 local = datetime(*localtm[:6])
1508 try:
Alexander Belopolskyff493c92012-06-22 12:25:57 -04001509 # Extract TZ data if available
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001510 gmtoff = localtm.tm_gmtoff
1511 zone = localtm.tm_zone
1512 except AttributeError:
1513 # Compute UTC offset and compare with the value implied
1514 # by tm_isdst. If the values match, use the zone name
1515 # implied by tm_isdst.
1516 delta = local - datetime(*_time.gmtime(ts)[:6])
1517 dst = _time.daylight and localtm.tm_isdst > 0
Alexander Belopolsky93c9cd02012-06-22 16:04:19 -04001518 gmtoff = -(_time.altzone if dst else _time.timezone)
1519 if delta == timedelta(seconds=gmtoff):
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001520 tz = timezone(delta, _time.tzname[dst])
1521 else:
1522 tz = timezone(delta)
1523 else:
Alexander Belopolsky93c9cd02012-06-22 16:04:19 -04001524 tz = timezone(timedelta(seconds=gmtoff), zone)
Alexander Belopolskyff493c92012-06-22 12:25:57 -04001525
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001526 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001527 raise TypeError("tz argument must be an instance of tzinfo")
1528
1529 mytz = self.tzinfo
1530 if mytz is None:
1531 raise ValueError("astimezone() requires an aware datetime")
1532
1533 if tz is mytz:
1534 return self
1535
1536 # Convert self to UTC, and attach the new time zone object.
1537 myoffset = self.utcoffset()
1538 if myoffset is None:
1539 raise ValueError("astimezone() requires an aware datetime")
1540 utc = (self - myoffset).replace(tzinfo=tz)
1541
1542 # Convert from UTC to tz's local time.
1543 return tz.fromutc(utc)
1544
1545 # Ways to produce a string.
1546
1547 def ctime(self):
1548 "Return ctime() style string."
1549 weekday = self.toordinal() % 7 or 7
1550 return "%s %s %2d %02d:%02d:%02d %04d" % (
1551 _DAYNAMES[weekday],
1552 _MONTHNAMES[self._month],
1553 self._day,
1554 self._hour, self._minute, self._second,
1555 self._year)
1556
1557 def isoformat(self, sep='T'):
1558 """Return the time formatted according to ISO.
1559
1560 This is 'YYYY-MM-DD HH:MM:SS.mmmmmm', or 'YYYY-MM-DD HH:MM:SS' if
1561 self.microsecond == 0.
1562
1563 If self.tzinfo is not None, the UTC offset is also attached, giving
1564 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM' or 'YYYY-MM-DD HH:MM:SS+HH:MM'.
1565
1566 Optional argument sep specifies the separator between date and
1567 time, default 'T'.
1568 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001569 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1570 _format_time(self._hour, self._minute, self._second,
1571 self._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001572 off = self.utcoffset()
1573 if off is not None:
1574 if off.days < 0:
1575 sign = "-"
1576 off = -off
1577 else:
1578 sign = "+"
1579 hh, mm = divmod(off, timedelta(hours=1))
1580 assert not mm % timedelta(minutes=1), "whole minute"
1581 mm //= timedelta(minutes=1)
1582 s += "%s%02d:%02d" % (sign, hh, mm)
1583 return s
1584
1585 def __repr__(self):
1586 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001587 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001588 self._hour, self._minute, self._second, self._microsecond]
1589 if L[-1] == 0:
1590 del L[-1]
1591 if L[-1] == 0:
1592 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001593 s = "%s.%s(%s)" % (self.__class__.__module__,
1594 self.__class__.__qualname__,
1595 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001596 if self._tzinfo is not None:
1597 assert s[-1:] == ")"
1598 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
1599 return s
1600
1601 def __str__(self):
1602 "Convert to string, for str()."
1603 return self.isoformat(sep=' ')
1604
1605 @classmethod
1606 def strptime(cls, date_string, format):
1607 'string, format -> new datetime parsed from a string (like time.strptime()).'
1608 import _strptime
1609 return _strptime._strptime_datetime(cls, date_string, format)
1610
1611 def utcoffset(self):
1612 """Return the timezone offset in minutes east of UTC (negative west of
1613 UTC)."""
1614 if self._tzinfo is None:
1615 return None
1616 offset = self._tzinfo.utcoffset(self)
1617 _check_utc_offset("utcoffset", offset)
1618 return offset
1619
1620 def tzname(self):
1621 """Return the timezone name.
1622
1623 Note that the name is 100% informational -- there's no requirement that
1624 it mean anything in particular. For example, "GMT", "UTC", "-500",
1625 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1626 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001627 if self._tzinfo is None:
1628 return None
1629 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001630 _check_tzname(name)
1631 return name
1632
1633 def dst(self):
1634 """Return 0 if DST is not in effect, or the DST offset (in minutes
1635 eastward) if DST is in effect.
1636
1637 This is purely informational; the DST offset has already been added to
1638 the UTC offset returned by utcoffset() if applicable, so there's no
1639 need to consult dst() unless you're interested in displaying the DST
1640 info.
1641 """
1642 if self._tzinfo is None:
1643 return None
1644 offset = self._tzinfo.dst(self)
1645 _check_utc_offset("dst", offset)
1646 return offset
1647
1648 # Comparisons of datetime objects with other.
1649
1650 def __eq__(self, other):
1651 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001652 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001653 elif not isinstance(other, date):
1654 return NotImplemented
1655 else:
1656 return False
1657
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001658 def __le__(self, other):
1659 if isinstance(other, datetime):
1660 return self._cmp(other) <= 0
1661 elif not isinstance(other, date):
1662 return NotImplemented
1663 else:
1664 _cmperror(self, other)
1665
1666 def __lt__(self, other):
1667 if isinstance(other, datetime):
1668 return self._cmp(other) < 0
1669 elif not isinstance(other, date):
1670 return NotImplemented
1671 else:
1672 _cmperror(self, other)
1673
1674 def __ge__(self, other):
1675 if isinstance(other, datetime):
1676 return self._cmp(other) >= 0
1677 elif not isinstance(other, date):
1678 return NotImplemented
1679 else:
1680 _cmperror(self, other)
1681
1682 def __gt__(self, other):
1683 if isinstance(other, datetime):
1684 return self._cmp(other) > 0
1685 elif not isinstance(other, date):
1686 return NotImplemented
1687 else:
1688 _cmperror(self, other)
1689
Alexander Belopolsky08313822012-06-15 20:19:47 -04001690 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001691 assert isinstance(other, datetime)
1692 mytz = self._tzinfo
1693 ottz = other._tzinfo
1694 myoff = otoff = None
1695
1696 if mytz is ottz:
1697 base_compare = True
1698 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04001699 myoff = self.utcoffset()
1700 otoff = other.utcoffset()
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001701 base_compare = myoff == otoff
1702
1703 if base_compare:
1704 return _cmp((self._year, self._month, self._day,
1705 self._hour, self._minute, self._second,
1706 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001707 (other._year, other._month, other._day,
1708 other._hour, other._minute, other._second,
1709 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001710 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001711 if allow_mixed:
1712 return 2 # arbitrary non-zero value
1713 else:
1714 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001715 # XXX What follows could be done more efficiently...
1716 diff = self - other # this will take offsets into account
1717 if diff.days < 0:
1718 return -1
1719 return diff and 1 or 0
1720
1721 def __add__(self, other):
1722 "Add a datetime and a timedelta."
1723 if not isinstance(other, timedelta):
1724 return NotImplemented
1725 delta = timedelta(self.toordinal(),
1726 hours=self._hour,
1727 minutes=self._minute,
1728 seconds=self._second,
1729 microseconds=self._microsecond)
1730 delta += other
1731 hour, rem = divmod(delta.seconds, 3600)
1732 minute, second = divmod(rem, 60)
1733 if 0 < delta.days <= _MAXORDINAL:
1734 return datetime.combine(date.fromordinal(delta.days),
1735 time(hour, minute, second,
1736 delta.microseconds,
1737 tzinfo=self._tzinfo))
1738 raise OverflowError("result out of range")
1739
1740 __radd__ = __add__
1741
1742 def __sub__(self, other):
1743 "Subtract two datetimes, or a datetime and a timedelta."
1744 if not isinstance(other, datetime):
1745 if isinstance(other, timedelta):
1746 return self + -other
1747 return NotImplemented
1748
1749 days1 = self.toordinal()
1750 days2 = other.toordinal()
1751 secs1 = self._second + self._minute * 60 + self._hour * 3600
1752 secs2 = other._second + other._minute * 60 + other._hour * 3600
1753 base = timedelta(days1 - days2,
1754 secs1 - secs2,
1755 self._microsecond - other._microsecond)
1756 if self._tzinfo is other._tzinfo:
1757 return base
1758 myoff = self.utcoffset()
1759 otoff = other.utcoffset()
1760 if myoff == otoff:
1761 return base
1762 if myoff is None or otoff is None:
1763 raise TypeError("cannot mix naive and timezone-aware time")
1764 return base + otoff - myoff
1765
1766 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001767 if self._hashcode == -1:
1768 tzoff = self.utcoffset()
1769 if tzoff is None:
1770 self._hashcode = hash(self._getstate()[0])
1771 else:
1772 days = _ymd2ord(self.year, self.month, self.day)
1773 seconds = self.hour * 3600 + self.minute * 60 + self.second
1774 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
1775 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001776
1777 # Pickle support.
1778
1779 def _getstate(self):
1780 yhi, ylo = divmod(self._year, 256)
1781 us2, us3 = divmod(self._microsecond, 256)
1782 us1, us2 = divmod(us2, 256)
1783 basestate = bytes([yhi, ylo, self._month, self._day,
1784 self._hour, self._minute, self._second,
1785 us1, us2, us3])
1786 if self._tzinfo is None:
1787 return (basestate,)
1788 else:
1789 return (basestate, self._tzinfo)
1790
1791 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001792 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1793 raise TypeError("bad tzinfo state arg")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001794 (yhi, ylo, self._month, self._day, self._hour,
1795 self._minute, self._second, us1, us2, us3) = string
1796 self._year = yhi * 256 + ylo
1797 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001798 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001799
1800 def __reduce__(self):
1801 return (self.__class__, self._getstate())
1802
1803
1804datetime.min = datetime(1, 1, 1)
1805datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1806datetime.resolution = timedelta(microseconds=1)
1807
1808
1809def _isoweek1monday(year):
1810 # Helper to calculate the day number of the Monday starting week 1
1811 # XXX This could be done more efficiently
1812 THURSDAY = 3
1813 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001814 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001815 week1monday = firstday - firstweekday
1816 if firstweekday > THURSDAY:
1817 week1monday += 7
1818 return week1monday
1819
1820class timezone(tzinfo):
1821 __slots__ = '_offset', '_name'
1822
1823 # Sentinel value to disallow None
1824 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001825 def __new__(cls, offset, name=_Omitted):
1826 if not isinstance(offset, timedelta):
1827 raise TypeError("offset must be a timedelta")
1828 if name is cls._Omitted:
1829 if not offset:
1830 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001831 name = None
1832 elif not isinstance(name, str):
1833 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001834 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001835 raise ValueError("offset must be a timedelta "
1836 "strictly between -timedelta(hours=24) and "
1837 "timedelta(hours=24).")
1838 if (offset.microseconds != 0 or offset.seconds % 60 != 0):
1839 raise ValueError("offset must be a timedelta "
1840 "representing a whole number of minutes")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001841 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001842
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001843 @classmethod
1844 def _create(cls, offset, name=None):
1845 self = tzinfo.__new__(cls)
1846 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001847 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001848 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001849
1850 def __getinitargs__(self):
1851 """pickle support"""
1852 if self._name is None:
1853 return (self._offset,)
1854 return (self._offset, self._name)
1855
1856 def __eq__(self, other):
Georg Brandl0085a242012-09-22 09:23:12 +02001857 if type(other) != timezone:
1858 return False
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001859 return self._offset == other._offset
1860
1861 def __hash__(self):
1862 return hash(self._offset)
1863
1864 def __repr__(self):
1865 """Convert to formal string, for repr().
1866
1867 >>> tz = timezone.utc
1868 >>> repr(tz)
1869 'datetime.timezone.utc'
1870 >>> tz = timezone(timedelta(hours=-5), 'EST')
1871 >>> repr(tz)
1872 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
1873 """
1874 if self is self.utc:
1875 return 'datetime.timezone.utc'
1876 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001877 return "%s.%s(%r)" % (self.__class__.__module__,
1878 self.__class__.__qualname__,
1879 self._offset)
1880 return "%s.%s(%r, %r)" % (self.__class__.__module__,
1881 self.__class__.__qualname__,
1882 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001883
1884 def __str__(self):
1885 return self.tzname(None)
1886
1887 def utcoffset(self, dt):
1888 if isinstance(dt, datetime) or dt is None:
1889 return self._offset
1890 raise TypeError("utcoffset() argument must be a datetime instance"
1891 " or None")
1892
1893 def tzname(self, dt):
1894 if isinstance(dt, datetime) or dt is None:
1895 if self._name is None:
1896 return self._name_from_offset(self._offset)
1897 return self._name
1898 raise TypeError("tzname() argument must be a datetime instance"
1899 " or None")
1900
1901 def dst(self, dt):
1902 if isinstance(dt, datetime) or dt is None:
1903 return None
1904 raise TypeError("dst() argument must be a datetime instance"
1905 " or None")
1906
1907 def fromutc(self, dt):
1908 if isinstance(dt, datetime):
1909 if dt.tzinfo is not self:
1910 raise ValueError("fromutc: dt.tzinfo "
1911 "is not self")
1912 return dt + self._offset
1913 raise TypeError("fromutc() argument must be a datetime instance"
1914 " or None")
1915
1916 _maxoffset = timedelta(hours=23, minutes=59)
1917 _minoffset = -_maxoffset
1918
1919 @staticmethod
1920 def _name_from_offset(delta):
1921 if delta < timedelta(0):
1922 sign = '-'
1923 delta = -delta
1924 else:
1925 sign = '+'
1926 hours, rest = divmod(delta, timedelta(hours=1))
1927 minutes = rest // timedelta(minutes=1)
1928 return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes)
1929
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001930timezone.utc = timezone._create(timedelta(0))
1931timezone.min = timezone._create(timezone._minoffset)
1932timezone.max = timezone._create(timezone._maxoffset)
Alexander Belopolskya4415142012-06-08 12:33:09 -04001933_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001934
Victor Stinner765531d2013-03-26 01:11:54 +01001935# Some time zone algebra. For a datetime x, let
1936# x.n = x stripped of its timezone -- its naive time.
1937# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
1938# return None
1939# x.d = x.dst(), and assuming that doesn't raise an exception or
1940# return None
1941# x.s = x's standard offset, x.o - x.d
1942#
1943# Now some derived rules, where k is a duration (timedelta).
1944#
1945# 1. x.o = x.s + x.d
1946# This follows from the definition of x.s.
1947#
1948# 2. If x and y have the same tzinfo member, x.s = y.s.
1949# This is actually a requirement, an assumption we need to make about
1950# sane tzinfo classes.
1951#
1952# 3. The naive UTC time corresponding to x is x.n - x.o.
1953# This is again a requirement for a sane tzinfo class.
1954#
1955# 4. (x+k).s = x.s
1956# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
1957#
1958# 5. (x+k).n = x.n + k
1959# Again follows from how arithmetic is defined.
1960#
1961# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
1962# (meaning that the various tzinfo methods exist, and don't blow up or return
1963# None when called).
1964#
1965# The function wants to return a datetime y with timezone tz, equivalent to x.
1966# x is already in UTC.
1967#
1968# By #3, we want
1969#
1970# y.n - y.o = x.n [1]
1971#
1972# The algorithm starts by attaching tz to x.n, and calling that y. So
1973# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
1974# becomes true; in effect, we want to solve [2] for k:
1975#
1976# (y+k).n - (y+k).o = x.n [2]
1977#
1978# By #1, this is the same as
1979#
1980# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
1981#
1982# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
1983# Substituting that into [3],
1984#
1985# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
1986# k - (y+k).s - (y+k).d = 0; rearranging,
1987# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
1988# k = y.s - (y+k).d
1989#
1990# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
1991# approximate k by ignoring the (y+k).d term at first. Note that k can't be
1992# very large, since all offset-returning methods return a duration of magnitude
1993# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
1994# be 0, so ignoring it has no consequence then.
1995#
1996# In any case, the new value is
1997#
1998# z = y + y.s [4]
1999#
2000# It's helpful to step back at look at [4] from a higher level: it's simply
2001# mapping from UTC to tz's standard time.
2002#
2003# At this point, if
2004#
2005# z.n - z.o = x.n [5]
2006#
2007# we have an equivalent time, and are almost done. The insecurity here is
2008# at the start of daylight time. Picture US Eastern for concreteness. The wall
2009# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2010# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2011# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2012# on the day DST starts. We want to return the 1:MM EST spelling because that's
2013# the only spelling that makes sense on the local wall clock.
2014#
2015# In fact, if [5] holds at this point, we do have the standard-time spelling,
2016# but that takes a bit of proof. We first prove a stronger result. What's the
2017# difference between the LHS and RHS of [5]? Let
2018#
2019# diff = x.n - (z.n - z.o) [6]
2020#
2021# Now
2022# z.n = by [4]
2023# (y + y.s).n = by #5
2024# y.n + y.s = since y.n = x.n
2025# x.n + y.s = since z and y are have the same tzinfo member,
2026# y.s = z.s by #2
2027# x.n + z.s
2028#
2029# Plugging that back into [6] gives
2030#
2031# diff =
2032# x.n - ((x.n + z.s) - z.o) = expanding
2033# x.n - x.n - z.s + z.o = cancelling
2034# - z.s + z.o = by #2
2035# z.d
2036#
2037# So diff = z.d.
2038#
2039# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2040# spelling we wanted in the endcase described above. We're done. Contrarily,
2041# if z.d = 0, then we have a UTC equivalent, and are also done.
2042#
2043# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2044# add to z (in effect, z is in tz's standard time, and we need to shift the
2045# local clock into tz's daylight time).
2046#
2047# Let
2048#
2049# z' = z + z.d = z + diff [7]
2050#
2051# and we can again ask whether
2052#
2053# z'.n - z'.o = x.n [8]
2054#
2055# If so, we're done. If not, the tzinfo class is insane, according to the
2056# assumptions we've made. This also requires a bit of proof. As before, let's
2057# compute the difference between the LHS and RHS of [8] (and skipping some of
2058# the justifications for the kinds of substitutions we've done several times
2059# already):
2060#
2061# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2062# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2063# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2064# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2065# - z.n + z.n - z.o + z'.o = cancel z.n
2066# - z.o + z'.o = #1 twice
2067# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2068# z'.d - z.d
2069#
2070# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2071# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2072# return z', not bothering to compute z'.d.
2073#
2074# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2075# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2076# would have to change the result dst() returns: we start in DST, and moving
2077# a little further into it takes us out of DST.
2078#
2079# There isn't a sane case where this can happen. The closest it gets is at
2080# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2081# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2082# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2083# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2084# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2085# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2086# standard time. Since that's what the local clock *does*, we want to map both
2087# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2088# in local time, but so it goes -- it's the way the local clock works.
2089#
2090# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2091# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2092# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2093# (correctly) concludes that z' is not UTC-equivalent to x.
2094#
2095# Because we know z.d said z was in daylight time (else [5] would have held and
2096# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2097# and we have stopped then), and there are only 2 possible values dst() can
2098# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2099# but the reasoning doesn't depend on the example -- it depends on there being
2100# two possible dst() outcomes, one zero and the other non-zero). Therefore
2101# z' must be in standard time, and is the spelling we want in this case.
2102#
2103# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2104# concerned (because it takes z' as being in standard time rather than the
2105# daylight time we intend here), but returning it gives the real-life "local
2106# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2107# tz.
2108#
2109# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2110# the 1:MM standard time spelling we want.
2111#
2112# So how can this break? One of the assumptions must be violated. Two
2113# possibilities:
2114#
2115# 1) [2] effectively says that y.s is invariant across all y belong to a given
2116# time zone. This isn't true if, for political reasons or continental drift,
2117# a region decides to change its base offset from UTC.
2118#
2119# 2) There may be versions of "double daylight" time where the tail end of
2120# the analysis gives up a step too early. I haven't thought about that
2121# enough to say.
2122#
2123# In any case, it's clear that the default fromutc() is strong enough to handle
2124# "almost all" time zones: so long as the standard offset is invariant, it
2125# doesn't matter if daylight time transition points change from year to year, or
2126# if daylight time is skipped in some years; it doesn't matter how large or
2127# small dst() may get within its bounds; and it doesn't even matter if some
2128# perverse time zone returns a negative dst()). So a breaking case must be
2129# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002130
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002131try:
2132 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002133except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002134 pass
2135else:
2136 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002137 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2138 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2139 _check_date_fields, _check_int_field, _check_time_fields,
2140 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2141 _date_class, _days_before_month, _days_before_year, _days_in_month,
2142 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd,
2143 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002144 # XXX Since import * above excludes names that start with _,
2145 # docstring does not get overwritten. In the future, it may be
2146 # appropriate to maintain a single module level docstring and
2147 # remove the following line.
2148 from _datetime import __doc__