-- |
-- Module      : Time.Compat
-- License     : BSD-style
-- Maintainer  : Nicolas DI PRIMA <nicolas@di-prima.fr>
--
-- Basic Time conversion compatibility.
--
-- This module aims to help conversion between the types from the package
-- time to the package hourglass.
--
-- Example of use (extracted from file Example/Time/Compat.hs):
--
-- > import Data.Hourglass        as H
-- > import Data.Hourglass.Compat as C
-- > import Data.Time             as T
-- >
-- > transpose :: T.ZonedTime
-- >           -> H.LocalTime H.DateTime
-- > transpose oldTime =
-- >     H.localTime
-- >         offsetTime
-- >         (H.DateTime newDate timeofday)
-- >   where
-- >     newDate :: H.Date
-- >     newDate = C.dateFromTAIEpoch $ T.toModifiedJulianDay $ T.localDay $ T.zonedTimeToLocalTime oldTime
-- >
-- >     timeofday :: H.TimeOfDay
-- >     timeofday = C.diffTimeToTimeOfDay $ T.timeOfDayToTime $ T.localTimeOfDay $ T.zonedTimeToLocalTime oldTime
-- >
-- >     offsetTime = H.TimezoneOffset $ fromIntegral $ T.timeZoneMinutes $ T.zonedTimeZone oldTime
--
module Time.Compat
    ( dateFromPOSIXEpoch
    , dateFromTAIEpoch
    , diffTimeToTimeOfDay
    ) where

import Data.Hourglass

-- | Convert an integer which represent the Number of days (To/From) POSIX Epoch
-- to a Date (POSIX Epoch is 1970-01-01).
dateFromPOSIXEpoch :: Integer -- ^ number of days since POSIX Epoch
                   -> Date
dateFromPOSIXEpoch day = do
    let sec = Elapsed $ fromIntegral $ day * 86400
    timeConvert sec

-- | Number of days between POSIX Epoch and TAI Epoch
-- (between 1858-11-17 and 1970-01-01)
daysTAItoPOSIX :: Integer
daysTAItoPOSIX = 40587

-- | Convert an integer which represents the Number of days (To/From) TAI Epoch
-- This function allows use of the package time to easily convert the Day into
-- the Hourglass Date representation (TAI Epoch is 1858-11-17).
-- 
-- This function allows user to easily convert a Data.Time.Calendar.Day into Date
--
-- > import qualified Data.Time.Calendar as T
-- >
-- > timeDay :: T.Day
-- >
-- > dateFromTAIEpoch $ T.toModifiedJulianDay timeDay
dateFromTAIEpoch :: Integer -- ^ number of days since TAI Epoch
                 -> Date
dateFromTAIEpoch dtai =
    dateFromPOSIXEpoch (dtai - daysTAItoPOSIX)

-- | Convert of differential of time of a day.
-- (it convers a Data.Time.Clock.DiffTime into a TimeOfDay)
--
-- Example with DiffTime type from time:
--
-- > import qualified Data.Time.Clock as T
-- >
-- > difftime :: T.DiffTime
-- >
-- > diffTimeToTimeOfDay difftime
--
-- Example with the TimeOfDay type from time:
--
-- > import qualified Data.Time.Clock as T
-- >
-- > timeofday :: T.TimeOfDay
-- >
-- > diffTimeToTimeOfDay $ T.timeOfDayToTime timeofday
diffTimeToTimeOfDay :: Real t
                    => t         -- ^ number of seconds of the time of the day
                    -> TimeOfDay
diffTimeToTimeOfDay dt = do
    TimeOfDay
        { todHour = fromIntegral hours
        , todMin  = fromIntegral minutes
        , todSec  = fromIntegral seconds
        , todNSec = fromIntegral nsecs
        }
  where
    r :: Rational
    r = toRational dt
    (secs, nR) = properFraction r :: (Integer, Rational)
    nsecs :: Integer
    nsecs = round (nR * 1000000000)
    (minsofday, seconds) = secs `divMod` 60 :: (Integer, Integer)
    (hours, minutes) = minsofday `divMod` 60 :: (Integer, Integer)