Commit e11b510a authored by Raymond Hettinger's avatar Raymond Hettinger

SF 658405: calendar.py to rely on the datetime module instead of the time

module.

The code is shorter, more readable, faster, and dramatically increases the
range of acceptable dates.

Also, used the floor division operator in leapdays().
parent 80475bb4
...@@ -15,10 +15,12 @@ convention). Use \function{setfirstweekday()} to set the first day of the ...@@ -15,10 +15,12 @@ convention). Use \function{setfirstweekday()} to set the first day of the
week to Sunday (6) or to any other weekday. Parameters that specify week to Sunday (6) or to any other weekday. Parameters that specify
dates are given as integers. dates are given as integers.
Most of these functions rely on the platform provided \function{mktime()}. Most of these functions rely on the \module{datetime} module which
Therefore, valid argument values may vary from system to system. uses an idealized calendar, the current Gregorian calendar indefinitely
On Unix, valid years are typically between \code{1970} and \code{2037}, extended in both directions. This matches the definition of the
but may be work between \code{1902} and \code{2037}. "proleptic Gregorian" calendar in Dershowitz and Reingold's book
"Calendrical Calculations", where it's the base calendar for all
computations.
\begin{funcdesc}{setfirstweekday}{weekday} \begin{funcdesc}{setfirstweekday}{weekday}
Sets the weekday (\code{0} is Monday, \code{6} is Sunday) to start Sets the weekday (\code{0} is Monday, \code{6} is Sunday) to start
......
...@@ -5,10 +5,7 @@ default, these calendars have Monday as the first day of the week, and ...@@ -5,10 +5,7 @@ default, these calendars have Monday as the first day of the week, and
Sunday as the last (the European convention). Use setfirstweekday() to Sunday as the last (the European convention). Use setfirstweekday() to
set the first day of the week (0=Monday, 6=Sunday).""" set the first day of the week (0=Monday, 6=Sunday)."""
# Revision 2: uses functions from built-in time module import datetime
# Import functions and variables from time module
from time import localtime, mktime, strftime
__all__ = ["error","setfirstweekday","firstweekday","isleap", __all__ = ["error","setfirstweekday","firstweekday","isleap",
"leapdays","weekday","monthrange","monthcalendar", "leapdays","weekday","monthrange","monthcalendar",
...@@ -35,7 +32,7 @@ class _localized_month: ...@@ -35,7 +32,7 @@ class _localized_month:
self.format = format self.format = format
def __getitem__(self, i): def __getitem__(self, i):
data = [strftime(self.format, (2001, j, 1, 12, 0, 0, 1, 1, 0)) data = [datetime.date(2001, j, 1).strftime(self.format)
for j in range(1, 13)] for j in range(1, 13)]
data.insert(0, "") data.insert(0, "")
return data[i] return data[i]
...@@ -49,7 +46,7 @@ class _localized_day: ...@@ -49,7 +46,7 @@ class _localized_day:
def __getitem__(self, i): def __getitem__(self, i):
# January 1, 2001, was a Monday. # January 1, 2001, was a Monday.
data = [strftime(self.format, (2001, 1, j+1, 12, 0, 0, j, j+1, 0)) data = [datetime.date(2001, 1, j+1).strftime(self.format)
for j in range(7)] for j in range(7)]
return data[i] return data[i]
...@@ -89,14 +86,12 @@ def leapdays(y1, y2): ...@@ -89,14 +86,12 @@ def leapdays(y1, y2):
Assume y1 <= y2.""" Assume y1 <= y2."""
y1 -= 1 y1 -= 1
y2 -= 1 y2 -= 1
return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400) return (y2//4 - y1//4) - (y2//100 - y1//100) + (y2//400 - y1//400)
def weekday(year, month, day): def weekday(year, month, day):
"""Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12), """Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12),
day (1-31).""" day (1-31)."""
secs = mktime((year, month, day, 0, 0, 0, 0, 0, 0)) return datetime.date(year, month, day).weekday()
tuple = localtime(secs)
return tuple[6]
def monthrange(year, month): def monthrange(year, month):
"""Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for """Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for
...@@ -213,17 +208,12 @@ def calendar(year, w=0, l=0, c=_spacing): ...@@ -213,17 +208,12 @@ def calendar(year, w=0, l=0, c=_spacing):
return s[:-l] + '\n' return s[:-l] + '\n'
EPOCH = 1970 EPOCH = 1970
_EPOCH_ORD = datetime.date(EPOCH, 1, 1).toordinal()
def timegm(tuple): def timegm(tuple):
"""Unrelated but handy function to calculate Unix timestamp from GMT.""" """Unrelated but handy function to calculate Unix timestamp from GMT."""
year, month, day, hour, minute, second = tuple[:6] year, month, day, hour, minute, second = tuple[:6]
assert year >= EPOCH days = datetime.date(year, month, day).toordinal() - _EPOCH_ORD
assert 1 <= month <= 12
days = 365*(year-EPOCH) + leapdays(EPOCH, year)
for i in range(1, month):
days = days + mdays[i]
if month > 2 and isleap(year):
days = days + 1
days = days + day - 1
hours = days*24 + hour hours = days*24 + hour
minutes = hours*60 + minute minutes = hours*60 + minute
seconds = minutes*60 + second seconds = minutes*60 + second
......
...@@ -443,6 +443,10 @@ Extension modules ...@@ -443,6 +443,10 @@ Extension modules
Library Library
------- -------
- calendar.py now depends on the new datetime module rather than
the time module. As a result, the range of allowable dates
has been increased.
- pdb has a new 'j(ump)' command to select the next line to be - pdb has a new 'j(ump)' command to select the next line to be
executed. executed.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment