blob: 6b2ac33a32782cf7c6eb2747c2fe266d77ba7b25 [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
Victor Stinner2ec55872015-09-02 19:16:07 +0200319def _round_half_up(x):
320 """Round to nearest with ties going away from zero."""
321 if x >= 0.0:
322 return _math.floor(x + 0.5)
323 else:
324 return _math.ceil(x - 0.5)
325
326
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000327class timedelta:
328 """Represent the difference between two datetime objects.
329
330 Supported operators:
331
332 - add, subtract timedelta
333 - unary plus, minus, abs
334 - compare to timedelta
Serhiy Storchaka95949422013-08-27 19:40:23 +0300335 - multiply, divide by int
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000336
337 In addition, datetime supports subtraction of two datetime objects
338 returning a timedelta, and addition or subtraction of a datetime
339 and a timedelta giving a datetime.
340
341 Representation: (days, seconds, microseconds). Why? Because I
342 felt like it.
343 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400344 __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000345
346 def __new__(cls, days=0, seconds=0, microseconds=0,
347 milliseconds=0, minutes=0, hours=0, weeks=0):
348 # Doing this efficiently and accurately in C is going to be difficult
349 # and error-prone, due to ubiquitous overflow possibilities, and that
350 # C double doesn't have enough bits of precision to represent
351 # microseconds over 10K years faithfully. The code here tries to make
352 # explicit where go-fast assumptions can be relied on, in order to
353 # guide the C implementation; it's way more convoluted than speed-
354 # ignoring auto-overflow-to-long idiomatic Python could be.
355
356 # XXX Check that all inputs are ints or floats.
357
358 # Final values, all integer.
359 # s and us fit in 32-bit signed ints; d isn't bounded.
360 d = s = us = 0
361
362 # Normalize everything to days, seconds, microseconds.
363 days += weeks*7
364 seconds += minutes*60 + hours*3600
365 microseconds += milliseconds*1000
366
367 # Get rid of all fractions, and normalize s and us.
368 # Take a deep breath <wink>.
369 if isinstance(days, float):
370 dayfrac, days = _math.modf(days)
371 daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
372 assert daysecondswhole == int(daysecondswhole) # can't overflow
373 s = int(daysecondswhole)
374 assert days == int(days)
375 d = int(days)
376 else:
377 daysecondsfrac = 0.0
378 d = days
379 assert isinstance(daysecondsfrac, float)
380 assert abs(daysecondsfrac) <= 1.0
381 assert isinstance(d, int)
382 assert abs(s) <= 24 * 3600
383 # days isn't referenced again before redefinition
384
385 if isinstance(seconds, float):
386 secondsfrac, seconds = _math.modf(seconds)
387 assert seconds == int(seconds)
388 seconds = int(seconds)
389 secondsfrac += daysecondsfrac
390 assert abs(secondsfrac) <= 2.0
391 else:
392 secondsfrac = daysecondsfrac
393 # daysecondsfrac isn't referenced again
394 assert isinstance(secondsfrac, float)
395 assert abs(secondsfrac) <= 2.0
396
397 assert isinstance(seconds, int)
398 days, seconds = divmod(seconds, 24*3600)
399 d += days
400 s += int(seconds) # can't overflow
401 assert isinstance(s, int)
402 assert abs(s) <= 2 * 24 * 3600
403 # seconds isn't referenced again before redefinition
404
405 usdouble = secondsfrac * 1e6
406 assert abs(usdouble) < 2.1e6 # exact value not critical
407 # secondsfrac isn't referenced again
408
409 if isinstance(microseconds, float):
Victor Stinner2ec55872015-09-02 19:16:07 +0200410 microseconds = _round_half_up(microseconds + usdouble)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000411 seconds, microseconds = divmod(microseconds, 1000000)
412 days, seconds = divmod(seconds, 24*3600)
413 d += days
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400414 s += seconds
415 else:
416 microseconds = int(microseconds)
417 seconds, microseconds = divmod(microseconds, 1000000)
418 days, seconds = divmod(seconds, 24*3600)
419 d += days
420 s += seconds
Victor Stinner2ec55872015-09-02 19:16:07 +0200421 microseconds = _round_half_up(microseconds + usdouble)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400422 assert isinstance(s, int)
423 assert isinstance(microseconds, int)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000424 assert abs(s) <= 3 * 24 * 3600
425 assert abs(microseconds) < 3.1e6
426
427 # Just a little bit of carrying possible for microseconds and seconds.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400428 seconds, us = divmod(microseconds, 1000000)
429 s += seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000430 days, s = divmod(s, 24*3600)
431 d += days
432
433 assert isinstance(d, int)
434 assert isinstance(s, int) and 0 <= s < 24*3600
435 assert isinstance(us, int) and 0 <= us < 1000000
436
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000437 if abs(d) > 999999999:
438 raise OverflowError("timedelta # of days is too large: %d" % d)
439
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400440 self = object.__new__(cls)
441 self._days = d
442 self._seconds = s
443 self._microseconds = us
444 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000445 return self
446
447 def __repr__(self):
448 if self._microseconds:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300449 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
450 self.__class__.__qualname__,
451 self._days,
452 self._seconds,
453 self._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000454 if self._seconds:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300455 return "%s.%s(%d, %d)" % (self.__class__.__module__,
456 self.__class__.__qualname__,
457 self._days,
458 self._seconds)
459 return "%s.%s(%d)" % (self.__class__.__module__,
460 self.__class__.__qualname__,
461 self._days)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000462
463 def __str__(self):
464 mm, ss = divmod(self._seconds, 60)
465 hh, mm = divmod(mm, 60)
466 s = "%d:%02d:%02d" % (hh, mm, ss)
467 if self._days:
468 def plural(n):
469 return n, abs(n) != 1 and "s" or ""
470 s = ("%d day%s, " % plural(self._days)) + s
471 if self._microseconds:
472 s = s + ".%06d" % self._microseconds
473 return s
474
475 def total_seconds(self):
476 """Total seconds in the duration."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400477 return ((self.days * 86400 + self.seconds) * 10**6 +
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000478 self.microseconds) / 10**6
479
480 # Read-only field accessors
481 @property
482 def days(self):
483 """days"""
484 return self._days
485
486 @property
487 def seconds(self):
488 """seconds"""
489 return self._seconds
490
491 @property
492 def microseconds(self):
493 """microseconds"""
494 return self._microseconds
495
496 def __add__(self, other):
497 if isinstance(other, timedelta):
498 # for CPython compatibility, we cannot use
499 # our __class__ here, but need a real timedelta
500 return timedelta(self._days + other._days,
501 self._seconds + other._seconds,
502 self._microseconds + other._microseconds)
503 return NotImplemented
504
505 __radd__ = __add__
506
507 def __sub__(self, other):
508 if isinstance(other, timedelta):
Alexander Belopolskyb6f5ec72011-04-05 20:07:38 -0400509 # for CPython compatibility, we cannot use
510 # our __class__ here, but need a real timedelta
511 return timedelta(self._days - other._days,
512 self._seconds - other._seconds,
513 self._microseconds - other._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000514 return NotImplemented
515
516 def __rsub__(self, other):
517 if isinstance(other, timedelta):
518 return -self + other
519 return NotImplemented
520
521 def __neg__(self):
522 # for CPython compatibility, we cannot use
523 # our __class__ here, but need a real timedelta
524 return timedelta(-self._days,
525 -self._seconds,
526 -self._microseconds)
527
528 def __pos__(self):
529 return self
530
531 def __abs__(self):
532 if self._days < 0:
533 return -self
534 else:
535 return self
536
537 def __mul__(self, other):
538 if isinstance(other, int):
539 # for CPython compatibility, we cannot use
540 # our __class__ here, but need a real timedelta
541 return timedelta(self._days * other,
542 self._seconds * other,
543 self._microseconds * other)
544 if isinstance(other, float):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500545 usec = self._to_microseconds()
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000546 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500547 return timedelta(0, 0, _divide_and_round(usec * a, b))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000548 return NotImplemented
549
550 __rmul__ = __mul__
551
552 def _to_microseconds(self):
553 return ((self._days * (24*3600) + self._seconds) * 1000000 +
554 self._microseconds)
555
556 def __floordiv__(self, other):
557 if not isinstance(other, (int, timedelta)):
558 return NotImplemented
559 usec = self._to_microseconds()
560 if isinstance(other, timedelta):
561 return usec // other._to_microseconds()
562 if isinstance(other, int):
563 return timedelta(0, 0, usec // other)
564
565 def __truediv__(self, other):
566 if not isinstance(other, (int, float, timedelta)):
567 return NotImplemented
568 usec = self._to_microseconds()
569 if isinstance(other, timedelta):
570 return usec / other._to_microseconds()
571 if isinstance(other, int):
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500572 return timedelta(0, 0, _divide_and_round(usec, other))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000573 if isinstance(other, float):
574 a, b = other.as_integer_ratio()
Alexander Belopolsky24d3dee2015-02-28 10:41:57 -0500575 return timedelta(0, 0, _divide_and_round(b * usec, a))
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000576
577 def __mod__(self, other):
578 if isinstance(other, timedelta):
579 r = self._to_microseconds() % other._to_microseconds()
580 return timedelta(0, 0, r)
581 return NotImplemented
582
583 def __divmod__(self, other):
584 if isinstance(other, timedelta):
585 q, r = divmod(self._to_microseconds(),
586 other._to_microseconds())
587 return q, timedelta(0, 0, r)
588 return NotImplemented
589
590 # Comparisons of timedelta objects with other.
591
592 def __eq__(self, other):
593 if isinstance(other, timedelta):
594 return self._cmp(other) == 0
595 else:
596 return False
597
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000598 def __le__(self, other):
599 if isinstance(other, timedelta):
600 return self._cmp(other) <= 0
601 else:
602 _cmperror(self, other)
603
604 def __lt__(self, other):
605 if isinstance(other, timedelta):
606 return self._cmp(other) < 0
607 else:
608 _cmperror(self, other)
609
610 def __ge__(self, other):
611 if isinstance(other, timedelta):
612 return self._cmp(other) >= 0
613 else:
614 _cmperror(self, other)
615
616 def __gt__(self, other):
617 if isinstance(other, timedelta):
618 return self._cmp(other) > 0
619 else:
620 _cmperror(self, other)
621
622 def _cmp(self, other):
623 assert isinstance(other, timedelta)
624 return _cmp(self._getstate(), other._getstate())
625
626 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400627 if self._hashcode == -1:
628 self._hashcode = hash(self._getstate())
629 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000630
631 def __bool__(self):
632 return (self._days != 0 or
633 self._seconds != 0 or
634 self._microseconds != 0)
635
636 # Pickle support.
637
638 def _getstate(self):
639 return (self._days, self._seconds, self._microseconds)
640
641 def __reduce__(self):
642 return (self.__class__, self._getstate())
643
644timedelta.min = timedelta(-999999999)
645timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
646 microseconds=999999)
647timedelta.resolution = timedelta(microseconds=1)
648
649class date:
650 """Concrete date type.
651
652 Constructors:
653
654 __new__()
655 fromtimestamp()
656 today()
657 fromordinal()
658
659 Operators:
660
661 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200662 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000663 __add__, __radd__, __sub__ (add/radd only with timedelta arg)
664
665 Methods:
666
667 timetuple()
668 toordinal()
669 weekday()
670 isoweekday(), isocalendar(), isoformat()
671 ctime()
672 strftime()
673
674 Properties (readonly):
675 year, month, day
676 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400677 __slots__ = '_year', '_month', '_day', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000678
679 def __new__(cls, year, month=None, day=None):
680 """Constructor.
681
682 Arguments:
683
684 year, month, day (required, base 1)
685 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400686 if month is None and isinstance(year, bytes) and len(year) == 4 and \
687 1 <= year[2] <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000688 # Pickle support
689 self = object.__new__(cls)
690 self.__setstate(year)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400691 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000692 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400693 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000694 self = object.__new__(cls)
695 self._year = year
696 self._month = month
697 self._day = day
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400698 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000699 return self
700
701 # Additional constructors
702
703 @classmethod
704 def fromtimestamp(cls, t):
705 "Construct a date from a POSIX timestamp (like time.time())."
706 y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
707 return cls(y, m, d)
708
709 @classmethod
710 def today(cls):
711 "Construct a date from time.time()."
712 t = _time.time()
713 return cls.fromtimestamp(t)
714
715 @classmethod
716 def fromordinal(cls, n):
717 """Contruct a date from a proleptic Gregorian ordinal.
718
719 January 1 of year 1 is day 1. Only the year, month and day are
720 non-zero in the result.
721 """
722 y, m, d = _ord2ymd(n)
723 return cls(y, m, d)
724
725 # Conversions to string
726
727 def __repr__(self):
728 """Convert to formal string, for repr().
729
730 >>> dt = datetime(2010, 1, 1)
731 >>> repr(dt)
732 'datetime.datetime(2010, 1, 1, 0, 0)'
733
734 >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
735 >>> repr(dt)
736 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
737 """
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300738 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
739 self.__class__.__qualname__,
740 self._year,
741 self._month,
742 self._day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000743 # XXX These shouldn't depend on time.localtime(), because that
744 # clips the usable dates to [1970 .. 2038). At least ctime() is
745 # easily done without using strftime() -- that's better too because
746 # strftime("%c", ...) is locale specific.
747
748
749 def ctime(self):
750 "Return ctime() style string."
751 weekday = self.toordinal() % 7 or 7
752 return "%s %s %2d 00:00:00 %04d" % (
753 _DAYNAMES[weekday],
754 _MONTHNAMES[self._month],
755 self._day, self._year)
756
757 def strftime(self, fmt):
758 "Format using strftime()."
759 return _wrap_strftime(self, fmt, self.timetuple())
760
761 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400762 if not isinstance(fmt, str):
763 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000764 if len(fmt) != 0:
765 return self.strftime(fmt)
766 return str(self)
767
768 def isoformat(self):
769 """Return the date formatted according to ISO.
770
771 This is 'YYYY-MM-DD'.
772
773 References:
774 - http://www.w3.org/TR/NOTE-datetime
775 - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
776 """
777 return "%04d-%02d-%02d" % (self._year, self._month, self._day)
778
779 __str__ = isoformat
780
781 # Read-only field accessors
782 @property
783 def year(self):
784 """year (1-9999)"""
785 return self._year
786
787 @property
788 def month(self):
789 """month (1-12)"""
790 return self._month
791
792 @property
793 def day(self):
794 """day (1-31)"""
795 return self._day
796
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200797 # Standard conversions, __eq__, __le__, __lt__, __ge__, __gt__,
798 # __hash__ (and helpers)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000799
800 def timetuple(self):
801 "Return local time tuple compatible with time.localtime()."
802 return _build_struct_time(self._year, self._month, self._day,
803 0, 0, 0, -1)
804
805 def toordinal(self):
806 """Return proleptic Gregorian ordinal for the year, month and day.
807
808 January 1 of year 1 is day 1. Only the year, month and day values
809 contribute to the result.
810 """
811 return _ymd2ord(self._year, self._month, self._day)
812
813 def replace(self, year=None, month=None, day=None):
814 """Return a new date with new values for the specified fields."""
815 if year is None:
816 year = self._year
817 if month is None:
818 month = self._month
819 if day is None:
820 day = self._day
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000821 return date(year, month, day)
822
823 # Comparisons of date objects with other.
824
825 def __eq__(self, other):
826 if isinstance(other, date):
827 return self._cmp(other) == 0
828 return NotImplemented
829
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000830 def __le__(self, other):
831 if isinstance(other, date):
832 return self._cmp(other) <= 0
833 return NotImplemented
834
835 def __lt__(self, other):
836 if isinstance(other, date):
837 return self._cmp(other) < 0
838 return NotImplemented
839
840 def __ge__(self, other):
841 if isinstance(other, date):
842 return self._cmp(other) >= 0
843 return NotImplemented
844
845 def __gt__(self, other):
846 if isinstance(other, date):
847 return self._cmp(other) > 0
848 return NotImplemented
849
850 def _cmp(self, other):
851 assert isinstance(other, date)
852 y, m, d = self._year, self._month, self._day
853 y2, m2, d2 = other._year, other._month, other._day
854 return _cmp((y, m, d), (y2, m2, d2))
855
856 def __hash__(self):
857 "Hash."
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400858 if self._hashcode == -1:
859 self._hashcode = hash(self._getstate())
860 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000861
862 # Computations
863
864 def __add__(self, other):
865 "Add a date to a timedelta."
866 if isinstance(other, timedelta):
867 o = self.toordinal() + other.days
868 if 0 < o <= _MAXORDINAL:
869 return date.fromordinal(o)
870 raise OverflowError("result out of range")
871 return NotImplemented
872
873 __radd__ = __add__
874
875 def __sub__(self, other):
876 """Subtract two dates, or a date and a timedelta."""
877 if isinstance(other, timedelta):
878 return self + timedelta(-other.days)
879 if isinstance(other, date):
880 days1 = self.toordinal()
881 days2 = other.toordinal()
882 return timedelta(days1 - days2)
883 return NotImplemented
884
885 def weekday(self):
886 "Return day of the week, where Monday == 0 ... Sunday == 6."
887 return (self.toordinal() + 6) % 7
888
889 # Day-of-the-week and week-of-the-year, according to ISO
890
891 def isoweekday(self):
892 "Return day of the week, where Monday == 1 ... Sunday == 7."
893 # 1-Jan-0001 is a Monday
894 return self.toordinal() % 7 or 7
895
896 def isocalendar(self):
897 """Return a 3-tuple containing ISO year, week number, and weekday.
898
899 The first ISO week of the year is the (Mon-Sun) week
900 containing the year's first Thursday; everything else derives
901 from that.
902
903 The first week is 1; Monday is 1 ... Sunday is 7.
904
905 ISO calendar algorithm taken from
906 http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
907 """
908 year = self._year
909 week1monday = _isoweek1monday(year)
910 today = _ymd2ord(self._year, self._month, self._day)
911 # Internally, week and day have origin 0
912 week, day = divmod(today - week1monday, 7)
913 if week < 0:
914 year -= 1
915 week1monday = _isoweek1monday(year)
916 week, day = divmod(today - week1monday, 7)
917 elif week >= 52:
918 if today >= _isoweek1monday(year+1):
919 year += 1
920 week = 0
921 return year, week+1, day+1
922
923 # Pickle support.
924
925 def _getstate(self):
926 yhi, ylo = divmod(self._year, 256)
927 return bytes([yhi, ylo, self._month, self._day]),
928
929 def __setstate(self, string):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000930 yhi, ylo, self._month, self._day = string
931 self._year = yhi * 256 + ylo
932
933 def __reduce__(self):
934 return (self.__class__, self._getstate())
935
936_date_class = date # so functions w/ args named "date" can get at the class
937
938date.min = date(1, 1, 1)
939date.max = date(9999, 12, 31)
940date.resolution = timedelta(days=1)
941
942class tzinfo:
943 """Abstract base class for time zone info classes.
944
945 Subclasses must override the name(), utcoffset() and dst() methods.
946 """
947 __slots__ = ()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400948
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000949 def tzname(self, dt):
950 "datetime -> string name of time zone."
951 raise NotImplementedError("tzinfo subclass must override tzname()")
952
953 def utcoffset(self, dt):
954 "datetime -> minutes east of UTC (negative for west of UTC)"
955 raise NotImplementedError("tzinfo subclass must override utcoffset()")
956
957 def dst(self, dt):
958 """datetime -> DST offset in minutes east of UTC.
959
960 Return 0 if DST not in effect. utcoffset() must include the DST
961 offset.
962 """
963 raise NotImplementedError("tzinfo subclass must override dst()")
964
965 def fromutc(self, dt):
966 "datetime in UTC -> datetime in local time."
967
968 if not isinstance(dt, datetime):
969 raise TypeError("fromutc() requires a datetime argument")
970 if dt.tzinfo is not self:
971 raise ValueError("dt.tzinfo is not self")
972
973 dtoff = dt.utcoffset()
974 if dtoff is None:
975 raise ValueError("fromutc() requires a non-None utcoffset() "
976 "result")
977
978 # See the long comment block at the end of this file for an
979 # explanation of this algorithm.
980 dtdst = dt.dst()
981 if dtdst is None:
982 raise ValueError("fromutc() requires a non-None dst() result")
983 delta = dtoff - dtdst
984 if delta:
985 dt += delta
986 dtdst = dt.dst()
987 if dtdst is None:
988 raise ValueError("fromutc(): dt.dst gave inconsistent "
989 "results; cannot convert")
990 return dt + dtdst
991
992 # Pickle support.
993
994 def __reduce__(self):
995 getinitargs = getattr(self, "__getinitargs__", None)
996 if getinitargs:
997 args = getinitargs()
998 else:
999 args = ()
1000 getstate = getattr(self, "__getstate__", None)
1001 if getstate:
1002 state = getstate()
1003 else:
1004 state = getattr(self, "__dict__", None) or None
1005 if state is None:
1006 return (self.__class__, args)
1007 else:
1008 return (self.__class__, args, state)
1009
1010_tzinfo_class = tzinfo
1011
1012class time:
1013 """Time with time zone.
1014
1015 Constructors:
1016
1017 __new__()
1018
1019 Operators:
1020
1021 __repr__, __str__
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +02001022 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001023
1024 Methods:
1025
1026 strftime()
1027 isoformat()
1028 utcoffset()
1029 tzname()
1030 dst()
1031
1032 Properties (readonly):
1033 hour, minute, second, microsecond, tzinfo
1034 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001035 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001036
1037 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None):
1038 """Constructor.
1039
1040 Arguments:
1041
1042 hour, minute (required)
1043 second, microsecond (default to zero)
1044 tzinfo (default to None)
1045 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001046 if isinstance(hour, bytes) and len(hour) == 6 and hour[0] < 24:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001047 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001048 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001049 self.__setstate(hour, minute or None)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001050 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001051 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001052 hour, minute, second, microsecond = _check_time_fields(
1053 hour, minute, second, microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001054 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001055 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001056 self._hour = hour
1057 self._minute = minute
1058 self._second = second
1059 self._microsecond = microsecond
1060 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001061 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001062 return self
1063
1064 # Read-only field accessors
1065 @property
1066 def hour(self):
1067 """hour (0-23)"""
1068 return self._hour
1069
1070 @property
1071 def minute(self):
1072 """minute (0-59)"""
1073 return self._minute
1074
1075 @property
1076 def second(self):
1077 """second (0-59)"""
1078 return self._second
1079
1080 @property
1081 def microsecond(self):
1082 """microsecond (0-999999)"""
1083 return self._microsecond
1084
1085 @property
1086 def tzinfo(self):
1087 """timezone info object"""
1088 return self._tzinfo
1089
1090 # Standard conversions, __hash__ (and helpers)
1091
1092 # Comparisons of time objects with other.
1093
1094 def __eq__(self, other):
1095 if isinstance(other, time):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001096 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001097 else:
1098 return False
1099
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001100 def __le__(self, other):
1101 if isinstance(other, time):
1102 return self._cmp(other) <= 0
1103 else:
1104 _cmperror(self, other)
1105
1106 def __lt__(self, other):
1107 if isinstance(other, time):
1108 return self._cmp(other) < 0
1109 else:
1110 _cmperror(self, other)
1111
1112 def __ge__(self, other):
1113 if isinstance(other, time):
1114 return self._cmp(other) >= 0
1115 else:
1116 _cmperror(self, other)
1117
1118 def __gt__(self, other):
1119 if isinstance(other, time):
1120 return self._cmp(other) > 0
1121 else:
1122 _cmperror(self, other)
1123
Alexander Belopolsky08313822012-06-15 20:19:47 -04001124 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001125 assert isinstance(other, time)
1126 mytz = self._tzinfo
1127 ottz = other._tzinfo
1128 myoff = otoff = None
1129
1130 if mytz is ottz:
1131 base_compare = True
1132 else:
1133 myoff = self.utcoffset()
1134 otoff = other.utcoffset()
1135 base_compare = myoff == otoff
1136
1137 if base_compare:
1138 return _cmp((self._hour, self._minute, self._second,
1139 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001140 (other._hour, other._minute, other._second,
1141 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001142 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001143 if allow_mixed:
1144 return 2 # arbitrary non-zero value
1145 else:
1146 raise TypeError("cannot compare naive and aware times")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001147 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1148 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1149 return _cmp((myhhmm, self._second, self._microsecond),
1150 (othhmm, other._second, other._microsecond))
1151
1152 def __hash__(self):
1153 """Hash."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001154 if self._hashcode == -1:
1155 tzoff = self.utcoffset()
1156 if not tzoff: # zero or None
1157 self._hashcode = hash(self._getstate()[0])
1158 else:
1159 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1160 timedelta(hours=1))
1161 assert not m % timedelta(minutes=1), "whole minute"
1162 m //= timedelta(minutes=1)
1163 if 0 <= h < 24:
1164 self._hashcode = hash(time(h, m, self.second, self.microsecond))
1165 else:
1166 self._hashcode = hash((h, m, self.second, self.microsecond))
1167 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001168
1169 # Conversion to string
1170
1171 def _tzstr(self, sep=":"):
1172 """Return formatted timezone offset (+xx:xx) or None."""
1173 off = self.utcoffset()
1174 if off is not None:
1175 if off.days < 0:
1176 sign = "-"
1177 off = -off
1178 else:
1179 sign = "+"
1180 hh, mm = divmod(off, timedelta(hours=1))
1181 assert not mm % timedelta(minutes=1), "whole minute"
1182 mm //= timedelta(minutes=1)
1183 assert 0 <= hh < 24
1184 off = "%s%02d%s%02d" % (sign, hh, sep, mm)
1185 return off
1186
1187 def __repr__(self):
1188 """Convert to formal string, for repr()."""
1189 if self._microsecond != 0:
1190 s = ", %d, %d" % (self._second, self._microsecond)
1191 elif self._second != 0:
1192 s = ", %d" % self._second
1193 else:
1194 s = ""
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001195 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1196 self.__class__.__qualname__,
1197 self._hour, self._minute, s)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001198 if self._tzinfo is not None:
1199 assert s[-1:] == ")"
1200 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
1201 return s
1202
1203 def isoformat(self):
1204 """Return the time formatted according to ISO.
1205
1206 This is 'HH:MM:SS.mmmmmm+zz:zz', or 'HH:MM:SS+zz:zz' if
1207 self.microsecond == 0.
1208 """
1209 s = _format_time(self._hour, self._minute, self._second,
1210 self._microsecond)
1211 tz = self._tzstr()
1212 if tz:
1213 s += tz
1214 return s
1215
1216 __str__ = isoformat
1217
1218 def strftime(self, fmt):
1219 """Format using strftime(). The date part of the timestamp passed
1220 to underlying strftime should not be used.
1221 """
Alexander Belopolskyb8bb4662011-01-08 00:13:34 +00001222 # The year must be >= 1000 else Python's strftime implementation
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001223 # can raise a bogus exception.
1224 timetuple = (1900, 1, 1,
1225 self._hour, self._minute, self._second,
1226 0, 1, -1)
1227 return _wrap_strftime(self, fmt, timetuple)
1228
1229 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001230 if not isinstance(fmt, str):
1231 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001232 if len(fmt) != 0:
1233 return self.strftime(fmt)
1234 return str(self)
1235
1236 # Timezone functions
1237
1238 def utcoffset(self):
1239 """Return the timezone offset in minutes east of UTC (negative west of
1240 UTC)."""
1241 if self._tzinfo is None:
1242 return None
1243 offset = self._tzinfo.utcoffset(None)
1244 _check_utc_offset("utcoffset", offset)
1245 return offset
1246
1247 def tzname(self):
1248 """Return the timezone name.
1249
1250 Note that the name is 100% informational -- there's no requirement that
1251 it mean anything in particular. For example, "GMT", "UTC", "-500",
1252 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1253 """
1254 if self._tzinfo is None:
1255 return None
1256 name = self._tzinfo.tzname(None)
1257 _check_tzname(name)
1258 return name
1259
1260 def dst(self):
1261 """Return 0 if DST is not in effect, or the DST offset (in minutes
1262 eastward) if DST is in effect.
1263
1264 This is purely informational; the DST offset has already been added to
1265 the UTC offset returned by utcoffset() if applicable, so there's no
1266 need to consult dst() unless you're interested in displaying the DST
1267 info.
1268 """
1269 if self._tzinfo is None:
1270 return None
1271 offset = self._tzinfo.dst(None)
1272 _check_utc_offset("dst", offset)
1273 return offset
1274
1275 def replace(self, hour=None, minute=None, second=None, microsecond=None,
1276 tzinfo=True):
1277 """Return a new time with new values for the specified fields."""
1278 if hour is None:
1279 hour = self.hour
1280 if minute is None:
1281 minute = self.minute
1282 if second is None:
1283 second = self.second
1284 if microsecond is None:
1285 microsecond = self.microsecond
1286 if tzinfo is True:
1287 tzinfo = self.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001288 return time(hour, minute, second, microsecond, tzinfo)
1289
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001290 # Pickle support.
1291
1292 def _getstate(self):
1293 us2, us3 = divmod(self._microsecond, 256)
1294 us1, us2 = divmod(us2, 256)
1295 basestate = bytes([self._hour, self._minute, self._second,
1296 us1, us2, us3])
1297 if self._tzinfo is None:
1298 return (basestate,)
1299 else:
1300 return (basestate, self._tzinfo)
1301
1302 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001303 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1304 raise TypeError("bad tzinfo state arg")
1305 self._hour, self._minute, self._second, us1, us2, us3 = string
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001306 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001307 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001308
1309 def __reduce__(self):
1310 return (time, self._getstate())
1311
1312_time_class = time # so functions w/ args named "time" can get at the class
1313
1314time.min = time(0, 0, 0)
1315time.max = time(23, 59, 59, 999999)
1316time.resolution = timedelta(microseconds=1)
1317
1318class datetime(date):
1319 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1320
1321 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001322 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001323 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001324 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001325
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001326 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
1327 microsecond=0, tzinfo=None):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001328 if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2] <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001329 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001330 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001331 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001332 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001333 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001334 year, month, day = _check_date_fields(year, month, day)
1335 hour, minute, second, microsecond = _check_time_fields(
1336 hour, minute, second, microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001337 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001338 self = object.__new__(cls)
1339 self._year = year
1340 self._month = month
1341 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001342 self._hour = hour
1343 self._minute = minute
1344 self._second = second
1345 self._microsecond = microsecond
1346 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001347 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001348 return self
1349
1350 # Read-only field accessors
1351 @property
1352 def hour(self):
1353 """hour (0-23)"""
1354 return self._hour
1355
1356 @property
1357 def minute(self):
1358 """minute (0-59)"""
1359 return self._minute
1360
1361 @property
1362 def second(self):
1363 """second (0-59)"""
1364 return self._second
1365
1366 @property
1367 def microsecond(self):
1368 """microsecond (0-999999)"""
1369 return self._microsecond
1370
1371 @property
1372 def tzinfo(self):
1373 """timezone info object"""
1374 return self._tzinfo
1375
1376 @classmethod
Victor Stinneradfefa52015-09-04 23:57:25 +02001377 def _fromtimestamp(cls, t, utc, tz):
1378 """Construct a datetime from a POSIX timestamp (like time.time()).
1379
1380 A timezone info object may be passed in as well.
1381 """
1382 frac, t = _math.modf(t)
1383 us = _round_half_up(frac * 1e6)
1384 if us >= 1000000:
1385 t += 1
1386 us -= 1000000
1387 elif us < 0:
1388 t -= 1
1389 us += 1000000
1390
1391 converter = _time.gmtime if utc else _time.localtime
1392 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1393 ss = min(ss, 59) # clamp out leap seconds if the platform has them
1394 return cls(y, m, d, hh, mm, ss, us, tz)
1395
1396 @classmethod
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001397 def fromtimestamp(cls, t, tz=None):
1398 """Construct a datetime from a POSIX timestamp (like time.time()).
1399
1400 A timezone info object may be passed in as well.
1401 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001402 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001403
Victor Stinneradfefa52015-09-04 23:57:25 +02001404 result = cls._fromtimestamp(t, tz is not None, tz)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001405 if tz is not None:
1406 result = tz.fromutc(result)
1407 return result
1408
1409 @classmethod
1410 def utcfromtimestamp(cls, t):
Alexander Belopolskye2e178e2015-03-01 14:52:07 -05001411 """Construct a naive UTC datetime from a POSIX timestamp."""
Victor Stinneradfefa52015-09-04 23:57:25 +02001412 return cls._fromtimestamp(t, True, None)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001413
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001414 @classmethod
1415 def now(cls, tz=None):
1416 "Construct a datetime from time.time() and optional time zone info."
1417 t = _time.time()
1418 return cls.fromtimestamp(t, tz)
1419
1420 @classmethod
1421 def utcnow(cls):
1422 "Construct a UTC datetime from time.time()."
1423 t = _time.time()
1424 return cls.utcfromtimestamp(t)
1425
1426 @classmethod
1427 def combine(cls, date, time):
1428 "Construct a datetime from a given date and a given time."
1429 if not isinstance(date, _date_class):
1430 raise TypeError("date argument must be a date instance")
1431 if not isinstance(time, _time_class):
1432 raise TypeError("time argument must be a time instance")
1433 return cls(date.year, date.month, date.day,
1434 time.hour, time.minute, time.second, time.microsecond,
1435 time.tzinfo)
1436
1437 def timetuple(self):
1438 "Return local time tuple compatible with time.localtime()."
1439 dst = self.dst()
1440 if dst is None:
1441 dst = -1
1442 elif dst:
1443 dst = 1
1444 else:
1445 dst = 0
1446 return _build_struct_time(self.year, self.month, self.day,
1447 self.hour, self.minute, self.second,
1448 dst)
1449
Alexander Belopolskya4415142012-06-08 12:33:09 -04001450 def timestamp(self):
1451 "Return POSIX timestamp as float"
1452 if self._tzinfo is None:
1453 return _time.mktime((self.year, self.month, self.day,
1454 self.hour, self.minute, self.second,
1455 -1, -1, -1)) + self.microsecond / 1e6
1456 else:
1457 return (self - _EPOCH).total_seconds()
1458
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001459 def utctimetuple(self):
1460 "Return UTC time tuple compatible with time.gmtime()."
1461 offset = self.utcoffset()
1462 if offset:
1463 self -= offset
1464 y, m, d = self.year, self.month, self.day
1465 hh, mm, ss = self.hour, self.minute, self.second
1466 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1467
1468 def date(self):
1469 "Return the date part."
1470 return date(self._year, self._month, self._day)
1471
1472 def time(self):
1473 "Return the time part, with tzinfo None."
1474 return time(self.hour, self.minute, self.second, self.microsecond)
1475
1476 def timetz(self):
1477 "Return the time part, with same tzinfo."
1478 return time(self.hour, self.minute, self.second, self.microsecond,
1479 self._tzinfo)
1480
1481 def replace(self, year=None, month=None, day=None, hour=None,
1482 minute=None, second=None, microsecond=None, tzinfo=True):
1483 """Return a new datetime with new values for the specified fields."""
1484 if year is None:
1485 year = self.year
1486 if month is None:
1487 month = self.month
1488 if day is None:
1489 day = self.day
1490 if hour is None:
1491 hour = self.hour
1492 if minute is None:
1493 minute = self.minute
1494 if second is None:
1495 second = self.second
1496 if microsecond is None:
1497 microsecond = self.microsecond
1498 if tzinfo is True:
1499 tzinfo = self.tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001500 return datetime(year, month, day, hour, minute, second, microsecond,
1501 tzinfo)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001502
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001503 def astimezone(self, tz=None):
1504 if tz is None:
1505 if self.tzinfo is None:
1506 raise ValueError("astimezone() requires an aware datetime")
1507 ts = (self - _EPOCH) // timedelta(seconds=1)
1508 localtm = _time.localtime(ts)
1509 local = datetime(*localtm[:6])
1510 try:
Alexander Belopolskyff493c92012-06-22 12:25:57 -04001511 # Extract TZ data if available
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001512 gmtoff = localtm.tm_gmtoff
1513 zone = localtm.tm_zone
1514 except AttributeError:
1515 # Compute UTC offset and compare with the value implied
1516 # by tm_isdst. If the values match, use the zone name
1517 # implied by tm_isdst.
1518 delta = local - datetime(*_time.gmtime(ts)[:6])
1519 dst = _time.daylight and localtm.tm_isdst > 0
Alexander Belopolsky93c9cd02012-06-22 16:04:19 -04001520 gmtoff = -(_time.altzone if dst else _time.timezone)
1521 if delta == timedelta(seconds=gmtoff):
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001522 tz = timezone(delta, _time.tzname[dst])
1523 else:
1524 tz = timezone(delta)
1525 else:
Alexander Belopolsky93c9cd02012-06-22 16:04:19 -04001526 tz = timezone(timedelta(seconds=gmtoff), zone)
Alexander Belopolskyff493c92012-06-22 12:25:57 -04001527
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001528 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001529 raise TypeError("tz argument must be an instance of tzinfo")
1530
1531 mytz = self.tzinfo
1532 if mytz is None:
1533 raise ValueError("astimezone() requires an aware datetime")
1534
1535 if tz is mytz:
1536 return self
1537
1538 # Convert self to UTC, and attach the new time zone object.
1539 myoffset = self.utcoffset()
1540 if myoffset is None:
1541 raise ValueError("astimezone() requires an aware datetime")
1542 utc = (self - myoffset).replace(tzinfo=tz)
1543
1544 # Convert from UTC to tz's local time.
1545 return tz.fromutc(utc)
1546
1547 # Ways to produce a string.
1548
1549 def ctime(self):
1550 "Return ctime() style string."
1551 weekday = self.toordinal() % 7 or 7
1552 return "%s %s %2d %02d:%02d:%02d %04d" % (
1553 _DAYNAMES[weekday],
1554 _MONTHNAMES[self._month],
1555 self._day,
1556 self._hour, self._minute, self._second,
1557 self._year)
1558
1559 def isoformat(self, sep='T'):
1560 """Return the time formatted according to ISO.
1561
1562 This is 'YYYY-MM-DD HH:MM:SS.mmmmmm', or 'YYYY-MM-DD HH:MM:SS' if
1563 self.microsecond == 0.
1564
1565 If self.tzinfo is not None, the UTC offset is also attached, giving
1566 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM' or 'YYYY-MM-DD HH:MM:SS+HH:MM'.
1567
1568 Optional argument sep specifies the separator between date and
1569 time, default 'T'.
1570 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001571 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1572 _format_time(self._hour, self._minute, self._second,
1573 self._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001574 off = self.utcoffset()
1575 if off is not None:
1576 if off.days < 0:
1577 sign = "-"
1578 off = -off
1579 else:
1580 sign = "+"
1581 hh, mm = divmod(off, timedelta(hours=1))
1582 assert not mm % timedelta(minutes=1), "whole minute"
1583 mm //= timedelta(minutes=1)
1584 s += "%s%02d:%02d" % (sign, hh, mm)
1585 return s
1586
1587 def __repr__(self):
1588 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001589 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001590 self._hour, self._minute, self._second, self._microsecond]
1591 if L[-1] == 0:
1592 del L[-1]
1593 if L[-1] == 0:
1594 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001595 s = "%s.%s(%s)" % (self.__class__.__module__,
1596 self.__class__.__qualname__,
1597 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001598 if self._tzinfo is not None:
1599 assert s[-1:] == ")"
1600 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
1601 return s
1602
1603 def __str__(self):
1604 "Convert to string, for str()."
1605 return self.isoformat(sep=' ')
1606
1607 @classmethod
1608 def strptime(cls, date_string, format):
1609 'string, format -> new datetime parsed from a string (like time.strptime()).'
1610 import _strptime
1611 return _strptime._strptime_datetime(cls, date_string, format)
1612
1613 def utcoffset(self):
1614 """Return the timezone offset in minutes east of UTC (negative west of
1615 UTC)."""
1616 if self._tzinfo is None:
1617 return None
1618 offset = self._tzinfo.utcoffset(self)
1619 _check_utc_offset("utcoffset", offset)
1620 return offset
1621
1622 def tzname(self):
1623 """Return the timezone name.
1624
1625 Note that the name is 100% informational -- there's no requirement that
1626 it mean anything in particular. For example, "GMT", "UTC", "-500",
1627 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1628 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001629 if self._tzinfo is None:
1630 return None
1631 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001632 _check_tzname(name)
1633 return name
1634
1635 def dst(self):
1636 """Return 0 if DST is not in effect, or the DST offset (in minutes
1637 eastward) if DST is in effect.
1638
1639 This is purely informational; the DST offset has already been added to
1640 the UTC offset returned by utcoffset() if applicable, so there's no
1641 need to consult dst() unless you're interested in displaying the DST
1642 info.
1643 """
1644 if self._tzinfo is None:
1645 return None
1646 offset = self._tzinfo.dst(self)
1647 _check_utc_offset("dst", offset)
1648 return offset
1649
1650 # Comparisons of datetime objects with other.
1651
1652 def __eq__(self, other):
1653 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001654 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001655 elif not isinstance(other, date):
1656 return NotImplemented
1657 else:
1658 return False
1659
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001660 def __le__(self, other):
1661 if isinstance(other, datetime):
1662 return self._cmp(other) <= 0
1663 elif not isinstance(other, date):
1664 return NotImplemented
1665 else:
1666 _cmperror(self, other)
1667
1668 def __lt__(self, other):
1669 if isinstance(other, datetime):
1670 return self._cmp(other) < 0
1671 elif not isinstance(other, date):
1672 return NotImplemented
1673 else:
1674 _cmperror(self, other)
1675
1676 def __ge__(self, other):
1677 if isinstance(other, datetime):
1678 return self._cmp(other) >= 0
1679 elif not isinstance(other, date):
1680 return NotImplemented
1681 else:
1682 _cmperror(self, other)
1683
1684 def __gt__(self, other):
1685 if isinstance(other, datetime):
1686 return self._cmp(other) > 0
1687 elif not isinstance(other, date):
1688 return NotImplemented
1689 else:
1690 _cmperror(self, other)
1691
Alexander Belopolsky08313822012-06-15 20:19:47 -04001692 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001693 assert isinstance(other, datetime)
1694 mytz = self._tzinfo
1695 ottz = other._tzinfo
1696 myoff = otoff = None
1697
1698 if mytz is ottz:
1699 base_compare = True
1700 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04001701 myoff = self.utcoffset()
1702 otoff = other.utcoffset()
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001703 base_compare = myoff == otoff
1704
1705 if base_compare:
1706 return _cmp((self._year, self._month, self._day,
1707 self._hour, self._minute, self._second,
1708 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001709 (other._year, other._month, other._day,
1710 other._hour, other._minute, other._second,
1711 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001712 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001713 if allow_mixed:
1714 return 2 # arbitrary non-zero value
1715 else:
1716 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001717 # XXX What follows could be done more efficiently...
1718 diff = self - other # this will take offsets into account
1719 if diff.days < 0:
1720 return -1
1721 return diff and 1 or 0
1722
1723 def __add__(self, other):
1724 "Add a datetime and a timedelta."
1725 if not isinstance(other, timedelta):
1726 return NotImplemented
1727 delta = timedelta(self.toordinal(),
1728 hours=self._hour,
1729 minutes=self._minute,
1730 seconds=self._second,
1731 microseconds=self._microsecond)
1732 delta += other
1733 hour, rem = divmod(delta.seconds, 3600)
1734 minute, second = divmod(rem, 60)
1735 if 0 < delta.days <= _MAXORDINAL:
1736 return datetime.combine(date.fromordinal(delta.days),
1737 time(hour, minute, second,
1738 delta.microseconds,
1739 tzinfo=self._tzinfo))
1740 raise OverflowError("result out of range")
1741
1742 __radd__ = __add__
1743
1744 def __sub__(self, other):
1745 "Subtract two datetimes, or a datetime and a timedelta."
1746 if not isinstance(other, datetime):
1747 if isinstance(other, timedelta):
1748 return self + -other
1749 return NotImplemented
1750
1751 days1 = self.toordinal()
1752 days2 = other.toordinal()
1753 secs1 = self._second + self._minute * 60 + self._hour * 3600
1754 secs2 = other._second + other._minute * 60 + other._hour * 3600
1755 base = timedelta(days1 - days2,
1756 secs1 - secs2,
1757 self._microsecond - other._microsecond)
1758 if self._tzinfo is other._tzinfo:
1759 return base
1760 myoff = self.utcoffset()
1761 otoff = other.utcoffset()
1762 if myoff == otoff:
1763 return base
1764 if myoff is None or otoff is None:
1765 raise TypeError("cannot mix naive and timezone-aware time")
1766 return base + otoff - myoff
1767
1768 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001769 if self._hashcode == -1:
1770 tzoff = self.utcoffset()
1771 if tzoff is None:
1772 self._hashcode = hash(self._getstate()[0])
1773 else:
1774 days = _ymd2ord(self.year, self.month, self.day)
1775 seconds = self.hour * 3600 + self.minute * 60 + self.second
1776 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
1777 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001778
1779 # Pickle support.
1780
1781 def _getstate(self):
1782 yhi, ylo = divmod(self._year, 256)
1783 us2, us3 = divmod(self._microsecond, 256)
1784 us1, us2 = divmod(us2, 256)
1785 basestate = bytes([yhi, ylo, self._month, self._day,
1786 self._hour, self._minute, self._second,
1787 us1, us2, us3])
1788 if self._tzinfo is None:
1789 return (basestate,)
1790 else:
1791 return (basestate, self._tzinfo)
1792
1793 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001794 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1795 raise TypeError("bad tzinfo state arg")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001796 (yhi, ylo, self._month, self._day, self._hour,
1797 self._minute, self._second, us1, us2, us3) = string
1798 self._year = yhi * 256 + ylo
1799 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001800 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001801
1802 def __reduce__(self):
1803 return (self.__class__, self._getstate())
1804
1805
1806datetime.min = datetime(1, 1, 1)
1807datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1808datetime.resolution = timedelta(microseconds=1)
1809
1810
1811def _isoweek1monday(year):
1812 # Helper to calculate the day number of the Monday starting week 1
1813 # XXX This could be done more efficiently
1814 THURSDAY = 3
1815 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001816 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001817 week1monday = firstday - firstweekday
1818 if firstweekday > THURSDAY:
1819 week1monday += 7
1820 return week1monday
1821
1822class timezone(tzinfo):
1823 __slots__ = '_offset', '_name'
1824
1825 # Sentinel value to disallow None
1826 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001827 def __new__(cls, offset, name=_Omitted):
1828 if not isinstance(offset, timedelta):
1829 raise TypeError("offset must be a timedelta")
1830 if name is cls._Omitted:
1831 if not offset:
1832 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001833 name = None
1834 elif not isinstance(name, str):
1835 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001836 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001837 raise ValueError("offset must be a timedelta "
1838 "strictly between -timedelta(hours=24) and "
1839 "timedelta(hours=24).")
1840 if (offset.microseconds != 0 or offset.seconds % 60 != 0):
1841 raise ValueError("offset must be a timedelta "
1842 "representing a whole number of minutes")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001843 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001844
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001845 @classmethod
1846 def _create(cls, offset, name=None):
1847 self = tzinfo.__new__(cls)
1848 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001849 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001850 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001851
1852 def __getinitargs__(self):
1853 """pickle support"""
1854 if self._name is None:
1855 return (self._offset,)
1856 return (self._offset, self._name)
1857
1858 def __eq__(self, other):
Georg Brandl0085a242012-09-22 09:23:12 +02001859 if type(other) != timezone:
1860 return False
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001861 return self._offset == other._offset
1862
1863 def __hash__(self):
1864 return hash(self._offset)
1865
1866 def __repr__(self):
1867 """Convert to formal string, for repr().
1868
1869 >>> tz = timezone.utc
1870 >>> repr(tz)
1871 'datetime.timezone.utc'
1872 >>> tz = timezone(timedelta(hours=-5), 'EST')
1873 >>> repr(tz)
1874 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
1875 """
1876 if self is self.utc:
1877 return 'datetime.timezone.utc'
1878 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001879 return "%s.%s(%r)" % (self.__class__.__module__,
1880 self.__class__.__qualname__,
1881 self._offset)
1882 return "%s.%s(%r, %r)" % (self.__class__.__module__,
1883 self.__class__.__qualname__,
1884 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001885
1886 def __str__(self):
1887 return self.tzname(None)
1888
1889 def utcoffset(self, dt):
1890 if isinstance(dt, datetime) or dt is None:
1891 return self._offset
1892 raise TypeError("utcoffset() argument must be a datetime instance"
1893 " or None")
1894
1895 def tzname(self, dt):
1896 if isinstance(dt, datetime) or dt is None:
1897 if self._name is None:
1898 return self._name_from_offset(self._offset)
1899 return self._name
1900 raise TypeError("tzname() argument must be a datetime instance"
1901 " or None")
1902
1903 def dst(self, dt):
1904 if isinstance(dt, datetime) or dt is None:
1905 return None
1906 raise TypeError("dst() argument must be a datetime instance"
1907 " or None")
1908
1909 def fromutc(self, dt):
1910 if isinstance(dt, datetime):
1911 if dt.tzinfo is not self:
1912 raise ValueError("fromutc: dt.tzinfo "
1913 "is not self")
1914 return dt + self._offset
1915 raise TypeError("fromutc() argument must be a datetime instance"
1916 " or None")
1917
1918 _maxoffset = timedelta(hours=23, minutes=59)
1919 _minoffset = -_maxoffset
1920
1921 @staticmethod
1922 def _name_from_offset(delta):
Alexander Belopolsky7827a5b2015-09-06 13:07:21 -04001923 if not delta:
1924 return 'UTC'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001925 if delta < timedelta(0):
1926 sign = '-'
1927 delta = -delta
1928 else:
1929 sign = '+'
1930 hours, rest = divmod(delta, timedelta(hours=1))
1931 minutes = rest // timedelta(minutes=1)
1932 return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes)
1933
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001934timezone.utc = timezone._create(timedelta(0))
1935timezone.min = timezone._create(timezone._minoffset)
1936timezone.max = timezone._create(timezone._maxoffset)
Alexander Belopolskya4415142012-06-08 12:33:09 -04001937_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001938
Victor Stinner765531d2013-03-26 01:11:54 +01001939# Some time zone algebra. For a datetime x, let
1940# x.n = x stripped of its timezone -- its naive time.
1941# x.o = x.utcoffset(), and assuming that doesn't raise an exception or
1942# return None
1943# x.d = x.dst(), and assuming that doesn't raise an exception or
1944# return None
1945# x.s = x's standard offset, x.o - x.d
1946#
1947# Now some derived rules, where k is a duration (timedelta).
1948#
1949# 1. x.o = x.s + x.d
1950# This follows from the definition of x.s.
1951#
1952# 2. If x and y have the same tzinfo member, x.s = y.s.
1953# This is actually a requirement, an assumption we need to make about
1954# sane tzinfo classes.
1955#
1956# 3. The naive UTC time corresponding to x is x.n - x.o.
1957# This is again a requirement for a sane tzinfo class.
1958#
1959# 4. (x+k).s = x.s
1960# This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
1961#
1962# 5. (x+k).n = x.n + k
1963# Again follows from how arithmetic is defined.
1964#
1965# Now we can explain tz.fromutc(x). Let's assume it's an interesting case
1966# (meaning that the various tzinfo methods exist, and don't blow up or return
1967# None when called).
1968#
1969# The function wants to return a datetime y with timezone tz, equivalent to x.
1970# x is already in UTC.
1971#
1972# By #3, we want
1973#
1974# y.n - y.o = x.n [1]
1975#
1976# The algorithm starts by attaching tz to x.n, and calling that y. So
1977# x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
1978# becomes true; in effect, we want to solve [2] for k:
1979#
1980# (y+k).n - (y+k).o = x.n [2]
1981#
1982# By #1, this is the same as
1983#
1984# (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
1985#
1986# By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
1987# Substituting that into [3],
1988#
1989# x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
1990# k - (y+k).s - (y+k).d = 0; rearranging,
1991# k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
1992# k = y.s - (y+k).d
1993#
1994# On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
1995# approximate k by ignoring the (y+k).d term at first. Note that k can't be
1996# very large, since all offset-returning methods return a duration of magnitude
1997# less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
1998# be 0, so ignoring it has no consequence then.
1999#
2000# In any case, the new value is
2001#
2002# z = y + y.s [4]
2003#
2004# It's helpful to step back at look at [4] from a higher level: it's simply
2005# mapping from UTC to tz's standard time.
2006#
2007# At this point, if
2008#
2009# z.n - z.o = x.n [5]
2010#
2011# we have an equivalent time, and are almost done. The insecurity here is
2012# at the start of daylight time. Picture US Eastern for concreteness. The wall
2013# time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
2014# sense then. The docs ask that an Eastern tzinfo class consider such a time to
2015# be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
2016# on the day DST starts. We want to return the 1:MM EST spelling because that's
2017# the only spelling that makes sense on the local wall clock.
2018#
2019# In fact, if [5] holds at this point, we do have the standard-time spelling,
2020# but that takes a bit of proof. We first prove a stronger result. What's the
2021# difference between the LHS and RHS of [5]? Let
2022#
2023# diff = x.n - (z.n - z.o) [6]
2024#
2025# Now
2026# z.n = by [4]
2027# (y + y.s).n = by #5
2028# y.n + y.s = since y.n = x.n
2029# x.n + y.s = since z and y are have the same tzinfo member,
2030# y.s = z.s by #2
2031# x.n + z.s
2032#
2033# Plugging that back into [6] gives
2034#
2035# diff =
2036# x.n - ((x.n + z.s) - z.o) = expanding
2037# x.n - x.n - z.s + z.o = cancelling
2038# - z.s + z.o = by #2
2039# z.d
2040#
2041# So diff = z.d.
2042#
2043# If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
2044# spelling we wanted in the endcase described above. We're done. Contrarily,
2045# if z.d = 0, then we have a UTC equivalent, and are also done.
2046#
2047# If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2048# add to z (in effect, z is in tz's standard time, and we need to shift the
2049# local clock into tz's daylight time).
2050#
2051# Let
2052#
2053# z' = z + z.d = z + diff [7]
2054#
2055# and we can again ask whether
2056#
2057# z'.n - z'.o = x.n [8]
2058#
2059# If so, we're done. If not, the tzinfo class is insane, according to the
2060# assumptions we've made. This also requires a bit of proof. As before, let's
2061# compute the difference between the LHS and RHS of [8] (and skipping some of
2062# the justifications for the kinds of substitutions we've done several times
2063# already):
2064#
2065# diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2066# x.n - (z.n + diff - z'.o) = replacing diff via [6]
2067# x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2068# x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2069# - z.n + z.n - z.o + z'.o = cancel z.n
2070# - z.o + z'.o = #1 twice
2071# -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2072# z'.d - z.d
2073#
2074# So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2075# we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2076# return z', not bothering to compute z'.d.
2077#
2078# How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2079# a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2080# would have to change the result dst() returns: we start in DST, and moving
2081# a little further into it takes us out of DST.
2082#
2083# There isn't a sane case where this can happen. The closest it gets is at
2084# the end of DST, where there's an hour in UTC with no spelling in a hybrid
2085# tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2086# that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2087# UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2088# time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2089# clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2090# standard time. Since that's what the local clock *does*, we want to map both
2091# UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2092# in local time, but so it goes -- it's the way the local clock works.
2093#
2094# When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2095# so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2096# z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2097# (correctly) concludes that z' is not UTC-equivalent to x.
2098#
2099# Because we know z.d said z was in daylight time (else [5] would have held and
2100# we would have stopped then), and we know z.d != z'.d (else [8] would have held
2101# and we have stopped then), and there are only 2 possible values dst() can
2102# return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2103# but the reasoning doesn't depend on the example -- it depends on there being
2104# two possible dst() outcomes, one zero and the other non-zero). Therefore
2105# z' must be in standard time, and is the spelling we want in this case.
2106#
2107# Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2108# concerned (because it takes z' as being in standard time rather than the
2109# daylight time we intend here), but returning it gives the real-life "local
2110# clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2111# tz.
2112#
2113# When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2114# the 1:MM standard time spelling we want.
2115#
2116# So how can this break? One of the assumptions must be violated. Two
2117# possibilities:
2118#
2119# 1) [2] effectively says that y.s is invariant across all y belong to a given
2120# time zone. This isn't true if, for political reasons or continental drift,
2121# a region decides to change its base offset from UTC.
2122#
2123# 2) There may be versions of "double daylight" time where the tail end of
2124# the analysis gives up a step too early. I haven't thought about that
2125# enough to say.
2126#
2127# In any case, it's clear that the default fromutc() is strong enough to handle
2128# "almost all" time zones: so long as the standard offset is invariant, it
2129# doesn't matter if daylight time transition points change from year to year, or
2130# if daylight time is skipped in some years; it doesn't matter how large or
2131# small dst() may get within its bounds; and it doesn't even matter if some
2132# perverse time zone returns a negative dst()). So a breaking case must be
2133# pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002134
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002135try:
2136 from _datetime import *
Brett Cannoncd171c82013-07-04 17:43:24 -04002137except ImportError:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00002138 pass
2139else:
2140 # Clean up unused names
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04002141 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2142 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2143 _check_date_fields, _check_int_field, _check_time_fields,
2144 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2145 _date_class, _days_before_month, _days_before_year, _days_in_month,
2146 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd,
2147 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002148 # XXX Since import * above excludes names that start with _,
2149 # docstring does not get overwritten. In the future, it may be
2150 # appropriate to maintain a single module level docstring and
2151 # remove the following line.
2152 from _datetime import __doc__