    {-# LANGUAGE Safe #-}

    module Data.Time.Calendar.JulianYearDay (
        -- * Year and day format
        module Data.Time.Calendar.JulianYearDay,
    ) where

    import Data.Time.Calendar.Days
    import Data.Time.Calendar.Private
    import Data.Time.Calendar.Types

    -- | Convert to proleptic Julian year and day format.
    toJulianYearAndDay :: Day -> (Year, DayOfYear)
    toJulianYearAndDay :: Day -> (Year, DayOfYear)
    toJulianYearAndDay (ModifiedJulianDay Year
    mjd) = (Year
    year, DayOfYear
    yd)
      where
        a :: Year
    a = Year
    mjd Year -> Year -> Year
    forall a. Num a => a -> a -> a
    + Year
    678577
        quad :: Year
    quad = Year -> Year -> Year
    forall a. Integral a => a -> a -> a
    div Year
    a Year
    1461
        d :: Year
    d = Year -> Year -> Year
    forall a. Integral a => a -> a -> a
    mod Year
    a Year
    1461
        y :: Year
    y = Year -> Year -> Year
    forall a. Ord a => a -> a -> a
    min (Year -> Year -> Year
    forall a. Integral a => a -> a -> a
    div Year
    d Year
    365) Year
    3
        yd :: DayOfYear
    yd = Year -> DayOfYear
    forall a. Num a => Year -> a
    fromInteger (Year
    d Year -> Year -> Year
    forall a. Num a => a -> a -> a
    - (Year
    y Year -> Year -> Year
    forall a. Num a => a -> a -> a
    * Year
    365) Year -> Year -> Year
    forall a. Num a => a -> a -> a
    + Year
    1)
        year :: Year
    year = Year
    quad Year -> Year -> Year
    forall a. Num a => a -> a -> a
    * Year
    4 Year -> Year -> Year
    forall a. Num a => a -> a -> a
    + Year
    y Year -> Year -> Year
    forall a. Num a => a -> a -> a
    + Year
    1

    -- | Convert from proleptic Julian year and day format.
    -- Invalid day numbers will be clipped to the correct range (1 to 365 or 366).
    fromJulianYearAndDay :: Year -> DayOfYear -> Day
    fromJulianYearAndDay :: Year -> DayOfYear -> Day
    fromJulianYearAndDay Year
    year DayOfYear
    day = Year -> Day
    ModifiedJulianDay Year
    mjd
      where
        y :: Year
    y = Year
    year Year -> Year -> Year
    forall a. Num a => a -> a -> a
    - Year
    1
        mjd :: Year
    mjd =
            ( DayOfYear -> Year
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral
                ( DayOfYear -> DayOfYear -> DayOfYear -> DayOfYear
    forall t. Ord t => t -> t -> t -> t
    clip
                    DayOfYear
    1
                    ( if Year -> Bool
    isJulianLeapYear Year
    year
                        then DayOfYear
    366
                        else DayOfYear
    365
                    )
                    DayOfYear
    day
                )
            )
                Year -> Year -> Year
    forall a. Num a => a -> a -> a
    + (Year
    365 Year -> Year -> Year
    forall a. Num a => a -> a -> a
    * Year
    y)
                Year -> Year -> Year
    forall a. Num a => a -> a -> a
    + (Year -> Year -> Year
    forall a. Integral a => a -> a -> a
    div Year
    y Year
    4)
                Year -> Year -> Year
    forall a. Num a => a -> a -> a
    - Year
    678578

    -- | Convert from proleptic Julian year and day format.
    -- Invalid day numbers will return Nothing
    fromJulianYearAndDayValid :: Year -> DayOfYear -> Maybe Day
    fromJulianYearAndDayValid :: Year -> DayOfYear -> Maybe Day
    fromJulianYearAndDayValid Year
    year DayOfYear
    day = do
        DayOfYear
    day' <-
            DayOfYear -> DayOfYear -> DayOfYear -> Maybe DayOfYear
    forall t. Ord t => t -> t -> t -> Maybe t
    clipValid
                DayOfYear
    1
                ( if Year -> Bool
    isJulianLeapYear Year
    year
                    then DayOfYear
    366
                    else DayOfYear
    365
                )
                DayOfYear
    day
        let y :: Year
    y = Year
    year Year -> Year -> Year
    forall a. Num a => a -> a -> a
    - Year
    1
            mjd :: Year
    mjd = (DayOfYear -> Year
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral DayOfYear
    day') Year -> Year -> Year
    forall a. Num a => a -> a -> a
    + (Year
    365 Year -> Year -> Year
    forall a. Num a => a -> a -> a
    * Year
    y) Year -> Year -> Year
    forall a. Num a => a -> a -> a
    + (Year -> Year -> Year
    forall a. Integral a => a -> a -> a
    div Year
    y Year
    4) Year -> Year -> Year
    forall a. Num a => a -> a -> a
    - Year
    678578
        Day -> Maybe Day
    forall a. a -> Maybe a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Year -> Day
    ModifiedJulianDay Year
    mjd)

    -- | Show in proleptic Julian year and day format (yyyy-ddd)
    showJulianYearAndDay :: Day -> String
    showJulianYearAndDay :: Day -> String
    showJulianYearAndDay Day
    date = (Year -> String
    forall t. ShowPadded t => t -> String
    show4 Year
    y) String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "-" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ (DayOfYear -> String
    forall t. ShowPadded t => t -> String
    show3 DayOfYear
    d)
      where
        (Year
    y, DayOfYear
    d) = Day -> (Year, DayOfYear)
    toJulianYearAndDay Day
    date

    -- | Is this year a leap year according to the proleptic Julian calendar?
    isJulianLeapYear :: Year -> Bool
    isJulianLeapYear :: Year -> Bool
    isJulianLeapYear Year
    year = (Year -> Year -> Year
    forall a. Integral a => a -> a -> a
    mod Year
    year Year
    4 Year -> Year -> Bool
    forall a. Eq a => a -> a -> Bool
    == Year
    0)