Doomsday rule

From Rosetta Code
Task
Doomsday rule
You are encouraged to solve this task according to the task description, using any language you may know.
About the task

John Conway (1937-2020), was a mathematician 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 on 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

   doomsday = (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 dividing 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



11l

Translation of: Python
F isleap(year)
   R year % 4 == 0 & (year % 100 != 0 | year % 400 == 0)

F weekday(year, month, day)
   V days = [‘Sunday’, ‘Monday’, ‘Tuesday’,
             ‘Wednesday’, ‘Thursday’, ‘Friday’, ‘Saturday’]
   V 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]]

   V c = year I/ 100
   V r = year % 100
   V s = r I/ 12
   V t = r % 12
   V c_anchor = (5 * (c % 4) + 2) % 7
   V doomsday = (s + t + (t I/ 4) + c_anchor) % 7
   V anchorday = dooms[isleap(year)][month - 1]
   V weekday = (doomsday + day - anchorday + 7) % 7
   R days[weekday]

L(year, month, day) [(1800, 1, 6), (1875, 3, 29), (1915, 12, 7),
     (1970, 12, 23), (2043, 5, 14), (2077, 2, 12), (2101, 4, 2)]
   print(‘#.-#02-#02 -> #.’.format(year, month, day, weekday(year, month, day)))
Output:
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

ALGOL 68

Translation of: ALGOL W
BEGIN # find the day of the week of dates using John Conway's Doomsday rule #
    # returns the day of the week (Sunday = 0, Monday = 1,...) for the date #
    #         specified by ccyy, mm and dd                                  #
    PROC dow = ( INT ccyy, mm, dd )INT:
        BEGIN
            INT  doomsday     = ( # Tuesday # 2
                              + ( 5 * ( ccyy MOD   4 ) )
                              + ( 4 * ( ccyy MOD 100 ) )
                              + ( 6 * ( ccyy MOD 400 ) )
                              )
                            MOD 7;
            BOOL is leap year = ccyy MOD 4 = 0
                            AND ( ccyy MOD 100 /= 0 OR ccyy MOD 400 = 0 );
            INT  anchor day   = CASE mm 
                                  IN IF is leap year THEN 4 ELSE 3 FI
                                   , IF is leap year THEN 1 ELSE 7 FI
                                   , 7, 4, 2, 6, 4, 1, 5, 3, 7, 5
                                ESAC;
        ( doomsday + ( dd - anchor day ) ) MOD 7
    END # dow # ;
    BEGIN # task test cases #
        # prints a test date and its day of the week #
        PROC test dow = ( INT ccyy, mm, dd )VOID:
             BEGIN
                 []CHAR   digit    = "0123456789"[ AT 0 ];
                 []STRING day name =
                          []STRING( "Sunday",   "Monday", "Tuesday", "Wednesday"
                                  , "Thursday", "Friday", "Saturday"
                                  )[ AT 0 ];
                 print( ( whole( ccyy, 0 )
                        , "-",  digit[ mm OVER 10 ], digit[ mm MOD 10 ]
                        , "-",  digit[ dd OVER 10 ], digit[ dd MOD 10 ]
                        , ": ", day name[ dow( ccyy, mm, dd ) ]
                        , newline
                        )
                      )
            END # test dow # ;
        test dow( 1800,  1,  6 );
        test dow( 1875,  3, 29 );
        test dow( 1915, 12,  7 );
        test dow( 1970, 12, 23 );
        test dow( 2043,  5, 14 );
        test dow( 2077,  2, 12 );
        test dow( 2101,  4,  2 );
        test dow( 2022,  6, 19 )
    END
END
Output:
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
2022-06-19: Sunday

ALGOL W

begin % find the day of the week of dates using John Conway's Doomsday rule %
    % returns the day of the week (Sunday = 0, Monday = 1,...) for the date %
    %         specified by ccyy, mm and dd                                  %
    integer procedure dow ( integer value ccyy, mm, dd ) ;
    begin
        integer doomsday, anchorDay;
        logical isLeapYear;
        doomsday   := ( % Tuesday % 2
                      + ( 5 * ( ccyy rem   4 ) )
                      + ( 4 * ( ccyy rem 100 ) )
                      + ( 6 * ( ccyy rem 400 ) )
                      )
                  rem 7;
        isLeapYear := ccyy rem 4 = 0 and ( ccyy rem 100 not = 0 or ccyy rem 400 = 0 );
        anchorDay  := case mm of ( if isLeapYear then 4 else 3
                                 , if isLeapYear then 1 else 7
                                 , 7, 4, 2, 6, 4, 1, 5, 3, 7, 5
                                 );
        ( doomsday + ( dd - anchorDay ) ) rem 7
    end dow ;
    begin % task test cases %
        % prints a test date and its day of the week %
        procedure testDow ( integer value ccyy, mm, dd ) ;
            write( i_w := 1, s_w := 0
                 , ccyy
                 , "-",  mm div 10, mm rem 10
                 , "-",  dd div 10, dd rem 10
                 , ": ", dayName( dow( ccyy, mm, dd ) )
                 );
        string(9) array dayName ( 0 :: 6 );
        dayName( 0 ) := "Sunday";    dayName( 1 ) := "Monday";   dayName( 2 ) := "Tuesday";
        dayName( 3 ) := "Wednesday"; dayName( 4 ) := "Thursday"; dayName( 5 ) := "Friday";
        dayName( 6 ) := "Saturday";
        testDow( 1800,  1,  6 );
        testDow( 1875,  3, 29 );
        testDow( 1915, 12,  7 );
        testDow( 1970, 12, 23 );
        testDow( 2043,  5, 14 );
        testDow( 2077,  2, 12 );
        testDow( 2101,  4,  2 );
        testDow( 2022,  6, 19 )
    end
end.
Output:
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
2022-06-19: Sunday

APL

Works with: Dyalog APL
weekday{⎕IO1
    days'Sunday' 'Monday' 'Tuesday' 'Wednesday' 'Thursday' 'Friday' 'Saturday'
    leap4 720=4 100 400|
    ld4 7 1 4 2 6 4 1 5 3 7 5
    nd3 7 7 4 2 6 4 1 5 3 7 5
    y m d
    cy÷100  r100|y
    sr÷12   t12|r
    can7|2+5×4|c
    doom7|s+t+can+⌊t÷4
    anchorm(1+leap y)nd ld
    (1+7|7+doom+d-anchor)days
}
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

AppleScript

on dayOfWeek(yyyymmdd)
    tell yyyymmdd to set {y, m, d} to {word 1 as integer, word 2 as integer, word 3 as integer}
    set doomsdayForYear to (y + y div 4 - y div 100 + y div 400 + 2) -- (mod 7 further down anyway)
    if ((m < 3) and ((y mod 4 = 0) and (y mod 100 > 0) or (y mod 400 = 0))) then set m to m + 12
    set doomsdayInMonth to item m of {3, 28, 7, 4, 2, 6, 4, 8, 5, 10, 7, 12, 4, 29}
    
    return item ((doomsdayForYear + d - doomsdayInMonth + 28) mod 7 + 1) of ¬
        {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
end dayOfWeek

on join(lst, delim)
    set astid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to delim
    set txt to lst as text
    set AppleScript's text item delimiters to astid
    return txt
end join

on task()
    set dateStrings to {"1800-01-06", "1875-03-29", "1915-12-07", "1970-12-23", "2043-05-14", "2077-02-12", "2101-04-02"}
    set output to {}
    repeat with yyyymmdd in dateStrings
        set end of output to yyyymmdd & " --> " & dayOfWeek(yyyymmdd)
    end repeat
    return join(output, linefeed)
end task

task()
Output:
"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"

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.

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
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.

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)))
$)
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

