~ubuntu-branches/ubuntu/karmic/pypy/karmic

« back to all changes in this revision

Viewing changes to pypy/lib/datetime.py

  • Committer: Bazaar Package Importer
  • Author(s): Alexandre Fayolle
  • Date: 2007-04-13 09:33:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070413093309-yoojh4jcoocu2krz
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""Concrete date/time and related types -- prototype implemented in Python.
 
2
 
 
3
See http://www.zope.org/Members/fdrake/DateTimeWiki/FrontPage
 
4
 
 
5
See also http://dir.yahoo.com/Reference/calendars/
 
6
 
 
7
For a primer on DST, including many current DST rules, see
 
8
http://webexhibits.org/daylightsaving/
 
9
 
 
10
For more about DST than you ever wanted to know, see
 
11
ftp://elsie.nci.nih.gov/pub/
 
12
 
 
13
Sources for time zone and DST data: http://www.twinsun.com/tz/tz-link.htm
 
14
 
 
15
This was originally copied from the sandbox of the CPython CVS repository.
 
16
Thanks to Tim Peters for suggesting using it. 
 
17
"""
 
18
 
 
19
import time as _time
 
20
import math as _math
 
21
 
 
22
MINYEAR = 1
 
23
MAXYEAR = 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]
 
37
dbm = 0
 
38
for dim in _DAYS_IN_MONTH[1:]:
 
39
    _DAYS_BEFORE_MONTH.append(dbm)
 
40
    dbm += dim
 
41
del dbm, dim
 
42
 
 
43
def _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
 
 
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)
 
50
 
 
51
def _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
 
 
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):
 
60
        return 29
 
61
    return _DAYS_IN_MONTH[month]
 
62
 
 
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))
 
68
 
 
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) +
 
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.
 
86
assert _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.
 
90
assert _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.
 
94
assert _DI100Y == 25 * _DI4Y - 1
 
95
 
 
96
def _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
 
 
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))
 
168
 
 
169
def _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.
 
177
def _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
 
 
230
def _call_tzinfo_method(tzinfo, methname, tzinfoarg):
 
231
    if tzinfo is None:
 
232
        return None
 
233
    return getattr(tzinfo, methname)(tzinfoarg)
 
234
 
 
235
# Just raise TypeError if the arg isn't None or a string.
 
236
def _check_tzname(name):
 
237
    if name is not None and not isinstance(name, str):
 
238
        raise TypeError("tzinfo.tzname() must return None or string, "
 
239
                        "not '%s'" % type(name))
 
240
 
 
241
# name is the offset-producing method, "utcoffset" or "dst".
 
242
# offset is what it returned.
 
243
# If offset isn't None or timedelta, raises TypeError.
 
244
# If offset is None, returns None.
 
245
# Else offset is checked for being in range, and a whole # of minutes.
 
246
# If it is, its integer value is returned.  Else ValueError is raised.
 
247
def _check_utc_offset(name, offset):
 
248
    assert name in ("utcoffset", "dst")
 
249
    if offset is None:
 
250
        return 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
 
 
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)
 
276
 
 
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)
 
286
 
 
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")
 
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
 
 
315
def _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
 
 
330
class 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
 
 
417
class 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
 
 
695
timedelta.min = timedelta(-999999999)
 
696
timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
 
697
                          microseconds=999999)
 
698
timedelta.resolution = timedelta(microseconds=1)
 
699
 
 
700
class 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
_date_class = date  # so functions w/ args named "date" can get at the class
 
985
 
 
986
date.min = date(1, 1, 1)
 
987
date.max = date(9999, 12, 31)
 
988
date.resolution = timedelta(days=1)
 
989
 
 
990
class tzinfo(object):
 
991
    """Abstract base class for time zone info classes.
 
992
 
 
993
    Subclasses must override the name(), utcoffset() and dst() methods.
 
