blob: 23ded3ec7e1c20a1386faa6f32c1bdfea9132f7c [file] [log] [blame]
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001"""Concrete date/time and related types -- prototype implemented in Python.
2
3See http://www.zope.org/Members/fdrake/DateTimeWiki/FrontPage
4
5See also http://dir.yahoo.com/Reference/calendars/
6
7For a primer on DST, including many current DST rules, see
8http://webexhibits.org/daylightsaving/
9
10For more about DST than you ever wanted to know, see
11ftp://elsie.nci.nih.gov/pub/
12
13Sources for time zone and DST data: http://www.twinsun.com/tz/tz-link.htm
14
15This was originally copied from the sandbox of the CPython CVS repository.
16Thanks to Tim Peters for suggesting using it.
17"""
18
19import time as _time
20import math as _math
21
22def _cmp(x, y):
23 return 0 if x == y else 1 if x > y else -1
24
25MINYEAR = 1
26MAXYEAR = 9999
27_MAXORDINAL = 3652059 # date.max.toordinal()
28
29# Utility functions, adapted from Python's Demo/classes/Dates.py, which
30# also assumes the current Gregorian calendar indefinitely extended in
31# both directions. Difference: Dates.py calls January 1 of year 0 day
32# number 1. The code here calls January 1 of year 1 day number 1. This is
33# to match the definition of the "proleptic Gregorian" calendar in Dershowitz
34# and Reingold's "Calendrical Calculations", where it's the base calendar
35# for all computations. See the book for algorithms for converting between
36# proleptic Gregorian ordinals and many other calendar systems.
37
38_DAYS_IN_MONTH = [None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
39
40_DAYS_BEFORE_MONTH = [None]
41dbm = 0
42for dim in _DAYS_IN_MONTH[1:]:
43 _DAYS_BEFORE_MONTH.append(dbm)
44 dbm += dim
45del dbm, dim
46
47def _is_leap(year):
48 "year -> 1 if leap year, else 0."
49 return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
50
51def _days_before_year(year):
52 "year -> number of days before January 1st of year."
53 y = year - 1
54 return y*365 + y//4 - y//100 + y//400
55
56def _days_in_month(year, month):
57 "year, month -> number of days in that month in that year."
58 assert 1 <= month <= 12, month
59 if month == 2 and _is_leap(year):
60 return 29
61 return _DAYS_IN_MONTH[month]
62
63def _days_before_month(year, month):
64 "year, month -> number of days in year preceeding first day of month."
65 assert 1 <= month <= 12, 'month must be in 1..12'
66 return _DAYS_BEFORE_MONTH[month] + (month > 2 and _is_leap(year))
67
68def _ymd2ord(year, month, day):
69 "year, month, day -> ordinal, considering 01-Jan-0001 as day 1."
70 assert 1 <= month <= 12, 'month must be in 1..12'
71 dim = _days_in_month(year, month)
72 assert 1 <= day <= dim, ('day must be in 1..%d' % dim)
73 return (_days_before_year(year) +
74 _days_before_month(year, month) +
75 day)
76
77_DI400Y = _days_before_year(401) # number of days in 400 years
78_DI100Y = _days_before_year(101) # " " " " 100 "
79_DI4Y = _days_before_year(5) # " " " " 4 "
80
81# A 4-year cycle has an extra leap day over what we'd get from pasting
82# together 4 single years.
83assert _DI4Y == 4 * 365 + 1
84
85# Similarly, a 400-year cycle has an extra leap day over what we'd get from
86# pasting together 4 100-year cycles.
87assert _DI400Y == 4 * _DI100Y + 1
88
89# OTOH, a 100-year cycle has one fewer leap day than we'd get from
90# pasting together 25 4-year cycles.
91assert _DI100Y == 25 * _DI4Y - 1
92
93def _ord2ymd(n):
94 "ordinal -> (year, month, day), considering 01-Jan-0001 as day 1."
95
96 # n is a 1-based index, starting at 1-Jan-1. The pattern of leap years
97 # repeats exactly every 400 years. The basic strategy is to find the
98 # closest 400-year boundary at or before n, then work with the offset
99 # from that boundary to n. Life is much clearer if we subtract 1 from
100 # n first -- then the values of n at 400-year boundaries are exactly
101 # those divisible by _DI400Y:
102 #
103 # D M Y n n-1
104 # -- --- ---- ---------- ----------------
105 # 31 Dec -400 -_DI400Y -_DI400Y -1
106 # 1 Jan -399 -_DI400Y +1 -_DI400Y 400-year boundary
107 # ...
108 # 30 Dec 000 -1 -2
109 # 31 Dec 000 0 -1
110 # 1 Jan 001 1 0 400-year boundary
111 # 2 Jan 001 2 1
112 # 3 Jan 001 3 2
113 # ...
114 # 31 Dec 400 _DI400Y _DI400Y -1
115 # 1 Jan 401 _DI400Y +1 _DI400Y 400-year boundary
116 n -= 1
117 n400, n = divmod(n, _DI400Y)
118 year = n400 * 400 + 1 # ..., -399, 1, 401, ...
119
120 # Now n is the (non-negative) offset, in days, from January 1 of year, to
121 # the desired date. Now compute how many 100-year cycles precede n.
122 # Note that it's possible for n100 to equal 4! In that case 4 full
123 # 100-year cycles precede the desired day, which implies the desired
124 # day is December 31 at the end of a 400-year cycle.
125 n100, n = divmod(n, _DI100Y)
126
127 # Now compute how many 4-year cycles precede it.
128 n4, n = divmod(n, _DI4Y)
129
130 # And now how many single years. Again n1 can be 4, and again meaning
131 # that the desired day is December 31 at the end of the 4-year cycle.
132 n1, n = divmod(n, 365)
133
134 year += n100 * 100 + n4 * 4 + n1
135 if n1 == 4 or n100 == 4:
136 assert n == 0
137 return year-1, 12, 31
138
139 # Now the year is correct, and n is the offset from January 1. We find
140 # the month via an estimate that's either exact or one too large.
141 leapyear = n1 == 3 and (n4 != 24 or n100 == 3)
142 assert leapyear == _is_leap(year)
143 month = (n + 50) >> 5
144 preceding = _DAYS_BEFORE_MONTH[month] + (month > 2 and leapyear)
145 if preceding > n: # estimate is too large
146 month -= 1
147 preceding -= _DAYS_IN_MONTH[month] + (month == 2 and leapyear)
148 n -= preceding
149 assert 0 <= n < _days_in_month(year, month)
150
151 # Now the year and month are correct, and n is the offset from the
152 # start of that month: we're done!
153 return year, month, n+1
154
155# Month and day names. For localized versions, see the calendar module.
156_MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
157 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
158_DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
159
160
161def _build_struct_time(y, m, d, hh, mm, ss, dstflag):
162 wday = (_ymd2ord(y, m, d) + 6) % 7
163 dnum = _days_before_month(y, m) + d
164 return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag))
165
166def _format_time(hh, mm, ss, us):
167 # Skip trailing microseconds when us==0.
168 result = "%02d:%02d:%02d" % (hh, mm, ss)
169 if us:
170 result += ".%06d" % us
171 return result
172
173# Correctly substitute for %z and %Z escapes in strftime formats.
174def _wrap_strftime(object, format, timetuple):
175 year = timetuple[0]
176 if year < 1900:
177 raise ValueError("year=%d is before 1900; the datetime strftime() "
178 "methods require year >= 1900" % year)
179 # Don't call utcoffset() or tzname() unless actually needed.
180 freplace = None # the string to use for %f
181 zreplace = None # the string to use for %z
182 Zreplace = None # the string to use for %Z
183
184 # Scan format for %z and %Z escapes, replacing as needed.
185 newformat = []
186 push = newformat.append
187 i, n = 0, len(format)
188 while i < n:
189 ch = format[i]
190 i += 1
191 if ch == '%':
192 if i < n:
193 ch = format[i]
194 i += 1
195 if ch == 'f':
196 if freplace is None:
197 freplace = '%06d' % getattr(object,
198 'microsecond', 0)
199 newformat.append(freplace)
200 elif ch == 'z':
201 if zreplace is None:
202 zreplace = ""
203 if hasattr(object, "utcoffset"):
204 offset = object.utcoffset()
205 if offset is not None:
206 sign = '+'
207 if offset.days < 0:
208 offset = -offset
209 sign = '-'
210 h, m = divmod(offset, timedelta(hours=1))
211 assert not m % timedelta(minutes=1), "whole minute"
212 m //= timedelta(minutes=1)
213 zreplace = '%c%02d%02d' % (sign, h, m)
214 assert '%' not in zreplace
215 newformat.append(zreplace)
216 elif ch == 'Z':
217 if Zreplace is None:
218 Zreplace = ""
219 if hasattr(object, "tzname"):
220 s = object.tzname()
221 if s is not None:
222 # strftime is going to have at this: escape %
223 Zreplace = s.replace('%', '%%')
224 newformat.append(Zreplace)
225 else:
226 push('%')
227 push(ch)
228 else:
229 push('%')
230 else:
231 push(ch)
232 newformat = "".join(newformat)
233 return _time.strftime(newformat, timetuple)
234
235def _call_tzinfo_method(tzinfo, methname, tzinfoarg):
236 if tzinfo is None:
237 return None
238 return getattr(tzinfo, methname)(tzinfoarg)
239
240# Just raise TypeError if the arg isn't None or a string.
241def _check_tzname(name):
242 if name is not None and not isinstance(name, str):
243 raise TypeError("tzinfo.tzname() must return None or string, "
244 "not '%s'" % type(name))
245
246# name is the offset-producing method, "utcoffset" or "dst".
247# offset is what it returned.
248# If offset isn't None or timedelta, raises TypeError.
249# If offset is None, returns None.
250# Else offset is checked for being in range, and a whole # of minutes.
251# If it is, its integer value is returned. Else ValueError is raised.
252def _check_utc_offset(name, offset):
253 assert name in ("utcoffset", "dst")
254 if offset is None:
255 return
256 if not isinstance(offset, timedelta):
257 raise TypeError("tzinfo.%s() must return None "
258 "or timedelta, not '%s'" % (name, type(offset)))
259 if offset % timedelta(minutes=1) or offset.microseconds:
260 raise ValueError("tzinfo.%s() must return a whole number "
261 "of minutes, got %s" % (name, offset))
262 if not -timedelta(1) < offset < timedelta(1):
263 raise ValueError("%s()=%s, must be must be strictly between"
264 " -timedelta(hours=24) and timedelta(hours=24)"
265 % (name, offset))
266
267def _check_date_fields(year, month, day):
268 if not isinstance(year, int):
269 raise TypeError('int expected')
270 if not MINYEAR <= year <= MAXYEAR:
271 raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year)
272 if not 1 <= month <= 12:
273 raise ValueError('month must be in 1..12', month)
274 dim = _days_in_month(year, month)
275 if not 1 <= day <= dim:
276 raise ValueError('day must be in 1..%d' % dim, day)
277
278def _check_time_fields(hour, minute, second, microsecond):
279 if not isinstance(hour, int):
280 raise TypeError('int expected')
281 if not 0 <= hour <= 23:
282 raise ValueError('hour must be in 0..23', hour)
283 if not 0 <= minute <= 59:
284 raise ValueError('minute must be in 0..59', minute)
285 if not 0 <= second <= 59:
286 raise ValueError('second must be in 0..59', second)
287 if not 0 <= microsecond <= 999999:
288 raise ValueError('microsecond must be in 0..999999', microsecond)
289
290def _check_tzinfo_arg(tz):
291 if tz is not None and not isinstance(tz, tzinfo):
292 raise TypeError("tzinfo argument must be None or of a tzinfo subclass")
293
294def _cmperror(x, y):
295 raise TypeError("can't compare '%s' to '%s'" % (
296 type(x).__name__, type(y).__name__))
297
298class timedelta:
299 """Represent the difference between two datetime objects.
300
301 Supported operators:
302
303 - add, subtract timedelta
304 - unary plus, minus, abs
305 - compare to timedelta
306 - multiply, divide by int/long
307
308 In addition, datetime supports subtraction of two datetime objects
309 returning a timedelta, and addition or subtraction of a datetime
310 and a timedelta giving a datetime.
311
312 Representation: (days, seconds, microseconds). Why? Because I
313 felt like it.
314 """
315 __slots__ = '_days', '_seconds', '_microseconds'
316
317 def __new__(cls, days=0, seconds=0, microseconds=0,
318 milliseconds=0, minutes=0, hours=0, weeks=0):
319 # Doing this efficiently and accurately in C is going to be difficult
320 # and error-prone, due to ubiquitous overflow possibilities, and that
321 # C double doesn't have enough bits of precision to represent
322 # microseconds over 10K years faithfully. The code here tries to make
323 # explicit where go-fast assumptions can be relied on, in order to
324 # guide the C implementation; it's way more convoluted than speed-
325 # ignoring auto-overflow-to-long idiomatic Python could be.
326
327 # XXX Check that all inputs are ints or floats.
328
329 # Final values, all integer.
330 # s and us fit in 32-bit signed ints; d isn't bounded.
331 d = s = us = 0
332
333 # Normalize everything to days, seconds, microseconds.
334 days += weeks*7
335 seconds += minutes*60 + hours*3600
336 microseconds += milliseconds*1000
337
338 # Get rid of all fractions, and normalize s and us.
339 # Take a deep breath <wink>.
340 if isinstance(days, float):
341 dayfrac, days = _math.modf(days)
342 daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
343 assert daysecondswhole == int(daysecondswhole) # can't overflow
344 s = int(daysecondswhole)
345 assert days == int(days)
346 d = int(days)
347 else:
348 daysecondsfrac = 0.0
349 d = days
350 assert isinstance(daysecondsfrac, float)
351 assert abs(daysecondsfrac) <= 1.0
352 assert isinstance(d, int)
353 assert abs(s) <= 24 * 3600
354 # days isn't referenced again before redefinition
355
356 if isinstance(seconds, float):
357 secondsfrac, seconds = _math.modf(seconds)
358 assert seconds == int(seconds)
359 seconds = int(seconds)
360 secondsfrac += daysecondsfrac
361 assert abs(secondsfrac) <= 2.0
362 else:
363 secondsfrac = daysecondsfrac
364 # daysecondsfrac isn't referenced again
365 assert isinstance(secondsfrac, float)
366 assert abs(secondsfrac) <= 2.0
367
368 assert isinstance(seconds, int)
369 days, seconds = divmod(seconds, 24*3600)
370 d += days
371 s += int(seconds) # can't overflow
372 assert isinstance(s, int)
373 assert abs(s) <= 2 * 24 * 3600
374 # seconds isn't referenced again before redefinition
375
376 usdouble = secondsfrac * 1e6
377 assert abs(usdouble) < 2.1e6 # exact value not critical
378 # secondsfrac isn't referenced again
379
380 if isinstance(microseconds, float):
381 microseconds += usdouble
382 microseconds = round(microseconds, 0)
383 seconds, microseconds = divmod(microseconds, 1e6)
384 assert microseconds == int(microseconds)
385 assert seconds == int(seconds)
386 days, seconds = divmod(seconds, 24.*3600.)
387 assert days == int(days)
388 assert seconds == int(seconds)
389 d += int(days)
390 s += int(seconds) # can't overflow
391 assert isinstance(s, int)
392 assert abs(s) <= 3 * 24 * 3600
393 else:
394 seconds, microseconds = divmod(microseconds, 1000000)
395 days, seconds = divmod(seconds, 24*3600)
396 d += days
397 s += int(seconds) # can't overflow
398 assert isinstance(s, int)
399 assert abs(s) <= 3 * 24 * 3600
400 microseconds = float(microseconds)
401 microseconds += usdouble
402 microseconds = round(microseconds, 0)
403 assert abs(s) <= 3 * 24 * 3600
404 assert abs(microseconds) < 3.1e6
405
406 # Just a little bit of carrying possible for microseconds and seconds.
407 assert isinstance(microseconds, float)
408 assert int(microseconds) == microseconds
409 us = int(microseconds)
410 seconds, us = divmod(us, 1000000)
411 s += seconds # cant't overflow
412 assert isinstance(s, int)
413 days, s = divmod(s, 24*3600)
414 d += days
415
416 assert isinstance(d, int)
417 assert isinstance(s, int) and 0 <= s < 24*3600
418 assert isinstance(us, int) and 0 <= us < 1000000
419
420 self = object.__new__(cls)
421
422 self._days = d
423 self._seconds = s
424 self._microseconds = us
425 if abs(d) > 999999999:
426 raise OverflowError("timedelta # of days is too large: %d" % d)
427
428 return self
429
430 def __repr__(self):
431 if self._microseconds:
432 return "%s(%d, %d, %d)" % ('datetime.' + self.__class__.__name__,
433 self._days,
434 self._seconds,
435 self._microseconds)
436 if self._seconds:
437 return "%s(%d, %d)" % ('datetime.' + self.__class__.__name__,
438 self._days,
439 self._seconds)
440 return "%s(%d)" % ('datetime.' + self.__class__.__name__, self._days)
441
442 def __str__(self):
443 mm, ss = divmod(self._seconds, 60)
444 hh, mm = divmod(mm, 60)
445 s = "%d:%02d:%02d" % (hh, mm, ss)
446 if self._days:
447 def plural(n):
448 return n, abs(n) != 1 and "s" or ""
449 s = ("%d day%s, " % plural(self._days)) + s
450 if self._microseconds:
451 s = s + ".%06d" % self._microseconds
452 return s
453
454 def total_seconds(self):
455 """Total seconds in the duration."""
456 return ((self.days * 86400 + self.seconds)*10**6 +
457 self.microseconds) / 10**6
458
459 # Read-only field accessors
460 @property
461 def days(self):
462 """days"""
463 return self._days
464
465 @property
466 def seconds(self):
467 """seconds"""
468 return self._seconds
469
470 @property
471 def microseconds(self):
472 """microseconds"""
473 return self._microseconds
474
475 def __add__(self, other):
476 if isinstance(other, timedelta):
477 # for CPython compatibility, we cannot use
478 # our __class__ here, but need a real timedelta
479 return timedelta(self._days + other._days,
480 self._seconds + other._seconds,
481 self._microseconds + other._microseconds)
482 return NotImplemented
483
484 __radd__ = __add__
485
486 def __sub__(self, other):
487 if isinstance(other, timedelta):
488 return self + -other
489 return NotImplemented
490
491 def __rsub__(self, other):
492 if isinstance(other, timedelta):
493 return -self + other
494 return NotImplemented
495
496 def __neg__(self):
497 # for CPython compatibility, we cannot use
498 # our __class__ here, but need a real timedelta
499 return timedelta(-self._days,
500 -self._seconds,
501 -self._microseconds)
502
503 def __pos__(self):
504 return self
505
506 def __abs__(self):
507 if self._days < 0:
508 return -self
509 else:
510 return self
511
512 def __mul__(self, other):
513 if isinstance(other, int):
514 # for CPython compatibility, we cannot use
515 # our __class__ here, but need a real timedelta
516 return timedelta(self._days * other,
517 self._seconds * other,
518 self._microseconds * other)
519 if isinstance(other, float):
520 a, b = other.as_integer_ratio()
521 return self * a / b
522 return NotImplemented
523
524 __rmul__ = __mul__
525
526 def _to_microseconds(self):
527 return ((self._days * (24*3600) + self._seconds) * 1000000 +
528 self._microseconds)
529
530 def __floordiv__(self, other):
531 if not isinstance(other, (int, timedelta)):
532 return NotImplemented
533 usec = self._to_microseconds()
534 if isinstance(other, timedelta):
535 return usec // other._to_microseconds()
536 if isinstance(other, int):
537 return timedelta(0, 0, usec // other)
538
539 def __truediv__(self, other):
540 if not isinstance(other, (int, float, timedelta)):
541 return NotImplemented
542 usec = self._to_microseconds()
543 if isinstance(other, timedelta):
544 return usec / other._to_microseconds()
545 if isinstance(other, int):
546 return timedelta(0, 0, usec / other)
547 if isinstance(other, float):
548 a, b = other.as_integer_ratio()
549 return timedelta(0, 0, b * usec / a)
550
551 def __mod__(self, other):
552 if isinstance(other, timedelta):
553 r = self._to_microseconds() % other._to_microseconds()
554 return timedelta(0, 0, r)
555 return NotImplemented
556
557 def __divmod__(self, other):
558 if isinstance(other, timedelta):
559 q, r = divmod(self._to_microseconds(),
560 other._to_microseconds())
561 return q, timedelta(0, 0, r)
562 return NotImplemented
563
564 # Comparisons of timedelta objects with other.
565
566 def __eq__(self, other):
567 if isinstance(other, timedelta):
568 return self._cmp(other) == 0
569 else:
570 return False
571
572 def __ne__(self, other):
573 if isinstance(other, timedelta):
574 return self._cmp(other) != 0
575 else:
576 return True
577
578 def __le__(self, other):
579 if isinstance(other, timedelta):
580 return self._cmp(other) <= 0
581 else:
582 _cmperror(self, other)
583
584 def __lt__(self, other):
585 if isinstance(other, timedelta):
586 return self._cmp(other) < 0
587 else:
588 _cmperror(self, other)
589
590 def __ge__(self, other):
591 if isinstance(other, timedelta):
592 return self._cmp(other) >= 0
593 else:
594 _cmperror(self, other)
595
596 def __gt__(self, other):
597 if isinstance(other, timedelta):
598 return self._cmp(other) > 0
599 else:
600 _cmperror(self, other)
601
602 def _cmp(self, other):
603 assert isinstance(other, timedelta)
604 return _cmp(self._getstate(), other._getstate())
605
606 def __hash__(self):
607 return hash(self._getstate())
608
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 """
655 __slots__ = '_year', '_month', '_day'
656
657 def __new__(cls, year, month=None, day=None):
658 """Constructor.
659
660 Arguments:
661
662 year, month, day (required, base 1)
663 """
664 if (isinstance(year, bytes) and len(year) == 4 and
665 1 <= year[2] <= 12 and month is None): # Month is sane
666 # Pickle support
667 self = object.__new__(cls)
668 self.__setstate(year)
669 return self
670 _check_date_fields(year, month, day)
671 self = object.__new__(cls)
672 self._year = year
673 self._month = month
674 self._day = day
675 return self
676
677 # Additional constructors
678
679 @classmethod
680 def fromtimestamp(cls, t):
681 "Construct a date from a POSIX timestamp (like time.time())."
682 y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
683 return cls(y, m, d)
684
685 @classmethod
686 def today(cls):
687 "Construct a date from time.time()."
688 t = _time.time()
689 return cls.fromtimestamp(t)
690
691 @classmethod
692 def fromordinal(cls, n):
693 """Contruct a date from a proleptic Gregorian ordinal.
694
695 January 1 of year 1 is day 1. Only the year, month and day are
696 non-zero in the result.
697 """
698 y, m, d = _ord2ymd(n)
699 return cls(y, m, d)
700
701 # Conversions to string
702
703 def __repr__(self):
704 """Convert to formal string, for repr().
705
706 >>> dt = datetime(2010, 1, 1)
707 >>> repr(dt)
708 'datetime.datetime(2010, 1, 1, 0, 0)'
709
710 >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
711 >>> repr(dt)
712 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
713 """
714 return "%s(%d, %d, %d)" % ('datetime.' + self.__class__.__name__,
715 self._year,
716 self._month,
717 self._day)
718 # XXX These shouldn't depend on time.localtime(), because that
719 # clips the usable dates to [1970 .. 2038). At least ctime() is
720 # easily done without using strftime() -- that's better too because
721 # strftime("%c", ...) is locale specific.
722
723
724 def ctime(self):
725 "Return ctime() style string."
726 weekday = self.toordinal() % 7 or 7
727 return "%s %s %2d 00:00:00 %04d" % (
728 _DAYNAMES[weekday],
729 _MONTHNAMES[self._month],
730 self._day, self._year)
731
732 def strftime(self, fmt):
733 "Format using strftime()."
734 return _wrap_strftime(self, fmt, self.timetuple())
735
736 def __format__(self, fmt):
737 if len(fmt) != 0:
738 return self.strftime(fmt)
739 return str(self)
740
741 def isoformat(self):
742 """Return the date formatted according to ISO.
743
744 This is 'YYYY-MM-DD'.
745
746 References:
747 - http://www.w3.org/TR/NOTE-datetime
748 - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
749 """
750 return "%04d-%02d-%02d" % (self._year, self._month, self._day)
751
752 __str__ = isoformat
753
754 # Read-only field accessors
755 @property
756 def year(self):
757 """year (1-9999)"""
758 return self._year
759
760 @property
761 def month(self):
762 """month (1-12)"""
763 return self._month
764
765 @property
766 def day(self):
767 """day (1-31)"""
768 return self._day
769
770 # Standard conversions, __cmp__, __hash__ (and helpers)
771
772 def timetuple(self):
773 "Return local time tuple compatible with time.localtime()."
774 return _build_struct_time(self._year, self._month, self._day,
775 0, 0, 0, -1)
776
777 def toordinal(self):
778 """Return proleptic Gregorian ordinal for the year, month and day.
779
780 January 1 of year 1 is day 1. Only the year, month and day values
781 contribute to the result.
782 """
783 return _ymd2ord(self._year, self._month, self._day)
784
785 def replace(self, year=None, month=None, day=None):
786 """Return a new date with new values for the specified fields."""
787 if year is None:
788 year = self._year
789 if month is None:
790 month = self._month
791 if day is None:
792 day = self._day
793 _check_date_fields(year, month, day)
794 return date(year, month, day)
795
796 # Comparisons of date objects with other.
797
798 def __eq__(self, other):
799 if isinstance(other, date):
800 return self._cmp(other) == 0
801 return NotImplemented
802
803 def __ne__(self, other):
804 if isinstance(other, date):
805 return self._cmp(other) != 0
806 return NotImplemented
807
808 def __le__(self, other):
809 if isinstance(other, date):
810 return self._cmp(other) <= 0
811 return NotImplemented
812
813 def __lt__(self, other):
814 if isinstance(other, date):
815 return self._cmp(other) < 0
816 return NotImplemented
817
818 def __ge__(self, other):
819 if isinstance(other, date):
820 return self._cmp(other) >= 0
821 return NotImplemented
822
823 def __gt__(self, other):
824 if isinstance(other, date):
825 return self._cmp(other) > 0
826 return NotImplemented
827
828 def _cmp(self, other):
829 assert isinstance(other, date)
830 y, m, d = self._year, self._month, self._day
831 y2, m2, d2 = other._year, other._month, other._day
832 return _cmp((y, m, d), (y2, m2, d2))
833
834 def __hash__(self):
835 "Hash."
836 return hash(self._getstate())
837
838 # Computations
839
840 def __add__(self, other):
841 "Add a date to a timedelta."
842 if isinstance(other, timedelta):
843 o = self.toordinal() + other.days
844 if 0 < o <= _MAXORDINAL:
845 return date.fromordinal(o)
846 raise OverflowError("result out of range")
847 return NotImplemented
848
849 __radd__ = __add__
850
851 def __sub__(self, other):
852 """Subtract two dates, or a date and a timedelta."""
853 if isinstance(other, timedelta):
854 return self + timedelta(-other.days)
855 if isinstance(other, date):
856 days1 = self.toordinal()
857 days2 = other.toordinal()
858 return timedelta(days1 - days2)
859 return NotImplemented
860
861 def weekday(self):
862 "Return day of the week, where Monday == 0 ... Sunday == 6."
863 return (self.toordinal() + 6) % 7
864
865 # Day-of-the-week and week-of-the-year, according to ISO
866
867 def isoweekday(self):
868 "Return day of the week, where Monday == 1 ... Sunday == 7."
869 # 1-Jan-0001 is a Monday
870 return self.toordinal() % 7 or 7
871
872 def isocalendar(self):
873 """Return a 3-tuple containing ISO year, week number, and weekday.
874
875 The first ISO week of the year is the (Mon-Sun) week
876 containing the year's first Thursday; everything else derives
877 from that.
878
879 The first week is 1; Monday is 1 ... Sunday is 7.
880
881 ISO calendar algorithm taken from
882 http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
883 """
884 year = self._year
885 week1monday = _isoweek1monday(year)
886 today = _ymd2ord(self._year, self._month, self._day)
887 # Internally, week and day have origin 0
888 week, day = divmod(today - week1monday, 7)
889 if week < 0:
890 year -= 1
891 week1monday = _isoweek1monday(year)
892 week, day = divmod(today - week1monday, 7)
893 elif week >= 52:
894 if today >= _isoweek1monday(year+1):
895 year += 1
896 week = 0
897 return year, week+1, day+1
898
899 # Pickle support.
900
901 def _getstate(self):
902 yhi, ylo = divmod(self._year, 256)
903 return bytes([yhi, ylo, self._month, self._day]),
904
905 def __setstate(self, string):
906 if len(string) != 4 or not (1 <= string[2] <= 12):
907 raise TypeError("not enough arguments")
908 yhi, ylo, self._month, self._day = string
909 self._year = yhi * 256 + ylo
910
911 def __reduce__(self):
912 return (self.__class__, self._getstate())
913
914_date_class = date # so functions w/ args named "date" can get at the class
915
916date.min = date(1, 1, 1)
917date.max = date(9999, 12, 31)
918date.resolution = timedelta(days=1)
919
920class tzinfo:
921 """Abstract base class for time zone info classes.
922
923 Subclasses must override the name(), utcoffset() and dst() methods.
924 """
925 __slots__ = ()
926 def tzname(self, dt):
927 "datetime -> string name of time zone."
928 raise NotImplementedError("tzinfo subclass must override tzname()")
929
930 def utcoffset(self, dt):
931 "datetime -> minutes east of UTC (negative for west of UTC)"
932 raise NotImplementedError("tzinfo subclass must override utcoffset()")
933
934 def dst(self, dt):
935 """datetime -> DST offset in minutes east of UTC.
936
937 Return 0 if DST not in effect. utcoffset() must include the DST
938 offset.
939 """
940 raise NotImplementedError("tzinfo subclass must override dst()")
941
942 def fromutc(self, dt):
943 "datetime in UTC -> datetime in local time."
944
945 if not isinstance(dt, datetime):
946 raise TypeError("fromutc() requires a datetime argument")
947 if dt.tzinfo is not self:
948 raise ValueError("dt.tzinfo is not self")
949
950 dtoff = dt.utcoffset()
951 if dtoff is None:
952 raise ValueError("fromutc() requires a non-None utcoffset() "
953 "result")
954
955 # See the long comment block at the end of this file for an
956 # explanation of this algorithm.
957 dtdst = dt.dst()
958 if dtdst is None:
959 raise ValueError("fromutc() requires a non-None dst() result")
960 delta = dtoff - dtdst
961 if delta:
962 dt += delta
963 dtdst = dt.dst()
964 if dtdst is None:
965 raise ValueError("fromutc(): dt.dst gave inconsistent "
966 "results; cannot convert")
967 return dt + dtdst
968
969 # Pickle support.
970
971 def __reduce__(self):
972 getinitargs = getattr(self, "__getinitargs__", None)
973 if getinitargs:
974 args = getinitargs()
975 else:
976 args = ()
977 getstate = getattr(self, "__getstate__", None)
978 if getstate:
979 state = getstate()
980 else:
981 state = getattr(self, "__dict__", None) or None
982 if state is None:
983 return (self.__class__, args)
984 else:
985 return (self.__class__, args, state)
986
987_tzinfo_class = tzinfo
988
989class time:
990 """Time with time zone.
991
992 Constructors:
993
994 __new__()
995
996 Operators:
997
998 __repr__, __str__
999 __cmp__, __hash__
1000
1001 Methods:
1002
1003 strftime()
1004 isoformat()
1005 utcoffset()
1006 tzname()
1007 dst()
1008
1009 Properties (readonly):
1010 hour, minute, second, microsecond, tzinfo
1011 """
1012
1013 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None):
1014 """Constructor.
1015
1016 Arguments:
1017
1018 hour, minute (required)
1019 second, microsecond (default to zero)
1020 tzinfo (default to None)
1021 """
1022 self = object.__new__(cls)
1023 if isinstance(hour, bytes) and len(hour) == 6:
1024 # Pickle support
1025 self.__setstate(hour, minute or None)
1026 return self
1027 _check_tzinfo_arg(tzinfo)
1028 _check_time_fields(hour, minute, second, microsecond)
1029 self._hour = hour
1030 self._minute = minute
1031 self._second = second
1032 self._microsecond = microsecond
1033 self._tzinfo = tzinfo
1034 return self
1035
1036 # Read-only field accessors
1037 @property
1038 def hour(self):
1039 """hour (0-23)"""
1040 return self._hour
1041
1042 @property
1043 def minute(self):
1044 """minute (0-59)"""
1045 return self._minute
1046
1047 @property
1048 def second(self):
1049 """second (0-59)"""
1050 return self._second
1051
1052 @property
1053 def microsecond(self):
1054 """microsecond (0-999999)"""
1055 return self._microsecond
1056
1057 @property
1058 def tzinfo(self):
1059 """timezone info object"""
1060 return self._tzinfo
1061
1062 # Standard conversions, __hash__ (and helpers)
1063
1064 # Comparisons of time objects with other.
1065
1066 def __eq__(self, other):
1067 if isinstance(other, time):
1068 return self._cmp(other) == 0
1069 else:
1070 return False
1071
1072 def __ne__(self, other):
1073 if isinstance(other, time):
1074 return self._cmp(other) != 0
1075 else:
1076 return True
1077
1078 def __le__(self, other):
1079 if isinstance(other, time):
1080 return self._cmp(other) <= 0
1081 else:
1082 _cmperror(self, other)
1083
1084 def __lt__(self, other):
1085 if isinstance(other, time):
1086 return self._cmp(other) < 0
1087 else:
1088 _cmperror(self, other)
1089
1090 def __ge__(self, other):
1091 if isinstance(other, time):
1092 return self._cmp(other) >= 0
1093 else:
1094 _cmperror(self, other)
1095
1096 def __gt__(self, other):
1097 if isinstance(other, time):
1098 return self._cmp(other) > 0
1099 else:
1100 _cmperror(self, other)
1101
1102 def _cmp(self, other):
1103 assert isinstance(other, time)
1104 mytz = self._tzinfo
1105 ottz = other._tzinfo
1106 myoff = otoff = None
1107
1108 if mytz is ottz:
1109 base_compare = True
1110 else:
1111 myoff = self.utcoffset()
1112 otoff = other.utcoffset()
1113 base_compare = myoff == otoff
1114
1115 if base_compare:
1116 return _cmp((self._hour, self._minute, self._second,
1117 self._microsecond),
1118 (other._hour, other._minute, other._second,
1119 other._microsecond))
1120 if myoff is None or otoff is None:
1121 raise TypeError("cannot compare naive and aware times")
1122 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1123 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1124 return _cmp((myhhmm, self._second, self._microsecond),
1125 (othhmm, other._second, other._microsecond))
1126
1127 def __hash__(self):
1128 """Hash."""
1129 tzoff = self.utcoffset()
1130 if not tzoff: # zero or None
1131 return hash(self._getstate()[0])
1132 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1133 timedelta(hours=1))
1134 assert not m % timedelta(minutes=1), "whole minute"
1135 m //= timedelta(minutes=1)
1136 if 0 <= h < 24:
1137 return hash(time(h, m, self.second, self.microsecond))
1138 return hash((h, m, self.second, self.microsecond))
1139
1140 # Conversion to string
1141
1142 def _tzstr(self, sep=":"):
1143 """Return formatted timezone offset (+xx:xx) or None."""
1144 off = self.utcoffset()
1145 if off is not None:
1146 if off.days < 0:
1147 sign = "-"
1148 off = -off
1149 else:
1150 sign = "+"
1151 hh, mm = divmod(off, timedelta(hours=1))
1152 assert not mm % timedelta(minutes=1), "whole minute"
1153 mm //= timedelta(minutes=1)
1154 assert 0 <= hh < 24
1155 off = "%s%02d%s%02d" % (sign, hh, sep, mm)
1156 return off
1157
1158 def __repr__(self):
1159 """Convert to formal string, for repr()."""
1160 if self._microsecond != 0:
1161 s = ", %d, %d" % (self._second, self._microsecond)
1162 elif self._second != 0:
1163 s = ", %d" % self._second
1164 else:
1165 s = ""
1166 s= "%s(%d, %d%s)" % ('datetime.' + self.__class__.__name__,
1167 self._hour, self._minute, s)
1168 if self._tzinfo is not None:
1169 assert s[-1:] == ")"
1170 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
1171 return s
1172
1173 def isoformat(self):
1174 """Return the time formatted according to ISO.
1175
1176 This is 'HH:MM:SS.mmmmmm+zz:zz', or 'HH:MM:SS+zz:zz' if
1177 self.microsecond == 0.
1178 """
1179 s = _format_time(self._hour, self._minute, self._second,
1180 self._microsecond)
1181 tz = self._tzstr()
1182 if tz:
1183 s += tz
1184 return s
1185
1186 __str__ = isoformat
1187
1188 def strftime(self, fmt):
1189 """Format using strftime(). The date part of the timestamp passed
1190 to underlying strftime should not be used.
1191 """
1192 # The year must be >= 1900 else Python's strftime implementation
1193 # can raise a bogus exception.
1194 timetuple = (1900, 1, 1,
1195 self._hour, self._minute, self._second,
1196 0, 1, -1)
1197 return _wrap_strftime(self, fmt, timetuple)
1198
1199 def __format__(self, fmt):
1200 if len(fmt) != 0:
1201 return self.strftime(fmt)
1202 return str(self)
1203
1204 # Timezone functions
1205
1206 def utcoffset(self):
1207 """Return the timezone offset in minutes east of UTC (negative west of
1208 UTC)."""
1209 if self._tzinfo is None:
1210 return None
1211 offset = self._tzinfo.utcoffset(None)
1212 _check_utc_offset("utcoffset", offset)
1213 return offset
1214
1215 def tzname(self):
1216 """Return the timezone name.
1217
1218 Note that the name is 100% informational -- there's no requirement that
1219 it mean anything in particular. For example, "GMT", "UTC", "-500",
1220 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1221 """
1222 if self._tzinfo is None:
1223 return None
1224 name = self._tzinfo.tzname(None)
1225 _check_tzname(name)
1226 return name
1227
1228 def dst(self):
1229 """Return 0 if DST is not in effect, or the DST offset (in minutes
1230 eastward) if DST is in effect.
1231
1232 This is purely informational; the DST offset has already been added to
1233 the UTC offset returned by utcoffset() if applicable, so there's no
1234 need to consult dst() unless you're interested in displaying the DST
1235 info.
1236 """
1237 if self._tzinfo is None:
1238 return None
1239 offset = self._tzinfo.dst(None)
1240 _check_utc_offset("dst", offset)
1241 return offset
1242
1243 def replace(self, hour=None, minute=None, second=None, microsecond=None,
1244 tzinfo=True):
1245 """Return a new time with new values for the specified fields."""
1246 if hour is None:
1247 hour = self.hour
1248 if minute is None:
1249 minute = self.minute
1250 if second is None:
1251 second = self.second
1252 if microsecond is None:
1253 microsecond = self.microsecond
1254 if tzinfo is True:
1255 tzinfo = self.tzinfo
1256 _check_time_fields(hour, minute, second, microsecond)
1257 _check_tzinfo_arg(tzinfo)
1258 return time(hour, minute, second, microsecond, tzinfo)
1259
1260 def __bool__(self):
1261 if self.second or self.microsecond:
1262 return True
1263 offset = self.utcoffset() or timedelta(0)
1264 return timedelta(hours=self.hour, minutes=self.minute) != offset
1265
1266 # Pickle support.
1267
1268 def _getstate(self):
1269 us2, us3 = divmod(self._microsecond, 256)
1270 us1, us2 = divmod(us2, 256)
1271 basestate = bytes([self._hour, self._minute, self._second,
1272 us1, us2, us3])
1273 if self._tzinfo is None:
1274 return (basestate,)
1275 else:
1276 return (basestate, self._tzinfo)
1277
1278 def __setstate(self, string, tzinfo):
1279 if len(string) != 6 or string[0] >= 24:
1280 raise TypeError("an integer is required")
1281 (self._hour, self._minute, self._second,
1282 us1, us2, us3) = string
1283 self._microsecond = (((us1 << 8) | us2) << 8) | us3
1284 if tzinfo is None or isinstance(tzinfo, _tzinfo_class):
1285 self._tzinfo = tzinfo
1286 else:
1287 raise TypeError("bad tzinfo state arg %r" % tzinfo)
1288
1289 def __reduce__(self):
1290 return (time, self._getstate())
1291
1292_time_class = time # so functions w/ args named "time" can get at the class
1293
1294time.min = time(0, 0, 0)
1295time.max = time(23, 59, 59, 999999)
1296time.resolution = timedelta(microseconds=1)
1297
1298class datetime(date):
1299 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
1300
1301 The year, month and day arguments are required. tzinfo may be None, or an
1302 instance of a tzinfo subclass. The remaining arguments may be ints or longs.
1303 """
1304
1305 __slots__ = date.__slots__ + (
1306 '_hour', '_minute', '_second',
1307 '_microsecond', '_tzinfo')
1308 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
1309 microsecond=0, tzinfo=None):
1310 if isinstance(year, bytes) and len(year) == 10:
1311 # Pickle support
1312 self = date.__new__(cls, year[:4])
1313 self.__setstate(year, month)
1314 return self
1315 _check_tzinfo_arg(tzinfo)
1316 _check_time_fields(hour, minute, second, microsecond)
1317 self = date.__new__(cls, year, month, day)
1318 self._hour = hour
1319 self._minute = minute
1320 self._second = second
1321 self._microsecond = microsecond
1322 self._tzinfo = tzinfo
1323 return self
1324
1325 # Read-only field accessors
1326 @property
1327 def hour(self):
1328 """hour (0-23)"""
1329 return self._hour
1330
1331 @property
1332 def minute(self):
1333 """minute (0-59)"""
1334 return self._minute
1335
1336 @property
1337 def second(self):
1338 """second (0-59)"""
1339 return self._second
1340
1341 @property
1342 def microsecond(self):
1343 """microsecond (0-999999)"""
1344 return self._microsecond
1345
1346 @property
1347 def tzinfo(self):
1348 """timezone info object"""
1349 return self._tzinfo
1350
1351 @classmethod
1352 def fromtimestamp(cls, t, tz=None):
1353 """Construct a datetime from a POSIX timestamp (like time.time()).
1354
1355 A timezone info object may be passed in as well.
1356 """
1357
1358 _check_tzinfo_arg(tz)
Alexander Belopolskyaeb03982010-07-26 02:36:41 +00001359
1360 converter = _time.localtime if tz is None else _time.gmtime
1361
1362 t, frac = divmod(t, 1.0)
1363 us = round(frac * 1e6)
1364
1365 # If timestamp is less than one microsecond smaller than a
1366 # full second, us can be rounded up to 1000000. In this case,
1367 # roll over to seconds, otherwise, ValueError is raised
1368 # by the constructor.
1369 if us == 1000000:
1370 t += 1
1371 us = 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001372 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001373 ss = min(ss, 59) # clamp out leap seconds if the platform has them
1374 result = cls(y, m, d, hh, mm, ss, us, tz)
1375 if tz is not None:
1376 result = tz.fromutc(result)
1377 return result
1378
1379 @classmethod
1380 def utcfromtimestamp(cls, t):
1381 "Construct a UTC datetime from a POSIX timestamp (like time.time())."
1382 if 1 - (t % 1.0) < 0.000001:
1383 t = float(int(t)) + 1
1384 if t < 0:
1385 t -= 1
1386 y, m, d, hh, mm, ss, weekday, jday, dst = _time.gmtime(t)
1387 us = int((t % 1.0) * 1000000)
1388 ss = min(ss, 59) # clamp out leap seconds if the platform has them
1389 return cls(y, m, d, hh, mm, ss, us)
1390
1391 # XXX This is supposed to do better than we *can* do by using time.time(),
1392 # XXX if the platform supports a more accurate way. The C implementation
1393 # XXX uses gettimeofday on platforms that have it, but that isn't
1394 # XXX available from Python. So now() may return different results
1395 # XXX across the implementations.
1396 @classmethod
1397 def now(cls, tz=None):
1398 "Construct a datetime from time.time() and optional time zone info."
1399 t = _time.time()
1400 return cls.fromtimestamp(t, tz)
1401
1402 @classmethod
1403 def utcnow(cls):
1404 "Construct a UTC datetime from time.time()."
1405 t = _time.time()
1406 return cls.utcfromtimestamp(t)
1407
1408 @classmethod
1409 def combine(cls, date, time):
1410 "Construct a datetime from a given date and a given time."
1411 if not isinstance(date, _date_class):
1412 raise TypeError("date argument must be a date instance")
1413 if not isinstance(time, _time_class):
1414 raise TypeError("time argument must be a time instance")
1415 return cls(date.year, date.month, date.day,
1416 time.hour, time.minute, time.second, time.microsecond,
1417 time.tzinfo)
1418
1419 def timetuple(self):
1420 "Return local time tuple compatible with time.localtime()."
1421 dst = self.dst()
1422 if dst is None:
1423 dst = -1
1424 elif dst:
1425 dst = 1
1426 else:
1427 dst = 0
1428 return _build_struct_time(self.year, self.month, self.day,
1429 self.hour, self.minute, self.second,
1430 dst)
1431
1432 def utctimetuple(self):
1433 "Return UTC time tuple compatible with time.gmtime()."
1434 offset = self.utcoffset()
1435 if offset:
1436 self -= offset
1437 y, m, d = self.year, self.month, self.day
1438 hh, mm, ss = self.hour, self.minute, self.second
1439 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1440
1441 def date(self):
1442 "Return the date part."
1443 return date(self._year, self._month, self._day)
1444
1445 def time(self):
1446 "Return the time part, with tzinfo None."
1447 return time(self.hour, self.minute, self.second, self.microsecond)
1448
1449 def timetz(self):
1450 "Return the time part, with same tzinfo."
1451 return time(self.hour, self.minute, self.second, self.microsecond,
1452 self._tzinfo)
1453
1454 def replace(self, year=None, month=None, day=None, hour=None,
1455 minute=None, second=None, microsecond=None, tzinfo=True):
1456 """Return a new datetime with new values for the specified fields."""
1457 if year is None:
1458 year = self.year
1459 if month is None:
1460 month = self.month
1461 if day is None:
1462 day = self.day
1463 if hour is None:
1464 hour = self.hour
1465 if minute is None:
1466 minute = self.minute
1467 if second is None:
1468 second = self.second
1469 if microsecond is None:
1470 microsecond = self.microsecond
1471 if tzinfo is True:
1472 tzinfo = self.tzinfo
1473 _check_date_fields(year, month, day)
1474 _check_time_fields(hour, minute, second, microsecond)
1475 _check_tzinfo_arg(tzinfo)
1476 return datetime(year, month, day, hour, minute, second,
1477 microsecond, tzinfo)
1478
1479 def astimezone(self, tz):
1480 if not isinstance(tz, tzinfo):
1481 raise TypeError("tz argument must be an instance of tzinfo")
1482
1483 mytz = self.tzinfo
1484 if mytz is None:
1485 raise ValueError("astimezone() requires an aware datetime")
1486
1487 if tz is mytz:
1488 return self
1489
1490 # Convert self to UTC, and attach the new time zone object.
1491 myoffset = self.utcoffset()
1492 if myoffset is None:
1493 raise ValueError("astimezone() requires an aware datetime")
1494 utc = (self - myoffset).replace(tzinfo=tz)
1495
1496 # Convert from UTC to tz's local time.
1497 return tz.fromutc(utc)
1498
1499 # Ways to produce a string.
1500
1501 def ctime(self):
1502 "Return ctime() style string."
1503 weekday = self.toordinal() % 7 or 7
1504 return "%s %s %2d %02d:%02d:%02d %04d" % (
1505 _DAYNAMES[weekday],
1506 _MONTHNAMES[self._month],
1507 self._day,
1508 self._hour, self._minute, self._second,
1509 self._year)
1510
1511 def isoformat(self, sep='T'):
1512 """Return the time formatted according to ISO.
1513
1514 This is 'YYYY-MM-DD HH:MM:SS.mmmmmm', or 'YYYY-MM-DD HH:MM:SS' if
1515 self.microsecond == 0.
1516
1517 If self.tzinfo is not None, the UTC offset is also attached, giving
1518 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM' or 'YYYY-MM-DD HH:MM:SS+HH:MM'.
1519
1520 Optional argument sep specifies the separator between date and
1521 time, default 'T'.
1522 """
1523 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day,
1524 sep) +
1525 _format_time(self._hour, self._minute, self._second,
1526 self._microsecond))
1527 off = self.utcoffset()
1528 if off is not None:
1529 if off.days < 0:
1530 sign = "-"
1531 off = -off
1532 else:
1533 sign = "+"
1534 hh, mm = divmod(off, timedelta(hours=1))
1535 assert not mm % timedelta(minutes=1), "whole minute"
1536 mm //= timedelta(minutes=1)
1537 s += "%s%02d:%02d" % (sign, hh, mm)
1538 return s
1539
1540 def __repr__(self):
1541 """Convert to formal string, for repr()."""
1542 L = [self._year, self._month, self._day, # These are never zero
1543 self._hour, self._minute, self._second, self._microsecond]
1544 if L[-1] == 0:
1545 del L[-1]
1546 if L[-1] == 0:
1547 del L[-1]
1548 s = ", ".join(map(str, L))
1549 s = "%s(%s)" % ('datetime.' + self.__class__.__name__, s)
1550 if self._tzinfo is not None:
1551 assert s[-1:] == ")"
1552 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
1553 return s
1554
1555 def __str__(self):
1556 "Convert to string, for str()."
1557 return self.isoformat(sep=' ')
1558
1559 @classmethod
1560 def strptime(cls, date_string, format):
1561 'string, format -> new datetime parsed from a string (like time.strptime()).'
1562 import _strptime
1563 return _strptime._strptime_datetime(cls, date_string, format)
1564
1565 def utcoffset(self):
1566 """Return the timezone offset in minutes east of UTC (negative west of
1567 UTC)."""
1568 if self._tzinfo is None:
1569 return None
1570 offset = self._tzinfo.utcoffset(self)
1571 _check_utc_offset("utcoffset", offset)
1572 return offset
1573
1574 def tzname(self):
1575 """Return the timezone name.
1576
1577 Note that the name is 100% informational -- there's no requirement that
1578 it mean anything in particular. For example, "GMT", "UTC", "-500",
1579 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1580 """
1581 name = _call_tzinfo_method(self._tzinfo, "tzname", self)
1582 _check_tzname(name)
1583 return name
1584
1585 def dst(self):
1586 """Return 0 if DST is not in effect, or the DST offset (in minutes
1587 eastward) if DST is in effect.
1588
1589 This is purely informational; the DST offset has already been added to
1590 the UTC offset returned by utcoffset() if applicable, so there's no
1591 need to consult dst() unless you're interested in displaying the DST
1592 info.
1593 """
1594 if self._tzinfo is None:
1595 return None
1596 offset = self._tzinfo.dst(self)
1597 _check_utc_offset("dst", offset)
1598 return offset
1599
1600 # Comparisons of datetime objects with other.
1601
1602 def __eq__(self, other):
1603 if isinstance(other, datetime):
1604 return self._cmp(other) == 0
1605 elif not isinstance(other, date):
1606 return NotImplemented
1607 else:
1608 return False
1609
1610 def __ne__(self, other):
1611 if isinstance(other, datetime):
1612 return self._cmp(other) != 0
1613 elif not isinstance(other, date):
1614 return NotImplemented
1615 else:
1616 return True
1617
1618 def __le__(self, other):
1619 if isinstance(other, datetime):
1620 return self._cmp(other) <= 0
1621 elif not isinstance(other, date):
1622 return NotImplemented
1623 else:
1624 _cmperror(self, other)
1625
1626 def __lt__(self, other):
1627 if isinstance(other, datetime):
1628 return self._cmp(other) < 0
1629 elif not isinstance(other, date):
1630 return NotImplemented
1631 else:
1632 _cmperror(self, other)
1633
1634 def __ge__(self, other):
1635 if isinstance(other, datetime):
1636 return self._cmp(other) >= 0
1637 elif not isinstance(other, date):
1638 return NotImplemented
1639 else:
1640 _cmperror(self, other)
1641
1642 def __gt__(self, other):
1643 if isinstance(other, datetime):
1644 return self._cmp(other) > 0
1645 elif not isinstance(other, date):
1646 return NotImplemented
1647 else:
1648 _cmperror(self, other)
1649
1650 def _cmp(self, other):
1651 assert isinstance(other, datetime)
1652 mytz = self._tzinfo
1653 ottz = other._tzinfo
1654 myoff = otoff = None
1655
1656 if mytz is ottz:
1657 base_compare = True
1658 else:
1659 if mytz is not None:
1660 myoff = self.utcoffset()
1661 if ottz is not None:
1662 otoff = other.utcoffset()
1663 base_compare = myoff == otoff
1664
1665 if base_compare:
1666 return _cmp((self._year, self._month, self._day,
1667 self._hour, self._minute, self._second,
1668 self._microsecond),
1669 (other._year, other._month, other._day,
1670 other._hour, other._minute, other._second,
1671 other._microsecond))
1672 if myoff is None or otoff is None:
1673 raise TypeError("cannot compare naive and aware datetimes")
1674 # XXX What follows could be done more efficiently...
1675 diff = self - other # this will take offsets into account
1676 if diff.days < 0:
1677 return -1
1678 return diff and 1 or 0
1679
1680 def __add__(self, other):
1681 "Add a datetime and a timedelta."
1682 if not isinstance(other, timedelta):
1683 return NotImplemented
1684 delta = timedelta(self.toordinal(),
1685 hours=self._hour,
1686 minutes=self._minute,
1687 seconds=self._second,
1688 microseconds=self._microsecond)
1689 delta += other
1690 hour, rem = divmod(delta.seconds, 3600)
1691 minute, second = divmod(rem, 60)
1692 if 0 < delta.days <= _MAXORDINAL:
1693 return datetime.combine(date.fromordinal(delta.days),
1694 time(hour, minute, second,
1695 delta.microseconds,
1696 tzinfo=self._tzinfo))
1697 raise OverflowError("result out of range")
1698
1699 __radd__ = __add__
1700
1701 def __sub__(self, other):
1702 "Subtract two datetimes, or a datetime and a timedelta."
1703 if not isinstance(other, datetime):
1704 if isinstance(other, timedelta):
1705 return self + -other
1706 return NotImplemented
1707
1708 days1 = self.toordinal()
1709 days2 = other.toordinal()
1710 secs1 = self._second + self._minute * 60 + self._hour * 3600
1711 secs2 = other._second + other._minute * 60 + other._hour * 3600
1712 base = timedelta(days1 - days2,
1713 secs1 - secs2,
1714 self._microsecond - other._microsecond)
1715 if self._tzinfo is other._tzinfo:
1716 return base
1717 myoff = self.utcoffset()
1718 otoff = other.utcoffset()
1719 if myoff == otoff:
1720 return base
1721 if myoff is None or otoff is None:
1722 raise TypeError("cannot mix naive and timezone-aware time")
1723 return base + otoff - myoff
1724
1725 def __hash__(self):
1726 tzoff = self.utcoffset()
1727 if tzoff is None:
1728 return hash(self._getstate()[0])
1729 days = _ymd2ord(self.year, self.month, self.day)
1730 seconds = self.hour * 3600 + self.minute * 60 + self.second
1731 return hash(timedelta(days, seconds, self.microsecond) - tzoff)
1732
1733 # Pickle support.
1734
1735 def _getstate(self):
1736 yhi, ylo = divmod(self._year, 256)
1737 us2, us3 = divmod(self._microsecond, 256)
1738 us1, us2 = divmod(us2, 256)
1739 basestate = bytes([yhi, ylo, self._month, self._day,
1740 self._hour, self._minute, self._second,
1741 us1, us2, us3])
1742 if self._tzinfo is None:
1743 return (basestate,)
1744 else:
1745 return (basestate, self._tzinfo)
1746
1747 def __setstate(self, string, tzinfo):
1748 (yhi, ylo, self._month, self._day, self._hour,
1749 self._minute, self._second, us1, us2, us3) = string
1750 self._year = yhi * 256 + ylo
1751 self._microsecond = (((us1 << 8) | us2) << 8) | us3
1752 if tzinfo is None or isinstance(tzinfo, _tzinfo_class):
1753 self._tzinfo = tzinfo
1754 else:
1755 raise TypeError("bad tzinfo state arg %r" % tzinfo)
1756
1757 def __reduce__(self):
1758 return (self.__class__, self._getstate())
1759
1760
1761datetime.min = datetime(1, 1, 1)
1762datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1763datetime.resolution = timedelta(microseconds=1)
1764
1765
1766def _isoweek1monday(year):
1767 # Helper to calculate the day number of the Monday starting week 1
1768 # XXX This could be done more efficiently
1769 THURSDAY = 3
1770 firstday = _ymd2ord(year, 1, 1)
1771 firstweekday = (firstday + 6) % 7 # See weekday() above
1772 week1monday = firstday - firstweekday
1773 if firstweekday > THURSDAY:
1774 week1monday += 7
1775 return week1monday
1776
1777class timezone(tzinfo):
1778 __slots__ = '_offset', '_name'
1779
1780 # Sentinel value to disallow None
1781 _Omitted = object()
1782 def __init__(self, offset, name=_Omitted):
1783 if name is self._Omitted:
1784 name = None
1785 elif not isinstance(name, str):
1786 raise TypeError("name must be a string")
1787 if isinstance(offset, timedelta):
1788 if self._minoffset <= offset <= self._maxoffset:
1789 if (offset.microseconds != 0 or
1790 offset.seconds % 60 != 0):
1791 raise ValueError("offset must be whole"
1792 " number of minutes")
1793 self._offset = offset
1794 else:
1795 raise ValueError("offset out of range")
1796 else:
1797 raise TypeError("offset must be timedelta")
1798
1799 self._name = name
1800
1801 def __getinitargs__(self):
1802 """pickle support"""
1803 if self._name is None:
1804 return (self._offset,)
1805 return (self._offset, self._name)
1806
1807 def __eq__(self, other):
1808 return self._offset == other._offset
1809
1810 def __hash__(self):
1811 return hash(self._offset)
1812
1813 def __repr__(self):
1814 """Convert to formal string, for repr().
1815
1816 >>> tz = timezone.utc
1817 >>> repr(tz)
1818 'datetime.timezone.utc'
1819 >>> tz = timezone(timedelta(hours=-5), 'EST')
1820 >>> repr(tz)
1821 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
1822 """
1823 if self is self.utc:
1824 return 'datetime.timezone.utc'
1825 if self._name is None:
1826 return "%s(%r)" % ('datetime.' + self.__class__.__name__,
1827 self._offset)
1828 return "%s(%r, %r)" % ('datetime.' + self.__class__.__name__,
1829 self._offset, self._name)
1830
1831 def __str__(self):
1832 return self.tzname(None)
1833
1834 def utcoffset(self, dt):
1835 if isinstance(dt, datetime) or dt is None:
1836 return self._offset
1837 raise TypeError("utcoffset() argument must be a datetime instance"
1838 " or None")
1839
1840 def tzname(self, dt):
1841 if isinstance(dt, datetime) or dt is None:
1842 if self._name is None:
1843 return self._name_from_offset(self._offset)
1844 return self._name
1845 raise TypeError("tzname() argument must be a datetime instance"
1846 " or None")
1847
1848 def dst(self, dt):
1849 if isinstance(dt, datetime) or dt is None:
1850 return None
1851 raise TypeError("dst() argument must be a datetime instance"
1852 " or None")
1853
1854 def fromutc(self, dt):
1855 if isinstance(dt, datetime):
1856 if dt.tzinfo is not self:
1857 raise ValueError("fromutc: dt.tzinfo "
1858 "is not self")
1859 return dt + self._offset
1860 raise TypeError("fromutc() argument must be a datetime instance"
1861 " or None")
1862
1863 _maxoffset = timedelta(hours=23, minutes=59)
1864 _minoffset = -_maxoffset
1865
1866 @staticmethod
1867 def _name_from_offset(delta):
1868 if delta < timedelta(0):
1869 sign = '-'
1870 delta = -delta
1871 else:
1872 sign = '+'
1873 hours, rest = divmod(delta, timedelta(hours=1))
1874 minutes = rest // timedelta(minutes=1)
1875 return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes)
1876
1877timezone.utc = timezone(timedelta(0))
1878timezone.min = timezone(timezone._minoffset)
1879timezone.max = timezone(timezone._maxoffset)
1880
1881"""
1882Some time zone algebra. For a datetime x, let
1883 x.n = x stripped of its timezone -- its naive time.
1884 x.o = x.utcoffset(), and assuming that doesn't raise an exception or
1885 return None
1886 x.d = x.dst(), and assuming that doesn't raise an exception or
1887 return None
1888 x.s = x's standard offset, x.o - x.d
1889
1890Now some derived rules, where k is a duration (timedelta).
1891
18921. x.o = x.s + x.d
1893 This follows from the definition of x.s.
1894
18952. If x and y have the same tzinfo member, x.s = y.s.
1896 This is actually a requirement, an assumption we need to make about
1897 sane tzinfo classes.
1898
18993. The naive UTC time corresponding to x is x.n - x.o.
1900 This is again a requirement for a sane tzinfo class.
1901
19024. (x+k).s = x.s
1903 This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
1904
19055. (x+k).n = x.n + k
1906 Again follows from how arithmetic is defined.
1907
1908Now we can explain tz.fromutc(x). Let's assume it's an interesting case
1909(meaning that the various tzinfo methods exist, and don't blow up or return
1910None when called).
1911
1912The function wants to return a datetime y with timezone tz, equivalent to x.
1913x is already in UTC.
1914
1915By #3, we want
1916
1917 y.n - y.o = x.n [1]
1918
1919The algorithm starts by attaching tz to x.n, and calling that y. So
1920x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
1921becomes true; in effect, we want to solve [2] for k:
1922
1923 (y+k).n - (y+k).o = x.n [2]
1924
1925By #1, this is the same as
1926
1927 (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
1928
1929By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
1930Substituting that into [3],
1931
1932 x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
1933 k - (y+k).s - (y+k).d = 0; rearranging,
1934 k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
1935 k = y.s - (y+k).d
1936
1937On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
1938approximate k by ignoring the (y+k).d term at first. Note that k can't be
1939very large, since all offset-returning methods return a duration of magnitude
1940less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
1941be 0, so ignoring it has no consequence then.
1942
1943In any case, the new value is
1944
1945 z = y + y.s [4]
1946
1947It's helpful to step back at look at [4] from a higher level: it's simply
1948mapping from UTC to tz's standard time.
1949
1950At this point, if
1951
1952 z.n - z.o = x.n [5]
1953
1954we have an equivalent time, and are almost done. The insecurity here is
1955at the start of daylight time. Picture US Eastern for concreteness. The wall
1956time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
1957sense then. The docs ask that an Eastern tzinfo class consider such a time to
1958be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
1959on the day DST starts. We want to return the 1:MM EST spelling because that's
1960the only spelling that makes sense on the local wall clock.
1961
1962In fact, if [5] holds at this point, we do have the standard-time spelling,
1963but that takes a bit of proof. We first prove a stronger result. What's the
1964difference between the LHS and RHS of [5]? Let
1965
1966 diff = x.n - (z.n - z.o) [6]
1967
1968Now
1969 z.n = by [4]
1970 (y + y.s).n = by #5
1971 y.n + y.s = since y.n = x.n
1972 x.n + y.s = since z and y are have the same tzinfo member,
1973 y.s = z.s by #2
1974 x.n + z.s
1975
1976Plugging that back into [6] gives
1977
1978 diff =
1979 x.n - ((x.n + z.s) - z.o) = expanding
1980 x.n - x.n - z.s + z.o = cancelling
1981 - z.s + z.o = by #2
1982 z.d
1983
1984So diff = z.d.
1985
1986If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
1987spelling we wanted in the endcase described above. We're done. Contrarily,
1988if z.d = 0, then we have a UTC equivalent, and are also done.
1989
1990If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
1991add to z (in effect, z is in tz's standard time, and we need to shift the
1992local clock into tz's daylight time).
1993
1994Let
1995
1996 z' = z + z.d = z + diff [7]
1997
1998and we can again ask whether
1999
2000 z'.n - z'.o = x.n [8]
2001
2002If so, we're done. If not, the tzinfo class is insane, according to the
2003assumptions we've made. This also requires a bit of proof. As before, let's
2004compute the difference between the LHS and RHS of [8] (and skipping some of
2005the justifications for the kinds of substitutions we've done several times
2006already):
2007
2008 diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2009 x.n - (z.n + diff - z'.o) = replacing diff via [6]
2010 x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2011 x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2012 - z.n + z.n - z.o + z'.o = cancel z.n
2013 - z.o + z'.o = #1 twice
2014 -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2015 z'.d - z.d
2016
2017So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2018we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2019return z', not bothering to compute z'.d.
2020
2021How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2022a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2023would have to change the result dst() returns: we start in DST, and moving
2024a little further into it takes us out of DST.
2025
2026There isn't a sane case where this can happen. The closest it gets is at
2027the end of DST, where there's an hour in UTC with no spelling in a hybrid
2028tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2029that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2030UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2031time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2032clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2033standard time. Since that's what the local clock *does*, we want to map both
2034UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2035in local time, but so it goes -- it's the way the local clock works.
2036
2037When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2038so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2039z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2040(correctly) concludes that z' is not UTC-equivalent to x.
2041
2042Because we know z.d said z was in daylight time (else [5] would have held and
2043we would have stopped then), and we know z.d != z'.d (else [8] would have held
2044and we we have stopped then), and there are only 2 possible values dst() can
2045return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2046but the reasoning doesn't depend on the example -- it depends on there being
2047two possible dst() outcomes, one zero and the other non-zero). Therefore
2048z' must be in standard time, and is the spelling we want in this case.
2049
2050Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2051concerned (because it takes z' as being in standard time rather than the
2052daylight time we intend here), but returning it gives the real-life "local
2053clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2054tz.
2055
2056When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2057the 1:MM standard time spelling we want.
2058
2059So how can this break? One of the assumptions must be violated. Two
2060possibilities:
2061
20621) [2] effectively says that y.s is invariant across all y belong to a given
2063 time zone. This isn't true if, for political reasons or continental drift,
2064 a region decides to change its base offset from UTC.
2065
20662) There may be versions of "double daylight" time where the tail end of
2067 the analysis gives up a step too early. I haven't thought about that
2068 enough to say.
2069
2070In any case, it's clear that the default fromutc() is strong enough to handle
2071"almost all" time zones: so long as the standard offset is invariant, it
2072doesn't matter if daylight time transition points change from year to year, or
2073if daylight time is skipped in some years; it doesn't matter how large or
2074small dst() may get within its bounds; and it doesn't even matter if some
2075perverse time zone returns a negative dst()). So a breaking case must be
2076pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
2077"""
2078try:
2079 from _datetime import *
2080except ImportError:
2081 pass
2082else:
2083 # Clean up unused names
2084 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH,
2085 _DI100Y, _DI400Y, _DI4Y, _MAXORDINAL, _MONTHNAMES,
2086 _build_struct_time, _call_tzinfo_method, _check_date_fields,
2087 _check_time_fields, _check_tzinfo_arg, _check_tzname,
2088 _check_utc_offset, _cmp, _cmperror, _date_class, _days_before_month,
2089 _days_before_year, _days_in_month, _format_time, _is_leap,
2090 _isoweek1monday, _math, _ord2ymd, _time, _time_class, _tzinfo_class,
2091 _wrap_strftime, _ymd2ord)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002092 # XXX Since import * above excludes names that start with _,
2093 # docstring does not get overwritten. In the future, it may be
2094 # appropriate to maintain a single module level docstring and
2095 # remove the following line.
2096 from _datetime import __doc__