#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;
}
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#

Translation of: Java
using System;

class Doom {
    public static void Main(string[] args) {
        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)
        };
        
        foreach (Date d in dates)
            Console.WriteLine($"{d.Format()}: {d.Weekday()}");
    }
}

class Date {
    private int year, month, day;
    
    private static readonly int[] leapDoom = {4,1,7,4,2,6,4,1,5,3,7,5};
    private static readonly int[] normDoom = {3,7,7,4,2,6,4,1,5,3,7,5};
    public static readonly 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 bool IsLeapYear() {
        return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
    }
    
    public string Format() {
        return $"{month:00}/{day:00}/{year:0000}";
    }
    
    public string Weekday() {
        int c = year / 100;
        int r = year % 100;
        int s = r / 12;
        int t = r % 12;
        
        int cAnchor = (5 * (c % 4) + 2) % 7;
        int doom = (s + t + t / 4 + cAnchor) % 7;
        int anchor = 
            IsLeapYear() ? leapDoom[month - 1] : normDoom[month - 1];
        
        return weekdays[(doom + day - anchor + 7) % 7];
    }
}
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

C++

#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;
}
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

CLU

leap_year = proc (year: int) returns (bool)
    return(year//4=0 & (year//100=0 | year//400=0))
end leap_year

weekday = proc (d: date) returns (string)
    own leapdoom: array[int] := array[int]$[4,1,7,2,4,6,4,1,5,3,7,5]
    own normdoom: array[int] := array[int]$[3,7,7,4,2,6,4,1,5,3,7,5]
    own days: array[string] := array[string]$[0:
        "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
        "Friday", "Saturday"
    ]
    
    c: int := d.year/100
    r: int := d.year//100
    s: int := r/12
    t: int := r//12
    
    c_anchor: int := (5 * (c//4) + 2) // 7
    doom: int := (s + t + t/4 + c_anchor) // 7
    anchor: int
    if leap_year(d.year) 
        then anchor := leapdoom[d.month]
        else anchor := normdoom[d.month]
    end
    return(days[(doom+d.day-anchor+7)//7])
end weekday

start_up = proc ()
    po: stream := stream$primary_output()
    dates: array[date] := array[date]$
       [date$create( 1, 6,1800,0,0,0),
        date$create(29, 3,1875,0,0,0),
        date$create( 7,12,1915,0,0,0),
        date$create(23,12,1970,0,0,0),
        date$create(14, 5,2043,0,0,0),
        date$create(12, 2,2077,0,0,0),
        date$create( 2, 4,2101,0,0,0)]
    
    for d: date in array[date]$elements(dates) do
        stream$puts(po, date$unparse_date(d))
        if d<now() 
            then stream$puts(po, " was on a ")
            else stream$puts(po, " will be on a ")
        end
        stream$putl(po, weekday(d))
    end
end start_up
Output:
1 June 1800 was on a Sunday
29 March 1875 was on a Monday
7 December 1915 was on a Tuesday
23 December 1970 was on a Wednesday
14 May 2043 will be on a Thursday
12 February 2077 will be on a Friday
2 April 2101 will be on a Saturday

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;
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

EasyLang

Translation of: C
func leap year .
   return if year mod 4 = 0 and (year mod 100 <> 0 or year mod 400 = 0)
.
func weekday year month day .
   normdoom[] = [ 3 7 7 4 2 6 4 1 5 3 7 5 ]
   c = year div 100
   r = year mod 100
   s = r div 12
   t = r mod 12
   c_anchor = (5 * (c mod 4) + 2) mod 7
   doom = (s + t + (t div 4) + c_anchor) mod 7
   anchor = normdoom[month]
   if leap year = 1 and month <= 2
      anchor = (anchor + 1) mod1 7
   .
   return (doom + day - anchor + 7) mod 7 + 1
.
wkdays$[] = [ "Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" ]
dates$[] = [ "1800-01-06" "1875-03-29" "1915-12-07" "1970-12-23" "2043-05-14" "2077-02-12" "2101-04-02" ]
for d$ in dates$[]
   write d$ & " -> "
   a[] = number strsplit d$ "-"
   print wkdays$[weekday a[1] a[2] a[3]]
.

Factor

Works with: Factor version 0.99 2021-02-05
USING: accessors calendar calendar.english formatting
generalizations kernel math math.order math.vectors sequences ;

: check-year ( year -- )  ! months and days checked by <date>
    1582 9999 between?
    [ "Year must be between 1582 and 9999." throw ] unless ;

: doomsday ( year -- n )
    { 4 100 400 } [ mod ] with map { 5 4 6 } vdot 2 + 7 mod ;

: anchorday ( year month -- m )
    1 - swap leap-year? { 4 1 } { 3 7 } ?
    { 7 4 2 6 4 1 5 3 7 5 } append nth ;

: weekday ( date -- str )
    [ year>> dup check-year doomsday ] [ day>> + ]
    [ dup year>> swap month>> anchorday - 7 + 7 mod ] tri
    day-names nth ;

: test ( date -- )
    [ "%B %d, %Y" strftime ]
    [ now before? "was" "will be" ? ]
    [ weekday ] tri
    "%s %s on a %s.\n" printf ;

1800 1 6
1875 3 29
1915 12 7
1970 12 23
2043 5 14
2077 2 12
2101 4 2
[ <date> test ] 3 7 mnapply
Output:
January 06, 1800 was on a Monday.
March 29, 1875 was on a Monday.
December 07, 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 02, 2101 will be on a Saturday.

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"
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

Fortran

      program someday   ! Calculates the day that a week falls on
          use datestuff
          implicit none
!
! PARAMETER definitions
!
          integer , parameter :: numdates = 7
!
! Local variable declarations
!
          character(30) , dimension(numdates) , save :: date_string
          integer , dimension(numdates) , save :: day
          character(9) , dimension(numdates) , save :: days
          integer :: j
          integer :: k
          integer , dimension(numdates) , save :: month
          integer , dimension(numdates) , save :: year
!
          data days/'Monday   ' , 'Tuesday  ' , 'Wednesday' , 'Thursday ' ,     &
              &'Friday   ' , 'Saturday ' , 'Sunday   '/
          data month/01 , 03 , 12 , 12 , 05 , 02 , 04/
          data day/06 , 29 , 07 , 23 , 14 , 12 , 02/
          data year/1800 , 1875 , 1915 , 1970 , 2043 , 2077 , 2101/
          data date_string/'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)'/                                                !
!*Code

          print *
          do j = 1 , numdates
              k = get_the_day(day(j) , month(j) , year(j))
              print '(a, t31,1a1,1x,a)' , date_string(j) , ':' , days(k)
          end do
      end program someday
      module datestuff
          implicit none
          public :: get_the_day
          private :: get_anchor_day , gregorian_leap_year
!
          enum , bind(c) ! Use enums to get greater clarity in the code
              enumerator :: january = 1 , february , march , april , may ,      &
                       & june , july , august , september , october , november ,&
                       & december
          end enum
          enum , bind(c)
              enumerator :: sunday = 0 , monday , tuesday , wednesday ,         &
                       & thursday , friday , saturday
          end enum
      contains
!
          pure function gregorian_leap_year(year) result(answer)      ! Tests if the year is a leap year
!
! Function and Dummy argument declarations
!
              logical :: answer
              integer , intent(in) :: year
!
              answer = .false.                              ! Set default to not a leap year
              if( mod(year , 4)==0 )answer = .true.         ! Year divisible by 4 = leap year
              if( mod(year , 100)==0 )then
                  if( mod(year , 400)==0 )then               ! Year divisible by 400 = century year that is leap year
                      answer = .true.
                  else
                      answer = .false.                       ! Century years are not leap years
                  end if
              end if
          end function gregorian_leap_year
!
          pure function get_anchor_day(year) result(answer) ! Returns Anchor Days in doomsday calculation
!Note: The days start as Monday = 1, Tuesday =2, etc until Sunday = 7
!The Doomsday rule, Doomsday algorithm or Doomsday method is an algorithm of determination of the day of the week for a given date.
!It provides a perpetual calendar because the Gregorian calendar moves in cycles of 400 years.
!It takes advantage of each year having a certain day of the week upon which certain easy-to-remember dates,
!called the doomsdays, fall; for example, the last day of February, 4/4, 6/6, 8/8, 10/10, and 12/12 all occur
! on the same day of the week in any year. Applying the Doomsday algorithm involves three steps: Determination of the anchor day
! for the century, calculation of the anchor day for the year from the one for the century, and selection of the closest date
! out of those that always fall on the doomsday, e.g., 4/4 and 6/6, and count of the number of days (modulo 7) between that
! date and the date in question to arrive at the day of the week. The technique applies to both the Gregorian calendar and the
! Julian calendar, although their doomsdays are usually different days of the week.
!
! Function and Dummy argument declarations
!
              integer :: answer
              integer , intent(in) :: year
!
! Local variable declarations
!
              integer :: diffyear
              integer :: div12
              integer :: numyears
              integer :: temp1
!
! End of declarations
!*Code
              numyears = mod(year , 100)                ! Get number of years greater than century

              temp1 = year - numyears                   ! Turn into a century year
              temp1 = mod(temp1 , 400)                  ! Now mod 400 to get base year for anchor day
              select case(temp1)                        ! Select the base day
              case(0)
                  answer = tuesday
              case(100)
                  answer = sunday
              case(200)
                  answer = friday
              case(300)
                  answer = wednesday
              case default                              ! Anything else is an error
                  ERROR Stop 'Bad Anchor Day'                    ! Finish with error
              end select
    !
    !Calculate the doomsday of any given year
    !
              div12 = int(numyears/12)               ! Get number of times 12 goes into year
              temp1 = mod(numyears , 12)             ! Get the remainer
              diffyear = int(temp1/4)                ! Div 4 (magic algorithm)
              answer = diffyear + div12 + answer + temp1
              answer = mod(answer , 7)
          end function get_anchor_day          ! Note: The days start as Sunday = 0, Monday = 1, Tuesday =2, etc until Saturda
!
          pure function get_the_day(day , month , year) result(answer)
! Note: The days start as Sunday = 0, Monday = 1, Tuesday =2, etc until Saturday = 6
!
! Function and Dummy argument declarations
              integer :: answer
              integer , intent(in) :: day
              integer , intent(in) :: month
              integer , intent(in) :: year
!
! Local variable declarations
              integer :: closest
              integer :: doomsday
              integer :: temp1
              integer :: temp2
              integer :: up_or_down
!
! End of declarations
!
    ! There are doomsdays in every month, so we know what month it is ...
    ! We need to find the doomsday in the relevant month
              select case(month)                                ! Scratch Variables
              case(january)
                  closest = merge(4,3,gregorian_leap_year(year))  ! Use merge as a ternary
              case(february)
                  closest = merge(29,28,gregorian_leap_year(year))  ! Use merge as a ternary
              case(march)
                  closest = 7
              case(april)
                  closest = 4
              case(may)
                  closest = 9
              case(june)
                  closest = 6
              case(july)
                  temp1 = abs(4 - day)
                  temp2 = abs(11 - day)
                  closest = merge(4,11,temp1<temp2)  ! Use merge as a ternary
              case(august)
                  closest = 8
              case(september)
                  closest = 5
              case(october)
                  temp1 = abs(10 - day)
                  temp2 = abs(31 - day)
                  closest = merge(10,31,temp1<temp2)  ! Use merge as a ternary
              case(november)
                  closest = 7
              case(december)
                  closest = 12
              case default
                  ERROR Stop 'Error in get the day'                   ! Stop on error
              end select
     !
     ! Ok now we get the doomsday in question - i.e. Monday, Tuesday for this year
              doomsday = get_anchor_day(year)           ! Get this years doomsday
    ! If closest day is less we need to count down, if it is bigger we count up

              if( closest>day )then
                  up_or_down = -7
              else if( closest<day )then
                  up_or_down = 7
              else
                  up_or_down = 0                    ! The days are equal. Set to zero so no counting needed
              end if
              temp1 = closest                       ! Set temp var to closest doomsday
              if( up_or_down>0 )then
                  do while ( temp1<=day )
                      temp2 = temp1
                      temp1 = temp1 + up_or_down    ! Count in sevens to the final
                  end do
                  temp1 = day - temp2
                  temp1 = (doomsday + 7) + temp1
              else if( up_or_down<0 )then
                  do while ( temp1>=day )
                      temp2 = temp1
                      temp1 = temp1 + up_or_down    ! Count in sevens to the final
                  end do
                  temp1 = temp2 - day               ! See how far away I am from this day
                  temp1 = (doomsday + 7) - temp1    ! Subtract the difference in days from the known doomsday
              else
                  temp1 = doomsday                  ! It fell on the doomsday
              end if
              answer = mod(temp1 , 7)               ! Turn Sundays into Zeros
          end function get_the_day
!
      end module datestuff
    !
Output:
1800-01-06 (January 6, 1800)  : Monday   
1875-03-29 (March 29, 1875)   : Monday   
1915-12-07 (December 7, 1915) : Tuesday  
1970-12-23 (December 23, 1970): Wednesday
2043-05-14 (May 14, 2043)     : Thursday 
2077-02-12 (February 12, 2077): Friday   
2101-04-02 (April 2, 2101)    : Saturday 

FreeBASIC

dim shared as ubyte fdoom(0 to 1, 1 to 12) = {_
    { 3, 7, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5 }, _
    { 4, 1, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5 } } 'the first doomsday in
                                             'each month for common
                                             'and leap years

dim shared as string*10 days(0 to 6) = {"Sunday", "Monday", "Tuesday", "Wednesday",_
                              "Thursday", "Friday", "Saturday"}

function doomsday(y as uinteger) as ubyte
    ' John Conway's doomsday formula
    return (2 + 5*(y mod 4) + 4*(y mod 100) + 6*(y mod 400)) mod 7
end function 

function leap(y as uinteger) as ubyte
    'is it a leap year? 
    'return 0 for common years, 1 for leap years
    if y mod 4 > 0 then return 0
    if y mod 100 = 0 and y mod 400 > 0 then return 0
    return 1
end function

function get_day(y as uinteger, m as ubyte, d as ubyte) as string
    dim as ubyte c = doomsday(y), diff
    diff = (7 + d - fdoom( leap(y), m )) mod 7
    return days( (c+diff) mod 7 )
end function

print get_day( 1800, 01, 06 )
print get_day( 1875, 03, 29 )
print get_day( 1915, 12, 07 )
print get_day( 1970, 12, 23 )
print get_day( 2043, 05, 14 )
print get_day( 2077, 02, 12 )
print get_day( 2101, 04, 02 )
Output:
Monday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday


FutureBasic

local fn IsLeapYear( year as NSUInteger ) as BOOL
  BOOL result = YES
  if ( year mod 4 > 0 ) then result = NO : exit fn
  if ( year mod 100 = 0 ) and ( year mod 400 > 0 ) then result = NO : exit fn
end fn = result

local fn DoomsdayWeekdayForDate( month as NSUInteger, day as NSUInteger, year as NSUInteger ) as CFStringRef
  CFArrayRef  weekdayNames   = @[@"Sunday", @"Monday", @"Tuesday", @"Wednesday", @"Thursday", @"Friday", @"Saturday"]
  CFArrayRef  normalYearDays = @[@4, @1, @7, @4, @2, @6, @4, @1, @5, @3, @7, @5]
  CFArrayRef  leapYearDays   = @[@3, @7, @7, @4, @2, @6, @4, @1, @5, @3, @7, @5]
  CFStringRef dayOfWeek      = @""
  NSUInteger  anchorday
  
  NSUInteger doomsday = ( 2 + 5 * ( year mod 4 ) + 4 * ( year mod 100 ) + 6 * ( year mod 400) ) mod 7
  if ( fn IsLeapYear( year ) ) then anchorday = intVal( normalYearDays[month-1] ) else anchorday = intVal( leapYearDays[month-1] )
  NSUInteger weekday = ( doomsday + day - anchorday + 7 ) mod 7
  if ( weekday == 0 ) then dayOfWeek = @"Sunday" else dayOfWeek = weekdayNames[weekday]
end fn = dayOfWeek

printf @"01-06-1800 : %@", fn DoomsdayWeekdayForDate(  1,  6, 1800 )
printf @"03-29-1875 : %@", fn DoomsdayWeekdayForDate(  3, 29, 1875 )
printf @"12-07-1915 : %@", fn DoomsdayWeekdayForDate( 12,  7, 1915 )
printf @"12-23-1970 : %@", fn DoomsdayWeekdayForDate( 12, 23, 1970 )
printf @"05-14-2043 : %@", fn DoomsdayWeekdayForDate(  5, 14, 2043 )
printf @"02-12-2077 : %@", fn DoomsdayWeekdayForDate(  2, 12, 2077 )
printf @"04-02-2101 : %@", fn DoomsdayWeekdayForDate(  4,  2, 2101 )

HandleEvents
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


Go

Translation of: Wren
package main

import (
    "fmt"
    "strconv"
)

var days = []string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}

func anchorDay(y int) int {
    return (2 + 5*(y%4) + 4*(y%100) + 6*(y%400)) % 7
}

func isLeapYear(y int) bool { return y%4 == 0 && (y%100 != 0 || y%400 == 0) }

var firstDaysCommon = []int{3, 7, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5}
var firstDaysLeap = []int{4, 1, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5}

func main() {
    dates := []string{
        "1800-01-06",
        "1875-03-29",
        "1915-12-07",
        "1970-12-23",
        "2043-05-14",
        "2077-02-12",
        "2101-04-02",
    }

    fmt.Println("Days of week given by Doomsday rule:")
    for _, date := range dates {
        y, _ := strconv.Atoi(date[0:4])
        m, _ := strconv.Atoi(date[5:7])
        m--
        d, _ := strconv.Atoi(date[8:10])
        a := anchorDay(y)
        f := firstDaysCommon[m]
        if isLeapYear(y) {
            f = firstDaysLeap[m]
        }
        w := d - f
        if w < 0 {
            w = 7 + w
        }
        dow := (a + w) % 7
        fmt.Printf("%s -> %s\n", date, days[dow])
    }
}
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

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 "%4d-%02d-%02d" y m d

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} =
  let 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
   in (doom + d - anchor + 7) `mod` 7

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
Output:
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

J

To find the doomsday for a month, find the number of days for each month in that year, and compute the running sum from right to left. Then add 1 to each of those numbers, find the mod 7 remainder and add 1 again

   1+7|1++/\.31 28 31 30 31 30 31 31 30 31 30 31 
3 7 7 4 2 6 4 1 5 3 7 5
   1+7|1++/\.31 29 31 30 31 30 31 31 30 31 30 31 
4 1 7 4 2 6 4 1 5 3 7 5

Also note that adding 7 is like adding 0 in modulo 7 arithmetic.

Thus:

get_weekday=: {{ 'Y M D'=. y
  Y0=. todayno Y,1 1
  Y1=. todayno 1+Y,0 0
  aday=. M{_,1+7|1++/\.>.//./}.|:todate Y0+i.Y1-Y0
  dday=. 7|2 5 4 6+/ .*1,4 100 400|/Y
  'day',~;(7|D+dday-aday){;:'Sun Mon Tues Wednes Thurs Fri Satur'
}}

That said, it's more concise to look up these anchor days. We can use the nonleap year sequence and adjust january and february's values for leap years by adding 1 or 2 (under 1 offset 7 modulo arithmetic).

get_weekday=: {{ 'Y M D'=. y
  leap=. 0~:/ .=4 100 400|/Y
  aday=. 1+7|(M*leap*3>M)+M{_ 2 6 6 3 1 5 3 0 4 2 6 4
  dday=. 7|2 5 4 6+/ .*1,4 100 400|/Y
  'day',~;(7|D+dday-aday){;:'Sun Mon Tues Wednes Thurs Fri Satur'
}}

These two implementations produce equivalent results.

Task examples:

   get_weekday 1800 1 6
Monday
   get_weekday 1875 3 29
Monday
   get_weekday 1915 12 7
Tuesday
   get_weekday 1970 12 23
Wednesday
   get_weekday 2043 5 14
Thursday
   get_weekday 2077 2 12
Friday
   get_weekday 2101 4 2
Saturday

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];
    }
}
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

jq

Translation of: Julia
Works with: jq

Works with gojq, the Go implementation of jq

Note that the assertions as defined here are only checked if the environment variable JQ_ASSERT is set.

def weekdaynames: ["Sunday", "Monday","Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

# For months 1 through 12, the date of the first doomsday that month.
def leapyear_firstdoomsdays: [4, 1, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5];
def 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 the past or future subject to 1582<=$year<=9999.
# Uses Conway's doomsday rule (see also https://en.wikipedia.org/wiki/Doomsday_rule)

def assert(exp; msg):
  if env.JQ_ASSERT then
    (exp as $e | if $e then . else . as $in | "assertion violation: \(msg) => \($e)" | error end)
  else . end;

def get_weekday($year; $month; $day):
    # sanity checks
      assert(1582 <= $year and $year <= 9999; "Invalid year (\($year) - should be after 1581 and 4 digits)")
    | assert( 1 <= $month and $month <= 12;   "Invalid month, should be between 1 and 12")
    | assert( 1 <= $day and $day <= 31;       "Invalid day, should be between 1 and 31")
 
    # Conway's doomsday algorithm
    | ((2 + 5 * ($year % 4) + 4 * ($year % 100) + 6 * ($year % 400)) % 7) as $doomsday
    # leap year determination:
    | (if (($year % 4 != 0) or ($year % 100 == 0 and $year % 400 != 0))
      then nonleapyear_firstdoomsdays[$month - 1]
      else leapyear_firstdoomsdays[$month - 1]
      end) as $anchorday
   | (($doomsday + $day - $anchorday + 7) % 7) as $weekday # IO==0
   | weekdaynames[$weekday] ;
 
("January 6, 1800 was on a "      + get_weekday(1800;  1;  6)),
("March 29, 1875 was on a "       + get_weekday(1875;  3; 29)),
("December 7, 1915 was on a "     + get_weekday(1915; 12;  7)),
("December 23, 1970 was on a "    + get_weekday(1970; 12; 23)),
("May 14, 2043 will be on a "     + get_weekday(2043;  5; 14)),
("February 12, 2077 will be on a "+ get_weekday(2077;  2; 12)),
("April 2, 2101 will be on a "    + get_weekday(2101;  4;  2)),
("April 2, 21011 will be on a "   + get_weekday(21011; 4;  2))
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
April 2, 21011 will be on a Tuesday

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
    doomsday = (2 + 5 * (year % 4) + 4 * (year % 100) + 6 * (year % 400)) % 7
    anchorday = (year % 4 != 0) || (year % 100 == 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))
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

Nim

We use the “times” standard module to parse the dates, check for leap years and compare results with those obtained with the doomsday rule (useful only to trap bugs in our implementation). We use also the “WeekDay” type of this module which is an enumeration starting with “dMon” for Monday and ending with “dSun” for Sunday.

import strformat, times

const
  NormDoom = [1: 3, 7, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5]
  LeapDoom = [1: 4, 1, 7, 2, 4, 6, 4, 1, 5, 3, 7, 5]

proc weekday(year, month, day: int): WeekDay =
  let doom = (2 + 5 * (year mod 4) + 4 * (year mod 100) + 6 * (year mod 400)) mod 7
  let anchor = if year.isLeapYear: LeapDoom[month] else: NormDoom[month]
  let wd = (doom + day - anchor + 7) mod 7
  result = if wd == 0: dSun else: WeekDay(wd - 1)

const Dates = ["1800-01-06", "1875-03-29", "1915-12-07",
               "1970-12-23", "2043-05-14", "2077-02-12", "2101-04-02"]

for date in Dates:
  let dt = date.parse("yyyy-MM-dd")
  let wday = weekday(dt.year, ord(dt.month), dt.monthday)
  if wday != dt.weekday:
    echo &"For {date}, expected {dt.weekday}, found {wday}."
  else:
    echo date, " → ", wday
Output:
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

Perl

Translation of: Raku
# 20210602 Perl programming solution

use strict;
use warnings;

sub dow ($) {
   my ($year, $month, $day) = split /-/;
   my @D = $year%($year%25?4:16) ? (3,7,7,4,2,6,4,1,5,3,7,5) : (4,1,7,2,4,6,4,1,5,3,7,5);
   my $c = int($year / 100);
   my $s = ($year % 100) / 12;
   my $t = ($year % 100) % 12;
   my $a = ( 5 * ($c % 4) + 2 ) % 7;
   my $b = ( $s + $t + int($t / 4) + $a ) % 7;

   qw ( Sunday Monday Tuesday Wednesday Thursday Friday Saturday ) [
      ($b + $day - $D[$month - 1] + 7) % 7 ]
}

for (qw( 1800-01-06 1875-03-29 1915-12-07 1970-12-23 2043-05-14 2077-02-12 2101-04-02 )) {
   print  $_, " is a : ", dow $_, "\n";
}
Output:
1800-01-06 is a : Monday
1875-03-29 is a : Monday
1915-12-07 is a : Tuesday
1970-12-23 is a : Wednesday
2043-05-14 is a : Thursday
2077-02-12 is a : Friday
2101-04-02 is a : Saturday

Phix

with javascript_semantics

include timedate.e

function doomsday_rule(integer y, m, d)
    integer yr4 = remainder(y,4),
            yr100 = remainder(y,100),
            yr400 = remainder(y,400),
            anchor_day = remainder(2 + 5*yr4 + 4*yr100 + 6*yr400,7)
    bool leap_year = yr4=0 and (yr100!=0 or yr400=0)
    sequence anchors = iff(leap_year?{4, 1, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5}
                                    :{3, 7, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5})
    integer w = d - anchors[m]
    if w<0 then w += 7 end if
    integer dow = remainder(anchor_day+w,7)
--  return dow
    return iff(dow=0?7:dow)     -- to agree with ISO 8601, and Phix.
end function

constant dates = {"1800-01-06",
                  "1875-03-29",
                  "1915-12-07",
                  "1970-12-23",
                  "2043-05-14",
                  "2077-02-12",
                  "2101-04-02"}

for i=1 to length(dates) do
    timedate dt = parse_date_string(dates[i],{"YYYY-MM-DD"})
    integer {y,m,d} = dt,
            bid = day_of_week(y,m,d),
            drd = doomsday_rule(y,m,d)
    string ds = format_timedate(dt,"Dddd Mmmm D, YYYY"),
           bis = day_of_week(y, m, d, bAsText:=true),
           ok = iff(bid==drd?"(ok)":"*** ERROR ***")
    printf(1,"%s\n%-30s (%d = %d ? %s)\n",{ds,bis,bid,drd,ok})
end for
Output:
Monday January 6, 1800
Monday                         (1 = 1 ? (ok))
Monday March 29, 1875
Monday                         (1 = 1 ? (ok))
Tuesday December 7, 1915
Tuesday                        (2 = 2 ? (ok))
Wednesday December 23, 1970
Wednesday                      (3 = 3 ? (ok))
Thursday May 14, 2043
Thursday                       (4 = 4 ? (ok))
Friday February 12, 2077
Friday                         (5 = 5 ? (ok))
Saturday April 2, 2101
Saturday                       (6 = 6 ? (ok))

PL/M

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
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

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)))
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

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 '';
}
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