994
    """
 
995
 
 
996
    def tzname(self, dt):
 
997
        "datetime -> string name of time zone."
 
998
        raise NotImplementedError("tzinfo subclass must override tzname()")
 
999
 
 
1000
    def utcoffset(self, dt):
 
1001
        "datetime -> minutes east of UTC (negative for west of UTC)"
 
1002
        raise NotImplementedError("tzinfo subclass must override utcoffset()")
 
1003
 
 
1004
    def dst(self, dt):
 
1005
        """datetime -> DST offset in minutes east of UTC.
 
1006
 
 
1007
        Return 0 if DST not in effect.  utcoffset() must include the DST
 
1008
        offset.
 
1009
        """
 
1010
        raise NotImplementedError("tzinfo subclass must override dst()")
 
1011
 
 
1012
    def fromutc(self, dt):
 
1013
        "datetime in UTC -> datetime in local time."
 
1014
 
 
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")
 
1019
 
 
1020
        dtoff = dt.utcoffset()
 
1021
        if dtoff is None:
 
1022
            raise ValueError("fromutc() requires a non-None utcoffset() "
 
1023
                             "result")
 
1024
 
 
1025
        # See the long comment block at the end of this file for an
 
1026
        # explanation of this algorithm.
 
1027
        dtdst = dt.dst()
 
1028
        if dtdst is None:
 
1029
            raise ValueError("fromutc() requires a non-None dst() result")
 
1030
        delta = dtoff - dtdst
 
1031
        if delta:
 
1032
            dt += delta
 
1033
            dtdst = dt.dst()
 
1034
            if dtdst is None:
 
1035
                raise ValueError("fromutc(): dt.dst gave inconsistent "
 
1036
                                 "results; cannot convert")
 
1037
        if dtdst:
 
1038
            return dt + dtdst
 
1039
        else:
 
1040
            return dt
 
1041
 
 
1042
    # Pickle support.
 
1043
 
 
1044
    __safe_for_unpickling__ = True      # For Python 2.2
 
1045
 
 
1046
    def __reduce__(self):
 
1047
        getinitargs = getattr(self, "__getinitargs__", None)
 
1048
        if getinitargs:
 
1049
            args = getinitargs()
 
1050
        else:
 
1051
            args = ()
 
1052
        getstate = getattr(self, "__getstate__", None)
 
1053
        if getstate:
 
1054
            state = getstate()
 
1055
        else:
 
1056
            state = getattr(self, "__dict__", None) or None
 
1057
        if state is None:
 
1058
            return (self.__class__, args)
 
1059
        else:
 
1060
            return (self.__class__, args, state)
 
1061
 
 
1062
_tzinfo_class = tzinfo   # so functions w/ args named "tinfo" can get at it
 
1063
 
 
1064
class time(object):
 
1065
    """Time with time zone.
 
1066
 
 
1067
    Constructors:
 
1068
 
 
1069
    __new__()
 
1070
 
 
1071
    Operators:
 
1072
 
 
1073
    __repr__, __str__
 
1074
    __cmp__, __hash__
 
1075
 
 
1076
    Methods:
 
1077
 
 
1078
    strftime()
 
1079
    isoformat()
 
1080
    utcoffset()
 
1081
    tzname()
 
1082
    dst()
 
1083
 
 
1084
    Properties (readonly):
 
1085
    hour, minute, second, microsecond, tzinfo
 
1086
    """
 
1087
 
 
1088
    def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None):
 
1089
        """Constructor.
 
1090
 
 
1091
        Arguments:
 
1092
 
 
1093
        hour, minute (required)
 
1094
        second, microsecond (default to zero)
 
1095
        tzinfo (default to None)
 
