-- a)
leapYear :: Int -> Bool
leapYear n = (n `mod` 4 == 0) && ( (n `mod` 100 /= 0) || (n `mod` 400 == 0) )
-- b)
data Month = Jan | Feb | Mar | Apr | May | Aug | Jun | Jul | Sep | Oct | Nov | Dec
deriving (Enum, Eq, Show)
-- c)
type Day = Int
type Year = Int
data Date = Date Day Month Year
deriving Show
-- d)
dateIsValid :: Date -> Bool
dateIsValid (Date d m y) | y < 0 || y > 9999 = False
| d < 0 = False
| m `elem` [Jan, Mar, May, Jul, Aug, Oct, Dec] = d < 32
| m `elem` [Apr, Jun, Sep, Nov, Feb] = d < 31
| m == Feb = if leapYear y then d < 30 else d < 29
| otherwise = False
-- e)
daysBetween :: Date -> Date -> Int
daysBetween (Date a b c) (Date x y z) = if dateDay (Date a b c) > dateDay (Date x y z)
then dateDay (Date a b c) - dateDay (Date x y z)
else dateDay (Date x y z) - dateDay (Date a b c)
where monthDay m = case m of Jan -> 0
Feb -> 31
Mar -> 59
Apr -> 90
May -> 120
Jun -> 151
Jul -> 181
Aug -> 211
Sep -> 243
Oct -> 273
Nov -> 304
Dec -> 334
countLeapYears (Date d m y) | m `elem` [Jan, Feb, May] = (y-1) `div` 4 - (y-1) `div` 100 + (y-1) `div` 400
| otherwise = y `div` 4 - y `div` 100 + y `div` 400
dateDay (Date d m y) = d + monthDay m + (y-1)*365 + countLeapYears (Date d m y)
getMonthNr :: Month -> Int
getMonthNr m = case m of Jan -> 1
Feb -> 2
Mar -> 3
Apr -> 4
May -> 5
Jun -> 6
Jul -> 7
Aug -> 8
Sep -> 9
Oct -> 10
Nov -> 11
Dec -> 12
-- f)
data Dow = Mon | Tue | Wen | Thu | Fri | Sat | Sun
deriving Show
-- g)
weekday :: Date -> Dow
weekday (Date d m y) = case daysBetween (Date d m y) (Date 3 Jan 2000) `mod` 7 of 0 -> Sun
1 -> Mon
2 -> Tue
3 -> Wen
4 -> Thu
5 -> Fri
_ -> Sat
I have got this code where I need to calculate the number of days between two days and then find the weekday of that date. While this code is correct in finding the answer for the given examples in the exercises daysBetween (Date 4 Nov 2021) (Date 1 Jan 2000) → 7978 and January 1st, 2021 was a Friday, it shows problems with most other dates. One of my tests involved the date Date 13 Aug 2009 and Date 3 Jan 2000 where the error is one day. I am not allowed to use predefined functions to find the difference between two dates or the specific weekday. Is there something wrong with the logic I have used? Or is there another way to implement an algorithm that searches for the difference between two days?
getMonthNr can be ignored or not, since I wrote it down while experimenting and left it there in case I would need it.
Edit: After correcting the code a 1 day shift occurs when the days are a few years apart (almost a decade) or a 2 day shift when the days are centuries to a few millennia apart.