comparison planemo/lib/python3.7/site-packages/future/backports/datetime.py @ 0:d30785e31577 draft

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