1096
        """
 
1097
        self = object.__new__(cls)
 
1098
        if isinstance(hour, str):
 
1099
            # Pickle support
 
1100
            self.__setstate(hour, minute or None)
 
1101
            return self
 
1102
        _check_tzinfo_arg(tzinfo)
 
1103
        _check_time_fields(hour, minute, second, microsecond)
 
1104
        self.__hour = hour
 
1105
        self.__minute = minute
 
1106
        self.__second = second
 
1107
        self.__microsecond = microsecond
 
1108
        self._tzinfo = tzinfo
 
1109
        return self
 
1110
 
 
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")
 
1118
 
 
1119
    # Standard conversions, __hash__ (and helpers)
 
1120
 
 
1121
    # Comparisons.
 
1122
 
 
1123
    def __eq__(self, other):
 
1124
        if isinstance(other, time):
 
1125
            return self.__cmp(other) == 0
 
1126
        else:
 
1127
            return False
 
1128
 
 
1129
    def __ne__(self, other):
 
1130
        if isinstance(other, time):
 
1131
            return self.__cmp(other) != 0
 
1132
        else:
 
1133
            return True
 
1134
 
 
1135
    def __le__(self, other):
 
1136
        if isinstance(other, time):
 
1137
            return self.__cmp(other) <= 0
 
1138
        else:
 
1139
            _cmperror(self, other)
 
1140
 
 
1141
    def __lt__(self, other):
 
1142
        if isinstance(other, time):
 
1143
            return self.__cmp(other) < 0
 
1144
        else:
 
1145
            _cmperror(self, other)
 
1146
 
 
1147
    def __ge__(self, other):
 
1148
        if isinstance(other, time):
 
1149
            return self.__cmp(other) >= 0
 
1150
        else:
 
1151
            _cmperror(self, other)
 
1152
 
 
1153
    def __gt__(self, other):
 
1154
        if isinstance(other, time):
 
1155
            return self.__cmp(other) > 0
 
1156
        else:
 
1157
            _cmperror(self, other)
 
1158
 
 
1159
    def __cmp(self, other):
 
1160
        assert isinstance(other, time)
 
1161
        mytz = self._tzinfo
 
1162
        ottz = other._tzinfo
 
1163
        myoff = otoff = None
 
1164
 
 
1165
        if mytz is ottz:
 
1166
            base_compare = True
 
1167
        else:
 
1168
            myoff = self._utcoffset()
 
1169
            otoff = other._utcoffset()
 
1170
            base_compare = myoff == otoff
 
1171
 
 
1172
        if base_compare:
 
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))
 
1184
 
 
1185
    def __hash__(self):
 
1186
        """Hash."""
 
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)
 
1191
        if 0 <= h < 24:
 
1192
            return hash(time(h, m, self.second, self.microsecond))
 
1193
        return hash((h, m, self.second, self.microsecond))
 
1194
 
 
1195
    # Conversion to string
 
1196
 
 
1197
    def _tzstr(self, sep=":"):
 
1198
        """Return formatted timezone offset (+xx:xx) or None."""
 
1199
        off = self._utcoffset()
 
1200
        if off is not None:
 
1201
            if off < 0:
 
1202
                sign = "-"
 
1203
                off = -off
 
1204
            else:
 
1205
                sign = "+"
 
1206
            hh, mm = divmod(off, 60)
 
1207
            assert 0 <= hh < 24
 
1208
            off = "%s%02d%s%02d" % (sign, hh, sep, mm)
 
1209
        return off
 
1210
 
 
1211
    def __repr__(self):
 
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
 
1217
        else:
 
1218
            s = ""
 
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 + ")"
 
1224
        return s
 
1225
 
 
1226
    def isoformat(self):
 
1227
        """Return the time formatted according to ISO.
 
1228
 
 
1229
        This is 'HH:MM:SS.mmmmmm+zz:zz', or 'HH:MM:SS+zz:zz' if
 
1230
        self.microsecond == 0.
 
1231
        """
 
1232
        s = _format_time(self.__hour, self.__minute, self.__second,
 
1233
                         self.__microsecond)
 
1234
        tz = self._tzstr()
 
1235
        if tz:
 
1236
            s += tz
 
1237
        return s
 
1238
 
 
1239
    __str__ = isoformat
 
1240
 
 
1241
    def strftime(self, fmt):
 
1242
        """Format using strftime().  The date part of the timestamp passed
 
1243
        to underlying strftime should not be used.
 
1244
        """
 
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,
 
1249
                     0, 1, -1)
 
1250
        return _wrap_strftime(self, fmt, timetuple)
 
1251
 
 
1252
    # Timezone functions
 
1253
 
 
1254
    def utcoffset(self):
 
1255
        """Return the timezone offset in minutes east of UTC (negative west of
 
1256
        UTC)."""
 
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)
 
1261
        return offset
 
1262
 
 
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)
 
1267
        return offset
 
1268
 
 
1269
    def tzname(self):
 
1270
        """Return the timezone name.
 
1271
 
 
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.
 
1275
        """
 
1276
        name = _call_tzinfo_method(self._tzinfo, "tzname", None)
 
1277
        _check_tzname(name)
 
1278
        return name
 
1279
 
 
1280
    def dst(self):
 
1281
        """Return 0 if DST is not in effect, or the DST offset (in minutes
 
1282
        eastward) if DST is in effect.
 
1283
 
 
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
 
1287
        info.
 
1288
        """
 
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)
 
1293
        return offset
 
1294
 
 
1295
    def replace(self, hour=None, minute=None, second=None, microsecond=None,
 
1296
                tzinfo=True):
 
1297
        """Return a new time with new values for the specified fields."""
 
1298
        if hour is None:
 
1299
            hour = self.hour
 
1300
        if minute is None:
 
1301
            minute = self.minute
 
1302
        if second is None:
 
1303
            second = self.second
 
1304
        if microsecond is None:
 
1305
            microsecond = self.microsecond
 
1306
        if tzinfo is True:
 
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)
 
1311
 
 
1312
    # Return an integer (or None) instead of a timedelta (or None).
 
1313
    def _dst(self):
 
1314
        offset = _call_tzinfo_method(self._tzinfo, "dst", None)
 
1315
        offset = _check_utc_offset("dst", offset)
 
1316
        return offset
 
1317
 
 
1318
    def __nonzero__(self):
 
1319
        if self.second or self.microsecond:
 
1320
            return 1
 
1321
        offset = self._utcoffset() or 0
 
1322
        return self.hour * 60 + self.minute - offset != 0
 
1323
 
 
1324
    # Pickle support.
 
1325
 
 
1326
    __safe_for_unpickling__ = True      # For Python 2.2
 
1327
 
 
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,
 
1332
                                  us1, us2, us3)
 
1333
        if self._tzinfo is None:
 
1334
            return (basestate,)
 
1335
        else:
 
1336
            return (basestate, self._tzinfo)
 
1337
 
 
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 = \
 
1342
                                                            map(ord, string)
 
1343
        self.__microsecond = (((us1 << 8) | us2) << 8) | us3
 
1344
        self._tzinfo = tzinfo
 
1345
 
 
1346
    def __reduce__(self):
 
1347
        return (time, self.__getstate())
 
1348
 
 
1349
_time_class = time  # so functions w/ args named "time" can get at the class
 
1350
 
 
1351
time.min = time(0, 0, 0)
 
1352
time.max = time(23, 59, 59, 999999)
 
1353
time.resolution = timedelta(microseconds=1)
 
1354
 
 
1355
class datetime(date):
 
1356
 
 
1357
    # XXX needs docstrings
 
1358
    # See http://www.zope.org/Members/fdrake/DateTimeWiki/TimeZoneInfo
 
1359
 
 
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):
 
1363
            # Pickle support
 
1364
            self = date.__new__(cls, year[:4])
 
1365
            self.__setstate(year, month)
 
1366
            return self
 
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 :-(
 
1371
        self.__year = year
 
1372
        self.__month = month
 
1373
        self.__day = day
 
1374
        self.__hour = hour
 
1375
        self.__minute = minute
 
1376
        self.__second = second
 
1377
        self.__microsecond = microsecond
 
1378
        self._tzinfo = tzinfo
 
1379
        return self
 
1380
 
 
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")
 
1388
 
 
1389
    def fromtimestamp(cls, t, tz=None):
 
1390
        """Construct a datetime from a POSIX timestamp (like time.time()).
 
1391
 
 
1392
        A timezone info object may be passed in as well.
 
