Doomsday rule: Difference between revisions

Add C# implementation
m (remove draft task label)
(Add C# implementation)
 
(18 intermediate revisions by 12 users not shown)
Line 1:
{{task}}
 
[[Category:Date and time]]
 
Line 424 ⟶ 426:
February 12, 2077 will be on a Friday.
April 2, 2101 will be on a Saturday.</pre>
 
 
=={{header|C#}}==
{{trans|Java}}
<syntaxhighlight lang="C#">
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];
}
}
</syntaxhighlight>
{{out}}
<pre>
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
 
</pre>
 
=={{header|C++}}==
Line 604 ⟶ 680:
2/12/2077: Friday
4/2/2101: Saturday</pre>
 
=={{header|EasyLang}}==
{{trans|C}}
<syntaxhighlight>
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]]
.
</syntaxhighlight>
 
=={{header|Factor}}==
Line 698 ⟶ 803:
M= 2 D= 12 Y= 2077 DAY=FRIDAY
M= 4 D= 2 Y= 2101 DAY=SATURDAY</pre>
 
=={{header|Fortran}}==
<syntaxhighlight lang="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
!
</syntaxhighlight>
{{out}}
<pre>
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
</pre>
 
=={{header|FreeBASIC}}==
Line 743 ⟶ 1,070:
Friday
Saturday</pre>
 
 
=={{header|FutureBasic}}==
<syntaxhighlight lang="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
</syntaxhighlight>
{{output}}
<pre>
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
</pre>
 
 
=={{header|Go}}==
Line 1,421 ⟶ 1,792:
04/02/2077 falls on Friday
04/02/2101 falls on Saturday
</pre>
 
=={{header|RPL}}==
{{works with|HP|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
» » '<span style="color:blue">WKDAY</span>' STO
 
{ 6.011800 29.031875 7.121915 23.12197 14.052043 12.022077 2.042101 } 1 « <span style="color:blue">WKDAY</span> » DOLIST
{{out}}
<pre>
1: { "Monday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Satursday" }
</pre>
 
Line 1,477 ⟶ 1,867:
2077-02-12: Friday
2101-04-02: Saturday
</pre>
 
=={{header|Scala}}==
{{trans|Java}}
<syntaxhighlight lang="Scala">
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")
}
</syntaxhighlight>
{{out}}
<pre>
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
 
</pre>
 
=={{header|uBasic/4tH}}==
{{trans|FreeBASIC}}
<syntaxhighlight lang="uBasic/4tH">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))</syntaxhighlight>
{{Out}}
<pre>Monday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
 
0 OK, 0:711</pre>
 
=={{header|UNIX Shell}}==
{{trans|raku}}
{{works with|Bash}}
<syntaxhighlight lang=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</syntaxhighlight>
 
{{out}}
<pre>Monday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
</pre>
 
Line 1,544 ⟶ 2,075:
{{libheader|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.
<syntaxhighlight lang="ecmascriptwren">import "./date" for Date
 
var days = ["Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday"]
Line 1,604 ⟶ 2,135:
</pre>
 
=={{header|XPL0}}==
{{trans|ALGOL W}}
<syntaxhighlight lang "XPL0">
\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</syntaxhighlight>
{{out}}
<pre>
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
</pre>
 
=={{header|Yabasic}}==
337

edits