Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion Lib/_pydatetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ def _get_class_module(self):
_DAYS_IN_MONTH = [-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

_DAYS_BEFORE_MONTH = [-1] # -1 is a placeholder for indexing purposes.

# This additional list stores the number of odd days before each month in the year.
_ODD_DAYS_BEFORE_MONTH = [-1, 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5] #-1 is a placeholder for indexing purposes.

dbm = 0
for dim in _DAYS_IN_MONTH[1:]:
_DAYS_BEFORE_MONTH.append(dbm)
Expand All @@ -53,6 +57,13 @@ def _days_before_year(year):
y = year - 1
return y*365 + y//4 - y//100 + y//400

def _odd_days_before_year(year):
"year -> number of odd days before January 1st of year."
y = year - 1
r = y%400
m100 = y%100
return r//300 + (r%300)//200*3 + ((r%300)%200)//100*5 + (m100//4)*2 + (m100 - m100//4)

def _days_in_month(year, month):
"year, month -> number of days in that month in that year."
assert 1 <= month <= 12, f"month must be in 1..12, not {month}"
Expand All @@ -74,6 +85,17 @@ def _ymd2ord(year, month, day):
_days_before_month(year, month) +
day)

# This additional function computes the number of odd days before the start of the given year way more reduced here than just multplying years with 365 & 366 and month values.
def _odd_ymd2ord(year, month, day):
"year, month, day -> ordinal, considering 01-Jan-0001 as day 1."
assert 1 <= month <= 12, f"month must be in 1..12, not {month}"
dim = _days_in_month(year, month)
assert 1 <= day <= dim, f"day must be in 1..{dim}, not {day}"
# return (_days_before_year(year) +
# _days_before_month(year, month) +
# day)
return (_odd_days_before_year(year) + _ODD_DAYS_BEFORE_MONTH[month - 1] + day + 1) if(_is_leap(year) and month > 2) else (_odd_days_before_year(year) + _ODD_DAYS_BEFORE_MONTH[month - 1] + day)

_DI400Y = _days_before_year(401) # number of days in 400 years
_DI100Y = _days_before_year(101) # " " " " 100 "
_DI4Y = _days_before_year(5) # " " " " 4 "
Expand Down Expand Up @@ -1181,6 +1203,14 @@ def toordinal(self):
"""
return _ymd2ord(self._year, self._month, self._day)

def to_odd_ordinal(self):
"""Return reduced number of proleptic Gregorian ordinal for the year, month and day.

January 1 of year 1 is day 1. Only the year, month and day values
contribute to the result.
"""
return _odd_ymd2ord(self._year, self._month, self._day)

def replace(self, year=None, month=None, day=None):
"""Return a new date with new values for the specified fields."""
if year is None:
Expand Down Expand Up @@ -1258,7 +1288,7 @@ def __sub__(self, other):

def weekday(self):
"Return day of the week, where Monday == 0 ... Sunday == 6."
return (self.toordinal() + 6) % 7
return (self.to_odd_ordinal()) % 7

# Day-of-the-week and week-of-the-year, according to ISO

Expand Down
31 changes: 30 additions & 1 deletion Modules/_datetimemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,12 @@ static const int _days_before_month[] = {
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
};

/* This additional array stores the number of odd days before each month in the year. */
static const int _odd_days_before_month[] = {
0, /* unused; this vector uses 1-based indexing */
0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5
};

/* year -> 1 if leap year, else 0. */
static int
is_leap(int year)
Expand Down Expand Up @@ -478,6 +484,21 @@ days_before_year(int year)
return y*365 + y/4 - y/100 + y/400;
}

/*This additional function here computes the number of odd days before the start of the given year.*/
static int
odd_days_before_year(int year)
{
int y = year - 1;
/* This is incorrect if year <= 0; we really want the floor
* here. But so long as MINYEAR is 1, the smallest year this
* can see is 1.
*/
assert (year >= 1);
int temp = (y%400);
int mod100 = (y%100);
return temp/300+(temp%300)/200*3+((temp%300)%200)/100*5 + (mod100/4)*2 + (mod100-mod100/4);
}

/* Number of days in 4, 100, and 400 year cycles. That these have
* the correct values is asserted in the module init function.
*/
Expand Down Expand Up @@ -576,11 +597,19 @@ ymd_to_ord(int year, int month, int day)
return days_before_year(year) + days_before_month(year, month) + day;
}

/* This additional function computes the number of odd days before the start of the given year way more reduced here than just multplying years with 365 & 366 and month values. */
/* year, month, day -> ordinal, considering 01-Jan-0001 as day 1. */
static int
odd_ymd_to_ord(int year, int month, int day)
{
return (is_leap(year) && month > 2) ? (odd_days_before_year(year) + _odd_days_before_month[month - 1] + day+1) : (odd_days_before_year(year) + _odd_days_before_month[month - 1] + day);
}

/* Day of week, where Monday==0, ..., Sunday==6. 1/1/1 was a Monday. */
static int
weekday(int year, int month, int day)
{
return (ymd_to_ord(year, month, day) + 6) % 7;
return (odd_ymd_to_ord(year, month, day)) % 7;
}

/* Ordinal of the Monday starting week 1 of the ISO year. Week 1 is the
Expand Down
Loading