REXX

/*REXX program finds the day─of─week for a specified date using Conway's Doomsday rule. */
parse arg $                                      /*obtain optional arguments from the CL*/
if $='' | $=","  then $=  ,                      /*Not specified?  Then use the default.*/
            '01/06/1800 03/29/1875 12/07/1915 12/23/1970 05/14/2043 04/02/2077 04/02/2101'
d= 'Sun Mon Tues Wednes Thurs Fri Satur'         /*list of days of the week, sans "day".*/
y.0= 3 7 7 4 2 6 4 1 5 3 7 5                     /*doomsday dates for non-leapyear month*/
y.1= 4 1 7 4 2 6 4 1 5 3 7 5                     /*    "      "    "      leapyear   "  */

      do j=1  for words($);        datum= word($, j)    /*process each of the dates.    */
      parse var  datum    mm  '/'  dd  "/"  yy          /*parse the date  ──►  mm dd yy */
      ly= leapyear(yy)                                  /*get indication of a leapyear. */
      wd= (doomsday(yy)+dd-word(y.ly, mm) + 7) // 7 + 1 /*obtain a code for the weekday.*/
      say datum    ' falls on '    word(d, wd)"day"     /*display day-of-week for date. */
      end   /*j*/
exit 0                                           /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
doomsday: parse arg ?;  return (2  +  5 * (?//4)  +  4 * (?//100)  +  6 * (?//400) ) // 7
leapyear: arg #; ly= #//4==0; if ly==0  then return 0;   return ((#//100\==0) | #//400==0)
output   when using the default inputs:
01/06/1800  falls on  Monday
03/29/1875  falls on  Monday
12/07/1915  falls on  Tuesday
12/23/1970  falls on  Wednesday
05/14/2043  falls on  Thursday
04/02/2077  falls on  Friday
04/02/2101  falls on  Saturday

RPL

Works with: HP version 48G
« IP LASTARG FP 100 * IP LASTARG FP 10000 * 
  → d m y
  « y DUP 100 MOD 4 400 IFTE MOD
    { 3 7 } { 4 1 } IFTE { 7 4 2 6 4 1 5 3 7 5 } + + 
    m GET d SWAP - 7 MOD 
    2 5 y 4 MOD * + 4 y 100 MOD * + 6 y 400 MOD * + 7 MOD 
    + 7 MOD
    { "Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Satursday" }
    SWAP 1 + GET
» » 'WKDAY' STO
{ 6.011800 29.031875 7.121915 23.12197 14.052043 12.022077 2.042101 } 1 « WKDAY » DOLIST
Output:
1: { "Monday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Satursday" }

Rust

fn day_of_week(year: u32, month: u32, day: u32) -> u32 {
    const LEAPYEAR_FIRSTDOOMSDAYS: [u32; 12] = [4, 1, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5];
    const NONLEAPYEAR_FIRSTDOOMSDAYS: [u32; 12] = [3, 7, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5];
    assert!(year > 1581 && year < 10000);
    assert!(month >= 1 && month <= 12);
    assert!(day >= 1 && day <= 31);
    let doomsday = (2 + 5 * (year % 4) + 4 * (year % 100) + 6 * (year % 400)) % 7;
    let anchorday = if year % 4 != 0 || (year % 100 == 0 && year % 400 != 0) {
        NONLEAPYEAR_FIRSTDOOMSDAYS[month as usize - 1]
    } else {
        LEAPYEAR_FIRSTDOOMSDAYS[month as usize - 1]
    };
    (doomsday + day + 7 - anchorday) % 7
}

fn print_day_of_week(year: u32, month: u32, day: u32) {
    const DAY_NAMES: [&str; 7] = [
        "Sunday",
        "Monday",
        "Tuesday",
        "Wednesday",
        "Thursday",
        "Friday",
        "Saturday",
    ];
    println!(
        "{:04}-{:02}-{:02}: {}",
        year,
        month,
        day,
        DAY_NAMES[day_of_week(year, month, day) as usize]
    );
}

fn main() {
    print_day_of_week(1800, 1, 6);
    print_day_of_week(1875, 3, 29);
    print_day_of_week(1915, 12, 7);
    print_day_of_week(1970, 12, 23);
    print_day_of_week(2043, 5, 14);
    print_day_of_week(2077, 2, 12);
    print_day_of_week(2101, 4, 2);
}
Output:
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

Scala

Translation of: Java
object Doom extends App {
  val dates = Array(
    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)
  )

  dates.foreach(d => println(s"${d.format}: ${d.weekday}"))
}

class Date(val year: Int, val month: Int, val day: Int) {
  import Date._

  def isLeapYear: Boolean = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)

  def format: String = f"$month%02d/$day%02d/$year%04d"

  def weekday: String = {
    val c = year / 100
    val r = year % 100
    val s = r / 12
    val t = r % 12

    val cAnchor = (5 * (c % 4) + 2) % 7
    val doom = (s + t + t / 4 + cAnchor) % 7
    val anchor = if (isLeapYear) leapdoom(month - 1) else normdoom(month - 1)

    weekdays((doom + day - anchor + 7) % 7)
  }
}

