Appendix B. Day of the Week (附录 B. 星期几)
本附录展示了如何从任何公历日期计算星期几。这对于理解为什么 RFC 3339 不包含星期几信息很重要——因为它可以精确计算。
Zeller's Congruence (泽勒同余)
计算星期几的常用算法是泽勒同余 (Zeller's Congruence), 由 Christian Zeller 于 1882 年发明。
Formula (公式)
h = (q + ⌊13(m+1)/5⌋ + K + ⌊K/4⌋ + ⌊J/4⌋ - 2J) mod 7
其中:
h: 星期几 (0 = 星期六, 1 = 星期日, 2 = 星期一, ..., 6 = 星期五)q: 月份中的日期 (1-31)m: 月份 (3-14, 其中 3 = 三月, 4 = 四月, ..., 12 = 十二月, 13 = 一月, 14 = 二月)K: 世纪中的年份 (year % 100)J: 世纪 (⌊year/100⌋)⌊x⌋: 向下取整函数
注意: 一月和二月被视为上一年的第 13 和第 14 个月。
Python Implementation
def day_of_week_zeller(year, month, day):
"""
Calculate day of week using Zeller's formula
Returns: 0=Saturday, 1=Sunday, ..., 6=Friday
"""
# January and February are treated as months 13 and 14 of previous year
if month < 3:
month += 12
year -= 1
q = day
m = month
K = year % 100
J = year // 100
h = (q + (13 * (m + 1)) // 5 + K + K // 4 + J // 4 - 2 * J) % 7
# Convert to common format: 0=Monday, ..., 6=Sunday
# Zeller: 0=Sat, 1=Sun, 2=Mon, 3=Tue, 4=Wed, 5=Thu, 6=Fri
# Adjust to: 0=Mon, 1=Tue, 2=Wed, 3=Thu, 4=Fri, 5=Sat, 6=Sun
return (h + 5) % 7
def day_name(year, month, day):
"""Return name of day of week"""
days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
'Friday', 'Saturday', 'Sunday']
return days[day_of_week_zeller(year, month, day)]
# Examples
print(day_name(2002, 7, 15)) # Monday
print(day_name(2000, 1, 1)) # Saturday
print(day_name(1999, 12, 31)) # Friday
Simpler Algorithm
For programming implementations, a more intuitive algorithm can be used:
def day_of_week_simple(year, month, day):
"""
Simplified day of week calculation
Returns: 0=Monday, ..., 6=Sunday
"""
# Cumulative days before each month (non-leap year)
t = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]
if month < 3:
year -= 1
y = year % 100
c = year // 100
return (y + y // 4 + c // 4 - 2 * c + t[month - 1] + day) % 7
JavaScript Implementation
function dayOfWeek(year, month, day) {
// JavaScript Date object automatically calculates day of week
const date = new Date(year, month - 1, day);
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday'];
return days[date.getDay()];
}
// Examples
console.log(dayOfWeek(2002, 7, 15)); // Monday
Verification Examples
| Date | Day of Week | Verified |
|---|---|---|
| 2002-07-15 | Monday | ✅ |
| 2000-01-01 | Saturday | ✅ |
| 1999-12-31 | Friday | ✅ |
| 1985-04-12 | Friday | ✅ |
| 1990-12-31 | Monday | ✅ |
Why RFC 3339 Doesn't Include Day of Week (为什么 RFC 3339 不包含星期几)
1. Redundant Information (冗余信息)
星期几可以从日期精确计算, 因此包含它会引入潜在的不一致性:
错误示例:
"Monday, 2002-07-16T10:00:00Z"
问题: 2002-07-16 实际上是星期二, 不是星期一
应该信任哪一个? 星期几还是日期?
2. Increased Complexity (增加的复杂性)
解析器需要处理验证和星期几与日期之间的不一致性。
3. Localization Issues (本地化问题)
星期几的名称在不同语言中不同:
英语: Monday, Tuesday, Wednesday, ...
法语: Lundi, Mardi, Mercredi, ...
中文: 星期一, 星期二, 星期三, ...
4. Doesn't Affect Time Point (不影响时间点)
星期几不影响时间点的确定, 它仅用于人类可读性。
Recommendation (建议)
如果需要显示星期几:
from datetime import datetime
# 解析 RFC 3339 时间戳
timestamp = "2002-07-15T10:00:00Z"
dt = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
# 计算并显示星期几
day_name = dt.strftime('%A')
print(f"{timestamp} is a {day_name}")
# 输出: 2002-07-15T10:00:00Z is a Monday
Conclusion (结论): 由于星期几可以从日期精确且确定地计算, 在时间戳格式中包含它不仅不必要, 而且有害。