注意事项:
在现在广泛使用的阳历中,公元1年(AD 1)之前是公元前1年(1 BC),不存在公元0年。和阳历不同,天文历法(astronomical reckoning)有0年。为了区别起见,天文历法不使用AD和BC,而使用正负号代替。天文年+1对应于公元1年(AD 1),而天文年0对应于公元前1年(1 BC),天文年-1对应于公元前2年(2 BC)。为了方便起见,我在本文及程序中都使用天文历法。
预览:
算法是基于这样的事实:+1年1月1日是星期一,+2年1月1日是星期二,依此类推。这是因为365%7=1!有了这个知识,我写了这个程序。我会解释我怎样得到这个结果的,希望对别人有点帮助。
How and Why
在我写这个程序之前,我注意到没有什么类和控件告诉我+1年1月1日是星期几,因此我想没有简单的传统方法去知道一个随机的日期是星期几。我必须另劈捷径,或者,至少改进旧的。
计算星期几传统的方法是基于一个已知星期数的基准日期。因为基准日期可以随机选择,我选择一个特殊的日期以使事情简单化。1月1日似乎是最好的选择,这样的话我不用考虑从基准日期到该年末有多少天。现在,我该选择哪一年呢?我选择0年。假设我们想知道YYYY年MM月DD日是星期几。如果我们知道了YYYY年1月1日是星期几的话,答案就很容易了。计算YYYY年1月1日的公式:
theDayOfJan_1(YYYY) = ( theDayOfJan_1(0) + YYYY * 365 +
theCountOfFeb_29(YYYY) ) % 7
theCountOfFeb_29(YYYY)是从0年到YYYY年之间2月29日的天数。
不幸的是,YYYY*365的结果可能会溢出。但是幸运的是,我只想知道的是模数。因为
( a + b + c ) % d = ( a %d + b % d + c % d ) % d,
并且:
( a * b ) % d = ( ( a % d ) * ( b % d ) ) %d,
因此:
( YYYY * 365 ) % 7 = ( ( YYYY % 7 ) * ( 365 % 7 ) ) % 7 = YYYY % 7,
theDayOfJan_1(YYYY) = ( theDayOfJan_1(0) % 7 + YYYY % 7 +
theCountOfFeb_29(YYYY) % 7 ) % 7,
但这仍旧还有一个问题;theDayOfJan_1(0)还不知道。好吧,这是我们用上述公式计算的第一个日期,但不是直接计算。公式可以化成:
theDayOfJan_1(0) = ( theDayOfJan_1(YYYY) - YYYY % 7 -
theCountOfFeb_29(YYYY) % 7 + 14 ) % 7,
假设YYYY等于+2000,那么+2000年1月1日是星期六于是:
theDayOfJan_1(2000) = 6,
YYYY % 7 = 2000 % 7 = 5,
theCountOfFeb_29(2000) = 484,
theDayOfJan_1(0) = ( 6 - 5 - 484 % 7 + 14 ) % 7 = 6,
那么说来0年1月1日是星期六。于是+1年1月1日是星期一,依次类推。
by:Jerry Jenkins 2002.10.15
from:codeGuru
翻译:snoopy
环境:Windows Linux