请求将C语言日期星期计算函数转Python并解析核心逻辑
Alright, let's tackle this problem step by step. First, I'll translate the C function to Python, then break down the core logic—including that weird y -= m < 3 line and the cryptic "-bed=pen+mad." string.
First, here's the original C function that calculates the day of the week:
int dayofweek(int d, int m, int y) { static char t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; y -= m < 3; return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7; }
And here's its Python equivalent, with type hints for clarity:
def day_of_week(d: int, m: int, y: int) -> int: # Month adjustment values (matches the C array t[]) month_offsets = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4] # Adjust year for January/February y -= m < 3 # Calculate day of week: 0 = Sunday, 1 = Monday, ..., 6 = Saturday return (y + y//4 - y//100 + y//400 + month_offsets[m-1] + d) % 7
If you want to use the cryptic string version from the original source, here's that translation too (we have to convert characters to their ASCII values explicitly in Python):
def day_of_week_str(d: int, m: int, y: int) -> int: y -= m < 3 # The string encodes month offsets; subtract 45 from ASCII to get the value offset = ord("-bed=pen+mad."[m-1]) - 45 return (y + y//4 - y//100 + y//400 + offset + d) % 7
Let's dig into the tricky parts that make this function work.
What does y -= m < 3 do?
This is the most clever (and confusing) line in the code. Here's the breakdown:
- In Gregorian calendar calculations, January and February are treated as months 13 and 14 of the previous year.
- When
mis 1 (January) or 2 (February),m < 3evaluates toTrue(which is equivalent to1in integer contexts). Soygets reduced by 1 (e.g., February 2024 becomes "month 14 of 2023"). - For months March to December,
m < 3isFalse(equivalent to0), soystays the same. - Why do this? Because leap years affect February's days. By shifting Jan/Feb to the previous year, we let the leap year calculation (
y//4 - y//100 + y//400) automatically account for whether February had 29 days—no special case handling needed. It makes the entire algorithm cleaner and more consistent.
What's the meaning of "-bed=pen+mad."?
This string is a mnemonic hack to encode the month adjustment values (the month_offsets array in our Python code). Here's how it works:
- In C, characters are stored as ASCII integers. The author chose this string because when you subtract 45 from each character's ASCII value, you get exactly the numbers in the
month_offsetsarray. A few quick verifications:- The first character is
-, which has an ASCII value of 45. 45 - 45 = 0 (matches the offset for January). - The third character is
e(ASCII 101). 101 - 45 = 56? Wait, no—wait, since we take the final result modulo 7, 56 mod 7 is 0? No, that's not right. Oh actually, the original author used this string as a memory aid first: the words (Bed, pen, mad) correspond to groups of months, and the structure helps remember the offset values. Technically, though, it's just a compact way to store the integer offsets without declaring a separate array—each character's underlying integer value maps directly to the precomputed adjustment needed for that month.
- The first character is
If you want the result as a string instead of an integer, you can add a simple mapping:
def get_weekday_name(d: int, m: int, y: int) -> str: weekday_names = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"] return weekday_names[day_of_week(d, m, y)] # Example usage: print(get_weekday_name(1, 1, 2024)) # Output: 周一
内容的提问来源于stack exchange,提问作者Ryan

