Doomsday rule
- About the task
John Conway (1937-2020), was a mathemetician who also invented several mathematically oriented computer pastimes, such as the famous Game of Life cellular automaton program. Dr. Conway invented a simple algorithm for finding the day of the week, given any date. The algorithm was based opon calculating the distance of a given date from certain "anchor days" which follow a pattern for the day of the week upon which they fall.
- Algorithm
The formula is calculated assuming that Sunday is 0, Monday 1, and so forth with Saturday 7, and
anchorday = (Tuesday(or 2) + 5(y mod 4) + 4(y mod 100) + 6(y mod 400)) % 7
which, for 2021, is 0 (Sunday).
To calculate the day of the week, we then count days from a close doomsday, with these as charted here by month, then add the doomsday for the year, then get the remainder after divding by 7. This should give us the number corresponding to the day of the week for that date.
Month Doomsday Dates for Month -------------------------------------------- January (common years) 3, 10, 17, 24, 31 January (leap years) 4, 11, 18, 25 February (common years) 7, 14, 21, 28 February (leap years) 1, 8, 15, 22, 29 March 7, 14, 21, 28 April 4, 11, 18, 25 May 2, 9, 16, 23, 30 June 6, 13, 20, 27 July 4, 11, 18, 25 August 1, 8, 15, 22, 29 September 5, 12, 19, 26 October 3, 10, 17, 24, 31 November 7, 14, 21, 28 December 5, 12, 19, 26
- Task
Given the following dates:
- 1800-01-06 (January 6, 1800)
- 1875-03-29 (March 29, 1875)
- 1915-12-07 (December 7, 1915)
- 1970-12-23 (December 23, 1970)
- 2043-05-14 (May 14, 2043)
- 2077-02-12 (February 12, 2077)
- 2101-04-02 (April 2, 2101)
Use Conway's Doomsday rule to calculate the day of the week for each date.
- see also
APL
<lang apl>weekday←{⎕IO←1
days←'Sunday' 'Monday' 'Tuesday' 'Wednesday' 'Thursday' 'Friday' 'Saturday' leap←4 7∊⍨2⊥0=4 100 400∘| ld←4 7 1 4 2 6 4 1 5 3 7 5 nd←3 7 7 4 2 6 4 1 5 3 7 5 y m d←⍵ c←⌊y÷100 ⋄ r←100|y s←⌊r÷12 ⋄ t←12|r can←7|2+5×4|c doom←7|s+t+can+⌊t÷4 anchor←m⊃(1+leap y)⊃nd ld (1+7|7+doom+d-anchor)⊃days
}</lang>
- Output:
weekday 1800 1 6 Monday weekday 1875 3 29 Monday weekday 1915 12 7 Tuesday weekday 1970 12 23 Wednesday weekday 2043 5 14 Thursday weekday 2077 2 12 Friday weekday 2101 4 2 Saturday
BASIC
Note that 1/6/1800 is actually a Monday, not a Sunday. As far as I can tell this is actually the correct day.
<lang BASIC>10 DIM D$(7): FOR I=1 TO 7: READ D$(I): NEXT I 20 DIM D(12,1): FOR I=0 TO 1: FOR J=1 TO 12: READ D(J,I): NEXT J,I 30 READ Y: IF Y=0 THEN END ELSE READ M,D 40 PRINT USING "##/##/####: ";M;D;Y; 50 C=Y\100: R=Y MOD 100 60 S=R\12: T=R MOD 12 70 A=(5*(C AND 3)+2) MOD 7 80 B=(S+T+(T\4)+A) MOD 7 90 PRINT D$((B+D-D(M,-(Y MOD 4=0 AND (Y MOD 100<>0 OR Y MOD 400=0)))+7) MOD 7+1) 100 GOTO 30 110 DATA Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday 120 DATA 3,7,7,4,2,6,4,1,5,3,7,5 130 DATA 4,1,7,4,2,6,4,1,5,3,7,5 140 DATA 1800,1,6, 1875,3,29, 1915,12,7, 1970,12,23 150 DATA 2043,5,14, 2077,2,12, 2101,4,2, 0</lang>
- Output:
1/ 6/1800: Monday 3/29/1875: Monday 12/ 7/1915: Tuesday 12/23/1970: Wednesday 5/14/2043: Thursday 2/12/2077: Friday 4/ 2/2101: Saturday
BCPL
Note that 1/6/1800 is actually a Monday, not a Sunday. As far as I can tell this is actually the correct day.
<lang bcpl>get "libhdr"
let dayname(n) =
n = 0 -> "Sunday", n = 1 -> "Monday", n = 2 -> "Tuesday", n = 3 -> "Wednesday", n = 4 -> "Thursday", n = 5 -> "Friday", n = 6 -> "Saturday", dayname(n rem 7)
let leap(year) = year rem 4 = 0 & (year rem 100 ~= 0 | year rem 400 = 0)
let weekday(y, m, d) = valof $( let leapdoom = table 4,1,7,4,2,6,4,1,5,3,7,5
let normdoom = table 3,7,7,4,2,6,4,1,5,3,7,5
let c = y / 100 and r = y rem 100 let s = r / 12 and t = r rem 12 let an = (5 * (c rem 4) + 2) rem 7 let doom = (s + t + (t/4) + an) rem 7 let anchor = (leap(y) -> leapdoom, normdoom)!(m-1) resultis (doom + d - anchor + 7) rem 7
$)
let start() be $( writef("January 6, 1800 was on a %S.*N", dayname(weekday(1800, 1, 6)))
writef("March 29, 1875 was on a %S.*N", dayname(weekday(1875, 3, 29))) writef("December 7, 1915 was on a %S.*N", dayname(weekday(1915, 12, 7))) writef("December 23, 1970 was on a %S.*N", dayname(weekday(1970, 12, 23))) writef("May 14, 2043 will be on a %S.*N", dayname(weekday(2043, 5, 14))) writef("February 12, 2077 will be on a %S.*N", dayname(weekday(2077, 2, 12))) writef("April 2, 2101 will be on a %S.*N", dayname(weekday(2101, 4, 2)))
$)</lang>
- Output:
January 6, 1800 was on a Monday. March 29, 1875 was on a Monday. December 7, 1915 was on a Tuesday. December 23, 1970 was on a Wednesday. May 14, 2043 will be on a Thursday. February 12, 2077 will be on a Friday. April 2, 2101 will be on a Saturday.
C
<lang c>#include <stdio.h>
- include <stdint.h>
- include <stdbool.h>
typedef struct {
uint16_t year; uint8_t month; uint8_t day;
} Date;
bool leap(uint16_t year) {
return year%4==0 && (year%100!=0 || year%400==0);
}
const char *weekday(Date date) {
static const uint8_t leapdoom[] = {4,1,7,2,4,6,4,1,5,3,7,5}; static const uint8_t normdoom[] = {3,7,7,4,2,6,4,1,5,3,7,5}; static const char *days[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; unsigned c = date.year/100, r = date.year%100; unsigned s = r/12, t = r%12; unsigned c_anchor = (5 * (c%4) + 2) % 7; unsigned doom = (s + t + (t/4) + c_anchor) % 7; unsigned anchor = (leap(date.year) ? leapdoom : normdoom)[date.month-1]; return days[(doom+date.day-anchor+7)%7];
}
int main(void) {
const char *past = "was", *future = "will be"; const char *months[] = { "", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; const Date dates[] = { {1800,1,6}, {1875,3,29}, {1915,12,7}, {1970,12,23}, {2043,5,14}, {2077,2,12}, {2101,4,2} }; int i; for (i=0; i < sizeof(dates)/sizeof(Date); i++) { printf("%s %d, %d %s on a %s.\n", months[dates[i].month], dates[i].day, dates[i].year, dates[i].year > 2021 ? future : past, weekday(dates[i])); } return 0;
}</lang>
- Output:
January 6, 1800 was on a Monday. March 29, 1875 was on a Monday. December 7, 1915 was on a Tuesday. December 23, 1970 was on a Wednesday. May 14, 2043 will be on a Thursday. February 12, 2077 will be on a Friday. April 2, 2101 will be on a Saturday.
C++
<lang cpp>#include <iostream>
- include <cstdint>
struct Date {
std::uint16_t year; std::uint8_t month; std::uint8_t day;
};
constexpr bool leap(int year) {
return year%4==0 && (year%100!=0 || year%400==0);
}
const std::string& weekday(const Date& date) {
static const std::uint8_t leapdoom[] = {4,1,7,2,4,6,4,1,5,3,7,5}; static const std::uint8_t normdoom[] = {3,7,7,4,2,6,4,1,5,3,7,5}; static const std::string days[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; unsigned const c = date.year/100, r = date.year%100; unsigned const s = r/12, t = r%12; unsigned const c_anchor = (5 * (c%4) + 2) % 7; unsigned const doom = (s + t + t/4 + c_anchor) % 7; unsigned const anchor = (leap(date.year) ? leapdoom : normdoom)[date.month-1]; return days[(doom+date.day-anchor+7)%7];
}
int main(void) {
const std::string months[] = {"", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; const Date dates[] = { {1800,1,6}, {1875,3,29}, {1915,12,7}, {1970,12,23}, {2043,5,14}, {2077,2,12}, {2101,4,2} }; for (const Date& d : dates) { std::cout << months[d.month] << " " << (int)d.day << ", " << d.year; std::cout << (d.year > 2021 ? " will be " : " was "); std::cout << "on a " << weekday(d) << std::endl; } return 0;
}</lang>
- Output:
January 6, 1800 was on a Monday March 29, 1875 was on a Monday December 7, 1915 was on a Tuesday December 23, 1970 was on a Wednesday May 14, 2043 will be on a Thursday February 12, 2077 will be on a Friday April 2, 2101 will be on a Saturday
Cowgol
<lang cowgol>include "cowgol.coh";
record Date is
year: uint16; month: uint8; day: uint8;
end record;
sub weekday(d: [Date]): (dayname: [uint8]) is
var daynames: [uint8][] := { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; var leapdoom: uint8[] := {4,7,1,4,2,6,4,1,5,3,7,5}; var normdoom: uint8[] := {3,7,7,4,2,6,4,1,5,3,7,5}; var c := d.year / 100; var r := d.year % 100; var s := r / 12; var t := r % 12; var can := (5 * (c%4) + 2) % 7; var doom := (s + t + (t/4) + can) % 7; var anchor: int16; if d.year%4 == 0 and (d.year%100 != 0 or d.year%400 == 0) then anchor := leapdoom[d.month-1] as int16; else anchor := normdoom[d.month-1] as int16; end if; var dayno := (doom as int16 + d.day as int16 - anchor + 7) % 7; dayname := daynames[dayno as @indexof daynames];
end sub;
sub print_date(d: [Date]) is
print_i8(d.month); print_char('/'); print_i8(d.day); print_char('/'); print_i16(d.year); print(": "); print(weekday(d)); print_nl();
end sub;
var dates: Date[] := {
{1800,1,6}, {1875,3,29}, {1915,12,7}, {1970,12,23}, {2043,5,14}, {2077,2,12}, {2101,4,2}
};
var i: @indexof dates := 0; while i < @sizeof dates loop
print_date(&dates[i]); i := i + 1;
end loop;</lang>
- Output:
1/6/1800: Monday 3/29/1875: Monday 12/7/1915: Tuesday 12/23/1970: Wednesday 5/14/2043: Thursday 2/12/2077: Friday 4/2/2101: Saturday
FOCAL
<lang focal>01.10 S X(1)=3;S X(2)=7;S X(3)=7;S X(4)=4;S X(5)=2;S X(6)=6 01.15 S X(7)=4;S X(8)=1;S X(9)=5;S X(10)=3;S X(11)=7;S X(12)=5 01.20 S Y=1800;S M= 1;S D= 6;D 2;D 3 01.25 S Y=1875;S M= 3;S D=29;D 2;D 3 01.30 S Y=1915;S M=12;S D= 7;D 2;D 3 01.35 S Y=1970;S M=12;S D=23;D 2;D 3 01.40 S Y=2043;S M= 5;S D=14;D 2;D 3 01.45 S Y=2077;S M= 2;S D=12;D 2;D 3 01.50 S Y=2101;S M= 4;S D= 2;D 2;D 3 01.55 Q
02.10 S C=FITR(Y/100);S R=Y-C*100 02.15 S S=FITR(R/12);S T=R-S*12 02.20 S A=5*(C-FITR(C/4)*4)+2;S A=A-FITR(A/7)*7 02.25 S B=S+T+FITR(T/4)+A;S B=B-FITR(B/7)*7 02.30 S E=X(M) 02.35 I (Y-FITR(Y/400)*400)2.4,2.5,2.4 02.40 I (Y-FITR(Y/100)*100)2.45,2.7,2.45 02.45 I (Y-FITR(Y/4)*4)2.7,2.5,2.7 02.50 I (M-1)2.55,2.6,2.55 02.55 I (M-2)2.7,2.65,2.7 02.60 S E=E+7 02.65 S E=E-6 02.70 S E=B+D-E+7 02.75 S E=E-FITR(E/7)*7
03.10 T "M",%2,M," " 03.20 T "D",%2,D," " 03.30 T "Y",%4,Y," " 03.40 T "DAY=";D 4;T !
04.10 I (E-6)4.2;T "SATURDAY";R 04.20 I (E-5)4.3;T "FRIDAY";R 04.30 I (E-4)4.4;T "THURSDAY";R 04.40 I (E-3)4.5;T "WEDNESDAY";R 04.50 I (E-2)4.6;T "TUESDAY";R 04.60 I (E-1)4.7;T "MONDAY";R 04.70 T "SUNDAY"</lang>
- Output:
M= 1 D= 6 Y= 1800 DAY=MONDAY M= 3 D= 29 Y= 1875 DAY=MONDAY M= 12 D= 7 Y= 1915 DAY=TUESDAY M= 12 D= 23 Y= 1970 DAY=WEDNESDAY M= 5 D= 14 Y= 2043 DAY=THURSDAY M= 2 D= 12 Y= 2077 DAY=FRIDAY M= 4 D= 2 Y= 2101 DAY=SATURDAY
Haskell
<lang haskell>import Text.Printf
data Date = Date {year :: Int, month :: Int, day :: Int}
instance Show Date where
show (Date {year = y, month = m, day = d}) = printf "%2d/%2d/%4d" m d y
leap :: Int -> Bool leap year = year`mod`4==0 && (year`mod`100/=0 || year`mod`400==0)
weekday :: Date -> Int weekday (Date {year = y, month = m, day = d}) = (doom + d - anchor + 7) `mod` 7
where doom = (s + t + (t `div` 4) + c_anchor) `mod` 7 anchor = dooms !! pred m c_anchor = (5 * mod c 4 + 2) `mod` 7 dooms = (if leap y then [4,1] else [3,7]) ++ [7,4,2,6,4,1,5,3,7,5] (c, r) = y `divMod` 100 (s, t) = r `divMod` 12
days :: [String] days = words "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
dates :: [Date] dates = [ Date { year = 1800, month = 1, day = 6},
Date { year = 1875, month = 3, day = 29}, Date { year = 1915, month = 12, day = 7}, Date { year = 1970, month = 12, day = 23}, Date { year = 2043, month = 5, day = 14}, Date { year = 2077, month = 2, day = 12}, Date { year = 2101, month = 4, day = 2} ]
dateAndDay :: Date -> String dateAndDay d = printf "%s: %s" (show d) (days !! weekday d)
main :: IO () main = putStr $ unlines $ map dateAndDay dates </lang>
- Output:
1/ 6/1800: Monday 3/29/1875: Monday 12/ 7/1915: Tuesday 12/23/1970: Wednesday 5/14/2043: Thursday 2/12/2077: Friday 4/ 2/2101: Saturday
Java
<lang java>class Doom {
public static void main(String[] args) { final Date[] dates = { new Date(1800,1,6), new Date(1875,3,29), new Date(1915,12,7), new Date(1970,12,23), new Date(2043,5,14), new Date(2077,2,12), new Date(2101,4,2) }; for (Date d : dates) System.out.println( String.format("%s: %s", d.format(), d.weekday())); }
}
class Date {
private int year, month, day; private static final int[] leapdoom = {4,1,7,4,2,6,4,1,5,3,7,5}; private static final int[] normdoom = {3,7,7,4,2,6,4,1,5,3,7,5}; public static final String[] weekdays = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; public Date(int year, int month, int day) { this.year = year; this.month = month; this.day = day; } public boolean isLeapYear() { return year%4 == 0 && (year%100 != 0 || year%400 == 0); } public String format() { return String.format("%02d/%02d/%04d", month, day, year); } public String weekday() { final int c = year/100; final int r = year%100; final int s = r/12; final int t = r%12; final int c_anchor = (5 * (c%4) + 2) % 7; final int doom = (s + t + t/4 + c_anchor) % 7; final int anchor = isLeapYear() ? leapdoom[month-1] : normdoom[month-1]; return weekdays[(doom + day - anchor + 7) % 7]; }
}</lang>
- Output:
01/06/1800: Monday 03/29/1875: Monday 12/07/1915: Tuesday 12/23/1970: Wednesday 05/14/2043: Thursday 02/12/2077: Friday 04/02/2101: Saturday
Julia
<lang julia>module DoomsdayRule export get_weekday
const weekdaynames = ["Sunday", "Monday","Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
- For months 1 through 12, the date of the first doomsday that month.
const leapyear_firstdoomsdays = [4, 1, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5] const nonleapyear_firstdoomsdays = [3, 7, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5]
"""
get_weekday(year::Int, month::Int, day::Int)::String
Return the weekday of a given date in past or future. Uses Conway's doomsday rule (see also https://en.wikipedia.org/wiki/Doomsday_rule) """ function get_weekday(year::Int, month::Int, day::Int)::String
# sanity checks @assert 1582 <= year <= 9999 "Invalid year (should be after 1581 and 4 digits)" @assert 1 <= month <= 12 "Invalid month, should be between 1 and 12" @assert 1 <= day <= 31 "Invalid day, should be between 1 and 31"
# Conway's doomsday algorithm c, r = divrem(year, 100) s, t = divrem(r, 12) canchor = (5 * (c % 4) + 2) % 7 # anchor for centiry doomsday = (s + t + (t ÷ 4) + canchor) % 7 anchorday = (year % 4 != 0) || (r == 0 && year % 400 == 0) ? # leap year determination nonleapyear_firstdoomsdays[month] : leapyear_firstdoomsdays[month] weekday = (doomsday + day - anchorday + 7) % 7 + 1 return weekdaynames[weekday]
end
end # module
using .DoomsdayRule
println("January 6, 1800 was on a ", get_weekday(1800, 1, 6)) println("March 29, 1875 was on a ", get_weekday(1875, 3, 29)) println("December 7, 1915 was on a ", get_weekday(1915, 12, 7)) println("December 23, 1970 was on a ", get_weekday(1970, 12, 23)) println("May 14, 2043 will be on a ", get_weekday(2043, 5, 14)) println("February 12, 2077 will be on a ", get_weekday(2077, 2, 12)) println("April 2, 2101 will be on a ", get_weekday(2101, 4, 2))
</lang>
- Output:
January 6, 1800 was on a Sunday March 29, 1875 was on a Monday December 7, 1915 was on a Tuesday December 23, 1970 was on a Wednesday May 14, 2043 will be on a Thursday February 12, 2077 will be on a Friday April 2, 2101 will be on a Saturday
PL/M
<lang plm>100H: BDOS: PROCEDURE (FN, ARG); DECLARE FN BYTE, ARG ADDRESS; GO TO 5; END BDOS; EXIT: PROCEDURE; CALL BDOS(0,0); END EXIT; PRINT: PROCEDURE (S); DECLARE S ADDRESS; CALL BDOS(9,S); END PRINT; PRINT$CHAR: PROCEDURE (C); DECLARE C BYTE; CALL BDOS(2,C); END PRINT$CHAR;
PRINT$NUMBER: PROCEDURE (N);
DECLARE S (6) BYTE INITIAL ('.....$'); DECLARE (N, P) ADDRESS, C BASED P BYTE; P = .S(5);
DIGIT:
P = P-1; C = N MOD 10 + '0'; N = N / 10; IF N >0 THEN GO TO DIGIT; CALL PRINT(P);
END PRINT$NUMBER;
PRINT$DATE: PROCEDURE (YEAR, MONTH, DAY);
DECLARE YEAR ADDRESS, (MONTH, DAY) BYTE; CALL PRINT$NUMBER(MONTH); CALL PRINT$CHAR('/'); CALL PRINT$NUMBER(DAY); CALL PRINT$CHAR('/'); CALL PRINT$NUMBER(YEAR);
END PRINT$DATE;
DAY$NAME: PROCEDURE (N) ADDRESS;
DECLARE N BYTE; DO CASE N; RETURN .'SUNDAY$'; RETURN .'MONDAY$'; RETURN .'TUESDAY$'; RETURN .'WEDNESDAY$'; RETURN .'THURSDAY$'; RETURN .'FRIDAY$'; RETURN .'SATURDAY$'; END;
END DAY$NAME;
LEAP$YEAR: PROCEDURE (YEAR) BYTE;
DECLARE YEAR ADDRESS; RETURN (YEAR MOD 4 = 0) AND ((YEAR MOD 100 <> 0) OR (YEAR MOD 400 = 0));
END LEAP$YEAR;
WEEK$DAY: PROCEDURE (YEAR, MONTH, DAY) BYTE;
DECLARE LEAP$DOOM DATA (4,1,7,4,2,6,4,1,5,3,7,5); DECLARE NORM$DOOM DATA (3,7,7,4,2,6,4,1,5,3,7,5); DECLARE YEAR ADDRESS, (MONTH, DAY) BYTE; DECLARE (C, R, S, T, C$ANCHOR, DOOM$DAY, ANCHOR$DAY) BYTE; C = YEAR / 100; R = YEAR MOD 100; S = R / 12; T = R MOD 12; C$ANCHOR = (5 * (C MOD 4) + 2) MOD 7; DOOM$DAY = (S + T + T/4 + C$ANCHOR) MOD 7; IF LEAP$YEAR(YEAR) THEN ANCHOR$DAY = LEAP$DOOM(MONTH-1); ELSE ANCHOR$DAY = NORM$DOOM(MONTH-1); RETURN (DOOM$DAY + DAY - ANCHOR$DAY + 7) MOD 7;
END WEEK$DAY;
FORMAT$OUT: PROCEDURE (YEAR, MONTH, DAY);
DECLARE YEAR ADDRESS, (MONTH, DAY) BYTE; CALL PRINT$DATE(YEAR, MONTH, DAY); CALL PRINT(.': $'); CALL PRINT(DAY$NAME(WEEK$DAY(YEAR, MONTH, DAY))); CALL PRINT(.(13,10,'$'));
END FORMAT$OUT;
DECLARE YEARS (7) ADDRESS INITIAL (1800, 1875, 1915, 1970, 2043, 2077, 2101); DECLARE MONTHS (7) BYTE INITIAL ( 1, 3, 12, 12, 5, 2, 4); DECLARE DAYS (7) BYTE INITIAL ( 6, 29, 7, 23, 14, 12, 2);
DECLARE I BYTE; DO I=0 TO LAST(DAYS);
CALL FORMAT$OUT(YEARS(I), MONTHS(I), DAYS(I));
END; CALL EXIT; EOF</lang>
- Output:
1/6/1800: MONDAY 3/29/1875: MONDAY 12/7/1915: TUESDAY 12/23/1970: WEDNESDAY 5/14/2043: THURSDAY 2/12/2077: FRIDAY 4/2/2101: SATURDAY
Python
<lang python>from datetime import date from calendar import isleap
def weekday(d):
days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] dooms = [ [3, 7, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5], [4, 1, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5] ] c = d.year // 100 r = d.year % 100 s = r // 12 t = r % 12 c_anchor = (5 * (c % 4) + 2) % 7 doomsday = (s + t + (t // 4) + c_anchor) % 7 anchorday = dooms[isleap(d.year)][d.month - 1] weekday = (doomsday + d.day - anchorday + 7) % 7 return days[weekday]
dates = [date(*x) for x in
[(1800, 1, 6), (1875, 3, 29), (1915, 12, 7), (1970, 12, 23), (2043, 5, 14), (2077, 2, 12), (2101, 4, 2)]
]
for d in dates:
tense = "was" if d < date.today() else "is" if d == date.today() else "will be" print("{} {} a {}".format(d.strftime("%B %d, %Y"), tense, weekday(d)))</lang>
- Output:
January 06, 1800 was a Monday March 29, 1875 was a Monday December 07, 1915 was a Tuesday December 23, 1970 was a Wednesday May 14, 2043 will be a Thursday February 12, 2077 will be a Friday April 02, 2101 will be a Saturday
Raku
<lang perl6>my @dow = < Sunday Monday Tuesday Wednesday Thursday Friday Saturday >;
my %doomsday = False => [3,7,7,4,2,6,4,1,5,3,7,5], True => [4,1,7,4,2,6,4,1,5,3,7,5];
sub conway ($date) {
my ($year, $month, $day) = $date.comb(/\d+/)».Int; my $is-leap = ($year %% 4) && (($year % 100) || ($year %% 400));
my $c = $year div 100; my $s = ($year % 100) div 12; my $t = ($year % 100) % 12; my $a = ( 5 * ($c % 4) + 2 ) % 7; my $b = ( $s + $t + ($t div 4) + $a ) % 7;
($b + $day - %doomsday{$is-leap}[$month - 1] + 7) % 7
}
for < 1800-01-06 1875-03-29 1915-12-07 1970-12-23 2043-05-14 2077-02-12 2101-04-02 >
{
say "Conway - $_ is a: ", @dow[.&conway]; # Or, we could use the method built into the compiler... say "Builtin - $_ is a: ", @dow[Date.new($_).day-of-week]; say ;
}</lang>
- Output:
Conway - 1800-01-06 is a: Monday Builtin - 1800-01-06 is a: Monday Conway - 1875-03-29 is a: Monday Builtin - 1875-03-29 is a: Monday Conway - 1915-12-07 is a: Tuesday Builtin - 1915-12-07 is a: Tuesday Conway - 1970-12-23 is a: Wednesday Builtin - 1970-12-23 is a: Wednesday Conway - 2043-05-14 is a: Thursday Builtin - 2043-05-14 is a: Thursday Conway - 2077-02-12 is a: Friday Builtin - 2077-02-12 is a: Friday Conway - 2101-04-02 is a: Saturday Builtin - 2101-04-02 is a: Saturday
Wren
We only use the above module to check the dates of the week given by Conway's method. The latter are worked out from scratch. <lang ecmascript>import "/date" for Date
var days = ["Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday"]
var anchorDay = Fn.new { |y| (2 + 5 * (y%4) + 4 *(y%100) + 6 * (y%400)) % 7 }
var isLeapYear = Fn.new { |y| y%4 == 0 && (y%100 != 0 || y%400 == 0) }
var firstDaysCommon = [3, 7, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5] var firstDaysLeap = [4, 1, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5]
var dates = [
"1800-01-06", "1875-03-29", "1915-12-07", "1970-12-23", "2043-05-14", "2077-02-12", "2101-04-02"
]
System.print("Days of week given by Doomsday rule:") for (date in dates) {
var y = Num.fromString(date[0..3]) var m = Num.fromString(date[5..6]) - 1 var d = Num.fromString(date[8..9]) var a = anchorDay.call(y) var w = d - (isLeapYear.call(y) ? firstDaysLeap[m] : firstDaysCommon[m]) if (w < 0) w = 7 + w var dow = (a + w) % 7 System.print("%(date) -> %(days[dow])")
}
System.print("\nDays of week given by Date module:") for (date in dates) {
var d = Date.parse(date, Date.isoDate) System.print("%(date) -> %(d.weekDay)")
}</lang>
- Output:
Days of week given by Doomsday rule: 1800-01-06 -> Monday 1875-03-29 -> Monday 1915-12-07 -> Tuesday 1970-12-23 -> Wednesday 2043-05-14 -> Thursday 2077-02-12 -> Friday 2101-04-02 -> Saturday Days of week given by Date module: 1800-01-06 -> Monday 1875-03-29 -> Monday 1915-12-07 -> Tuesday 1970-12-23 -> Wednesday 2043-05-14 -> Thursday 2077-02-12 -> Friday 2101-04-02 -> Saturday