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