1393
        """
 
1394
 
 
1395
        _check_tzinfo_arg(tz)
 
1396
        if tz is None:
 
1397
            converter = _time.localtime
 
1398
        else:
 
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)
 
1404
        if tz is not None:
 
1405
            result = tz.fromutc(result)
 
1406
        return result
 
1407
    fromtimestamp = classmethod(fromtimestamp)
 
1408
 
 
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)
 
1416
 
 
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."
 
1424
        t = _time.time()
 
1425
        return cls.fromtimestamp(t, tz)
 
1426
    now = classmethod(now)
 
1427
 
 
1428
    def utcnow(cls):
 
1429
        "Construct a UTC datetime from time.time()."
 
1430
        t = _time.time()
 
1431
        return cls.utcfromtimestamp(t)
 
1432
    utcnow = classmethod(utcnow)
 
1433
 
 
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,
 
1442
                   time.tzinfo)
 
1443
    combine = classmethod(combine)
 
1444
 
 
1445
    def timetuple(self):
 
1446
        "Return local time tuple compatible with time.localtime()."
 
1447
        dst = self._dst()
 
1448
        if dst is None:
 
1449
            dst = -1
 
1450
        elif dst:
 
1451
            dst = 1
 
1452
        return _build_struct_time(self.year, self.month, self.day,
 
1453
                                  self.hour, self.minute, self.second,
 
1454
                                  dst)
 
1455
 
 
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)
 
1466
 
 
1467
    def date(self):
 
1468
        "Return the date part."
 
1469
        return date(self.__year, self.__month, self.__day)
 
1470
 
 
1471
    def time(self):
 
1472
        "Return the time part, with tzinfo None."
 
1473
        return time(self.hour, self.minute, self.second, self.microsecond)
 
1474
 
 
1475
    def timetz(self):
 
1476
        "Return the time part, with same tzinfo."
 
1477
        return time(self.hour, self.minute, self.second, self.microsecond,
 
1478
                    self._tzinfo)
 
1479
 
 
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."""
 
1483
        if year is None:
 
1484
            year = self.year
 
1485
        if month is None:
 
1486
            month = self.month
 
1487
        if day is None:
 
1488
            day = self.day
 
1489
        if hour is None:
 
1490
            hour = self.hour
 
1491
        if minute is None:
 
1492
            minute = self.minute
 
1493
        if second is None:
 
1494
            second = self.second
 
1495
        if microsecond is None:
 
1496
            microsecond = self.microsecond
 
1497
        if tzinfo is True:
 
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)
 
1504
 
 
1505
    def astimezone(self, tz):
 
1506
        if not isinstance(tz, tzinfo):
 
1507
            raise TypeError("tz argument must be an instance of tzinfo")
 
1508
 
 
1509
        mytz = self.tzinfo
 
1510
        if mytz is None:
 
1511
            raise ValueError("astimezone() requires an aware datetime")
 
1512
 
 
1513
        if tz is mytz:
 
1514
            return self
 
1515
 
 
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)
 
1521
 
 
1522
        # Convert from UTC to tz's local time.
 
1523
        return tz.fromutc(utc)
 
1524
 
 
1525
    # Ways to produce a string.
 
1526
 
 
1527
    def ctime(self):
 
1528
        "Format a la ctime()."
 
1529
        t = tmxxx(self.__year, self.__month, self.__day, self.__hour,
 
1530
                  self.__minute, self.__second)
 
1531
        return t.ctime()
 
1532
 
 
1533
    def isoformat(self, sep='T'):
 
1534
        """Return the time formatted according to ISO.
 
1535
 
 
1536
        This is 'YYYY-MM-DD HH:MM:SS.mmmmmm', or 'YYYY-MM-DD HH:MM:SS' if
 
1537
        self.microsecond == 0.
 
1538
 
 
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'.
 
1541
 
 
1542
        Optional argument sep specifies the separator between date and
 
1543
        time, default 'T'.
 
1544
        """
 
1545
        s = ("%04d-%02d-%02d%c" % (self.__year, self.__month, self.__day,
 
1546
                                  sep) +
 
1547
                _format_time(self.__hour, self.__minute, self.__second,
 
1548
                             self.__microsecond))
 
1549
        off = self._utcoffset()
 
1550
        if off is not None:
 
1551
            if off < 0:
 
1552
                sign = "-"
 