object Date {
  private val leapdoom = Array(4, 1, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5)
  private val normdoom = Array(3, 7, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5)
  val weekdays = Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
}
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

uBasic/4tH

Translation of: FreeBASIC
Dim @f(24)
Push 3, 7, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5 ' the first doomsday in each 
Push 4, 1, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5 ' month for common and leap years
For x = 23 to 0 Step -1 : @f(x) = Pop() : Next
                                       
Dim @d(7)
Push "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
For x = 6 To 0 Step -1 : @d(x) = Pop() : Next

Print Show(FUNC(_get_day(1800, 01, 06)))
Print Show(FUNC(_get_day(1875, 03, 29)))
Print Show(FUNC(_get_day(1915, 12, 07)))
Print Show(FUNC(_get_day(1970, 12, 23)))
Print Show(FUNC(_get_day(2043, 05, 14)))
Print Show(FUNC(_get_day(2077, 02, 12)))
Print Show(FUNC(_get_day(2101, 04, 02)))

End

_doomsday                              ' John Conway's doomsday formula
Param (1) : Return ((2 + 5*(a@ % 4) + 4*(a@ % 100) + 6*(a@ % 400)) % 7)
 
_leap                                  ' is it a leap year?  
  Param (1) 
                 
  If (a@ % 4 > 0) Then Return (0)      ' return 0 for common years
  If (a@ % 100 = 0) * (a@ % 400 > 0) Then Return (0)
