module Data.Time.Calendar.MonthDay
    (
    monthAndDayToDayOfYear,monthAndDayToDayOfYearValid,dayOfYearToMonthAndDay,monthLength
    ) where

import Data.Time.Calendar.Private

-- | Convert month and day in the Gregorian or Julian calendars to day of year.
-- First arg is leap year flag.
monthAndDayToDayOfYear :: Bool -> Int -> Int -> Int
monthAndDayToDayOfYear :: Bool -> Int -> Int -> Int
monthAndDayToDayOfYear isLeap :: Bool
isLeap month :: Int
month day :: Int
day = (Int -> Int -> Int
forall a. Integral a => a -> a -> a
div (367 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
month'' Int -> Int -> Int
forall a. Num a => a -> a -> a
- 362) 12) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
k Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
day' where
    month' :: Int
month' = Int -> Int -> Int -> Int
forall t. Ord t => t -> t -> t -> t
clip 1 12 Int
month
    day' :: Int
day' = Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int -> Int -> Int
forall t. Ord t => t -> t -> t -> t
clip 1 (Bool -> Int -> Int
monthLength' Bool
isLeap Int
month') Int
day)
    month'' :: Int
month'' = Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
month'
    k :: Int
k = if Int
month' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= 2 then 0 else if Bool
isLeap then -1 else -2

-- | Convert month and day in the Gregorian or Julian calendars to day of year.
-- First arg is leap year flag.
monthAndDayToDayOfYearValid :: Bool -> Int -> Int -> Maybe Int
monthAndDayToDayOfYearValid :: Bool -> Int -> Int -> Maybe Int
monthAndDayToDayOfYearValid isLeap :: Bool
isLeap month :: Int
month day :: Int
day = do
    Int
month' <- Int -> Int -> Int -> Maybe Int
forall t. Ord t => t -> t -> t -> Maybe t
clipValid 1 12 Int
month
    Int
day' <- Int -> Int -> Int -> Maybe Int
forall t. Ord t => t -> t -> t -> Maybe t
clipValid 1 (Bool -> Int -> Int
monthLength' Bool
isLeap Int
month') Int
day
    let
        day'' :: Int
day'' = Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
day'
        month'' :: Int
month'' = Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
month'
        k :: Int
k = if Int
month' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= 2 then 0 else if Bool
isLeap then -1 else -2
    Int -> Maybe Int
forall (m :: * -> *) a. Monad m => a -> m a
return ((Int -> Int -> Int
forall a. Integral a => a -> a -> a
div (367 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
month'' Int -> Int -> Int
forall a. Num a => a -> a -> a
- 362) 12) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
k Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
day'')

-- | Convert day of year in the Gregorian or Julian calendars to month and day.
-- First arg is leap year flag.
dayOfYearToMonthAndDay :: Bool -> Int -> (Int,Int)
dayOfYearToMonthAndDay :: Bool -> Int -> (Int, Int)
dayOfYearToMonthAndDay isLeap :: Bool
isLeap yd :: Int
yd = [Int] -> Int -> (Int, Int)
findMonthDay (Bool -> [Int]
monthLengths Bool
isLeap) (Int -> Int -> Int -> Int
forall t. Ord t => t -> t -> t -> t
clip 1 (if Bool
isLeap then 366 else 365) Int
yd)

findMonthDay :: [Int] -> Int -> (Int,Int)
findMonthDay :: [Int] -> Int -> (Int, Int)
findMonthDay (n :: Int
n:ns :: [Int]
ns) yd :: Int
yd | Int
yd Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
n = (\(m :: Int
m,d :: Int
d) -> (Int
m Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1,Int
d)) ([Int] -> Int -> (Int, Int)
findMonthDay [Int]
ns (Int
yd Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
n))
findMonthDay _ yd :: Int
yd = (1,Int
yd)

-- | The length of a given month in the Gregorian or Julian calendars.
-- First arg is leap year flag.
monthLength :: Bool -> Int -> Int
monthLength :: Bool -> Int -> Int
monthLength isLeap :: Bool
isLeap month' :: Int
month' = Bool -> Int -> Int
monthLength' Bool
isLeap (Int -> Int -> Int -> Int
forall t. Ord t => t -> t -> t -> t
clip 1 12 Int
month')

monthLength' :: Bool -> Int -> Int
monthLength' :: Bool -> Int -> Int
monthLength' isLeap :: Bool
isLeap month' :: Int
month' = (Bool -> [Int]
monthLengths Bool
isLeap) [Int] -> Int -> Int
forall a. [a] -> Int -> a
!! (Int
month' Int -> Int -> Int
forall a. Num a => a -> a -> a
- 1)

monthLengths :: Bool -> [Int]
monthLengths :: Bool -> [Int]
monthLengths isleap :: Bool
isleap =
    [31,if Bool
isleap then 29 else 28,31,30,31,30,31,31,30,31,30,31]
    --J        F                   M  A  M  J  J  A  S  O  N  D