blob: 86c80c3101c1804237f0efb4c51778879d6c2d25 [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
300class timedelta:
301 """Represent the difference between two datetime objects.
302
303 Supported operators:
304
305 - add, subtract timedelta
306 - unary plus, minus, abs
307 - compare to timedelta
Serhiy Storchaka95949422013-08-27 19:40:23 +0300308 - multiply, divide by int
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000309
310 In addition, datetime supports subtraction of two datetime objects
311 returning a timedelta, and addition or subtraction of a datetime
312 and a timedelta giving a datetime.
313
314 Representation: (days, seconds, microseconds). Why? Because I
315 felt like it.
316 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400317 __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000318
319 def __new__(cls, days=0, seconds=0, microseconds=0,
320 milliseconds=0, minutes=0, hours=0, weeks=0):
321 # Doing this efficiently and accurately in C is going to be difficult
322 # and error-prone, due to ubiquitous overflow possibilities, and that
323 # C double doesn't have enough bits of precision to represent
324 # microseconds over 10K years faithfully. The code here tries to make
325 # explicit where go-fast assumptions can be relied on, in order to
326 # guide the C implementation; it's way more convoluted than speed-
327 # ignoring auto-overflow-to-long idiomatic Python could be.
328
329 # XXX Check that all inputs are ints or floats.
330
331 # Final values, all integer.
332 # s and us fit in 32-bit signed ints; d isn't bounded.
333 d = s = us = 0
334
335 # Normalize everything to days, seconds, microseconds.
336 days += weeks*7
337 seconds += minutes*60 + hours*3600
338 microseconds += milliseconds*1000
339
340 # Get rid of all fractions, and normalize s and us.
341 # Take a deep breath <wink>.
342 if isinstance(days, float):
343 dayfrac, days = _math.modf(days)
344 daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
345 assert daysecondswhole == int(daysecondswhole) # can't overflow
346 s = int(daysecondswhole)
347 assert days == int(days)
348 d = int(days)
349 else:
350 daysecondsfrac = 0.0
351 d = days
352 assert isinstance(daysecondsfrac, float)
353 assert abs(daysecondsfrac) <= 1.0
354 assert isinstance(d, int)
355 assert abs(s) <= 24 * 3600
356 # days isn't referenced again before redefinition
357
358 if isinstance(seconds, float):
359 secondsfrac, seconds = _math.modf(seconds)
360 assert seconds == int(seconds)
361 seconds = int(seconds)
362 secondsfrac += daysecondsfrac
363 assert abs(secondsfrac) <= 2.0
364 else:
365 secondsfrac = daysecondsfrac
366 # daysecondsfrac isn't referenced again
367 assert isinstance(secondsfrac, float)
368 assert abs(secondsfrac) <= 2.0
369
370 assert isinstance(seconds, int)
371 days, seconds = divmod(seconds, 24*3600)
372 d += days
373 s += int(seconds) # can't overflow
374 assert isinstance(s, int)
375 assert abs(s) <= 2 * 24 * 3600
376 # seconds isn't referenced again before redefinition
377
378 usdouble = secondsfrac * 1e6
379 assert abs(usdouble) < 2.1e6 # exact value not critical
380 # secondsfrac isn't referenced again
381
382 if isinstance(microseconds, float):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400383 microseconds = round(microseconds + usdouble)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000384 seconds, microseconds = divmod(microseconds, 1000000)
385 days, seconds = divmod(seconds, 24*3600)
386 d += days
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400387 s += seconds
388 else:
389 microseconds = int(microseconds)
390 seconds, microseconds = divmod(microseconds, 1000000)
391 days, seconds = divmod(seconds, 24*3600)
392 d += days
393 s += seconds
394 microseconds = round(microseconds + usdouble)
395 assert isinstance(s, int)
396 assert isinstance(microseconds, int)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000397 assert abs(s) <= 3 * 24 * 3600
398 assert abs(microseconds) < 3.1e6
399
400 # Just a little bit of carrying possible for microseconds and seconds.
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400401 seconds, us = divmod(microseconds, 1000000)
402 s += seconds
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000403 days, s = divmod(s, 24*3600)
404 d += days
405
406 assert isinstance(d, int)
407 assert isinstance(s, int) and 0 <= s < 24*3600
408 assert isinstance(us, int) and 0 <= us < 1000000
409
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000410 if abs(d) > 999999999:
411 raise OverflowError("timedelta # of days is too large: %d" % d)
412
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400413 self = object.__new__(cls)
414 self._days = d
415 self._seconds = s
416 self._microseconds = us
417 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000418 return self
419
420 def __repr__(self):
421 if self._microseconds:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300422 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
423 self.__class__.__qualname__,
424 self._days,
425 self._seconds,
426 self._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000427 if self._seconds:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300428 return "%s.%s(%d, %d)" % (self.__class__.__module__,
429 self.__class__.__qualname__,
430 self._days,
431 self._seconds)
432 return "%s.%s(%d)" % (self.__class__.__module__,
433 self.__class__.__qualname__,
434 self._days)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000435
436 def __str__(self):
437 mm, ss = divmod(self._seconds, 60)
438 hh, mm = divmod(mm, 60)
439 s = "%d:%02d:%02d" % (hh, mm, ss)
440 if self._days:
441 def plural(n):
442 return n, abs(n) != 1 and "s" or ""
443 s = ("%d day%s, " % plural(self._days)) + s
444 if self._microseconds:
445 s = s + ".%06d" % self._microseconds
446 return s
447
448 def total_seconds(self):
449 """Total seconds in the duration."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400450 return ((self.days * 86400 + self.seconds) * 10**6 +
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000451 self.microseconds) / 10**6
452
453 # Read-only field accessors
454 @property
455 def days(self):
456 """days"""
457 return self._days
458
459 @property
460 def seconds(self):
461 """seconds"""
462 return self._seconds
463
464 @property
465 def microseconds(self):
466 """microseconds"""
467 return self._microseconds
468
469 def __add__(self, other):
470 if isinstance(other, timedelta):
471 # for CPython compatibility, we cannot use
472 # our __class__ here, but need a real timedelta
473 return timedelta(self._days + other._days,
474 self._seconds + other._seconds,
475 self._microseconds + other._microseconds)
476 return NotImplemented
477
478 __radd__ = __add__
479
480 def __sub__(self, other):
481 if isinstance(other, timedelta):
Alexander Belopolskyb6f5ec72011-04-05 20:07:38 -0400482 # for CPython compatibility, we cannot use
483 # our __class__ here, but need a real timedelta
484 return timedelta(self._days - other._days,
485 self._seconds - other._seconds,
486 self._microseconds - other._microseconds)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000487 return NotImplemented
488
489 def __rsub__(self, other):
490 if isinstance(other, timedelta):
491 return -self + other
492 return NotImplemented
493
494 def __neg__(self):
495 # for CPython compatibility, we cannot use
496 # our __class__ here, but need a real timedelta
497 return timedelta(-self._days,
498 -self._seconds,
499 -self._microseconds)
500
501 def __pos__(self):
502 return self
503
504 def __abs__(self):
505 if self._days < 0:
506 return -self
507 else:
508 return self
509
510 def __mul__(self, other):
511 if isinstance(other, int):
512 # for CPython compatibility, we cannot use
513 # our __class__ here, but need a real timedelta
514 return timedelta(self._days * other,
515 self._seconds * other,
516 self._microseconds * other)
517 if isinstance(other, float):
518 a, b = other.as_integer_ratio()
519 return self * a / b
520 return NotImplemented
521
522 __rmul__ = __mul__
523
524 def _to_microseconds(self):
525 return ((self._days * (24*3600) + self._seconds) * 1000000 +
526 self._microseconds)
527
528 def __floordiv__(self, other):
529 if not isinstance(other, (int, timedelta)):
530 return NotImplemented
531 usec = self._to_microseconds()
532 if isinstance(other, timedelta):
533 return usec // other._to_microseconds()
534 if isinstance(other, int):
535 return timedelta(0, 0, usec // other)
536
537 def __truediv__(self, other):
538 if not isinstance(other, (int, float, timedelta)):
539 return NotImplemented
540 usec = self._to_microseconds()
541 if isinstance(other, timedelta):
542 return usec / other._to_microseconds()
543 if isinstance(other, int):
544 return timedelta(0, 0, usec / other)
545 if isinstance(other, float):
546 a, b = other.as_integer_ratio()
547 return timedelta(0, 0, b * usec / a)
548
549 def __mod__(self, other):
550 if isinstance(other, timedelta):
551 r = self._to_microseconds() % other._to_microseconds()
552 return timedelta(0, 0, r)
553 return NotImplemented
554
555 def __divmod__(self, other):
556 if isinstance(other, timedelta):
557 q, r = divmod(self._to_microseconds(),
558 other._to_microseconds())
559 return q, timedelta(0, 0, r)
560 return NotImplemented
561
562 # Comparisons of timedelta objects with other.
563
564 def __eq__(self, other):
565 if isinstance(other, timedelta):
566 return self._cmp(other) == 0
567 else:
568 return False
569
570 def __ne__(self, other):
571 if isinstance(other, timedelta):
572 return self._cmp(other) != 0
573 else:
574 return True
575
576 def __le__(self, other):
577 if isinstance(other, timedelta):
578 return self._cmp(other) <= 0
579 else:
580 _cmperror(self, other)
581
582 def __lt__(self, other):
583 if isinstance(other, timedelta):
584 return self._cmp(other) < 0
585 else:
586 _cmperror(self, other)
587
588 def __ge__(self, other):
589 if isinstance(other, timedelta):
590 return self._cmp(other) >= 0
591 else:
592 _cmperror(self, other)
593
594 def __gt__(self, other):
595 if isinstance(other, timedelta):
596 return self._cmp(other) > 0
597 else:
598 _cmperror(self, other)
599
600 def _cmp(self, other):
601 assert isinstance(other, timedelta)
602 return _cmp(self._getstate(), other._getstate())
603
604 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400605 if self._hashcode == -1:
606 self._hashcode = hash(self._getstate())
607 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000608
609 def __bool__(self):
610 return (self._days != 0 or
611 self._seconds != 0 or
612 self._microseconds != 0)
613
614 # Pickle support.
615
616 def _getstate(self):
617 return (self._days, self._seconds, self._microseconds)
618
619 def __reduce__(self):
620 return (self.__class__, self._getstate())
621
622timedelta.min = timedelta(-999999999)
623timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
624 microseconds=999999)
625timedelta.resolution = timedelta(microseconds=1)
626
627class date:
628 """Concrete date type.
629
630 Constructors:
631
632 __new__()
633 fromtimestamp()
634 today()
635 fromordinal()
636
637 Operators:
638
639 __repr__, __str__
640 __cmp__, __hash__
641 __add__, __radd__, __sub__ (add/radd only with timedelta arg)
642
643 Methods:
644
645 timetuple()
646 toordinal()
647 weekday()
648 isoweekday(), isocalendar(), isoformat()
649 ctime()
650 strftime()
651
652 Properties (readonly):
653 year, month, day
654 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400655 __slots__ = '_year', '_month', '_day', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000656
657 def __new__(cls, year, month=None, day=None):
658 """Constructor.
659
660 Arguments:
661
662 year, month, day (required, base 1)
663 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400664 if month is None and isinstance(year, bytes) and len(year) == 4 and \
665 1 <= year[2] <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000666 # Pickle support
667 self = object.__new__(cls)
668 self.__setstate(year)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400669 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000670 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400671 year, month, day = _check_date_fields(year, month, day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000672 self = object.__new__(cls)
673 self._year = year
674 self._month = month
675 self._day = day
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400676 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000677 return self
678
679 # Additional constructors
680
681 @classmethod
682 def fromtimestamp(cls, t):
683 "Construct a date from a POSIX timestamp (like time.time())."
684 y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
685 return cls(y, m, d)
686
687 @classmethod
688 def today(cls):
689 "Construct a date from time.time()."
690 t = _time.time()
691 return cls.fromtimestamp(t)
692
693 @classmethod
694 def fromordinal(cls, n):
695 """Contruct a date from a proleptic Gregorian ordinal.
696
697 January 1 of year 1 is day 1. Only the year, month and day are
698 non-zero in the result.
699 """
700 y, m, d = _ord2ymd(n)
701 return cls(y, m, d)
702
703 # Conversions to string
704
705 def __repr__(self):
706 """Convert to formal string, for repr().
707
708 >>> dt = datetime(2010, 1, 1)
709 >>> repr(dt)
710 'datetime.datetime(2010, 1, 1, 0, 0)'
711
712 >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
713 >>> repr(dt)
714 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
715 """
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300716 return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
717 self.__class__.__qualname__,
718 self._year,
719 self._month,
720 self._day)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000721 # XXX These shouldn't depend on time.localtime(), because that
722 # clips the usable dates to [1970 .. 2038). At least ctime() is
723 # easily done without using strftime() -- that's better too because
724 # strftime("%c", ...) is locale specific.
725
726
727 def ctime(self):
728 "Return ctime() style string."
729 weekday = self.toordinal() % 7 or 7
730 return "%s %s %2d 00:00:00 %04d" % (
731 _DAYNAMES[weekday],
732 _MONTHNAMES[self._month],
733 self._day, self._year)
734
735 def strftime(self, fmt):
736 "Format using strftime()."
737 return _wrap_strftime(self, fmt, self.timetuple())
738
739 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400740 if not isinstance(fmt, str):
741 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000742 if len(fmt) != 0:
743 return self.strftime(fmt)
744 return str(self)
745
746 def isoformat(self):
747 """Return the date formatted according to ISO.
748
749 This is 'YYYY-MM-DD'.
750
751 References:
752 - http://www.w3.org/TR/NOTE-datetime
753 - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
754 """
755 return "%04d-%02d-%02d" % (self._year, self._month, self._day)
756
757 __str__ = isoformat
758
759 # Read-only field accessors
760 @property
761 def year(self):
762 """year (1-9999)"""
763 return self._year
764
765 @property
766 def month(self):
767 """month (1-12)"""
768 return self._month
769
770 @property
771 def day(self):
772 """day (1-31)"""
773 return self._day
774
775 # Standard conversions, __cmp__, __hash__ (and helpers)
776
777 def timetuple(self):
778 "Return local time tuple compatible with time.localtime()."
779 return _build_struct_time(self._year, self._month, self._day,
780 0, 0, 0, -1)
781
782 def toordinal(self):
783 """Return proleptic Gregorian ordinal for the year, month and day.
784
785 January 1 of year 1 is day 1. Only the year, month and day values
786 contribute to the result.
787 """
788 return _ymd2ord(self._year, self._month, self._day)
789
790 def replace(self, year=None, month=None, day=None):
791 """Return a new date with new values for the specified fields."""
792 if year is None:
793 year = self._year
794 if month is None:
795 month = self._month
796 if day is None:
797 day = self._day
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000798 return date(year, month, day)
799
800 # Comparisons of date objects with other.
801
802 def __eq__(self, other):
803 if isinstance(other, date):
804 return self._cmp(other) == 0
805 return NotImplemented
806
807 def __ne__(self, other):
808 if isinstance(other, date):
809 return self._cmp(other) != 0
810 return NotImplemented
811
812 def __le__(self, other):
813 if isinstance(other, date):
814 return self._cmp(other) <= 0
815 return NotImplemented
816
817 def __lt__(self, other):
818 if isinstance(other, date):
819 return self._cmp(other) < 0
820 return NotImplemented
821
822 def __ge__(self, other):
823 if isinstance(other, date):
824 return self._cmp(other) >= 0
825 return NotImplemented
826
827 def __gt__(self, other):
828 if isinstance(other, date):
829 return self._cmp(other) > 0
830 return NotImplemented
831
832 def _cmp(self, other):
833 assert isinstance(other, date)
834 y, m, d = self._year, self._month, self._day
835 y2, m2, d2 = other._year, other._month, other._day
836 return _cmp((y, m, d), (y2, m2, d2))
837
838 def __hash__(self):
839 "Hash."
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400840 if self._hashcode == -1:
841 self._hashcode = hash(self._getstate())
842 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000843
844 # Computations
845
846 def __add__(self, other):
847 "Add a date to a timedelta."
848 if isinstance(other, timedelta):
849 o = self.toordinal() + other.days
850 if 0 < o <= _MAXORDINAL:
851 return date.fromordinal(o)
852 raise OverflowError("result out of range")
853 return NotImplemented
854
855 __radd__ = __add__
856
857 def __sub__(self, other):
858 """Subtract two dates, or a date and a timedelta."""
859 if isinstance(other, timedelta):
860 return self + timedelta(-other.days)
861 if isinstance(other, date):
862 days1 = self.toordinal()
863 days2 = other.toordinal()
864 return timedelta(days1 - days2)
865 return NotImplemented
866
867 def weekday(self):
868 "Return day of the week, where Monday == 0 ... Sunday == 6."
869 return (self.toordinal() + 6) % 7
870
871 # Day-of-the-week and week-of-the-year, according to ISO
872
873 def isoweekday(self):
874 "Return day of the week, where Monday == 1 ... Sunday == 7."
875 # 1-Jan-0001 is a Monday
876 return self.toordinal() % 7 or 7
877
878 def isocalendar(self):
879 """Return a 3-tuple containing ISO year, week number, and weekday.
880
881 The first ISO week of the year is the (Mon-Sun) week
882 containing the year's first Thursday; everything else derives
883 from that.
884
885 The first week is 1; Monday is 1 ... Sunday is 7.
886
887 ISO calendar algorithm taken from
888 http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
889 """
890 year = self._year
891 week1monday = _isoweek1monday(year)
892 today = _ymd2ord(self._year, self._month, self._day)
893 # Internally, week and day have origin 0
894 week, day = divmod(today - week1monday, 7)
895 if week < 0:
896 year -= 1
897 week1monday = _isoweek1monday(year)
898 week, day = divmod(today - week1monday, 7)
899 elif week >= 52:
900 if today >= _isoweek1monday(year+1):
901 year += 1
902 week = 0
903 return year, week+1, day+1
904
905 # Pickle support.
906
907 def _getstate(self):
908 yhi, ylo = divmod(self._year, 256)
909 return bytes([yhi, ylo, self._month, self._day]),
910
911 def __setstate(self, string):
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000912 yhi, ylo, self._month, self._day = string
913 self._year = yhi * 256 + ylo
914
915 def __reduce__(self):
916 return (self.__class__, self._getstate())
917
918_date_class = date # so functions w/ args named "date" can get at the class
919
920date.min = date(1, 1, 1)
921date.max = date(9999, 12, 31)
922date.resolution = timedelta(days=1)
923
924class tzinfo:
925 """Abstract base class for time zone info classes.
926
927 Subclasses must override the name(), utcoffset() and dst() methods.
928 """
929 __slots__ = ()
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -0400930
Alexander Belopolskycf86e362010-07-23 19:25:47 +0000931 def tzname(self, dt):
932 "datetime -> string name of time zone."
933 raise NotImplementedError("tzinfo subclass must override tzname()")
934
935 def utcoffset(self, dt):
936 "datetime -> minutes east of UTC (negative for west of UTC)"
937 raise NotImplementedError("tzinfo subclass must override utcoffset()")
938
939 def dst(self, dt):
940 """datetime -> DST offset in minutes east of UTC.
941
942 Return 0 if DST not in effect. utcoffset() must include the DST
943 offset.
944 """
945 raise NotImplementedError("tzinfo subclass must override dst()")
946
947 def fromutc(self, dt):
948 "datetime in UTC -> datetime in local time."
949
950 if not isinstance(dt, datetime):
951 raise TypeError("fromutc() requires a datetime argument")
952 if dt.tzinfo is not self:
953 raise ValueError("dt.tzinfo is not self")
954
955 dtoff = dt.utcoffset()
956 if dtoff is None:
957 raise ValueError("fromutc() requires a non-None utcoffset() "
958 "result")
959
960 # See the long comment block at the end of this file for an
961 # explanation of this algorithm.
962 dtdst = dt.dst()
963 if dtdst is None:
964 raise ValueError("fromutc() requires a non-None dst() result")
965 delta = dtoff - dtdst
966 if delta:
967 dt += delta
968 dtdst = dt.dst()
969 if dtdst is None:
970 raise ValueError("fromutc(): dt.dst gave inconsistent "
971 "results; cannot convert")
972 return dt + dtdst
973
974 # Pickle support.
975
976 def __reduce__(self):
977 getinitargs = getattr(self, "__getinitargs__", None)
978 if getinitargs:
979 args = getinitargs()
980 else:
981 args = ()
982 getstate = getattr(self, "__getstate__", None)
983 if getstate:
984 state = getstate()
985 else:
986 state = getattr(self, "__dict__", None) or None
987 if state is None:
988 return (self.__class__, args)
989 else:
990 return (self.__class__, args, state)
991
992_tzinfo_class = tzinfo
993
994class time:
995 """Time with time zone.
996
997 Constructors:
998
999 __new__()
1000
1001 Operators:
1002
1003 __repr__, __str__
1004 __cmp__, __hash__
1005
1006 Methods:
1007
1008 strftime()
1009 isoformat()
1010 utcoffset()
1011 tzname()
1012 dst()
1013
1014 Properties (readonly):
1015 hour, minute, second, microsecond, tzinfo
1016 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001017 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode'
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001018
1019 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None):
1020 """Constructor.
1021
1022 Arguments:
1023
1024 hour, minute (required)
1025 second, microsecond (default to zero)
1026 tzinfo (default to None)
1027 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001028 if isinstance(hour, bytes) and len(hour) == 6 and hour[0] < 24:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001029 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001030 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001031 self.__setstate(hour, minute or None)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001032 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001033 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001034 hour, minute, second, microsecond = _check_time_fields(
1035 hour, minute, second, microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001036 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001037 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001038 self._hour = hour
1039 self._minute = minute
1040 self._second = second
1041 self._microsecond = microsecond
1042 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001043 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001044 return self
1045
1046 # Read-only field accessors
1047 @property
1048 def hour(self):
1049 """hour (0-23)"""
1050 return self._hour
1051
1052 @property
1053 def minute(self):
1054 """minute (0-59)"""
1055 return self._minute
1056
1057 @property
1058 def second(self):
1059 """second (0-59)"""
1060 return self._second
1061
1062 @property
1063 def microsecond(self):
1064 """microsecond (0-999999)"""
1065 return self._microsecond
1066
1067 @property
1068 def tzinfo(self):
1069 """timezone info object"""
1070 return self._tzinfo
1071
1072 # Standard conversions, __hash__ (and helpers)
1073
1074 # Comparisons of time objects with other.
1075
1076 def __eq__(self, other):
1077 if isinstance(other, time):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001078 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001079 else:
1080 return False
1081
1082 def __ne__(self, other):
1083 if isinstance(other, time):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001084 return self._cmp(other, allow_mixed=True) != 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001085 else:
1086 return True
1087
1088 def __le__(self, other):
1089 if isinstance(other, time):
1090 return self._cmp(other) <= 0
1091 else:
1092 _cmperror(self, other)
1093
1094 def __lt__(self, other):
1095 if isinstance(other, time):
1096 return self._cmp(other) < 0
1097 else:
1098 _cmperror(self, other)
1099
1100 def __ge__(self, other):
1101 if isinstance(other, time):
1102 return self._cmp(other) >= 0
1103 else:
1104 _cmperror(self, other)
1105
1106 def __gt__(self, other):
1107 if isinstance(other, time):
1108 return self._cmp(other) > 0
1109 else:
1110 _cmperror(self, other)
1111
Alexander Belopolsky08313822012-06-15 20:19:47 -04001112 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001113 assert isinstance(other, time)
1114 mytz = self._tzinfo
1115 ottz = other._tzinfo
1116 myoff = otoff = None
1117
1118 if mytz is ottz:
1119 base_compare = True
1120 else:
1121 myoff = self.utcoffset()
1122 otoff = other.utcoffset()
1123 base_compare = myoff == otoff
1124
1125 if base_compare:
1126 return _cmp((self._hour, self._minute, self._second,
1127 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001128 (other._hour, other._minute, other._second,
1129 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001130 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001131 if allow_mixed:
1132 return 2 # arbitrary non-zero value
1133 else:
1134 raise TypeError("cannot compare naive and aware times")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001135 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1136 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1137 return _cmp((myhhmm, self._second, self._microsecond),
1138 (othhmm, other._second, other._microsecond))
1139
1140 def __hash__(self):
1141 """Hash."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001142 if self._hashcode == -1:
1143 tzoff = self.utcoffset()
1144 if not tzoff: # zero or None
1145 self._hashcode = hash(self._getstate()[0])
1146 else:
1147 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1148 timedelta(hours=1))
1149 assert not m % timedelta(minutes=1), "whole minute"
1150 m //= timedelta(minutes=1)
1151 if 0 <= h < 24:
1152 self._hashcode = hash(time(h, m, self.second, self.microsecond))
1153 else:
1154 self._hashcode = hash((h, m, self.second, self.microsecond))
1155 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001156
1157 # Conversion to string
1158
1159 def _tzstr(self, sep=":"):
1160 """Return formatted timezone offset (+xx:xx) or None."""
1161 off = self.utcoffset()
1162 if off is not None:
1163 if off.days < 0:
1164 sign = "-"
1165 off = -off
1166 else:
1167 sign = "+"
1168 hh, mm = divmod(off, timedelta(hours=1))
1169 assert not mm % timedelta(minutes=1), "whole minute"
1170 mm //= timedelta(minutes=1)
1171 assert 0 <= hh < 24
1172 off = "%s%02d%s%02d" % (sign, hh, sep, mm)
1173 return off
1174
1175 def __repr__(self):
1176 """Convert to formal string, for repr()."""
1177 if self._microsecond != 0:
1178 s = ", %d, %d" % (self._second, self._microsecond)
1179 elif self._second != 0:
1180 s = ", %d" % self._second
1181 else:
1182 s = ""
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001183 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1184 self.__class__.__qualname__,
1185 self._hour, self._minute, s)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001186 if self._tzinfo is not None:
1187 assert s[-1:] == ")"
1188 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
1189 return s
1190
1191 def isoformat(self):
1192 """Return the time formatted according to ISO.
1193
1194 This is 'HH:MM:SS.mmmmmm+zz:zz', or 'HH:MM:SS+zz:zz' if
1195 self.microsecond == 0.
1196 """
1197 s = _format_time(self._hour, self._minute, self._second,
1198 self._microsecond)
1199 tz = self._tzstr()
1200 if tz:
1201 s += tz
1202 return s
1203
1204 __str__ = isoformat
1205
1206 def strftime(self, fmt):
1207 """Format using strftime(). The date part of the timestamp passed
1208 to underlying strftime should not be used.
1209 """
Alexander Belopolskyb8bb4662011-01-08 00:13:34 +00001210 # The year must be >= 1000 else Python's strftime implementation
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001211 # can raise a bogus exception.
1212 timetuple = (1900, 1, 1,
1213 self._hour, self._minute, self._second,
1214 0, 1, -1)
1215 return _wrap_strftime(self, fmt, timetuple)
1216
1217 def __format__(self, fmt):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001218 if not isinstance(fmt, str):
1219 raise TypeError("must be str, not %s" % type(fmt).__name__)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001220 if len(fmt) != 0:
1221 return self.strftime(fmt)
1222 return str(self)
1223
1224 # Timezone functions
1225
1226 def utcoffset(self):
1227 """Return the timezone offset in minutes east of UTC (negative west of
1228 UTC)."""
1229 if self._tzinfo is None:
1230 return None
1231 offset = self._tzinfo.utcoffset(None)
1232 _check_utc_offset("utcoffset", offset)
1233 return offset
1234
1235 def tzname(self):
1236 """Return the timezone name.
1237
1238 Note that the name is 100% informational -- there's no requirement that
1239 it mean anything in particular. For example, "GMT", "UTC", "-500",
1240 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1241 """
1242 if self._tzinfo is None:
1243 return None
1244 name = self._tzinfo.tzname(None)
1245 _check_tzname(name)
1246 return name
1247
1248 def dst(self):
1249 """Return 0 if DST is not in effect, or the DST offset (in minutes
1250 eastward) if DST is in effect.
1251
1252 This is purely informational; the DST offset has already been added to
1253 the UTC offset returned by utcoffset() if applicable, so there's no
1254 need to consult dst() unless you're interested in displaying the DST
1255 info.
1256 """
1257 if self._tzinfo is None:
1258 return None
1259 offset = self._tzinfo.dst(None)
1260 _check_utc_offset("dst", offset)
1261 return offset
1262
1263 def replace(self, hour=None, minute=None, second=None, microsecond=None,
1264 tzinfo=True):
1265 """Return a new time with new values for the specified fields."""
1266 if hour is None:
1267 hour = self.hour
1268 if minute is None:
1269 minute = self.minute
1270 if second is None:
1271 second = self.second
1272 if microsecond is None:
1273 microsecond = self.microsecond
1274 if tzinfo is True:
1275 tzinfo = self.tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001276 return time(hour, minute, second, microsecond, tzinfo)
1277
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001278 # Pickle support.
1279
1280 def _getstate(self):
1281 us2, us3 = divmod(self._microsecond, 256)
1282 us1, us2 = divmod(us2, 256)
1283 basestate = bytes([self._hour, self._minute, self._second,
1284 us1, us2, us3])
1285 if self._tzinfo is None:
1286 return (basestate,)
1287 else:
1288 return (basestate, self._tzinfo)
1289
1290 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001291 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1292 raise TypeError("bad tzinfo state arg")
1293 self._hour, self._minute, self._second, us1, us2, us3 = string
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001294 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001295 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001296
1297 def __reduce__(self):
1298 return (time, self._getstate())
1299
1300_time_class = time # so functions w/ args named "time" can get at the class
1301
1302time.min = time(0, 0, 0)
1303time.max = time(23, 59, 59, 999999)
1304time.resolution = timedelta(microseconds=1)
1305
1306class datetime(date):
1307 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1308
1309 The year, month and day arguments are required. tzinfo may be None, or an
Serhiy Storchaka95949422013-08-27 19:40:23 +03001310 instance of a tzinfo subclass. The remaining arguments may be ints.
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001311 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001312 __slots__ = date.__slots__ + time.__slots__
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001313
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001314 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
1315 microsecond=0, tzinfo=None):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001316 if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2] <= 12:
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001317 # Pickle support
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001318 self = object.__new__(cls)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001319 self.__setstate(year, month)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001320 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001321 return self
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001322 year, month, day = _check_date_fields(year, month, day)
1323 hour, minute, second, microsecond = _check_time_fields(
1324 hour, minute, second, microsecond)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001325 _check_tzinfo_arg(tzinfo)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001326 self = object.__new__(cls)
1327 self._year = year
1328 self._month = month
1329 self._day = day
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001330 self._hour = hour
1331 self._minute = minute
1332 self._second = second
1333 self._microsecond = microsecond
1334 self._tzinfo = tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001335 self._hashcode = -1
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001336 return self
1337
1338 # Read-only field accessors
1339 @property
1340 def hour(self):
1341 """hour (0-23)"""
1342 return self._hour
1343
1344 @property
1345 def minute(self):
1346 """minute (0-59)"""
1347 return self._minute
1348
1349 @property
1350 def second(self):
1351 """second (0-59)"""
1352 return self._second
1353
1354 @property
1355 def microsecond(self):
1356 """microsecond (0-999999)"""
1357 return self._microsecond
1358
1359 @property
1360 def tzinfo(self):
1361 """timezone info object"""
1362 return self._tzinfo
1363
1364 @classmethod
1365 def fromtimestamp(cls, t, tz=None):
1366 """Construct a datetime from a POSIX timestamp (like time.time()).
1367
1368 A timezone info object may be passed in as well.
1369 """
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001370 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001371
1372 converter = _time.localtime if tz is None else _time.gmtime
1373
1374 t, frac = divmod(t, 1.0)
Victor Stinner5d272cc2012-03-13 13:35:55 +01001375 us = int(frac * 1e6)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001376
1377 # If timestamp is less than one microsecond smaller than a
1378 # full second, us can be rounded up to 1000000. In this case,
1379 # roll over to seconds, otherwise, ValueError is raised
1380 # by the constructor.
1381 if us == 1000000:
1382 t += 1
1383 us = 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001384 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001385 ss = min(ss, 59) # clamp out leap seconds if the platform has them
1386 result = cls(y, m, d, hh, mm, ss, us, tz)
1387 if tz is not None:
1388 result = tz.fromutc(result)
1389 return result
1390
1391 @classmethod
1392 def utcfromtimestamp(cls, t):
1393 "Construct a UTC datetime from a POSIX timestamp (like time.time())."
Alexander Belopolsky3e62f782010-09-21 16:30:56 +00001394 t, frac = divmod(t, 1.0)
Victor Stinner5d272cc2012-03-13 13:35:55 +01001395 us = int(frac * 1e6)
Alexander Belopolsky3e62f782010-09-21 16:30:56 +00001396
1397 # If timestamp is less than one microsecond smaller than a
1398 # full second, us can be rounded up to 1000000. In this case,
1399 # roll over to seconds, otherwise, ValueError is raised
1400 # by the constructor.
1401 if us == 1000000:
1402 t += 1
1403 us = 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001404 y, m, d, hh, mm, ss, weekday, jday, dst = _time.gmtime(t)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001405 ss = min(ss, 59) # clamp out leap seconds if the platform has them
1406 return cls(y, m, d, hh, mm, ss, us)
1407
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001408 @classmethod
1409 def now(cls, tz=None):
1410 "Construct a datetime from time.time() and optional time zone info."
1411 t = _time.time()
1412 return cls.fromtimestamp(t, tz)
1413
1414 @classmethod
1415 def utcnow(cls):
1416 "Construct a UTC datetime from time.time()."
1417 t = _time.time()
1418 return cls.utcfromtimestamp(t)
1419
1420 @classmethod
1421 def combine(cls, date, time):
1422 "Construct a datetime from a given date and a given time."
1423 if not isinstance(date, _date_class):
1424 raise TypeError("date argument must be a date instance")
1425 if not isinstance(time, _time_class):
1426 raise TypeError("time argument must be a time instance")
1427 return cls(date.year, date.month, date.day,
1428 time.hour, time.minute, time.second, time.microsecond,
1429 time.tzinfo)
1430
1431 def timetuple(self):
1432 "Return local time tuple compatible with time.localtime()."
1433 dst = self.dst()
1434 if dst is None:
1435 dst = -1
1436 elif dst:
1437 dst = 1
1438 else:
1439 dst = 0
1440 return _build_struct_time(self.year, self.month, self.day,
1441 self.hour, self.minute, self.second,
1442 dst)
1443
Alexander Belopolskya4415142012-06-08 12:33:09 -04001444 def timestamp(self):
1445 "Return POSIX timestamp as float"
1446 if self._tzinfo is None:
1447 return _time.mktime((self.year, self.month, self.day,
1448 self.hour, self.minute, self.second,
1449 -1, -1, -1)) + self.microsecond / 1e6
1450 else:
1451 return (self - _EPOCH).total_seconds()
1452
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001453 def utctimetuple(self):
1454 "Return UTC time tuple compatible with time.gmtime()."
1455 offset = self.utcoffset()
1456 if offset:
1457 self -= offset
1458 y, m, d = self.year, self.month, self.day
1459 hh, mm, ss = self.hour, self.minute, self.second
1460 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1461
1462 def date(self):
1463 "Return the date part."
1464 return date(self._year, self._month, self._day)
1465
1466 def time(self):
1467 "Return the time part, with tzinfo None."
1468 return time(self.hour, self.minute, self.second, self.microsecond)
1469
1470 def timetz(self):
1471 "Return the time part, with same tzinfo."
1472 return time(self.hour, self.minute, self.second, self.microsecond,
1473 self._tzinfo)
1474
1475 def replace(self, year=None, month=None, day=None, hour=None,
1476 minute=None, second=None, microsecond=None, tzinfo=True):
1477 """Return a new datetime with new values for the specified fields."""
1478 if year is None:
1479 year = self.year
1480 if month is None:
1481 month = self.month
1482 if day is None:
1483 day = self.day
1484 if hour is None:
1485 hour = self.hour
1486 if minute is None:
1487 minute = self.minute
1488 if second is None:
1489 second = self.second
1490 if microsecond is None:
1491 microsecond = self.microsecond
1492 if tzinfo is True:
1493 tzinfo = self.tzinfo
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001494 return datetime(year, month, day, hour, minute, second, microsecond,
1495 tzinfo)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001496
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001497 def astimezone(self, tz=None):
1498 if tz is None:
1499 if self.tzinfo is None:
1500 raise ValueError("astimezone() requires an aware datetime")
1501 ts = (self - _EPOCH) // timedelta(seconds=1)
1502 localtm = _time.localtime(ts)
1503 local = datetime(*localtm[:6])
1504 try:
Alexander Belopolskyff493c92012-06-22 12:25:57 -04001505 # Extract TZ data if available
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001506 gmtoff = localtm.tm_gmtoff
1507 zone = localtm.tm_zone
1508 except AttributeError:
1509 # Compute UTC offset and compare with the value implied
1510 # by tm_isdst. If the values match, use the zone name
1511 # implied by tm_isdst.
1512 delta = local - datetime(*_time.gmtime(ts)[:6])
1513 dst = _time.daylight and localtm.tm_isdst > 0
Alexander Belopolsky93c9cd02012-06-22 16:04:19 -04001514 gmtoff = -(_time.altzone if dst else _time.timezone)
1515 if delta == timedelta(seconds=gmtoff):
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001516 tz = timezone(delta, _time.tzname[dst])
1517 else:
1518 tz = timezone(delta)
1519 else:
Alexander Belopolsky93c9cd02012-06-22 16:04:19 -04001520 tz = timezone(timedelta(seconds=gmtoff), zone)
Alexander Belopolskyff493c92012-06-22 12:25:57 -04001521
Alexander Belopolskyfdc860f2012-06-22 12:23:23 -04001522 elif not isinstance(tz, tzinfo):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001523 raise TypeError("tz argument must be an instance of tzinfo")
1524
1525 mytz = self.tzinfo
1526 if mytz is None:
1527 raise ValueError("astimezone() requires an aware datetime")
1528
1529 if tz is mytz:
1530 return self
1531
1532 # Convert self to UTC, and attach the new time zone object.
1533 myoffset = self.utcoffset()
1534 if myoffset is None:
1535 raise ValueError("astimezone() requires an aware datetime")
1536 utc = (self - myoffset).replace(tzinfo=tz)
1537
1538 # Convert from UTC to tz's local time.
1539 return tz.fromutc(utc)
1540
1541 # Ways to produce a string.
1542
1543 def ctime(self):
1544 "Return ctime() style string."
1545 weekday = self.toordinal() % 7 or 7
1546 return "%s %s %2d %02d:%02d:%02d %04d" % (
1547 _DAYNAMES[weekday],
1548 _MONTHNAMES[self._month],
1549 self._day,
1550 self._hour, self._minute, self._second,
1551 self._year)
1552
1553 def isoformat(self, sep='T'):
1554 """Return the time formatted according to ISO.
1555
1556 This is 'YYYY-MM-DD HH:MM:SS.mmmmmm', or 'YYYY-MM-DD HH:MM:SS' if
1557 self.microsecond == 0.
1558
1559 If self.tzinfo is not None, the UTC offset is also attached, giving
1560 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM' or 'YYYY-MM-DD HH:MM:SS+HH:MM'.
1561
1562 Optional argument sep specifies the separator between date and
1563 time, default 'T'.
1564 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001565 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1566 _format_time(self._hour, self._minute, self._second,
1567 self._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001568 off = self.utcoffset()
1569 if off is not None:
1570 if off.days < 0:
1571 sign = "-"
1572 off = -off
1573 else:
1574 sign = "+"
1575 hh, mm = divmod(off, timedelta(hours=1))
1576 assert not mm % timedelta(minutes=1), "whole minute"
1577 mm //= timedelta(minutes=1)
1578 s += "%s%02d:%02d" % (sign, hh, mm)
1579 return s
1580
1581 def __repr__(self):
1582 """Convert to formal string, for repr()."""
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001583 L = [self._year, self._month, self._day, # These are never zero
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001584 self._hour, self._minute, self._second, self._microsecond]
1585 if L[-1] == 0:
1586 del L[-1]
1587 if L[-1] == 0:
1588 del L[-1]
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001589 s = "%s.%s(%s)" % (self.__class__.__module__,
1590 self.__class__.__qualname__,
1591 ", ".join(map(str, L)))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001592 if self._tzinfo is not None:
1593 assert s[-1:] == ")"
1594 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
1595 return s
1596
1597 def __str__(self):
1598 "Convert to string, for str()."
1599 return self.isoformat(sep=' ')
1600
1601 @classmethod
1602 def strptime(cls, date_string, format):
1603 'string, format -> new datetime parsed from a string (like time.strptime()).'
1604 import _strptime
1605 return _strptime._strptime_datetime(cls, date_string, format)
1606
1607 def utcoffset(self):
1608 """Return the timezone offset in minutes east of UTC (negative west of
1609 UTC)."""
1610 if self._tzinfo is None:
1611 return None
1612 offset = self._tzinfo.utcoffset(self)
1613 _check_utc_offset("utcoffset", offset)
1614 return offset
1615
1616 def tzname(self):
1617 """Return the timezone name.
1618
1619 Note that the name is 100% informational -- there's no requirement that
1620 it mean anything in particular. For example, "GMT", "UTC", "-500",
1621 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1622 """
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001623 if self._tzinfo is None:
1624 return None
1625 name = self._tzinfo.tzname(self)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001626 _check_tzname(name)
1627 return name
1628
1629 def dst(self):
1630 """Return 0 if DST is not in effect, or the DST offset (in minutes
1631 eastward) if DST is in effect.
1632
1633 This is purely informational; the DST offset has already been added to
1634 the UTC offset returned by utcoffset() if applicable, so there's no
1635 need to consult dst() unless you're interested in displaying the DST
1636 info.
1637 """
1638 if self._tzinfo is None:
1639 return None
1640 offset = self._tzinfo.dst(self)
1641 _check_utc_offset("dst", offset)
1642 return offset
1643
1644 # Comparisons of datetime objects with other.
1645
1646 def __eq__(self, other):
1647 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001648 return self._cmp(other, allow_mixed=True) == 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001649 elif not isinstance(other, date):
1650 return NotImplemented
1651 else:
1652 return False
1653
1654 def __ne__(self, other):
1655 if isinstance(other, datetime):
Alexander Belopolsky08313822012-06-15 20:19:47 -04001656 return self._cmp(other, allow_mixed=True) != 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001657 elif not isinstance(other, date):
1658 return NotImplemented
1659 else:
1660 return True
1661
1662 def __le__(self, other):
1663 if isinstance(other, datetime):
1664 return self._cmp(other) <= 0
1665 elif not isinstance(other, date):
1666 return NotImplemented
1667 else:
1668 _cmperror(self, other)
1669
1670 def __lt__(self, other):
1671 if isinstance(other, datetime):
1672 return self._cmp(other) < 0
1673 elif not isinstance(other, date):
1674 return NotImplemented
1675 else:
1676 _cmperror(self, other)
1677
1678 def __ge__(self, other):
1679 if isinstance(other, datetime):
1680 return self._cmp(other) >= 0
1681 elif not isinstance(other, date):
1682 return NotImplemented
1683 else:
1684 _cmperror(self, other)
1685
1686 def __gt__(self, other):
1687 if isinstance(other, datetime):
1688 return self._cmp(other) > 0
1689 elif not isinstance(other, date):
1690 return NotImplemented
1691 else:
1692 _cmperror(self, other)
1693
Alexander Belopolsky08313822012-06-15 20:19:47 -04001694 def _cmp(self, other, allow_mixed=False):
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001695 assert isinstance(other, datetime)
1696 mytz = self._tzinfo
1697 ottz = other._tzinfo
1698 myoff = otoff = None
1699
1700 if mytz is ottz:
1701 base_compare = True
1702 else:
Alexander Belopolsky016ef552012-06-15 18:15:25 -04001703 myoff = self.utcoffset()
1704 otoff = other.utcoffset()
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001705 base_compare = myoff == otoff
1706
1707 if base_compare:
1708 return _cmp((self._year, self._month, self._day,
1709 self._hour, self._minute, self._second,
1710 self._microsecond),
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001711 (other._year, other._month, other._day,
1712 other._hour, other._minute, other._second,
1713 other._microsecond))
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001714 if myoff is None or otoff is None:
Alexander Belopolsky08313822012-06-15 20:19:47 -04001715 if allow_mixed:
1716 return 2 # arbitrary non-zero value
1717 else:
1718 raise TypeError("cannot compare naive and aware datetimes")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001719 # XXX What follows could be done more efficiently...
1720 diff = self - other # this will take offsets into account
1721 if diff.days < 0:
1722 return -1
1723 return diff and 1 or 0
1724
1725 def __add__(self, other):
1726 "Add a datetime and a timedelta."
1727 if not isinstance(other, timedelta):
1728 return NotImplemented
1729 delta = timedelta(self.toordinal(),
1730 hours=self._hour,
1731 minutes=self._minute,
1732 seconds=self._second,
1733 microseconds=self._microsecond)
1734 delta += other
1735 hour, rem = divmod(delta.seconds, 3600)
1736 minute, second = divmod(rem, 60)
1737 if 0 < delta.days <= _MAXORDINAL:
1738 return datetime.combine(date.fromordinal(delta.days),
1739 time(hour, minute, second,
1740 delta.microseconds,
1741 tzinfo=self._tzinfo))
1742 raise OverflowError("result out of range")
1743
1744 __radd__ = __add__
1745
1746 def __sub__(self, other):
1747 "Subtract two datetimes, or a datetime and a timedelta."
1748 if not isinstance(other, datetime):
1749 if isinstance(other, timedelta):
1750 return self + -other
1751 return NotImplemented
1752
1753 days1 = self.toordinal()
1754 days2 = other.toordinal()
1755 secs1 = self._second + self._minute * 60 + self._hour * 3600
1756 secs2 = other._second + other._minute * 60 + other._hour * 3600
1757 base = timedelta(days1 - days2,
1758 secs1 - secs2,
1759 self._microsecond - other._microsecond)
1760 if self._tzinfo is other._tzinfo:
1761 return base
1762 myoff = self.utcoffset()
1763 otoff = other.utcoffset()
1764 if myoff == otoff:
1765 return base
1766 if myoff is None or otoff is None:
1767 raise TypeError("cannot mix naive and timezone-aware time")
1768 return base + otoff - myoff
1769
1770 def __hash__(self):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001771 if self._hashcode == -1:
1772 tzoff = self.utcoffset()
1773 if tzoff is None:
1774 self._hashcode = hash(self._getstate()[0])
1775 else:
1776 days = _ymd2ord(self.year, self.month, self.day)
1777 seconds = self.hour * 3600 + self.minute * 60 + self.second
1778 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
1779 return self._hashcode
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001780
1781 # Pickle support.
1782
1783 def _getstate(self):
1784 yhi, ylo = divmod(self._year, 256)
1785 us2, us3 = divmod(self._microsecond, 256)
1786 us1, us2 = divmod(us2, 256)
1787 basestate = bytes([yhi, ylo, self._month, self._day,
1788 self._hour, self._minute, self._second,
1789 us1, us2, us3])
1790 if self._tzinfo is None:
1791 return (basestate,)
1792 else:
1793 return (basestate, self._tzinfo)
1794
1795 def __setstate(self, string, tzinfo):
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001796 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1797 raise TypeError("bad tzinfo state arg")
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001798 (yhi, ylo, self._month, self._day, self._hour,
1799 self._minute, self._second, us1, us2, us3) = string
1800 self._year = yhi * 256 + ylo
1801 self._microsecond = (((us1 << 8) | us2) << 8) | us3
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001802 self._tzinfo = tzinfo
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001803
1804 def __reduce__(self):
1805 return (self.__class__, self._getstate())
1806
1807
1808datetime.min = datetime(1, 1, 1)
1809datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1810datetime.resolution = timedelta(microseconds=1)
1811
1812
1813def _isoweek1monday(year):
1814 # Helper to calculate the day number of the Monday starting week 1
1815 # XXX This could be done more efficiently
1816 THURSDAY = 3
1817 firstday = _ymd2ord(year, 1, 1)
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001818 firstweekday = (firstday + 6) % 7 # See weekday() above
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001819 week1monday = firstday - firstweekday
1820 if firstweekday > THURSDAY:
1821 week1monday += 7
1822 return week1monday
1823
1824class timezone(tzinfo):
1825 __slots__ = '_offset', '_name'
1826
1827 # Sentinel value to disallow None
1828 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001829 def __new__(cls, offset, name=_Omitted):
1830 if not isinstance(offset, timedelta):
1831 raise TypeError("offset must be a timedelta")
1832 if name is cls._Omitted:
1833 if not offset:
1834 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001835 name = None
1836 elif not isinstance(name, str):
1837 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001838 if not cls._minoffset <= offset <= cls._maxoffset:
Alexander Belopolsky6c7a4182014-09-28 19:11:56 -04001839 raise ValueError("offset must be a timedelta "
1840 "strictly between -timedelta(hours=24) and "
1841 "timedelta(hours=24).")
1842 if (offset.microseconds != 0 or offset.seconds % 60 != 0):
1843 raise ValueError("offset must be a timedelta "
1844 "representing a whole number of minutes")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001845 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001846
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001847 @classmethod
1848 def _create(cls, offset, name=None):
1849 self = tzinfo.__new__(cls)
1850 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001851 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001852 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001853
1854 def __getinitargs__(self):
1855 """pickle support"""
1856 if self._name is None:
1857 return (self._offset,)
1858 return (self._offset, self._name)
1859
1860 def __eq__(self, other):
Georg Brandl0085a242012-09-22 09:23:12 +02001861 if type(other) != timezone:
1862 return False
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001863 return self._offset == other._offset
1864
1865 def __hash__(self):
1866 return hash(self._offset)
1867
1868 def __repr__(self):
1869 """Convert to formal string, for repr().
1870
1871 >>> tz = timezone.utc
1872 >>> repr(tz)
1873 'datetime.timezone.utc'
1874 >>> tz = timezone(timedelta(hours=-5), 'EST')
1875 >>> repr(tz)
1876 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
1877 """
1878 if self is self.utc:
1879 return 'datetime.timezone.utc'
1880 if self._name is None:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001881 return "%s.%s(%r)" % (self.__class__.__module__,
1882 self.__class__.__qualname__,
1883 self._offset)
1884 return "%s.%s(%r, %r)" % (self.__class__.__module__,
1885 self.__class__.__qualname__,
1886 self._offset, self._name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001887
1888 def __str__(self):
1889 return self.tzname(None)
1890
1891 def utcoffset(self, dt):
1892 if isinstance(dt, datetime) or dt is None:
1893 return self._offset
1894 raise TypeError("utcoffset() argument must be a datetime instance"
1895 " or None")
1896
1897 def tzname(self, dt):
1898 if isinstance(dt, datetime) or dt is None:
1899 if self._name is None:
1900 return self._name_from_offset(self._offset)
1901 return self._name
1902 raise TypeError("tzname() argument must be a datetime instance"
1903 " or None")
1904
1905 def dst(self, dt):
1906 if isinstance(dt, datetime) or dt is None:
1907 return None
1908 raise TypeError("dst() argument must be a datetime instance"
1909 " or None")
1910
1911 def fromutc(self, dt):
1912 if isinstance(dt, datetime):
1913 if dt.tzinfo is not self:
1914 raise ValueError("fromutc: dt.tzinfo "
1915 "is not self")
1916 return dt + self._offset
1917 raise TypeError("fromutc() argument must be a datetime instance"
1918 " or None")
1919
1920 _maxoffset = timedelta(hours=23, minutes=59)
1921 _minoffset = -_maxoffset
1922
1923 @staticmethod
1924 def _name_from_offset(delta):
1925 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__