Return (1)                             ' 1 for leap years

_get_day
  Param (3)
  Local (2)

  d@ = FUNC(_doomsday(a@))
  e@ = (7 + c@ - @f(FUNC(_leap(a@)) * 2 + (b@-1))) % 7
Return (@d((d@+e@) % 7))
Output:
Monday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday

0 OK, 0:711

UNIX Shell

Translation of: raku
Works with: Bash
#!/usr/bin/env bash

day-of-the-week()
  if [[ "$1" =~ ([0-9]{4})-([0-9]{2})-([0-9]{2}) ]]
  then
    local -ra names=({Sun,Mon,Tues,Wednes,Thurs,Fri,Satur}day) doomsday=({37,41}7426415375)
    local -i i c s t a b
    local -i {year,month,day}=${BASH_REMATCH[++i]}
    echo ${names[
      c=year/100,
      s=(year%100)/12,
      t=(year % 100) % 12,
      a=(5*(c%4)+2) % 7,
      b=(s + t + (t / 4) + a ) % 7,
      (b + day - ${doomsday[(year%4 == 0) && ((year%100) || (year%400 == 0))]:month-1:1} + 7) % 7
    ]}
  else return 1
  fi

for date in 1800-01-06 1875-03-29 1915-12-07 1970-12-23 2043-05-14 2077-02-12 2101-04-02 
do day-of-the-week "$date"
done
Output:
Monday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday

V (Vlang)

Translation of: Go
const 
(
	days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
	first_days_common = [3, 7, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5]
	first_days_leap = [4, 1, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5]
)

fn main() {
	dates := [
		"1800-01-06",
		"1875-03-29",
		"1915-12-07",
		"1970-12-23",
		"2043-05-14",
		"2077-02-12",
		"2101-04-02"
	]
	mut y, mut m, mut d, mut a, mut f, mut w, mut dow := 0,0,0,0,0,0,0
	println("Days of week given by Doomsday rule:")
	for date in dates {
		y = date[0..4].int()
		m = date[5..7].int()
		m--
		d = date[8..10].int()
		a = anchor_day(y)
		f = first_days_common[m]
		if is_leap_year(y) {
			f = first_days_leap[m]
		}
		w = d - f
		if w < 0 {
			w = 7 + w
		}
		dow = (a + w) % 7
		println('$date -> ${days[dow]}')
	}
}

fn anchor_day(y int) int {
	return (2 + 5 *(y % 4) + 4 * (y % 100) + 6 *(y % 400)) % 7
}

fn is_leap_year(y int) bool { 
	return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0) 
}
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

Wren

Library: Wren-date

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.

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)")
}
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

XPL0

Translation of: ALGOL W
\Finds the day of the week of a date using John Conway's Doomsday rule.
\Returns the day of the week (Sunday = 0, Monday = 1,...) for the date
\ specified by CCYY, MM and DD.
function DOW ( CCYY, MM, DD );
integer CCYY, MM, DD;
integer Doomsday, AnchorDay, LeapYear, Dooms;
begin
Doomsday  := rem(( \Tuesday \2
                 + 5 * rem( CCYY/4 )
                 + 4 * rem( CCYY/100 )
                 + 6 * rem( CCYY/400 )
                 ) / 7);
