ホームページ  >  記事  >  ウェブフロントエンド  >  カレンダークエリアルゴリズム 特定の日の曜日の計算方法_基礎知識

カレンダークエリアルゴリズム 特定の日の曜日の計算方法_基礎知識

WBOY
WBOYオリジナル
2016-05-16 17:46:422819ブラウズ

特定の日が何曜日であるかを計算するにはどうすればよいですか?
——ツェラーの公式
歴史上の特定の日は何曜日ですか?未来は何曜日ですか?この問題に関しては多くの計算式(一般的な計算式 2 つと区分的計算式の一部)が存在しますが、最も有名なものは Zeller の公式です。つまり、 w=y [y/4] [c/4]-2c [26(m 1)/10] d-1

式中の記号の意味は以下の通りです。 c: 世紀-1 ; y: 年 (2 桁); m: 月 (m は 3 以上、14 以下、つまり、Zeiler の式では、特定の年の 1 月と 2 月は次のようになります)前年の 13 日と 14 日として計算されます。たとえば、2003 年 1 月 1 日は 2002 年 12 月 1 日として計算されます。d: 日は、整数部分のみが必要です。 (C は世紀から 1 を引いたもの、y は西暦の下 2 桁、M は月、d は日です。1 月と 2 月は前年の 13 月と 14 月に従って計算されます。現時点では、C と y は両方とも 1 年の値として計算されます。)

計算された W を 7 で割ったときの余りが曜日になります。余りが 0 の場合は日曜日です。

2049 年 10 月 1 日 (建国記念日 100 周年) を例として、ツェラー式を使用して計算します。
ツェラー式: w=y [y/ 4] ] [c/4]-2c [26(m 1)/10] d-1
=49 [49/4] [20/4]-2×20 [26× (10 1)/10] 1 -1
=49 [12.25] 5-40 [28.6]
=49 12 5-40 28
=54 (7 で割ると余りが 5)
つまり、10 月 1 日2049 年 (100 回目の建国記念日) は金曜日です。

あなたの誕生日(生まれた日、今年、来年)は何曜日ですか?試してみてもいいかもしれません。

ただし、上記の計算式は 1582 年 10 月 15 日以降の状況にのみ適合します (当時の教皇は、カエサルが制定したユリウス暦を、現在使用されているグレゴリオ暦であるグレゴリオ暦に変更しました)。

過程の導出:(推論に興味のない方は読み飛ばしてください)

週制は古くから伝わる制度です。聖書の創世記に、神は天地創造に6日かかり、7日目に休んだと記されていることから、人々も仕事や生活を7日周期で定め、日曜日が休みになっていると言われています。実際的な観点からは、7 日のサイクルがより適切です。したがって、中国の伝統的な勤務サイクルは10日であるが(たとえば、王波の『滕王閣序』には「十十日休息」と書かれており、役人は10日を1サイクルとして勤務し、10日目に休暇を取るという意味である)。 、しかし後に西週制も採用されました。

日常生活の中で、特定の日が何曜日であるかを知るという問題によく遭遇します。場合によっては、歴史上の特定の日が何曜日だったかを知りたい場合もあります。通常、この問題を解決する有効な方法はカレンダーを見ることですが、私たちは常にカレンダーを持ち歩くことはありませんし、ましてや数千年の歴史を持つ永久カレンダーなどは言うまでもありません。コンピュータ プログラミングで特定の日が何曜日であるかを計算したい場合、事前に永久カレンダーを保存することはさらに非現実的です。この時、何らかの計算式を使って年、月、日から曜日を割り出す方法はあるのでしょうか?

