blob: 29ffe246aa4996e6a7ae3ae9ce4d2d1da27e4e69 [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())."
Alexander Belopolsky3e62f782010-09-21 16:30:56 +00001382 t, frac = divmod(t, 1.0)
1383 us = round(frac * 1e6)
1384
1385 # If timestamp is less than one microsecond smaller than a
1386 # full second, us can be rounded up to 1000000. In this case,
1387 # roll over to seconds, otherwise, ValueError is raised
1388 # by the constructor.
1389 if us == 1000000:
1390 t += 1
1391 us = 0
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001392 y, m, d, hh, mm, ss, weekday, jday, dst = _time.gmtime(t)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001393 ss = min(ss, 59) # clamp out leap seconds if the platform has them
1394 return cls(y, m, d, hh, mm, ss, us)
1395
1396 # XXX This is supposed to do better than we *can* do by using time.time(),
1397 # XXX if the platform supports a more accurate way. The C implementation
1398 # XXX uses gettimeofday on platforms that have it, but that isn't
1399 # XXX available from Python. So now() may return different results
1400 # XXX across the implementations.
1401 @classmethod
1402 def now(cls, tz=None):
1403 "Construct a datetime from time.time() and optional time zone info."
1404 t = _time.time()
1405 return cls.fromtimestamp(t, tz)
1406
1407 @classmethod
1408 def utcnow(cls):
1409 "Construct a UTC datetime from time.time()."
1410 t = _time.time()
1411 return cls.utcfromtimestamp(t)
1412
1413 @classmethod
1414 def combine(cls, date, time):
1415 "Construct a datetime from a given date and a given time."
1416 if not isinstance(date, _date_class):
1417 raise TypeError("date argument must be a date instance")
1418 if not isinstance(time, _time_class):
1419 raise TypeError("time argument must be a time instance")
1420 return cls(date.year, date.month, date.day,
1421 time.hour, time.minute, time.second, time.microsecond,
1422 time.tzinfo)
1423
1424 def timetuple(self):
1425 "Return local time tuple compatible with time.localtime()."
1426 dst = self.dst()
1427 if dst is None:
1428 dst = -1
1429 elif dst:
1430 dst = 1
1431 else:
1432 dst = 0
1433 return _build_struct_time(self.year, self.month, self.day,
1434 self.hour, self.minute, self.second,
1435 dst)
1436
1437 def utctimetuple(self):
1438 "Return UTC time tuple compatible with time.gmtime()."
1439 offset = self.utcoffset()
1440 if offset:
1441 self -= offset
1442 y, m, d = self.year, self.month, self.day
1443 hh, mm, ss = self.hour, self.minute, self.second
1444 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1445
1446 def date(self):
1447 "Return the date part."
1448 return date(self._year, self._month, self._day)
1449
1450 def time(self):
1451 "Return the time part, with tzinfo None."
1452 return time(self.hour, self.minute, self.second, self.microsecond)
1453
1454 def timetz(self):
1455 "Return the time part, with same tzinfo."
1456 return time(self.hour, self.minute, self.second, self.microsecond,
1457 self._tzinfo)
1458
1459 def replace(self, year=None, month=None, day=None, hour=None,
1460 minute=None, second=None, microsecond=None, tzinfo=True):
1461 """Return a new datetime with new values for the specified fields."""
1462 if year is None:
1463 year = self.year
1464 if month is None:
1465 month = self.month
1466 if day is None:
1467 day = self.day
1468 if hour is None:
1469 hour = self.hour
1470 if minute is None:
1471 minute = self.minute
1472 if second is None:
1473 second = self.second
1474 if microsecond is None:
1475 microsecond = self.microsecond
1476 if tzinfo is True:
1477 tzinfo = self.tzinfo
1478 _check_date_fields(year, month, day)
1479 _check_time_fields(hour, minute, second, microsecond)
1480 _check_tzinfo_arg(tzinfo)
1481 return datetime(year, month, day, hour, minute, second,
1482 microsecond, tzinfo)
1483
1484 def astimezone(self, tz):
1485 if not isinstance(tz, tzinfo):
1486 raise TypeError("tz argument must be an instance of tzinfo")
1487
1488 mytz = self.tzinfo
1489 if mytz is None:
1490 raise ValueError("astimezone() requires an aware datetime")
1491
1492 if tz is mytz:
1493 return self
1494
1495 # Convert self to UTC, and attach the new time zone object.
1496 myoffset = self.utcoffset()
1497 if myoffset is None:
1498 raise ValueError("astimezone() requires an aware datetime")
1499 utc = (self - myoffset).replace(tzinfo=tz)
1500
1501 # Convert from UTC to tz's local time.
1502 return tz.fromutc(utc)
1503
1504 # Ways to produce a string.
1505
1506 def ctime(self):
1507 "Return ctime() style string."
1508 weekday = self.toordinal() % 7 or 7
1509 return "%s %s %2d %02d:%02d:%02d %04d" % (
1510 _DAYNAMES[weekday],
1511 _MONTHNAMES[self._month],
1512 self._day,
1513 self._hour, self._minute, self._second,
1514 self._year)
1515
1516 def isoformat(self, sep='T'):
1517 """Return the time formatted according to ISO.
1518
1519 This is 'YYYY-MM-DD HH:MM:SS.mmmmmm', or 'YYYY-MM-DD HH:MM:SS' if
1520 self.microsecond == 0.
1521
1522 If self.tzinfo is not None, the UTC offset is also attached, giving
1523 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM' or 'YYYY-MM-DD HH:MM:SS+HH:MM'.
1524
1525 Optional argument sep specifies the separator between date and
1526 time, default 'T'.
1527 """
1528 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day,
1529 sep) +
1530 _format_time(self._hour, self._minute, self._second,
1531 self._microsecond))
1532 off = self.utcoffset()
1533 if off is not None:
1534 if off.days < 0:
1535 sign = "-"
1536 off = -off
1537 else:
1538 sign = "+"
1539 hh, mm = divmod(off, timedelta(hours=1))
1540 assert not mm % timedelta(minutes=1), "whole minute"
1541 mm //= timedelta(minutes=1)
1542 s += "%s%02d:%02d" % (sign, hh, mm)
1543 return s
1544
1545 def __repr__(self):
1546 """Convert to formal string, for repr()."""
1547 L = [self._year, self._month, self._day, # These are never zero
1548 self._hour, self._minute, self._second, self._microsecond]
1549 if L[-1] == 0:
1550 del L[-1]
1551 if L[-1] == 0:
1552 del L[-1]
1553 s = ", ".join(map(str, L))
1554 s = "%s(%s)" % ('datetime.' + self.__class__.__name__, s)
1555 if self._tzinfo is not None:
1556 assert s[-1:] == ")"
1557 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
1558 return s
1559
1560 def __str__(self):
1561 "Convert to string, for str()."
1562 return self.isoformat(sep=' ')
1563
1564 @classmethod
1565 def strptime(cls, date_string, format):
1566 'string, format -> new datetime parsed from a string (like time.strptime()).'
1567 import _strptime
1568 return _strptime._strptime_datetime(cls, date_string, format)
1569
1570 def utcoffset(self):
1571 """Return the timezone offset in minutes east of UTC (negative west of
1572 UTC)."""
1573 if self._tzinfo is None:
1574 return None
1575 offset = self._tzinfo.utcoffset(self)
1576 _check_utc_offset("utcoffset", offset)
1577 return offset
1578
1579 def tzname(self):
1580 """Return the timezone name.
1581
1582 Note that the name is 100% informational -- there's no requirement that
1583 it mean anything in particular. For example, "GMT", "UTC", "-500",
1584 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1585 """
1586 name = _call_tzinfo_method(self._tzinfo, "tzname", self)
1587 _check_tzname(name)
1588 return name
1589
1590 def dst(self):
1591 """Return 0 if DST is not in effect, or the DST offset (in minutes
1592 eastward) if DST is in effect.
1593
1594 This is purely informational; the DST offset has already been added to
1595 the UTC offset returned by utcoffset() if applicable, so there's no
1596 need to consult dst() unless you're interested in displaying the DST
1597 info.
1598 """
1599 if self._tzinfo is None:
1600 return None
1601 offset = self._tzinfo.dst(self)
1602 _check_utc_offset("dst", offset)
1603 return offset
1604
1605 # Comparisons of datetime objects with other.
1606
1607 def __eq__(self, other):
1608 if isinstance(other, datetime):
1609 return self._cmp(other) == 0
1610 elif not isinstance(other, date):
1611 return NotImplemented
1612 else:
1613 return False
1614
1615 def __ne__(self, other):
1616 if isinstance(other, datetime):
1617 return self._cmp(other) != 0
1618 elif not isinstance(other, date):
1619 return NotImplemented
1620 else:
1621 return True
1622
1623 def __le__(self, other):
1624 if isinstance(other, datetime):
1625 return self._cmp(other) <= 0
1626 elif not isinstance(other, date):
1627 return NotImplemented
1628 else:
1629 _cmperror(self, other)
1630
1631 def __lt__(self, other):
1632 if isinstance(other, datetime):
1633 return self._cmp(other) < 0
1634 elif not isinstance(other, date):
1635 return NotImplemented
1636 else:
1637 _cmperror(self, other)
1638
1639 def __ge__(self, other):
1640 if isinstance(other, datetime):
1641 return self._cmp(other) >= 0
1642 elif not isinstance(other, date):
1643 return NotImplemented
1644 else:
1645 _cmperror(self, other)
1646
1647 def __gt__(self, other):
1648 if isinstance(other, datetime):
1649 return self._cmp(other) > 0
1650 elif not isinstance(other, date):
1651 return NotImplemented
1652 else:
1653 _cmperror(self, other)
1654
1655 def _cmp(self, other):
1656 assert isinstance(other, datetime)
1657 mytz = self._tzinfo
1658 ottz = other._tzinfo
1659 myoff = otoff = None
1660
1661 if mytz is ottz:
1662 base_compare = True
1663 else:
1664 if mytz is not None:
1665 myoff = self.utcoffset()
1666 if ottz is not None:
1667 otoff = other.utcoffset()
1668 base_compare = myoff == otoff
1669
1670 if base_compare:
1671 return _cmp((self._year, self._month, self._day,
1672 self._hour, self._minute, self._second,
1673 self._microsecond),
1674 (other._year, other._month, other._day,
1675 other._hour, other._minute, other._second,
1676 other._microsecond))
1677 if myoff is None or otoff is None:
1678 raise TypeError("cannot compare naive and aware datetimes")
1679 # XXX What follows could be done more efficiently...
1680 diff = self - other # this will take offsets into account
1681 if diff.days < 0:
1682 return -1
1683 return diff and 1 or 0
1684
1685 def __add__(self, other):
1686 "Add a datetime and a timedelta."
1687 if not isinstance(other, timedelta):
1688 return NotImplemented
1689 delta = timedelta(self.toordinal(),
1690 hours=self._hour,
1691 minutes=self._minute,
1692 seconds=self._second,
1693 microseconds=self._microsecond)
1694 delta += other
1695 hour, rem = divmod(delta.seconds, 3600)
1696 minute, second = divmod(rem, 60)
1697 if 0 < delta.days <= _MAXORDINAL:
1698 return datetime.combine(date.fromordinal(delta.days),
1699 time(hour, minute, second,
1700 delta.microseconds,
1701 tzinfo=self._tzinfo))
1702 raise OverflowError("result out of range")
1703
1704 __radd__ = __add__
1705
1706 def __sub__(self, other):
1707 "Subtract two datetimes, or a datetime and a timedelta."
1708 if not isinstance(other, datetime):
1709 if isinstance(other, timedelta):
1710 return self + -other
1711 return NotImplemented
1712
1713 days1 = self.toordinal()
1714 days2 = other.toordinal()
1715 secs1 = self._second + self._minute * 60 + self._hour * 3600
1716 secs2 = other._second + other._minute * 60 + other._hour * 3600
1717 base = timedelta(days1 - days2,
1718 secs1 - secs2,
1719 self._microsecond - other._microsecond)
1720 if self._tzinfo is other._tzinfo:
1721 return base
1722 myoff = self.utcoffset()
1723 otoff = other.utcoffset()
1724 if myoff == otoff:
1725 return base
1726 if myoff is None or otoff is None:
1727 raise TypeError("cannot mix naive and timezone-aware time")
1728 return base + otoff - myoff
1729
1730 def __hash__(self):
1731 tzoff = self.utcoffset()
1732 if tzoff is None:
1733 return hash(self._getstate()[0])
1734 days = _ymd2ord(self.year, self.month, self.day)
1735 seconds = self.hour * 3600 + self.minute * 60 + self.second
1736 return hash(timedelta(days, seconds, self.microsecond) - tzoff)
1737
1738 # Pickle support.
1739
1740 def _getstate(self):
1741 yhi, ylo = divmod(self._year, 256)
1742 us2, us3 = divmod(self._microsecond, 256)
1743 us1, us2 = divmod(us2, 256)
1744 basestate = bytes([yhi, ylo, self._month, self._day,
1745 self._hour, self._minute, self._second,
1746 us1, us2, us3])
1747 if self._tzinfo is None:
1748 return (basestate,)
1749 else:
1750 return (basestate, self._tzinfo)
1751
1752 def __setstate(self, string, tzinfo):
1753 (yhi, ylo, self._month, self._day, self._hour,
1754 self._minute, self._second, us1, us2, us3) = string
1755 self._year = yhi * 256 + ylo
1756 self._microsecond = (((us1 << 8) | us2) << 8) | us3
1757 if tzinfo is None or isinstance(tzinfo, _tzinfo_class):
1758 self._tzinfo = tzinfo
1759 else:
1760 raise TypeError("bad tzinfo state arg %r" % tzinfo)
1761
1762 def __reduce__(self):
1763 return (self.__class__, self._getstate())
1764
1765
1766datetime.min = datetime(1, 1, 1)
1767datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1768datetime.resolution = timedelta(microseconds=1)
1769
1770
1771def _isoweek1monday(year):
1772 # Helper to calculate the day number of the Monday starting week 1
1773 # XXX This could be done more efficiently
1774 THURSDAY = 3
1775 firstday = _ymd2ord(year, 1, 1)
1776 firstweekday = (firstday + 6) % 7 # See weekday() above
1777 week1monday = firstday - firstweekday
1778 if firstweekday > THURSDAY:
1779 week1monday += 7
1780 return week1monday
1781
1782class timezone(tzinfo):
1783 __slots__ = '_offset', '_name'
1784
1785 # Sentinel value to disallow None
1786 _Omitted = object()
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001787 def __new__(cls, offset, name=_Omitted):
1788 if not isinstance(offset, timedelta):
1789 raise TypeError("offset must be a timedelta")
1790 if name is cls._Omitted:
1791 if not offset:
1792 return cls.utc
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001793 name = None
1794 elif not isinstance(name, str):
1795 raise TypeError("name must be a string")
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001796 if not cls._minoffset <= offset <= cls._maxoffset:
1797 raise ValueError("offset must be a timedelta"
1798 " strictly between -timedelta(hours=24) and"
1799 " timedelta(hours=24).")
1800 if (offset.microseconds != 0 or
1801 offset.seconds % 60 != 0):
1802 raise ValueError("offset must be a timedelta"
1803 " representing a whole number of minutes")
1804 return cls._create(offset, name)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001805
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001806 @classmethod
1807 def _create(cls, offset, name=None):
1808 self = tzinfo.__new__(cls)
1809 self._offset = offset
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001810 self._name = name
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001811 return self
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001812
1813 def __getinitargs__(self):
1814 """pickle support"""
1815 if self._name is None:
1816 return (self._offset,)
1817 return (self._offset, self._name)
1818
1819 def __eq__(self, other):
1820 return self._offset == other._offset
1821
1822 def __hash__(self):
1823 return hash(self._offset)
1824
1825 def __repr__(self):
1826 """Convert to formal string, for repr().
1827
1828 >>> tz = timezone.utc
1829 >>> repr(tz)
1830 'datetime.timezone.utc'
1831 >>> tz = timezone(timedelta(hours=-5), 'EST')
1832 >>> repr(tz)
1833 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
1834 """
1835 if self is self.utc:
1836 return 'datetime.timezone.utc'
1837 if self._name is None:
1838 return "%s(%r)" % ('datetime.' + self.__class__.__name__,
1839 self._offset)
1840 return "%s(%r, %r)" % ('datetime.' + self.__class__.__name__,
1841 self._offset, self._name)
1842
1843 def __str__(self):
1844 return self.tzname(None)
1845
1846 def utcoffset(self, dt):
1847 if isinstance(dt, datetime) or dt is None:
1848 return self._offset
1849 raise TypeError("utcoffset() argument must be a datetime instance"
1850 " or None")
1851
1852 def tzname(self, dt):
1853 if isinstance(dt, datetime) or dt is None:
1854 if self._name is None:
1855 return self._name_from_offset(self._offset)
1856 return self._name
1857 raise TypeError("tzname() argument must be a datetime instance"
1858 " or None")
1859
1860 def dst(self, dt):
1861 if isinstance(dt, datetime) or dt is None:
1862 return None
1863 raise TypeError("dst() argument must be a datetime instance"
1864 " or None")
1865
1866 def fromutc(self, dt):
1867 if isinstance(dt, datetime):
1868 if dt.tzinfo is not self:
1869 raise ValueError("fromutc: dt.tzinfo "
1870 "is not self")
1871 return dt + self._offset
1872 raise TypeError("fromutc() argument must be a datetime instance"
1873 " or None")
1874
1875 _maxoffset = timedelta(hours=23, minutes=59)
1876 _minoffset = -_maxoffset
1877
1878 @staticmethod
1879 def _name_from_offset(delta):
1880 if delta < timedelta(0):
1881 sign = '-'
1882 delta = -delta
1883 else:
1884 sign = '+'
1885 hours, rest = divmod(delta, timedelta(hours=1))
1886 minutes = rest // timedelta(minutes=1)
1887 return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes)
1888
Alexander Belopolsky1bcbaab2010-10-14 17:03:51 +00001889timezone.utc = timezone._create(timedelta(0))
1890timezone.min = timezone._create(timezone._minoffset)
1891timezone.max = timezone._create(timezone._maxoffset)
Alexander Belopolskycf86e362010-07-23 19:25:47 +00001892
1893"""
1894Some time zone algebra. For a datetime x, let
1895 x.n = x stripped of its timezone -- its naive time.
1896 x.o = x.utcoffset(), and assuming that doesn't raise an exception or
1897 return None
1898 x.d = x.dst(), and assuming that doesn't raise an exception or
1899 return None
1900 x.s = x's standard offset, x.o - x.d
1901
1902Now some derived rules, where k is a duration (timedelta).
1903
19041. x.o = x.s + x.d
1905 This follows from the definition of x.s.
1906
19072. If x and y have the same tzinfo member, x.s = y.s.
1908 This is actually a requirement, an assumption we need to make about
1909 sane tzinfo classes.
1910
19113. The naive UTC time corresponding to x is x.n - x.o.
1912 This is again a requirement for a sane tzinfo class.
1913
19144. (x+k).s = x.s
1915 This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
1916
19175. (x+k).n = x.n + k
1918 Again follows from how arithmetic is defined.
1919
1920Now we can explain tz.fromutc(x). Let's assume it's an interesting case
1921(meaning that the various tzinfo methods exist, and don't blow up or return
1922None when called).
1923
1924The function wants to return a datetime y with timezone tz, equivalent to x.
1925x is already in UTC.
1926
1927By #3, we want
1928
1929 y.n - y.o = x.n [1]
1930
1931The algorithm starts by attaching tz to x.n, and calling that y. So
1932x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
1933becomes true; in effect, we want to solve [2] for k:
1934
1935 (y+k).n - (y+k).o = x.n [2]
1936
1937By #1, this is the same as
1938
1939 (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
1940
1941By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
1942Substituting that into [3],
1943
1944 x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
1945 k - (y+k).s - (y+k).d = 0; rearranging,
1946 k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
1947 k = y.s - (y+k).d
1948
1949On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
1950approximate k by ignoring the (y+k).d term at first. Note that k can't be
1951very large, since all offset-returning methods return a duration of magnitude
1952less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
1953be 0, so ignoring it has no consequence then.
1954
1955In any case, the new value is
1956
1957 z = y + y.s [4]
1958
1959It's helpful to step back at look at [4] from a higher level: it's simply
1960mapping from UTC to tz's standard time.
1961
1962At this point, if
1963
1964 z.n - z.o = x.n [5]
1965
1966we have an equivalent time, and are almost done. The insecurity here is
1967at the start of daylight time. Picture US Eastern for concreteness. The wall
1968time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
1969sense then. The docs ask that an Eastern tzinfo class consider such a time to
1970be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
1971on the day DST starts. We want to return the 1:MM EST spelling because that's
1972the only spelling that makes sense on the local wall clock.
1973
1974In fact, if [5] holds at this point, we do have the standard-time spelling,
1975but that takes a bit of proof. We first prove a stronger result. What's the
1976difference between the LHS and RHS of [5]? Let
1977
1978 diff = x.n - (z.n - z.o) [6]
1979
1980Now
1981 z.n = by [4]
1982 (y + y.s).n = by #5
1983 y.n + y.s = since y.n = x.n
1984 x.n + y.s = since z and y are have the same tzinfo member,
1985 y.s = z.s by #2
1986 x.n + z.s
1987
1988Plugging that back into [6] gives
1989
1990 diff =
1991 x.n - ((x.n + z.s) - z.o) = expanding
1992 x.n - x.n - z.s + z.o = cancelling
1993 - z.s + z.o = by #2
1994 z.d
1995
1996So diff = z.d.
1997
1998If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
1999spelling we wanted in the endcase described above. We're done. Contrarily,
2000if z.d = 0, then we have a UTC equivalent, and are also done.
2001
2002If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
2003add to z (in effect, z is in tz's standard time, and we need to shift the
2004local clock into tz's daylight time).
2005
2006Let
2007
2008 z' = z + z.d = z + diff [7]
2009
2010and we can again ask whether
2011
2012 z'.n - z'.o = x.n [8]
2013
2014If so, we're done. If not, the tzinfo class is insane, according to the
2015assumptions we've made. This also requires a bit of proof. As before, let's
2016compute the difference between the LHS and RHS of [8] (and skipping some of
2017the justifications for the kinds of substitutions we've done several times
2018already):
2019
2020 diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
2021 x.n - (z.n + diff - z'.o) = replacing diff via [6]
2022 x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
2023 x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
2024 - z.n + z.n - z.o + z'.o = cancel z.n
2025 - z.o + z'.o = #1 twice
2026 -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
2027 z'.d - z.d
2028
2029So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
2030we've found the UTC-equivalent so are done. In fact, we stop with [7] and
2031return z', not bothering to compute z'.d.
2032
2033How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
2034a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
2035would have to change the result dst() returns: we start in DST, and moving
2036a little further into it takes us out of DST.
2037
2038There isn't a sane case where this can happen. The closest it gets is at
2039the end of DST, where there's an hour in UTC with no spelling in a hybrid
2040tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
2041that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
2042UTC) because the docs insist on that, but 0:MM is taken as being in daylight
2043time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
2044clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
2045standard time. Since that's what the local clock *does*, we want to map both
2046UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
2047in local time, but so it goes -- it's the way the local clock works.
2048
2049When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
2050so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
2051z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
2052(correctly) concludes that z' is not UTC-equivalent to x.
2053
2054Because we know z.d said z was in daylight time (else [5] would have held and
2055we would have stopped then), and we know z.d != z'.d (else [8] would have held
2056and we we have stopped then), and there are only 2 possible values dst() can
2057return in Eastern, it follows that z'.d must be 0 (which it is in the example,
2058but the reasoning doesn't depend on the example -- it depends on there being
2059two possible dst() outcomes, one zero and the other non-zero). Therefore
2060z' must be in standard time, and is the spelling we want in this case.
2061
2062Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
2063concerned (because it takes z' as being in standard time rather than the
2064daylight time we intend here), but returning it gives the real-life "local
2065clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
2066tz.
2067
2068When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
2069the 1:MM standard time spelling we want.
2070
2071So how can this break? One of the assumptions must be violated. Two
2072possibilities:
2073
20741) [2] effectively says that y.s is invariant across all y belong to a given
2075 time zone. This isn't true if, for political reasons or continental drift,
2076 a region decides to change its base offset from UTC.
2077
20782) There may be versions of "double daylight" time where the tail end of
2079 the analysis gives up a step too early. I haven't thought about that
2080 enough to say.
2081
2082In any case, it's clear that the default fromutc() is strong enough to handle
2083"almost all" time zones: so long as the standard offset is invariant, it
2084doesn't matter if daylight time transition points change from year to year, or
2085if daylight time is skipped in some years; it doesn't matter how large or
2086small dst() may get within its bounds; and it doesn't even matter if some
2087perverse time zone returns a negative dst()). So a breaking case must be
2088pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
2089"""
2090try:
2091 from _datetime import *
2092except ImportError:
2093 pass
2094else:
2095 # Clean up unused names
2096 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH,
2097 _DI100Y, _DI400Y, _DI4Y, _MAXORDINAL, _MONTHNAMES,
2098 _build_struct_time, _call_tzinfo_method, _check_date_fields,
2099 _check_time_fields, _check_tzinfo_arg, _check_tzname,
2100 _check_utc_offset, _cmp, _cmperror, _date_class, _days_before_month,
2101 _days_before_year, _days_in_month, _format_time, _is_leap,
2102 _isoweek1monday, _math, _ord2ymd, _time, _time_class, _tzinfo_class,
2103 _wrap_strftime, _ymd2ord)
Alexander Belopolskya5658742010-07-23 20:03:53 +00002104 # XXX Since import * above excludes names that start with _,
2105 # docstring does not get overwritten. In the future, it may be
2106 # appropriate to maintain a single module level docstring and
2107 # remove the following line.
2108 from _datetime import __doc__