module Chronos.Posix
( epoch
, epochDay
, dayLength
, add
, diff
, now
, toUtc
, fromUtc
, toDatetime
, toOffsetDatetime
, fromDatetime
, fromOffsetDatetime
, truncateToDay
, fromDay
) where
import Chronos.Types
import Chronos.Internal.CTimespec
import Chronos.Internal.Conversion as Conv
import Foreign.C.Types (CLong(..),CTime(..))
import Data.Word
import Data.Int
import qualified Chronos.Nanoseconds as Nanoseconds
epoch :: PosixTime
epoch = PosixTime 0
epochDay :: Day
epochDay = Day 40587
dayLength :: Nanoseconds
dayLength = Nanoseconds 86400000000000
add :: Nanoseconds -> PosixTime -> PosixTime
add (Nanoseconds a) (PosixTime b) = PosixTime (a + b)
diff :: PosixTime -> PosixTime -> Nanoseconds
diff (PosixTime a) (PosixTime b) = Nanoseconds (a b)
now :: IO PosixTime
now = fmap PosixTime getPosixNanoseconds
toUtc :: PosixTime -> UtcTime
toUtc (PosixTime i) = let (d,t) = divMod i (getNanoseconds dayLength)
in UtcTime (Conv.addDay (fromIntegral d) epochDay) (fromIntegral t)
fromUtc :: UtcTime -> PosixTime
fromUtc (UtcTime d ns') = PosixTime $ getNanoseconds $ Nanoseconds.add
(Nanoseconds.scale (fromIntegral (Conv.diffDay d epochDay)) dayLength)
(if ns > dayLength then dayLength else ns)
where ns = Nanoseconds (fromIntegral ns')
toDatetime :: PosixTime -> Datetime
toDatetime = Conv.utcTimeToDatetime . toUtc
toOffsetDatetime :: Offset -> PosixTime -> OffsetDatetime
toOffsetDatetime offset = Conv.utcTimeToOffsetDatetime offset . toUtc
fromDatetime :: Datetime -> PosixTime
fromDatetime = fromUtc . Conv.datetimeToUtcTime
fromOffsetDatetime :: OffsetDatetime -> PosixTime
fromOffsetDatetime = fromUtc . Conv.offsetDatetimeToUtcTime
truncateToDay :: PosixTime -> Day
truncateToDay (PosixTime i) = Day (fromIntegral (div i 86400000000000) + 40587)
fromDay :: Day -> PosixTime
fromDay (Day d) = PosixTime (fromIntegral (d 40587) * 86400000000000)