答えは「はい」です。実際、私たちもよくこれをやります。簡単な例から始めましょう。たとえば、2004 年 5 月 1 日が土曜日であることがわかっている場合、「世界禁煙デー」が 2004 年 5 月 31 日である曜日を計算することは難しくありません。私たちは、1 日から 31 日まで指で数えることができ、同時に週を数えることができ、最終的には 5 月 31 日が月曜日であると数えることができます。
実際、数学的な計算をするときに指を使う必要はありません。週は 7 日周期で循環することがわかっているため、5 月 1 日は土曜日であり、7 日後の 5 月 8 日も土曜日になります。日付で言えば、8-1=7 となり、7 の倍数になります。同様に、5 月 15 日、5 月 22 日、5 月 29 日も土曜日であり、5 月 1 日との日付の差はそれぞれ 14、21、28 であり、これも 7 の倍数です。 5月31日はどうでしょうか? 31-1=30、7の倍数ではありませんが、31を7で割った余りは2です。
これは、5月31日の週は5月1日の週の2日後であることを意味します。土曜日の2日後は月曜日です。

この簡単な計算は、週を計算するための基本的な考え方を示しています。まず、計算したい日より前の特定の曜日を知り、その日を標準として使用する必要があります。計算の場合、それは計算の「原点」に相当します。次に、計算したい日と決定した日の差が何日あるかを知り、この日付の差を7で割ります。余りは計算したい日が決定した日から何日後かを示します。は。余りが 0 の場合は、2 つの日の日数が同じであることを意味します。明らかに、「原点」として日曜日を選択した場合、残りは曜日とまったく同じになり、計算がより便利になります。

しかし、2 日の間の日数を直接計算するのは依然として面倒です。たとえば、1982 年 7 月 29 日から 2004 年 5 月 1 日までの距離は 7947 日であり、一度に計算することはできません。これには 3 つの期間が含まれます。1 番目は 1982 年 7 月 29 日以降の残りの日数、2 番目は 1983 年から 2003 年までの丸 21 年間の合計日数、3 番目は元旦から 5 月までの期間です。 2004 年 1 月の日数。 2 番目の期間は計算が簡単で、21*365 5 = 7670 日に相当します。5 を追加する理由は、この期間に 5 つの閏年があるためです。たとえば、3 番目の段落では、5 月までの 4 か月の日数と日付の値を合計する必要があります (つまり、31 29 31 30 1 = 122 日)。同様に、
段落では、7 月以降の 5 か月の日数と 7 月の残りの日数を合計し、合計 155 日を加算する必要があります。
つまり、合計の日数は 122 7670 155 = 7947 日になります。

よく考えてください。「原点」の日付を 12 月 31 日として選択すると、第 1 期は 1 年間になります。このように、第 1 期と第 2 期は 1 年間になる可能性があります。 1 年全体の合計が 2 日間の年の差から 1 を引いたものと正確に等しくなるように、これらを結合して計算します。さらに、「原点」の日付を紀元前 1 年 12 月 31 日 (または天文学者が使用する西暦 0 年 12 月 31 日) として選択すると、年全体の合計数は、数えたい日の年から 1 を引いたものになります。この単純化の後は、2 つの期間を計算するだけで済みます。1 つ目は、多数の年間の合計日数であり、2 つ目は、計算したい日がその年の日です。偶然にも、グレゴリオ暦の年と月の設定に従って、逆算すると、紀元前 1 年 12 月 31 日がたまたま日曜日でした。つまり、このようにして計算された合計日数を 7 で割った余りになります。たまたまその曜日でした。したがって、ここでの疑問は
たった 1 つです。これほど多くの年のうち、閏年は何年あるのかということです。これには、グレゴリオ暦の閏規則を理解する必要があります。

グレゴリオ暦は平年が 365 日、閏年が 366 日であることはわかっています。閏の設定方法は、4で割り切れる年は2月に1日追加しますが、100で割り切れる年は閏なし、400で割り切れる年は閏となります。したがって、1600 年、2000 年、2400 年などの年はすべてうるう年ですが、1700 年、1800 年、1900 年、2100 年は通常の年になります。紀元前 1 年は、グレゴリオ暦では閏年でもあります。

