You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2112 lines
72 KiB

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