1553
                off = -off
 
1554
            else:
 
1555
                sign = "+"
 
1556
            hh, mm = divmod(off, 60)
 
1557
            s += "%s%02d:%02d" % (sign, hh, mm)
 
1558
        return s
 
1559
 
 
1560
    def __repr__(self):
 
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]
 
1564
        while L[-1] == 0:
 
1565
            del L[-1]
 
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 + ")"
 
1571
        return s
 
1572
 
 
1573
    def __str__(self):
 
1574
        "Convert to string, for str()."
 
1575
        return self.isoformat(sep=' ')
 
1576
 
 
1577
    def utcoffset(self):
 
1578
        """Return the timezone offset in minutes east of UTC (negative west of
 
1579
        UTC)."""
 
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)
 
1584
        return offset
 
1585
 
 
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)
 
1590
        return offset
 
1591
 
 
1592
    def tzname(self):
 
1593
        """Return the timezone name.
 
1594
 
 
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.
 
1598
        """
 
1599
        name = _call_tzinfo_method(self._tzinfo, "tzname", self)
 
1600
        _check_tzname(name)
 
1601
        return name
 
1602
 
 
1603
    def dst(self):
 
1604
        """Return 0 if DST is not in effect, or the DST offset (in minutes
 
1605
        eastward) if DST is in effect.
 
1606
 
 
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
 
1610
        info.
 
1611
        """
 
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)
 
1616
        return offset
 
1617
 
 
1618
    # Return an integer (or None) instead of a timedelta (or None).1573
 
1619
    def _dst(self):
 
1620
        offset = _call_tzinfo_method(self._tzinfo, "dst", self)
 
1621
        offset = _check_utc_offset("dst", offset)
 
1622
        return offset
 
1623
 
 
1624
    # Comparisons.
 
1625
 
 
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
 
1631
        else:
 
1632
            return False
 
1633
 
 
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
 
1639
        else:
 
1640
            return True
 
1641
 
 
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
 
1647
        else:
 
1648
            _cmperror(self, other)
 
1649
 
 
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
 
1655
        else:
 
1656
            _cmperror(self, other)
 
1657
 
 
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
 
1663
        else:
 
1664
            _cmperror(self, other)
 
1665
 
 
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
 
1671
        else:
 
1672
            _cmperror(self, other)
 
1673
 
 
1674
    def __cmp(self, other):
 
1675
        assert isinstance(other, datetime)
 
1676
        mytz = self._tzinfo
 
1677
        ottz = other._tzinfo
 
1678
        myoff = otoff = None
 
1679
 
 
1680
        if mytz is ottz:
 
1681
            base_compare = True
 
1682
        else:
 
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
 
1688
 
 
1689
        if base_compare:
 
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
 
1701
        if diff.days < 0:
 
1702
            return -1
 
1703
        return diff and 1 or 0
 
1704
 
 
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,
 
1710
                  self.__month,
 
1711
                  self.__day + other.days,
 
1712
                  self.__hour,
 
1713
                  self.__minute,
 
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)
 
1720
        return result
 
1721
 
 
1722
    __radd__ = __add__
 
1723
 
 
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
 
1730
 
 
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,
 
1736
                         secs1 - secs2,
 
1737
                         self.__microsecond - other.__microsecond)
 
1738
        if self._tzinfo is other._tzinfo:
 
1739
            return base
 
1740
        myoff = self._utcoffset()
 
1741
        otoff = other._utcoffset()
 
1742
        if myoff == otoff:
 
1743
            return base
 
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)
 
1747
 
 
1748
    def __hash__(self):
 
1749
        tzoff = self._utcoffset()
 
1750
        if tzoff is None:
 
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))
 
1755
 
 
1756
    # Pickle support.
 
1757
 
 
1758
    __safe_for_unpickling__ = True      # For Python 2.2
 
1759
 
 
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,
 
1766
                                   us1, us2, us3)
 
1767
        if self._tzinfo is None:
 
1768
            return (basestate,)
 
1769
        else:
 
1770
            return (basestate, self._tzinfo)
 
1771
 
 
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
 