したがって、紀元前 1 年 (または西暦 0 年) 12 月 31 日から Y 年の特定の日までのすべての年の閏年の数は、
[(Y -1) に等しくなります。 /4] - [(Y-1)/100] [(Y-1)/400]、

[...] は整数部分のみを取ることを意味します。 1 番目の項目は 4 で割り切れる年数を追加する必要があることを示し、2 番目の項目は 100 で割り切れる年数を削除する必要があることを示し、3 番目の項目は 400 で割り切れる年数を追加する必要があることを示しています。 Y を 1 減らす必要がある理由は、
特定の日の曜日を計算するための最初の式が次のとおりであるためです:

W = (Y-1)*365 [(Y -1) /4] - [(Y-1)/100] [(Y-1)/400] D. (1)

ここで D は、今年のこの日の累積日数です。計算された W は、紀元前 1 年 (または西暦 0) の 12 月 31 日からこの日までの日数です。 W を 7 で割ると余りになります。この日が曜日になります。たとえば、2004 年 5 月 1 日を計算してみましょう:

W = (2004-1)*365 [(2004-1)/4] - [(2004-1)/100] [(2004-1 ) /400] (31 29 31 30 1) = 731702,
731702 / 7 = 104528...6、余りは 6 で、この日は土曜日であることを示します。これは事実と一致しています。

上記の式 (1) は非常に正確ですが、計算される数値が大きすぎるため、使用するのが非常に不便です。よく考えてみると、実はWという日数は7で割った余りを求めるために使われているだけなのです。このことから、この W 値を単純化する必要があるのは、その剰余と同じであるより小さい正の整数を見つけることだけです。正確な週数を計算します。

明らかに、W が非常に大きい理由は、式の最初の項 (Y-1)*365 が大きすぎるためです。実際、

(Y-1)*365 = (Y-1) * (364 1)
= (Y-1) * (7*52 1)
= 52 * ( Y -1) * 7 (Y-1),

この結果の最初の項は 7 の倍数で、7 で割った余りは 0 なので、(Y-1)* の余りは365 を 7 で割った値は、実際には Y-1 を 7 で割った余りに等しいです。この関係は次のように表すことができます:

(Y-1)*365 ≡ Y-1 (mod 7)。

このうち、≡は整数論で合同を表す記号で、7を法(つまり約数)としたとき、≡の両側の数字が合同であることを意味します。したがって、(Y-1) を使用して (Y-1)*365 を置き換えることができ、曜日を計算するための有名で最も一般的な公式が得られます:

W = (Y- 1) ) [(Y-1)/4] - [(Y-1)/100] [(Y-1)/400] D. (2)

この式は非常に使いやすいですが、累積日数 D の計算も面倒なので、最も有用な式とは言えません
。月番号と日付を使用して直接計算できますか?答えも「はい」です。各
月の日数を観察することもできます。リストは次のとおりです:

月: 1 月、2 月、3 月、4 月、5 月、6 月、7 月、8 月、9 月、10 月、 11月、12月
------------------------------------------ ---- ------------------------
日数: 31 28(29) 31 30 31 30 31 31 30 31 30 31

この日数から 28 (=4*7) を引いても、W を 7 で割った余りの値には影響しません。このようにして、別の
テーブルを取得します。

月: 1 月、2 月、3 月、4 月、5 月、6 月、7 月、8 月、9 月、10 月、11 月、12 月
--- -- ------------------------------------------------ -- ----------------
残り日数: 3 0(1) 3 2 3 2 3 3 2 3 2 3
平年累計: 3 3 6 8 11 13 16 19 21 24 26 29
閏年の累計: 3 4 7 9 12 14 17 20 22 25 27 30

よく見ると、1月と2月、3月から7月を除いていることがわかります。 1 月の 5 か月の残りの日数は 3,2,3,2,3 であり、8 月から 12 月の 5 か月の残りの日数も 3,2,3,2,3 であり、まさにその繰り返しです。対応する累積日数のうち、翌月の累積日数と前月の累積日数の差から28を引いたものがこの繰り返しになります。この規則が存在するからこそ、平年と閏年の累積日数は次の数式で簡単に表すことができます。