LeapYear  := rem(CCYY/4) = 0 and ( rem(CCYY/100) # 0 or rem(CCYY/ 400) = 0 );
Dooms     := [[4, 1, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5],
              [3, 7, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5]];
AnchorDay := Dooms(if LeapYear then 0 else 1, MM-1);
return rem( ( Doomsday + ( DD - AnchorDay ) + 7 ) / 7);
end; \DOW

\Prints a test date and its day of the week
procedure TestDOW ( CCYY, MM, DD );
integer CCYY, MM, DD;
integer DayName;
begin
DayName := ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
            "Saturday"];
IntOut(0, CCYY);
ChOut(0, ^-);  IntOut(0, MM/10);  IntOut(0, rem(0));
ChOut(0, ^-);  IntOut(0, DD/10);  IntOut(0, rem(0));
Text(0, ": "); Text(0, DayName( DOW( CCYY, MM, DD ) ));
CrLf(0);
end;

begin   \task test cases
TestDOW( 1800,  1,  6 );
TestDOW( 1875,  3, 29 );
TestDOW( 1915, 12,  7 );
TestDOW( 1970, 12, 23 );
TestDOW( 2043,  5, 14 );
TestDOW( 2077,  2, 12 );
TestDOW( 2101,  4,  2 );
TestDOW( 2022,  6, 19 )
end
Output:
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
2022-06-19: Sunday

