1
"""Concrete date/time and related types -- prototype implemented in Python.
3
See http://www.zope.org/Members/fdrake/DateTimeWiki/FrontPage
5
See also http://dir.yahoo.com/Reference/calendars/
7
For a primer on DST, including many current DST rules, see
8
http://webexhibits.org/daylightsaving/
10
For more about DST than you ever wanted to know, see
11
ftp://elsie.nci.nih.gov/pub/
13
Sources for time zone and DST data: http://www.twinsun.com/tz/tz-link.htm
15
This was originally copied from the sandbox of the CPython CVS repository.
16
Thanks to Tim Peters for suggesting using it.
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.
34
_DAYS_IN_MONTH = [None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
36
_DAYS_BEFORE_MONTH = [None]
38
for dim in _DAYS_IN_MONTH[1:]:
39
_DAYS_BEFORE_MONTH.append(dbm)
44
"year -> 1 if leap year, else 0."
45
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
47
def _days_in_year(year):
48
"year -> number of days in year (366 if a leap year, else 365)."
49
return 365 + _is_leap(year)
51
def _days_before_year(year):
52
"year -> number of days before January 1st of year."
54
return y*365 + y//4 - y//100 + y//400
56
def _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):
61
return _DAYS_IN_MONTH[month]
63
def _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))
69
def _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) +
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 "
84
# A 4-year cycle has an extra leap day over what we'd get from pasting
85
# together 4 single years.
86
assert _DI4Y == 4 * 365 + 1
88
# Similarly, a 400-year cycle has an extra leap day over what we'd get from
89
# pasting together 4 100-year cycles.
90
assert _DI400Y == 4 * _DI100Y + 1
92
# OTOH, a 100-year cycle has one fewer leap day than we'd get from
93
# pasting together 25 4-year cycles.
94
assert _DI100Y == 25 * _DI4Y - 1
97
"ordinal -> (year, month, day), considering 01-Jan-0001 as day 1."
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:
107
# -- --- ---- ---------- ----------------
108
# 31 Dec -400 -_DI400Y -_DI400Y -1
109
# 1 Jan -399 -_DI400Y +1 -_DI400Y 400-year boundary
113
# 1 Jan 001 1 0 400-year boundary
117
# 31 Dec 400 _DI400Y _DI400Y -1
118
# 1 Jan 401 _DI400Y +1 _DI400Y 400-year boundary
120
n400, n = divmod(n, _DI400Y)
121
year = n400 * 400 + 1 # ..., -399, 1, 401, ...
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)
130
# Now compute how many 4-year cycles precede it.
131
n4, n = divmod(n, _DI4Y)
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)
137
year += n100 * 100 + n4 * 4 + n1
138
if n1 == 4 or n100 == 4:
140
return year-1, 12, 31
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
150
preceding -= _DAYS_IN_MONTH[month] + (month == 2 and leapyear)
152
assert 0 <= n < _days_in_month(year, month)
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
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"]
164
def _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))
169
def _format_time(hh, mm, ss, us):
170
# Skip trailing microseconds when us==0.
171
result = "%02d:%02d:%02d" % (hh, mm, ss)
173
result += ".%06d" % us
176
# Correctly substitute for %z and %Z escapes in strftime formats.
177
def _wrap_strftime(object, format, timetuple):
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
186
# Scan format for %z and %Z escapes, replacing as needed.
188
push = newformat.append
189
i, n = 0, len(format)
200
if hasattr(object, "_utcoffset"):
201
offset = object._utcoffset()
202
if offset is not None:
207
h, m = divmod(offset, 60)
208
zreplace = '%c%02d%02d' % (sign, h, m)
209
assert '%' not in zreplace
210
newformat.append(zreplace)
214
if hasattr(object, "tzname"):
217
# strftime is going to have at this: escape %
218
Zreplace = s.replace('%', '%%')
219
newformat.append(Zreplace)
227
newformat = "".join(newformat)
228
return _time.strftime(newformat, timetuple)
230
def _call_tzinfo_method(tzinfo, methname, tzinfoarg):
233
return getattr(tzinfo, methname)(tzinfoarg)
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))
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")
251
if not isinstance(offset, timedelta):
252
raise TypeError("tzinfo.%s() must return None "
253
"or timedelta, not '%s'" % (name, type(offset)))
255
if days < -1 or days > 0:
256
offset = 1440 # trigger out-of-range
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 "
264
if -1440 < offset < 1440:
266
raise ValueError("%s()=%d, must be in -1439..1439" % (name, offset))
268
def _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)
277
def _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)
287
def _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")
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:
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.
302
# 2. Else __eq__ and __ne__ return False and True, respectively. This is
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.
316
raise TypeError("can't compare '%s' to '%s'" % (
317
type(x).__name__, type(y).__name__))
319
# This is a start at a struct tm workalike. Goals:
321
# + Works the same way across platforms.
322
# + Handles all the fields datetime needs handled, without 1970-2038 glitches.
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).
328
_ORD1970 = _ymd2ord(1970, 1, 1) # base ordinal for UNIX epoch
334
def __init__(self, year, month, day, hour=0, minute=0, second=0,
336
# Normalize all the inputs, and store the normalized values.
337
if not 0 <= microsecond <= 999999:
338
carry, microsecond = divmod(microsecond, 1000000)
340
if not 0 <= second <= 59:
341
carry, second = divmod(second, 60)
343
if not 0 <= minute <= 59:
344
carry, minute = divmod(minute, 60)
346
if not 0 <= hour <= 23:
347
carry, hour = divmod(hour, 24)
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
355
# Saying 12 months == 1 year should be non-controversial.
356
if not 1 <= month <= 12:
357
carry, month = divmod(month-1, 12)
360
assert 1 <= month <= 12
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
374
day = _days_in_month(year, month)
376
year, month, day = year-1, 12, 31
377
elif day == dim + 1: # move forward a day
384
self.ordinal = _ymd2ord(year, month, 1) + (day - 1)
385
year, month, day = _ord2ymd(self.ordinal)
387
self.year, self.month, self.day = year, month, day
388
self.hour, self.minute, self.second = hour, minute, second
389
self.microsecond = microsecond
392
"""Return proleptic Gregorian ordinal for the year, month and day.
394
January 1 of year 1 is day 1. Only the year, month and day values
395
contribute to the result.
397
if self.ordinal is None:
398
self.ordinal = _ymd2ord(self.year, self.month, self.day)
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
408
"Return ctime() style string."
409
weekday = self.toordinal() % 7 or 7
410
return "%s %s %2d %02d:%02d:%02d %04d" % (
412
_MONTHNAMES[self.month],
414
self.hour, self.minute, self.second,
417
class timedelta(object):
418
"""Represent the difference between two datetime objects.
422
- add, subtract timedelta
423
- unary plus, minus, abs
424
- compare to timedelta
425
- multiply, divide by int/long
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.
431
Representation: (days, seconds, microseconds). Why? Because I
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.
446
# XXX Check that all inputs are ints, longs or floats.
448
# Final values, all integer.
449
# s and us fit in 32-bit signed ints; d isn't bounded.
452
# Normalize everything to days, seconds, microseconds.
454
seconds += minutes*60 + hours*3600
455
microseconds += milliseconds*1000
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)
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
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
482
secondsfrac = daysecondsfrac
483
# daysecondsfrac isn't referenced again
484
assert isinstance(secondsfrac, float)
485
assert abs(secondsfrac) <= 2.0
487
assert isinstance(seconds, (int, long))
488
days, seconds = divmod(seconds, 24*3600)
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
495
usdouble = secondsfrac * 1e6
496
assert abs(usdouble) < 2.1e6 # exact value not critical
497
# secondsfrac isn't referenced again
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)
509
s += int(seconds) # can't overflow
510
assert isinstance(s, int)
511
assert abs(s) <= 3 * 24 * 3600
513
seconds, microseconds = divmod(microseconds, 1000000)
514
days, seconds = divmod(seconds, 24*3600)
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
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)
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
539
self = object.__new__(cls)
543
self.__microseconds = us
544
if abs(d) > 999999999:
545
raise OverflowError("timedelta # of days is too large: %d" % d)
550
if self.__microseconds:
551
return "%s(%d, %d, %d)" % ('datetime.' + self.__class__.__name__,
556
return "%s(%d, %d)" % ('datetime.' + self.__class__.__name__,
559
return "%s(%d)" % ('datetime.' + self.__class__.__name__, self.__days)
562
mm, ss = divmod(self.__seconds, 60)
563
hh, mm = divmod(mm, 60)
564
s = "%d:%02d:%02d" % (hh, mm, ss)
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
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,
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
589
def __sub__(self, other):
590
if isinstance(other, timedelta):
592
return NotImplemented
594
def __rsub__(self, other):
595
if isinstance(other, timedelta):
597
return NotImplemented
600
# for CPython compatibility, we cannot use
601
# our __class__ here, but need a real timedelta
602
return timedelta(-self.__days,
604
-self.__microseconds)
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
626
def __div__(self, other):
627
if isinstance(other, (int, long)):
628
usec = ((self.__days * (24*3600L) + self.__seconds) * 1000000 +
630
return timedelta(0, 0, usec // other)
631
return NotImplemented
633
__floordiv__ = __div__
637
def __eq__(self, other):
638
if isinstance(other, timedelta):
639
return self.__cmp(other) == 0
643
def __ne__(self, other):
644
if isinstance(other, timedelta):
645
return self.__cmp(other) != 0
649
def __le__(self, other):
650
if isinstance(other, timedelta):
651
return self.__cmp(other) <= 0
653
_cmperror(self, other)
655
def __lt__(self, other):
656
if isinstance(other, timedelta):
657
return self.__cmp(other) < 0
659
_cmperror(self, other)
661
def __ge__(self, other):
662
if isinstance(other, timedelta):
663
return self.__cmp(other) >= 0
665
_cmperror(self, other)
667
def __gt__(self, other):
668
if isinstance(other, timedelta):
669
return self.__cmp(other) > 0
671
_cmperror(self, other)
673
def __cmp(self, other):
674
assert isinstance(other, timedelta)
675
return cmp(self.__getstate(), other.__getstate())
678
return hash(self.__getstate())
680
def __nonzero__(self):
681
return (self.__days != 0 or
682
self.__seconds != 0 or
683
self.__microseconds != 0)
687
__safe_for_unpickling__ = True # For Python 2.2
689
def __getstate(self):
690
return (self.__days, self.__seconds, self.__microseconds)
692
def __reduce__(self):
693
return (self.__class__, self.__getstate())
695
timedelta.min = timedelta(-999999999)
696
timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
698
timedelta.resolution = timedelta(microseconds=1)
701
"""Concrete date type.
714
__add__, __radd__, __sub__ (add/radd only with timedelta arg)
721
isoweekday(), isocalendar(), isoformat()
725
Properties (readonly):
729
def __new__(cls, year, month=None, day=None):
734
year, month, day (required, base 1)
736
if isinstance(year, str):
738
self = object.__new__(cls)
739
self.__setstate(year)
741
_check_date_fields(year, month, day)
742
self = object.__new__(cls)
748
# Additional constructors
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)
754
fromtimestamp = classmethod(fromtimestamp)
757
"Construct a date from time.time()."
759
return cls.fromtimestamp(t)
760
today = classmethod(today)
762
def fromordinal(cls, n):
763
"""Contruct a date from a proleptic Gregorian ordinal.
765
January 1 of year 1 is day 1. Only the year, month and day are
766
non-zero in the result.
768
y, m, d = _ord2ymd(n)
770
fromordinal = classmethod(fromordinal)
772
# Conversions to string
775
"Convert to formal string, for repr()."
776
return "%s(%d, %d, %d)" % ('datetime.' + self.__class__.__name__,
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.
786
"Format a la ctime()."
787
return tmxxx(self.__year, self.__month, self.__day).ctime()
789
def strftime(self, fmt):
790
"Format using strftime()."
791
return _wrap_strftime(self, fmt, self.timetuple())
794
"""Return the date formatted according to ISO.
796
This is 'YYYY-MM-DD'.
799
- http://www.w3.org/TR/NOTE-datetime
800
- http://www.cl.cam.ac.uk/~mgk25/iso-time.html
802
return "%04d-%02d-%02d" % (self.__year, self.__month, self.__day)
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)")
812
# Standard conversions, __cmp__, __hash__ (and helpers)
815
"Return local time tuple compatible with time.localtime()."
816
return _build_struct_time(self.__year, self.__month, self.__day,
820
"""Return proleptic Gregorian ordinal for the year, month and day.
822
January 1 of year 1 is day 1. Only the year, month and day values
823
contribute to the result.
825
return _ymd2ord(self.__year, self.__month, self.__day)
827
def replace(self, year=None, month=None, day=None):
828
"""Return a new date with new values for the specified fields."""
835
_check_date_fields(year, month, day)
836
return date(year, month, day)
840
def __eq__(self, other):
841
if isinstance(other, date):
842
return self.__cmp(other) == 0
843
elif hasattr(other, "timetuple"):
844
return NotImplemented
848
def __ne__(self, other):
849
if isinstance(other, date):
850
return self.__cmp(other) != 0
851
elif hasattr(other, "timetuple"):
852
return NotImplemented
856
def __le__(self, other):
857
if isinstance(other, date):
858
return self.__cmp(other) <= 0
859
elif hasattr(other, "timetuple"):
860
return NotImplemented
862
_cmperror(self, other)
864
def __lt__(self, other):
865
if isinstance(other, date):
866
return self.__cmp(other) < 0
867
elif hasattr(other, "timetuple"):
868
return NotImplemented
870
_cmperror(self, other)
872
def __ge__(self, other):
873
if isinstance(other, date):
874
return self.__cmp(other) >= 0
875
elif hasattr(other, "timetuple"):
876
return NotImplemented
878
_cmperror(self, other)
880
def __gt__(self, other):
881
if isinstance(other, date):
882
return self.__cmp(other) > 0
883
elif hasattr(other, "timetuple"):
884
return NotImplemented
886
_cmperror(self, other)
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))
896
return hash(self.__getstate())
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))
905
def __add__(self, other):
906
"Add a date to a timedelta."
907
if isinstance(other, timedelta):
908
t = tmxxx(self.__year,
910
self.__day + other.days)
911
self._checkOverflow(t.year)
912
result = date(t.year, t.month, t.day)
915
# XXX Should be 'return NotImplemented', but there's a bug in 2.2...
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
930
"Return day of the week, where Monday == 0 ... Sunday == 6."
931
return (self.toordinal() + 6) % 7
933
# Day-of-the-week and week-of-the-year, according to ISO
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
940
def isocalendar(self):
941
"""Return a 3-tuple containing ISO year, week number, and weekday.
943
The first ISO week of the year is the (Mon-Sun) week
944
containing the year's first Thursday; everything else derives
947
The first week is 1; Monday is 1 ... Sunday is 7.
949
ISO calendar algorithm taken from
950
http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
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)
959
week1monday = _isoweek1monday(year)
960
week, day = divmod(today - week1monday, 7)
962
if today >= _isoweek1monday(year+1):
965
return year, week+1, day+1
969
__safe_for_unpickling__ = True # For Python 2.2
971
def __getstate(self):
972
yhi, ylo = divmod(self.__year, 256)
973
return ("%c%c%c%c" % (yhi, ylo, self.__month, self.__day), )
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
981
def __reduce__(self):
982
return (self.__class__, self.__getstate())
984
_date_class = date # so functions w/ args named "date" can get at the class
986
date.min = date(1, 1, 1)
987
date.max = date(9999, 12, 31)
988
date.resolution = timedelta(days=1)
990
class tzinfo(object):
991
"""Abstract base class for time zone info classes.
993
Subclasses must override the name(), utcoffset() and dst() methods.
996
def tzname(self, dt):
997
"datetime -> string name of time zone."
998
raise NotImplementedError("tzinfo subclass must override tzname()")
1000
def utcoffset(self, dt):
1001
"datetime -> minutes east of UTC (negative for west of UTC)"
1002
raise NotImplementedError("tzinfo subclass must override utcoffset()")
1005
"""datetime -> DST offset in minutes east of UTC.
1007
Return 0 if DST not in effect. utcoffset() must include the DST
1010
raise NotImplementedError("tzinfo subclass must override dst()")
1012
def fromutc(self, dt):
1013
"datetime in UTC -> datetime in local time."
1015
if not isinstance(dt, datetime):
1016
raise TypeError("fromutc() requires a datetime argument")
1017
if dt.tzinfo is not self:
1018
raise ValueError("dt.tzinfo is not self")
1020
dtoff = dt.utcoffset()
1022
raise ValueError("fromutc() requires a non-None utcoffset() "
1025
# See the long comment block at the end of this file for an
1026
# explanation of this algorithm.
1029
raise ValueError("fromutc() requires a non-None dst() result")
1030
delta = dtoff - dtdst
1035
raise ValueError("fromutc(): dt.dst gave inconsistent "
1036
"results; cannot convert")
1044
__safe_for_unpickling__ = True # For Python 2.2
1046
def __reduce__(self):
1047
getinitargs = getattr(self, "__getinitargs__", None)
1049
args = getinitargs()
1052
getstate = getattr(self, "__getstate__", None)
1056
state = getattr(self, "__dict__", None) or None
1058
return (self.__class__, args)
1060
return (self.__class__, args, state)
1062
_tzinfo_class = tzinfo # so functions w/ args named "tinfo" can get at it
1065
"""Time with time zone.
1084
Properties (readonly):
1085
hour, minute, second, microsecond, tzinfo
1088
def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None):
1093
hour, minute (required)
1094
second, microsecond (default to zero)
1095
tzinfo (default to None)
1097
self = object.__new__(cls)
1098
if isinstance(hour, str):
1100
self.__setstate(hour, minute or None)
1102
_check_tzinfo_arg(tzinfo)
1103
_check_time_fields(hour, minute, second, microsecond)
1105
self.__minute = minute
1106
self.__second = second
1107
self.__microsecond = microsecond
1108
self._tzinfo = tzinfo
1111
# Read-only field accessors
1112
hour = property(lambda self: self.__hour, doc="hour (0-23)")
1113
minute = property(lambda self: self.__minute, doc="minute (0-59)")
1114
second = property(lambda self: self.__second, doc="second (0-59)")
1115
microsecond = property(lambda self: self.__microsecond,
1116
doc="microsecond (0-999999)")
1117
tzinfo = property(lambda self: self._tzinfo, doc="timezone info object")
1119
# Standard conversions, __hash__ (and helpers)
1123
def __eq__(self, other):
1124
if isinstance(other, time):
1125
return self.__cmp(other) == 0
1129
def __ne__(self, other):
1130
if isinstance(other, time):
1131
return self.__cmp(other) != 0
1135
def __le__(self, other):
1136
if isinstance(other, time):
1137
return self.__cmp(other) <= 0
1139
_cmperror(self, other)
1141
def __lt__(self, other):
1142
if isinstance(other, time):
1143
return self.__cmp(other) < 0
1145
_cmperror(self, other)
1147
def __ge__(self, other):
1148
if isinstance(other, time):
1149
return self.__cmp(other) >= 0
1151
_cmperror(self, other)
1153
def __gt__(self, other):
1154
if isinstance(other, time):
1155
return self.__cmp(other) > 0
1157
_cmperror(self, other)
1159
def __cmp(self, other):
1160
assert isinstance(other, time)
1162
ottz = other._tzinfo
1163
myoff = otoff = None
1168
myoff = self._utcoffset()
1169
otoff = other._utcoffset()
1170
base_compare = myoff == otoff
1173
return cmp((self.__hour, self.__minute, self.__second,
1174
self.__microsecond),
1175
(other.__hour, other.__minute, other.__second,
1176
other.__microsecond))
1177
if myoff is None or otoff is None:
1178
# XXX Buggy in 2.2.2.
1179
raise TypeError("cannot compare naive and aware times")
1180
myhhmm = self.__hour * 60 + self.__minute - myoff
1181
othhmm = other.__hour * 60 + other.__minute - otoff
1182
return cmp((myhhmm, self.__second, self.__microsecond),
1183
(othhmm, other.__second, other.__microsecond))
1187
tzoff = self._utcoffset()
1188
if not tzoff: # zero or None
1189
return hash(self.__getstate()[0])
1190
h, m = divmod(self.hour * 60 + self.minute - tzoff, 60)
1192
return hash(time(h, m, self.second, self.microsecond))
1193
return hash((h, m, self.second, self.microsecond))
1195
# Conversion to string
1197
def _tzstr(self, sep=":"):
1198
"""Return formatted timezone offset (+xx:xx) or None."""
1199
off = self._utcoffset()
1206
hh, mm = divmod(off, 60)
1208
off = "%s%02d%s%02d" % (sign, hh, sep, mm)
1212
"""Convert to formal string, for repr()."""
1213
if self.__microsecond != 0:
1214
s = ", %d, %d" % (self.__second, self.__microsecond)
1215
elif self.__second != 0:
1216
s = ", %d" % self.__second
1219
s= "%s(%d, %d%s)" % ('datetime.' + self.__class__.__name__,
1220
self.__hour, self.__minute, s)
1221
if self._tzinfo is not None:
1222
assert s[-1:] == ")"
1223
s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
1226
def isoformat(self):
1227
"""Return the time formatted according to ISO.
1229
This is 'HH:MM:SS.mmmmmm+zz:zz', or 'HH:MM:SS+zz:zz' if
1230
self.microsecond == 0.
1232
s = _format_time(self.__hour, self.__minute, self.__second,
1241
def strftime(self, fmt):
1242
"""Format using strftime(). The date part of the timestamp passed
1243
to underlying strftime should not be used.
1245
# The year must be >= 1900 else Python's strftime implementation
1246
# can raise a bogus exception.
1247
timetuple = (1900, 1, 1,
1248
self.__hour, self.__minute, self.__second,
1250
return _wrap_strftime(self, fmt, timetuple)
1252
# Timezone functions
1254
def utcoffset(self):
1255
"""Return the timezone offset in minutes east of UTC (negative west of
1257
offset = _call_tzinfo_method(self._tzinfo, "utcoffset", None)
1258
offset = _check_utc_offset("utcoffset", offset)
1259
if offset is not None:
1260
offset = timedelta(minutes=offset)
1263
# Return an integer (or None) instead of a timedelta (or None).
1264
def _utcoffset(self):
1265
offset = _call_tzinfo_method(self._tzinfo, "utcoffset", None)
1266
offset = _check_utc_offset("utcoffset", offset)
1270
"""Return the timezone name.
1272
Note that the name is 100% informational -- there's no requirement that
1273
it mean anything in particular. For example, "GMT", "UTC", "-500",
1274
"-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1276
name = _call_tzinfo_method(self._tzinfo, "tzname", None)
1281
"""Return 0 if DST is not in effect, or the DST offset (in minutes
1282
eastward) if DST is in effect.
1284
This is purely informational; the DST offset has already been added to
1285
the UTC offset returned by utcoffset() if applicable, so there's no
1286
need to consult dst() unless you're interested in displaying the DST
1289
offset = _call_tzinfo_method(self._tzinfo, "dst", None)
1290
offset = _check_utc_offset("dst", offset)
1291
if offset is not None:
1292
offset = timedelta(minutes=offset)
1295
def replace(self, hour=None, minute=None, second=None, microsecond=None,
1297
"""Return a new time with new values for the specified fields."""
1301
minute = self.minute
1303
second = self.second
1304
if microsecond is None:
1305
microsecond = self.microsecond
1307
tzinfo = self.tzinfo
1308
_check_time_fields(hour, minute, second, microsecond)
1309
_check_tzinfo_arg(tzinfo)
1310
return time(hour, minute, second, microsecond, tzinfo)
1312
# Return an integer (or None) instead of a timedelta (or None).
1314
offset = _call_tzinfo_method(self._tzinfo, "dst", None)
1315
offset = _check_utc_offset("dst", offset)
1318
def __nonzero__(self):
1319
if self.second or self.microsecond:
1321
offset = self._utcoffset() or 0
1322
return self.hour * 60 + self.minute - offset != 0
1326
__safe_for_unpickling__ = True # For Python 2.2
1328
def __getstate(self):
1329
us2, us3 = divmod(self.__microsecond, 256)
1330
us1, us2 = divmod(us2, 256)
1331
basestate = ("%c" * 6) % (self.__hour, self.__minute, self.__second,
1333
if self._tzinfo is None:
1336
return (basestate, self._tzinfo)
1338
def __setstate(self, string, tzinfo):
1339
if len(string) != 6 or ord(string[0]) >= 24:
1340
raise TypeError("an integer is required")
1341
self.__hour, self.__minute, self.__second, us1, us2, us3 = \
1343
self.__microsecond = (((us1 << 8) | us2) << 8) | us3
1344
self._tzinfo = tzinfo
1346
def __reduce__(self):
1347
return (time, self.__getstate())
1349
_time_class = time # so functions w/ args named "time" can get at the class
1351
time.min = time(0, 0, 0)
1352
time.max = time(23, 59, 59, 999999)
1353
time.resolution = timedelta(microseconds=1)
1355
class datetime(date):
1357
# XXX needs docstrings
1358
# See http://www.zope.org/Members/fdrake/DateTimeWiki/TimeZoneInfo
1360
def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
1361
microsecond=0, tzinfo=None):
1362
if isinstance(year, str):
1364
self = date.__new__(cls, year[:4])
1365
self.__setstate(year, month)
1367
_check_tzinfo_arg(tzinfo)
1368
_check_time_fields(hour, minute, second, microsecond)
1369
self = date.__new__(cls, year, month, day)
1370
# XXX This duplicates __year, __month, __day for convenience :-(
1372
self.__month = month
1375
self.__minute = minute
1376
self.__second = second
1377
self.__microsecond = microsecond
1378
self._tzinfo = tzinfo
1381
# Read-only field accessors
1382
hour = property(lambda self: self.__hour, doc="hour (0-23)")
1383
minute = property(lambda self: self.__minute, doc="minute (0-59)")
1384
second = property(lambda self: self.__second, doc="second (0-59)")
1385
microsecond = property(lambda self: self.__microsecond,
1386
doc="microsecond (0-999999)")
1387
tzinfo = property(lambda self: self._tzinfo, doc="timezone info object")
1389
def fromtimestamp(cls, t, tz=None):
1390
"""Construct a datetime from a POSIX timestamp (like time.time()).
1392
A timezone info object may be passed in as well.
1395
_check_tzinfo_arg(tz)
1397
converter = _time.localtime
1399
converter = _time.gmtime
1400
y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1401
us = int((t % 1.0) * 1000000)
1402
ss = min(ss, 59) # clamp out leap seconds if the platform has them
1403
result = cls(y, m, d, hh, mm, ss, us, tz)
1405
result = tz.fromutc(result)
1407
fromtimestamp = classmethod(fromtimestamp)
1409
def utcfromtimestamp(cls, t):
1410
"Construct a UTC datetime from a POSIX timestamp (like time.time())."
1411
y, m, d, hh, mm, ss, weekday, jday, dst = _time.gmtime(t)
1412
us = int((t % 1.0) * 1000000)
1413
ss = min(ss, 59) # clamp out leap seconds if the platform has them
1414
return cls(y, m, d, hh, mm, ss, us)
1415
utcfromtimestamp = classmethod(utcfromtimestamp)
1417
# XXX This is supposed to do better than we *can* do by using time.time(),
1418
# XXX if the platform supports a more accurate way. The C implementation
1419
# XXX uses gettimeofday on platforms that have it, but that isn't
1420
# XXX available from Python. So now() may return different results
1421
# XXX across the implementations.
1422
def now(cls, tz=None):
1423
"Construct a datetime from time.time() and optional time zone info."
1425
return cls.fromtimestamp(t, tz)
1426
now = classmethod(now)
1429
"Construct a UTC datetime from time.time()."
1431
return cls.utcfromtimestamp(t)
1432
utcnow = classmethod(utcnow)
1434
def combine(cls, date, time):
1435
"Construct a datetime from a given date and a given time."
1436
if not isinstance(date, _date_class):
1437
raise TypeError("date argument must be a date instance")
1438
if not isinstance(time, _time_class):
1439
raise TypeError("time argument must be a time instance")
1440
return cls(date.year, date.month, date.day,
1441
time.hour, time.minute, time.second, time.microsecond,
1443
combine = classmethod(combine)
1445
def timetuple(self):
1446
"Return local time tuple compatible with time.localtime()."
1452
return _build_struct_time(self.year, self.month, self.day,
1453
self.hour, self.minute, self.second,
1456
def utctimetuple(self):
1457
"Return UTC time tuple compatible with time.gmtime()."
1458
y, m, d = self.year, self.month, self.day
1459
hh, mm, ss = self.hour, self.minute, self.second
1460
offset = self._utcoffset()
1461
if offset: # neither None nor 0
1462
tm = tmxxx(y, m, d, hh, mm - offset)
1463
y, m, d = tm.year, tm.month, tm.day
1464
hh, mm = tm.hour, tm.minute
1465
return _build_struct_time(y, m, d, hh, mm, ss, 0)
1468
"Return the date part."
1469
return date(self.__year, self.__month, self.__day)
1472
"Return the time part, with tzinfo None."
1473
return time(self.hour, self.minute, self.second, self.microsecond)
1476
"Return the time part, with same tzinfo."
1477
return time(self.hour, self.minute, self.second, self.microsecond,
1480
def replace(self, year=None, month=None, day=None, hour=None,
1481
minute=None, second=None, microsecond=None, tzinfo=True):
1482
"""Return a new datetime with new values for the specified fields."""
1492
minute = self.minute
1494
second = self.second
1495
if microsecond is None:
1496
microsecond = self.microsecond
1498
tzinfo = self.tzinfo
1499
_check_date_fields(year, month, day)
1500
_check_time_fields(hour, minute, second, microsecond)
1501
_check_tzinfo_arg(tzinfo)
1502
return datetime(year, month, day, hour, minute, second,
1503
microsecond, tzinfo)
1505
def astimezone(self, tz):
1506
if not isinstance(tz, tzinfo):
1507
raise TypeError("tz argument must be an instance of tzinfo")
1511
raise ValueError("astimezone() requires an aware datetime")
1516
# Convert self to UTC, and attach the new time zone object.
1517
myoffset = self.utcoffset()
1518
if myoffset is None:
1519
raise ValuError("astimezone() requires an aware datetime")
1520
utc = (self - myoffset).replace(tzinfo=tz)
1522
# Convert from UTC to tz's local time.
1523
return tz.fromutc(utc)
1525
# Ways to produce a string.
1528
"Format a la ctime()."
1529
t = tmxxx(self.__year, self.__month, self.__day, self.__hour,
1530
self.__minute, self.__second)
1533
def isoformat(self, sep='T'):
1534
"""Return the time formatted according to ISO.
1536
This is 'YYYY-MM-DD HH:MM:SS.mmmmmm', or 'YYYY-MM-DD HH:MM:SS' if
1537
self.microsecond == 0.
1539
If self.tzinfo is not None, the UTC offset is also attached, giving
1540
'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM' or 'YYYY-MM-DD HH:MM:SS+HH:MM'.
1542
Optional argument sep specifies the separator between date and
1545
s = ("%04d-%02d-%02d%c" % (self.__year, self.__month, self.__day,
1547
_format_time(self.__hour, self.__minute, self.__second,
1548
self.__microsecond))
1549
off = self._utcoffset()
1556
hh, mm = divmod(off, 60)
1557
s += "%s%02d:%02d" % (sign, hh, mm)
1561
"Convert to formal string, for repr()."
1562
L = [self.__year, self.__month, self.__day, # These are never zero
1563
self.__hour, self.__minute, self.__second, self.__microsecond]
1566
s = ", ".join(map(str, L))
1567
s = "%s(%s)" % ('datetime.' + self.__class__.__name__, s)
1568
if self._tzinfo is not None:
1569
assert s[-1:] == ")"
1570
s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
1574
"Convert to string, for str()."
1575
return self.isoformat(sep=' ')
1577
def utcoffset(self):
1578
"""Return the timezone offset in minutes east of UTC (negative west of
1580
offset = _call_tzinfo_method(self._tzinfo, "utcoffset", self)
1581
offset = _check_utc_offset("utcoffset", offset)
1582
if offset is not None:
1583
offset = timedelta(minutes=offset)
1586
# Return an integer (or None) instead of a timedelta (or None).
1587
def _utcoffset(self):
1588
offset = _call_tzinfo_method(self._tzinfo, "utcoffset", self)
1589
offset = _check_utc_offset("utcoffset", offset)
1593
"""Return the timezone name.
1595
Note that the name is 100% informational -- there's no requirement that
1596
it mean anything in particular. For example, "GMT", "UTC", "-500",
1597
"-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
1599
name = _call_tzinfo_method(self._tzinfo, "tzname", self)
1604
"""Return 0 if DST is not in effect, or the DST offset (in minutes
1605
eastward) if DST is in effect.
1607
This is purely informational; the DST offset has already been added to
1608
the UTC offset returned by utcoffset() if applicable, so there's no
1609
need to consult dst() unless you're interested in displaying the DST
1612
offset = _call_tzinfo_method(self._tzinfo, "dst", self)
1613
offset = _check_utc_offset("dst", offset)
1614
if offset is not None:
1615
offset = timedelta(minutes=offset)
1618
# Return an integer (or None) instead of a timedelta (or None).1573
1620
offset = _call_tzinfo_method(self._tzinfo, "dst", self)
1621
offset = _check_utc_offset("dst", offset)
1626
def __eq__(self, other):
1627
if isinstance(other, datetime):
1628
return self.__cmp(other) == 0
1629
elif hasattr(other, "timetuple") and not isinstance(other, date):
1630
return NotImplemented
1634
def __ne__(self, other):
1635
if isinstance(other, datetime):
1636
return self.__cmp(other) != 0
1637
elif hasattr(other, "timetuple") and not isinstance(other, date):
1638
return NotImplemented
1642
def __le__(self, other):
1643
if isinstance(other, datetime):
1644
return self.__cmp(other) <= 0
1645
elif hasattr(other, "timetuple") and not isinstance(other, date):
1646
return NotImplemented
1648
_cmperror(self, other)
1650
def __lt__(self, other):
1651
if isinstance(other, datetime):
1652
return self.__cmp(other) < 0
1653
elif hasattr(other, "timetuple") and not isinstance(other, date):
1654
return NotImplemented
1656
_cmperror(self, other)
1658
def __ge__(self, other):
1659
if isinstance(other, datetime):
1660
return self.__cmp(other) >= 0
1661
elif hasattr(other, "timetuple") and not isinstance(other, date):
1662
return NotImplemented
1664
_cmperror(self, other)
1666
def __gt__(self, other):
1667
if isinstance(other, datetime):
1668
return self.__cmp(other) > 0
1669
elif hasattr(other, "timetuple") and not isinstance(other, date):
1670
return NotImplemented
1672
_cmperror(self, other)
1674
def __cmp(self, other):
1675
assert isinstance(other, datetime)
1677
ottz = other._tzinfo
1678
myoff = otoff = None
1683
if mytz is not None:
1684
myoff = self._utcoffset()
1685
if ottz is not None:
1686
otoff = other._utcoffset()
1687
base_compare = myoff == otoff
1690
return cmp((self.__year, self.__month, self.__day,
1691
self.__hour, self.__minute, self.__second,
1692
self.__microsecond),
1693
(other.__year, other.__month, other.__day,
1694
other.__hour, other.__minute, other.__second,
1695
other.__microsecond))
1696
if myoff is None or otoff is None:
1697
# XXX Buggy in 2.2.2.
1698
raise TypeError("cannot compare naive and aware datetimes")
1699
# XXX What follows could be done more efficiently...
1700
diff = self - other # this will take offsets into account
1703
return diff and 1 or 0
1705
def __add__(self, other):
1706
"Add a datetime and a timedelta."
1707
if not isinstance(other, timedelta):
1708
return NotImplemented
1709
t = tmxxx(self.__year,
1711
self.__day + other.days,
1714
self.__second + other.seconds,
1715
self.__microsecond + other.microseconds)
1716
self._checkOverflow(t.year)
1717
result = datetime(t.year, t.month, t.day,
1718
t.hour, t.minute, t.second,
1719
t.microsecond, tzinfo=self._tzinfo)
1724
def __sub__(self, other):
1725
"Subtract two datetimes, or a datetime and a timedelta."
1726
if not isinstance(other, datetime):
1727
if isinstance(other, timedelta):
1728
return self + -other
1729
return NotImplemented
1731
days1 = self.toordinal()
1732
days2 = other.toordinal()
1733
secs1 = self.__second + self.__minute * 60 + self.__hour * 3600
1734
secs2 = other.__second + other.__minute * 60 + other.__hour * 3600
1735
base = timedelta(days1 - days2,
1737
self.__microsecond - other.__microsecond)
1738
if self._tzinfo is other._tzinfo:
1740
myoff = self._utcoffset()
1741
otoff = other._utcoffset()
1744
if myoff is None or otoff is None:
1745
raise TypeError, "cannot mix naive and timezone-aware time"
1746
return base + timedelta(minutes = otoff-myoff)
1749
tzoff = self._utcoffset()
1751
return hash(self.__getstate()[0])
1752
days = _ymd2ord(self.year, self.month, self.day)
1753
seconds = self.hour * 3600 + (self.minute - tzoff) * 60 + self.second
1754
return hash(timedelta(days, seconds, self.microsecond))
1758
__safe_for_unpickling__ = True # For Python 2.2
1760
def __getstate(self):
1761
yhi, ylo = divmod(self.__year, 256)
1762
us2, us3 = divmod(self.__microsecond, 256)
1763
us1, us2 = divmod(us2, 256)
1764
basestate = ("%c" * 10) % (yhi, ylo, self.__month, self.__day,
1765
self.__hour, self.__minute, self.__second,
1767
if self._tzinfo is None:
1770
return (basestate, self._tzinfo)
1772
def __setstate(self, string, tzinfo):
1773
(yhi, ylo, self.__month, self.__day, self.__hour,
1774
self.__minute, self.__second, us1, us2, us3) = map(ord, string)
1775
self.__year = yhi * 256 + ylo
1776
self.__microsecond = (((us1 << 8) | us2) << 8) | us3
1777
self._tzinfo = tzinfo
1779
def __reduce__(self):
1780
return (self.__class__, self.__getstate())
1783
datetime.min = datetime(1, 1, 1)
1784
datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1785
datetime.resolution = timedelta(microseconds=1)
1788
def _isoweek1monday(year):
1789
# Helper to calculate the day number of the Monday starting week 1
1790
# XXX This could be done more efficiently
1792
firstday = _ymd2ord(year, 1, 1)
1793
firstweekday = (firstday + 6) % 7 # See weekday() above
1794
week1monday = firstday - firstweekday
1795
if firstweekday > THURSDAY:
1800
Some time zone algebra. For a datetime x, let
1801
x.n = x stripped of its timezone -- its naive time.
1802
x.o = x.utcoffset(), and assuming that doesn't raise an exception or
1804
x.d = x.dst(), and assuming that doesn't raise an exception or
1806
x.s = x's standard offset, x.o - x.d
1808
Now some derived rules, where k is a duration (timedelta).
1811
This follows from the definition of x.s.
1813
2. If x and y have the same tzinfo member, x.s = y.s.
1814
This is actually a requirement, an assumption we need to make about
1815
sane tzinfo classes.
1817
3. The naive UTC time corresponding to x is x.n - x.o.
1818
This is again a requirement for a sane tzinfo class.
1821
This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
1823
5. (x+k).n = x.n + k
1824
Again follows from how arithmetic is defined.
1826
Now we can explain tz.fromutc(x). Let's assume it's an interesting case
1827
(meaning that the various tzinfo methods exist, and don't blow up or return
1830
The function wants to return a datetime y with timezone tz, equivalent to x.
1831
x is already in UTC.
1837
The algorithm starts by attaching tz to x.n, and calling that y. So
1838
x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
1839
becomes true; in effect, we want to solve [2] for k:
1841
(y+k).n - (y+k).o = x.n [2]
1843
By #1, this is the same as
1845
(y+k).n - ((y+k).s + (y+k).d) = x.n [3]
1847
By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
1848
Substituting that into [3],
1850
x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
1851
k - (y+k).s - (y+k).d = 0; rearranging,
1852
k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
1855
On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
1856
approximate k by ignoring the (y+k).d term at first. Note that k can't be
1857
very large, since all offset-returning methods return a duration of magnitude
1858
less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
1859
be 0, so ignoring it has no consequence then.
1861
In any case, the new value is
1865
It's helpful to step back at look at [4] from a higher level: it's simply
1866
mapping from UTC to tz's standard time.
1872
we have an equivalent time, and are almost done. The insecurity here is
1873
at the start of daylight time. Picture US Eastern for concreteness. The wall
1874
time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
1875
sense then. The docs ask that an Eastern tzinfo class consider such a time to
1876
be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
1877
on the day DST starts. We want to return the 1:MM EST spelling because that's
1878
the only spelling that makes sense on the local wall clock.
1880
In fact, if [5] holds at this point, we do have the standard-time spelling,
1881
but that takes a bit of proof. We first prove a stronger result. What's the
1882
difference between the LHS and RHS of [5]? Let
1884
diff = x.n - (z.n - z.o) [6]
1889
y.n + y.s = since y.n = x.n
1890
x.n + y.s = since z and y are have the same tzinfo member,
1894
Plugging that back into [6] gives
1897
x.n - ((x.n + z.s) - z.o) = expanding
1898
x.n - x.n - z.s + z.o = cancelling
1904
If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
1905
spelling we wanted in the endcase described above. We're done. Contrarily,
1906
if z.d = 0, then we have a UTC equivalent, and are also done.
1908
If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
1909
add to z (in effect, z is in tz's standard time, and we need to shift the
1910
local clock into tz's daylight time).
1914
z' = z + z.d = z + diff [7]
1916
and we can again ask whether
1918
z'.n - z'.o = x.n [8]
1920
If so, we're done. If not, the tzinfo class is insane, according to the
1921
assumptions we've made. This also requires a bit of proof. As before, let's
1922
compute the difference between the LHS and RHS of [8] (and skipping some of
1923
the justifications for the kinds of substitutions we've done several times
1926
diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
1927
x.n - (z.n + diff - z'.o) = replacing diff via [6]
1928
x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
1929
x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
1930
- z.n + z.n - z.o + z'.o = cancel z.n
1931
- z.o + z'.o = #1 twice
1932
-z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
1935
So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
1936
we've found the UTC-equivalent so are done. In fact, we stop with [7] and
1937
return z', not bothering to compute z'.d.
1939
How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
1940
a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
1941
would have to change the result dst() returns: we start in DST, and moving
1942
a little further into it takes us out of DST.
1944
There isn't a sane case where this can happen. The closest it gets is at
1945
the end of DST, where there's an hour in UTC with no spelling in a hybrid
1946
tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
1947
that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
1948
UTC) because the docs insist on that, but 0:MM is taken as being in daylight
1949
time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
1950
clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
1951
standard time. Since that's what the local clock *does*, we want to map both
1952
UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
1953
in local time, but so it goes -- it's the way the local clock works.
1955
When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
1956
so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
1957
z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
1958
(correctly) concludes that z' is not UTC-equivalent to x.
1960
Because we know z.d said z was in daylight time (else [5] would have held and
1961
we would have stopped then), and we know z.d != z'.d (else [8] would have held
1962
and we we have stopped then), and there are only 2 possible values dst() can
1963
return in Eastern, it follows that z'.d must be 0 (which it is in the example,
1964
but the reasoning doesn't depend on the example -- it depends on there being
1965
two possible dst() outcomes, one zero and the other non-zero). Therefore
1966
z' must be in standard time, and is the spelling we want in this case.
1968
Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
1969
concerned (because it takes z' as being in standard time rather than the
1970
daylight time we intend here), but returning it gives the real-life "local
1971
clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
1974
When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
1975
the 1:MM standard time spelling we want.
1977
So how can this break? One of the assumptions must be violated. Two
1980
1) [2] effectively says that y.s is invariant across all y belong to a given
1981
time zone. This isn't true if, for political reasons or continental drift,
1982
a region decides to change its base offset from UTC.
1984
2) There may be versions of "double daylight" time where the tail end of
1985
the analysis gives up a step too early. I haven't thought about that
1988
In any case, it's clear that the default fromutc() is strong enough to handle
1989
"almost all" time zones: so long as the standard offset is invariant, it
1990
doesn't matter if daylight time transition points change from year to year, or
1991
if daylight time is skipped in some years; it doesn't matter how large or
1992
small dst() may get within its bounds; and it doesn't even matter if some
1993
perverse time zone returns a negative dst()). So a breaking case must be
1994
pretty bizarre, and a tzinfo subclass can override fromutc() if it is.