module Data.Astro.Time.GregorianCalendar
(
isLeapYear
, dayNumber
, easterDayInYear
, gregorianDateAdjustment
)
where
import Data.Time.Calendar (Day(..), fromGregorian, toGregorian)
isGregorianDate :: Integer -> Int -> Int -> Bool
isGregorianDate y m d = y > gyear
|| (y == gyear && m > gmonth)
|| (y == gyear && m == gmonth && d >= gday)
where gyear = 1582
gmonth = 10
gday = 15
gregorianDateAdjustment :: Integer -> Int ->Int -> Int
gregorianDateAdjustment year month day =
if isGregorianDate year month day
then let y = if month < 3 then year - 1 else year
y' = fromIntegral y
a = truncate (y' / 100)
in 2 - a + truncate(fromIntegral a/4)
else 0
isLeapYear :: Integer -> Bool
isLeapYear year =
year `mod` 4 == 0
&& (year `mod` 100 /= 0 || year `mod` 400 == 0)
dayNumber :: Day -> Int
dayNumber date =
(daysBeforeMonth year month) + day
where (year, month, day) = toGregorian date
easterDayInYear :: Int -> Day
easterDayInYear year =
let a = year `mod` 19
b = year `div` 100
c = year `mod` 100
d = b `div` 4
e = b `mod` 4
f = (b+8) `div` 25
g = (b-f+1) `div` 3
h = (19*a+b-d-g+15) `mod` 30
i = c `div` 4
k = c `mod` 4
l = (32+2*e+2*i-h-k) `mod` 7
m = (a+11*h+22*l) `div` 451
n' = (h+l-7*m+114)
n = n' `div` 31
p = n' `mod` 31
in fromGregorian (fromIntegral year) n (p+1)
daysBeforeMonth :: Integer -> Int -> Int
daysBeforeMonth year month =
let a = if isLeapYear year then 62 else 63
month' = (fromIntegral month) :: Double
in if month > 2 then
truncate $ ((month' + 1.0) * 30.6) - a
else truncate $ (month' - 1.0)*a*0.5