This is an interesting problem that gets more complicated pre-1582. The code works for 1582 or later, but falls over for earlier dates. From what I found, Sunday was the first day of the week from 321CE after Emperor Constantine.
program main
implicit none
integer :: y, m, d, dow
logical :: valid
character(len=9) :: day_name(7)
! Day names, Sunday = 1
day_name = ['Sunday ', 'Monday ', 'Tuesday ', 'Wednesday', &
'Thursday ', 'Friday ', 'Saturday ']
print *, 'Enter year, month, and day:'
read(*,*) y, m, d
valid = is_valid_date(y, m, d)
if (valid) then
dow = day_of_week_mixed(y, m, d)
write(*,'('The input date ', I4.4, '-', I2.2, '-', I2.2, ' is a valid date (', A, ').')') &
y, m, d, trim(day_name(dow))
else
write(*,'('The input date ', I4.4, '-', I2.2, '-', I2.2, ' is NOT a valid date.')') y, m, d
end if
contains
!-----------------------------------------------
logical function is_valid_date(y, m, d)
implicit none
integer, intent(in) :: y, m, d
integer :: D_each_M(12)
D_each_M = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
is_valid_date = .true.
if ((m < 1 .or. m > 12) .or. (d < 1 .or. d > D_each_M(m))) then
is_valid_date = .false.
end if
! Leap-year rule (Gregorian)
if ((mod(y,4) == 0 .and. mod(y,100) /= 0) .or. mod(y,400) == 0) then
if (m == 2) D_each_M(2) = 29
else if (y < 1582 .or. (y == 1582 .and. (m < 10 .or. (m == 10 .and. d < 5)))) then
! Julian leap-year rule before Gregorian reform
if (mod(y,4) == 0 .and. m == 2) D_each_M(2) = 29
end if
! Missing days during the reform
if (y == 1582 .and. m == 10 .and. d > 4 .and. d < 15) then
is_valid_date = .false.
end if
end function is_valid_date
!-----------------------------------------------
integer function day_of_week_mixed(y, m, d)
! Compute day of week correctly across Julian and Gregorian calendars
implicit none
integer, intent(in) :: y, m, d
integer :: jd
jd = julian_day_number(y, m, d)
day_of_week_mixed = mod(jd + 1, 7) + 1
! Sunday = 1, Monday = 2, ..., Saturday = 7
end function day_of_week_mixed
!-----------------------------------------------
integer function julian_day_number(y, m, d)
! Returns Julian Day Number for any date (handles both calendars)
implicit none
integer, intent(in) :: y, m, d
integer :: a, b, yy, mm
yy = y
mm = m
if (m <= 2) then
yy = yy - 1
mm = mm + 12
end if
if ( (y > 1582) .or. (y == 1582 .and. (m > 10 .or. (m == 10 .and. d >= 15))) ) then
! Gregorian calendar
a = yy / 100
b = 2 - a + a / 4
else
! Julian calendar
b = 0
end if
julian_day_number = int(365.25d0 * (yy + 4716)) + int(30.6001d0 * (mm + 1)) + d + b - 1524
end function julian_day_number
end program main