Yabasic

Translation of: FreeBASIC
dim fdoom(1, 12)
for x = 0 to arraysize(fdoom(),1)
    for y = 1 to arraysize(fdoom(),2)
        read fdoom(x, y)
    next y
next x

dim days$(6)
for x = 0 to arraysize(days$(),1)
    read days$(x)
next x

sub doomsday(y)
    // John Conway's doomsday formula
    return mod((2 + 5*mod(y, 4) + 4*mod(y, 100) + 6*mod(y, 400)), 7)
end sub 

sub leap(y)
    //is it a leap year? 
    //return 0 for common years, 1 for leap years
    if mod(y, 4) > 0 then return 0 : fi
    if mod(y, 100) = 0 and mod(y, 400) > 0 then return 0 : fi
    return 1
end sub

sub get_day$(d, m, y)
    c = doomsday(y)
    diff = mod((7 + d - fdoom(leap(y), m)), 7)
    return days$(mod((c+diff), 7))
end sub

print get_day$(06, 01, 1800)
print get_day$(29, 03, 1875)
print get_day$(07, 12, 1915)
print get_day$(23, 12, 1970)
print get_day$(14, 05, 2043)
print get_day$(12, 02, 2077)
print get_day$(02, 04, 2101)
end

//the first doomsday in each month for common and leap years
data 3, 7, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5
data 4, 1, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5
data "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
Output:
Igual que la entrada de FreeBASIC.