╭ d (M = 1 の場合)
D = { 31 d; (M=2 の場合) (3)
╰ [ 13 * (M 1) / 5 ] - 7 (M-1) * 28 d i. (M ≥ 3 の場合)

ここで、[...] は整数部分のみを取得することを意味し、M と d はそれぞれ、通常の年では i=0 の計算対象の月と日です。閏年では i=1。 M≧3 という式について説明する必要があります。[13*(M 1)/5]-7 は、上の 2 番目の表の年間平均累積値として計算されます。(M-1)*28 を加算すると、合計数がカウントされます。 days の月に先立つすべての月の days。これは、丸め演算を使用して 3,2,3,2,3 のサイクルを実現する非常に賢い方法です。たとえば、2004 年 5 月 1 日の場合、次のようになります:

D = [ 13 * (5 1) / 5 ] - 7 (5-1) * 28 1 1
= 122,

これは、まさに 2004 年 5 月 1 日の累計日数です。

さらに変更を加えて、1 月と 2 月を前年の「13 日」と「14 日」として扱うとします。この計算式に従っているだけでなく、このため閏日も The になります。前の「年」の最終日 (合計 14 か月) は d の一部となるため、閏年の影響も除去され、式は次のように簡略化されます:

D = [ 13 * (M 1)/5]−7(M−1)×28 d. (3≤M≤14) (4)

曜日を計算するための上記の式は、次のようにさらに簡略化できます。

W = (Y-1) [(Y-1 )/ 4] - [(Y-1)/100] [(Y-1)/400] [ 13 * (M 1) / 5 ] - 7 (M-1) * 28 d.

-7 と (M-1)*28 はどちらも 7 で割り切れるため、これら 2 つの項目を削除すると、W を 7 で割った余りは変化せず、式は次のようになります。

W = (Y-1) [(Y-1)/4] - [(Y-1)/100] [(Y-1)/400] [ 13 * (M 1) / 5 ] d. (5)

もちろん、1 月と 2 月は前年の 13 番目と 14 番目の月とみなされていることに注意してください。したがって、1 月と 2 月の M を除いた曜日の週を計算します。 , を押す 13 または 14 を数えるとき、Y 年も 1 引く必要があります。たとえば、2004 年 1 月 1 日は木曜日です。次の式を使用して計算します。

W = (2003-1) [(2003-1)/4] - [(2003-1)/100 ] [( 2003-1)/400] [13*(13 1)/5]
1
= 2002 500 - 20 5 36 1
= 2524;
2524 / 7 = 360… …4.これは現実と一致しています。

式 (5) はすでに年、月、日から曜日を計算する式ですが、最も簡潔なものではありません。年の処理を改善する方法はまだあります。まずこの式を使用して、各世紀の最初の年の 3 月 1 日の週を計算してみましょう。リストは次のとおりです:

年: 1(401,801,…,2001) 101(501,901,…,2101)
----------------------------------------------- --- ------------------
週: 4 2
=================== === ========================
年: 201(601,1001,…,2201) 301(701,1101,…, 2301)
------------------------------------------ --- --------------------
週: 0 5

今週は 4 世紀ごとに繰り返されることがわかります。 301 年 3 月 1 日の週番号 (701、1101、...、2301) を -2 とすると (整数論の余りの定義によれば、-2 は 5 を 7 で割った余りと同じです)、したがって、この変換のように行うことができます)、この繰り返しシーケンスは正確に 4,2,0,-2 の算術シーケンスになります。これに基づいて、各世紀の最初の年の 3 月 1 日の曜日を計算する次の式を得ることができます:

W = (4 - C mod 4) * 2 - 4。 (6)

式中、C は世紀の世紀番号から 1 を引いた値、mod は剰余演算、つまり剰余を求めることを表します。たとえば、2001 年 3 月 1 日の場合、C=20 の場合:

W = (4 - 20 mod 4) * 2 - 4
= 8 - 4
= 4。

式 (6) を式 (5) に代入すると、変換後に次のようになります。

(Y-1) [(Y-1)/4] - [(Y-1) ) /100] [(Y-1)/400] ≡ (4 - C mod 4) * 2 - 1
(mod 7). (7)

よって、式(5)の (Y-1) [(Y-1)/4] - [(Y-1)/100] [(Y-1)/400] となります。各世紀の最初の年の曜日を計算する場合、4 つの項は ​​(4 - C mod 4) * 2 - 1 に置き換えることができます。この式は次のように記述されます:

W = (4 - C mod 4) * 2 - 1 [13 * (M 1) / 5] d. (8)

各世紀の最初の年の日付と週の計算式を使えば、その世紀の他の年の日付と週の計算式は簡単に得られます。100年では00で終わる年が最後の年となるため、「100年に閏なし、400年に閏する」というルールは考慮する必要はなく、「4年に1度閏する」というルールだけを考慮する必要があります。年」。式 (1) を式 (2) に簡略化する方法に従って、式 (5) よりも式 (8) から簡単に、任意の日の曜日を計算する式を得ることができます:

W = (4 - C mod 4) * 2 - 1 (y-1) [y/4] [13 * (M 1) / 5] d. (9)

ここで、y は西暦の下 2 桁です。

モジュロ演算が四則演算ではないと考えると、(4 - C mod 4) * 2 をさらに四則演算のみを含む式に書き換えることができます。商 q と世紀の余り r から 1 C を引いたものを 4 で割ったものとの間には次の関係があるためです:

4q r = C,

ここで、r は C mod 4 です。したがって、次のようになります。

r = C - 4q
= C - 4 * [C/4] があります。 (10)

の場合、

(4 - C mod 4) * 2 = (4 - C 4 * [C/4]) * 2
= 8 - 2C 8 * [ C/4]
≡ [C/4] - 2C 1 (mod 7). (11)

式 (11) を (9) に代入すると、次のようになります。

W = [C/4] - 2C y [y/4] [13 * (M 1) /5] d-1. (12)

この式は、世紀、西暦の下 2 桁、月、日から 1 を引いて 7 で割ることで W を計算できます。得られた余りは、その年の日を示します。唯一の要件は、1 月と 2 月を前年の 13 月と 14 月として扱い、C と y の両方を前年の年に基づいて評価することです。したがって、一般に、これが特定の日の曜日を計算するための最良の式であると考えられています。この公式は 1886 年にドイツの数学者クリスチャン ツェラー (1822-1899) によって初めて導出されたため、一般にツェラーの公式として知られています。口頭計算を容易にするために、式中の [13 * (M 1) / 5] は [26 * (M 1) / 10] と表記されることがよくあります。

ここで、2004 年 5 月 1 日の週を計算してみましょう。明らかに、C=20、y=4、M=5、d=1 を Zeiler の
式に代入すると、次のようになります。
W = [20/4] - 40 4 1 [13 * (5 1) / 5] 1 - 1
= -15。

負の数の剰余は、慣例的な剰余の概念に従って計算することはできず、整数論における剰余の定義に従ってのみ計算できることに注意してください。計算を容易にするために、7 の整数倍を加算して正の数にすることができます。たとえば、70 を加算すると 55 になります。 これを再度 7 で割ると、余りが 6 となり、この日は土曜日であることがわかります。これは現実と一致しており、式 (2) で計算された結果とも一致しています。

最後に、上記の式はすべてグレゴリオ暦の閏規則に基づいていることに注意してください。ザイラーは、ユリウス暦の場合、対応する式

W = 5 - C y [y/4] [13 * (M 1) / 5] d - 1 も導き出しました。 (13)

このようにして、カレンダーを一度も参照することなく、任意の日の曜日を計算する問題を最終的に解決しました。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。