Wpisany przez Tomasz Lubiński,
02 marca 2008 20:12
Przedstawiony tutaj algorytm pozwala na szybkie obliczenie dnia tygodnia dla podanej daty dzień-miesiąc-rok. Wszystkie przedstawione operacje dzielenia są operacjami dzielenia całkowitego - tzn. odrzucającymi resztę. Czyli 5/2 = 2.
Na początku obliczymy dzień tygodnia dla pierwszego stycznia podanego roku. 0 oznacza poniedziałek, 1 wtorek, ... 6 niedzielę.
Teraz zdefiniujemy pomocniczą tabelę określającą ile dni roku minęło dla podanego miesiąca. Tabela zdefiniowana jest dla roku nieprzestępnego:
Następnie wyznaczymy dzień roku:
Mamy już teraz wszystkie niezbędne dane do wyznaczenia dnia tygodnia. Do obliczonego dnia tygodnia dla 1 stycznia dodajemy wyznaczony dzień roku pomniejszony o 1 i dzielimy całość modulo 7. Wynik to dzień tygodnia dla podanej daty, 0 oznacza poniedziałek, 1 wtorek, ... 6 niedzielę.
dzień tygodnia = (dzień tygodnia dla 1 stycznia + dzień roku - 1) mod 7
Wyznaczymy dzień tygodnia dla: 15-2-2008.
A więc najpierw obliczymy dzień tygodnia dla 1 stycznia.
YY = (rok-1) mod 100 = (2008-1) mod 100 = 2007 mod 100 = 7.
C = (rok-1) - YY = (2008-1) - 7 = 2007 - 7 = 2000.
G = YY + YY/4 = 7 + 7/4 = 7 + 1 = 8.
dzień tygodnia dla 1 stycznia = (((((C / 100) mod 4) * 5) + G) mod 7) = (((((2000 / 100) mod 4) * 5) + 8) mod 7) = ((((20 mod 4) * 5) + 8) mod 7) = (((0 * 5) + 8) mod 7) = ((0 + 8) mod 7) = 8 mod 7 = 1.
Zatem 1 stycznia 2008 roku to wtorek.
Teraz obliczymy, którym dniem roku 2008 jest dzień 15-2.
dzień roku = 31 + 15 = 46.
Podany rok jest rokiem przestępnym, ale podany miesiąc nie jest późniejszy niż luty a więc nie dodajmy 1 do dnia roku.
A więc ostatecznie:
dzień tygodnia = (dzień tygodnia dla 1 stycznia + dzień roku - 1) mod 7 = (1 + 46 - 1) mod 7 = 46 mod 7 = 4.
A więc 15-2-2008 to piątek.
Na początku obliczymy dzień tygodnia dla pierwszego stycznia podanego roku. 0 oznacza poniedziałek, 1 wtorek, ... 6 niedzielę.
- YY = (rok-1) mod 100
- C = (rok-1) - YY
- G = YY + YY/4
- dzień tygodnia dla 1 stycznia = (((((C / 100) mod 4) * 5) + G) mod 7)
Teraz zdefiniujemy pomocniczą tabelę określającą ile dni roku minęło dla podanego miesiąca. Tabela zdefiniowana jest dla roku nieprzestępnego:
Miesiąc | liczba dni |
styczeń | 0 |
luty | 31 |
marzec | 59 |
kwiecień | 90 |
maj | 120 |
czerwiec | 151 |
lipiec | 181 |
sierpień | 212 |
wrzesień | 243 |
październik | 273 |
listopad | 304 |
grudzień | 334 |
Następnie wyznaczymy dzień roku:
- dzień roku = liczba dni, które minęły dla podanego miesiąca odczytane z tabeli powyżej + dzień miesiąca
- Teraz jeszcze należy sprawdzić czy należy dodać jeden dzień w związku z latami przestępnymi. A więc dzień roku należy zwiększyć o 1 jeżeli podany miesiąc jest po lutym oraz podany rok jest przestępny
Mamy już teraz wszystkie niezbędne dane do wyznaczenia dnia tygodnia. Do obliczonego dnia tygodnia dla 1 stycznia dodajemy wyznaczony dzień roku pomniejszony o 1 i dzielimy całość modulo 7. Wynik to dzień tygodnia dla podanej daty, 0 oznacza poniedziałek, 1 wtorek, ... 6 niedzielę.
Przykład:
Wyznaczymy dzień tygodnia dla: 15-2-2008.
A więc najpierw obliczymy dzień tygodnia dla 1 stycznia.
YY = (rok-1) mod 100 = (2008-1) mod 100 = 2007 mod 100 = 7.
C = (rok-1) - YY = (2008-1) - 7 = 2007 - 7 = 2000.
G = YY + YY/4 = 7 + 7/4 = 7 + 1 = 8.
dzień tygodnia dla 1 stycznia = (((((C / 100) mod 4) * 5) + G) mod 7) = (((((2000 / 100) mod 4) * 5) + 8) mod 7) = ((((20 mod 4) * 5) + 8) mod 7) = (((0 * 5) + 8) mod 7) = ((0 + 8) mod 7) = 8 mod 7 = 1.
Zatem 1 stycznia 2008 roku to wtorek.
Teraz obliczymy, którym dniem roku 2008 jest dzień 15-2.
dzień roku = 31 + 15 = 46.
Podany rok jest rokiem przestępnym, ale podany miesiąc nie jest późniejszy niż luty a więc nie dodajmy 1 do dnia roku.
A więc ostatecznie:
dzień tygodnia = (dzień tygodnia dla 1 stycznia + dzień roku - 1) mod 7 = (1 + 46 - 1) mod 7 = 46 mod 7 = 4.
A więc 15-2-2008 to piątek.
Implementacje
Autor | Język programowania | Komentarz | Otwórz | Pobierz | Ocena |
Tomasz Lubiński | C# | MS Visual Studio .net | .cs | .cs | ***** / 2 |
Tomasz Lubiński | C/C++ | .cpp | .cpp | ***** / 12 | |
Michał Burchardt | C/C++ | C++ | .cpp | .cpp | ***** / 18 |
Tomasz Lubiński | Delphi/Pascal | .pas | .pas | ***** / 4 | |
Tomasz Lubiński | Java | .java | .java | ***** / 4 | |
Nikodem Solarz | Ruby | Metoda obliczająca | .rb | .rb | ***** / 0 |
Nikodem Solarz | Ruby | Gotowy program obliczający | .rb | .rb | ***** / 0 |
Poprawiony: 30 lipca 2012 18:15
Dzień 1 stycznia roku 1 + liczba lat od roku 1 * liczba dni w roku + liczba lat przestępnych od roku 1 do roku poprzedzający zadany rok + liczba dni w roku bieżącym i to wszystko modulo 7. Tak więc jakaś wyższa matematyka to to nie jest
A więc najpierw obliczymy dzień tygodnia dla 1 stycznia 2014 roku.
YY = (rok-1) mod 100 = (2014-1) mod 100 = 2013 mod 100 = 13.
C = (rok-1) - YY = (2014-1) - 13 = 2013 - 13 = 2000.
G = YY + YY/4 = 13 + 13/4 = 13 + 3 = 16.
dzień tygodnia dla 1 stycznia = (((((C / 100) mod 4) * 5) + G) mod 7) = (((((2000 / 100) mod 4) * 5) + 16) mod 7) = ((((20 mod 4) * 5) + 16) mod 7) = (((0 * 5) + 16) mod 7) = ((0 + 16) mod 7) = 16 mod 7 = 2.
Zatem 1 stycznia 2014 roku to środa.
Teraz obliczymy, którym dniem roku 2014 jest dzień 12 listopada.
dzień roku = 304 + 12 = 316.
Podany miesiąc jest późniejszy niż luty ale podany rok nie jest rokiem przestępnym więc nie dodajmy 1 do dnia roku.
A więc ostatecznie:
dzień tygodnia = (dzień tygodnia dla 1 stycznia + dzień roku - 1) mod 7 = (2 + 316 - 1) mod 7 = 317 mod 7 = 2.
A więc 12-11-2014 to środa - wszystko się zgadza.
c=miesiąc
g=dzień
dzień tygodnia = ([23m/9] + d + 4 + y + [z/4] + [z/100] + [z/400] - c) mod 7gdzie [ ] oznacza część całkowitą liczby
mod – funkcja modulo (reszta z dzielenia)
m – numer miesiąca (ang. month) (od stycznia = 1 do grudnia = 12)
d – numer dnia (ang. day) miesiąca
y – rok (ang. year)
z – rok z poprawką: z = y - 1 jeżeli m < 3; z = y, jeżeli m >= 3
c – korekta (ang. correction): c = 0, jeżeli m < 3; c = 2, jeżeli m >= 3
dni tygodnia ze zbioru {0, 1, 2, 3, 4, 5, 6}, gdzie: 0 – wtorek, 1 – środa, 2 – czwartek, 3 – piątek, 4 – sobota, 5 – niedziela, 6 – poniedziałek
Zaletą wzoru Mike'a Keitha jest możliwość zapisania go w języku programowania C w jednej linii liczącej raptem 45 znaków.