1778
 
 
1779
    def __reduce__(self):
 
1780
        return (self.__class__, self.__getstate())
 
1781
 
 
1782
 
 
1783
datetime.min = datetime(1, 1, 1)
 
1784
datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
 
1785
datetime.resolution = timedelta(microseconds=1)
 
1786
 
 
1787
 
 
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
 
1791
    THURSDAY = 3
 
1792
    firstday = _ymd2ord(year, 1, 1)
 
1793
    firstweekday = (firstday + 6) % 7 # See weekday() above
 
1794
    week1monday = firstday - firstweekday
 
1795
    if firstweekday > THURSDAY:
 
1796
        week1monday += 7
 
1797
    return week1monday
 
1798
 
 
1799
"""
 
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
 
1803
          return None
 
1804
    x.d = x.dst(), and assuming that doesn't raise an exception or
 
1805
          return None
 
1806
    x.s = x's standard offset, x.o - x.d
 
1807
 
 
1808
Now some derived rules, where k is a duration (timedelta).
 
1809
 
 
1810
1. x.o = x.s + x.d
 
1811
   This follows from the definition of x.s.
 
1812
 
 
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.
 
1816
 
 
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.
 
1819
 
 
1820
4. (x+k).s = x.s
 
1821
   This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
 
1822
 
 
1823
5. (x+k).n = x.n + k
 
1824
   Again follows from how arithmetic is defined.
 
1825
 
 
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
 
1828
None when called).
 
1829
 
 
1830
The function wants to return a datetime y with timezone tz, equivalent to x.
 
1831
x is already in UTC.
 
1832
 
 
1833
By #3, we want
 
1834
 
 
1835
    y.n - y.o = x.n                             [1]
 
1836
 
 
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:
 
1840
 
 
1841
   (y+k).n - (y+k).o = x.n                      [2]
 
1842
 
 
1843
By #1, this is the same as
 
1844
 
 
1845
   (y+k).n - ((y+k).s + (y+k).d) = x.n          [3]
 
1846
 
 
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],
 
1849
 
 
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
 
1853
   k = y.s - (y+k).d
 
1854
 
 
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.
 
1860
 
 
1861
In any case, the new value is
 
1862
 
 
1863
    z = y + y.s                                 [4]
 
1864
 
 
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.
 
1867
 
 
1868
At this point, if
 
1869
 
 
1870
    z.n - z.o = x.n                             [5]
 
1871
 
 
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.
 
1879
 
 
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
 
1883
 
 
1884
    diff = x.n - (z.n - z.o)                    [6]
 
1885
 
 
1886
Now
 
1887
    z.n =                       by [4]
 
1888
    (y + y.s).n =               by #5
 
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,
 
1891
                                    y.s = z.s by #2
 
1892
    x.n + z.s
 
1893
 
 
1894
Plugging that back into [6] gives
 
1895
 
 
1896
    diff =
 
1897
    x.n - ((x.n + z.s) - z.o) =     expanding
 
1898
    x.n - x.n - z.s + z.o =         cancelling
 
1899
    - z.s + z.o =                   by #2
 
1900
    z.d
 
1901
 
 
1902
So diff = z.d.
 
1903
 
 
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.
 
1907
 
 
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).
 
1911
 
 
1912
Let
 
1913
 
 
1914
    z' = z + z.d = z + diff                     [7]
 
1915
 
 
1916
and we can again ask whether
 
1917
 
 
1918
    z'.n - z'.o = x.n                           [8]
 
1919
 
 
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
 
1924
already):
 
1925
 
 
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
 
1933
            z'.d - z.d
 
1934
 
 
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.
 
1938
 
 
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.
 
1943
 
 
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.
 
1954
 
 
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.
 
1959
 
 
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.
 
1967
 
 
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
 
1972
tz.
 
1973
 
 
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.
 
1976
 
 
1977
So how can this break?  One of the assumptions must be violated.  Two
 
1978
possibilities:
 
1979
 
 
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.
 
1983
 
 
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
 
1986
   enough to say.
 
1987
 
 
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.
 
1995
"""
 
1996