{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveDataTypeable #-} module Data.Time.Clock.System.Compat ( systemEpochDay, SystemTime(..), truncateSystemTimeLeapSecond, getSystemTime, systemToUTCTime, utcToSystemTime, systemToTAITime, ) where import Data.Time.Orphans () #if MIN_VERSION_time(1,8,0) import Data.Time.Clock.System #else import Control.DeepSeq (NFData (..)) import Data.Int (Int64) import Data.Word (Word32) import Data.Typeable (Typeable) import Data.Time.Clock.TAI.Compat import Data.Time.Clock.POSIX import Data.Time.Compat -- | 'SystemTime' is time returned by system clock functions. -- Its semantics depends on the clock function, but the epoch is typically the beginning of 1970. -- Note that 'systemNanoseconds' of 1E9 to 2E9-1 can be used to represent leap seconds. data SystemTime = MkSystemTime { systemSeconds :: {-# UNPACK #-} !Int64 , systemNanoseconds :: {-# UNPACK #-} !Word32 } deriving (Eq,Ord,Show,Typeable) instance NFData SystemTime where rnf a = a `seq` () -- | Get the system time, epoch start of 1970 UTC, leap-seconds ignored. -- 'getSystemTime' is typically much faster than 'getCurrentTime'. getSystemTime :: IO SystemTime -- Use gettimeofday getSystemTime = do t <- getPOSIXTime let secs = truncate t let nsecs = truncate $ 1000000000 * (t - fromIntegral secs) return (MkSystemTime secs nsecs) -- | Map leap-second values to the start of the following second. -- The resulting 'systemNanoseconds' will always be in the range 0 to 1E9-1. truncateSystemTimeLeapSecond :: SystemTime -> SystemTime truncateSystemTimeLeapSecond (MkSystemTime seconds nanoseconds) | nanoseconds >= 1000000000 = MkSystemTime (succ seconds) 0 truncateSystemTimeLeapSecond t = t -- | Convert 'SystemTime' to 'UTCTime', matching zero 'SystemTime' to midnight of 'systemEpochDay' UTC. systemToUTCTime :: SystemTime -> UTCTime systemToUTCTime (MkSystemTime seconds nanoseconds) = let days :: Int64 timeSeconds :: Int64 (days, timeSeconds) = seconds `divMod` 86400 day :: Day day = addDays (fromIntegral days) systemEpochDay timeNanoseconds :: Int64 timeNanoseconds = timeSeconds * 1000000000 + (fromIntegral nanoseconds) timePicoseconds :: Int64 timePicoseconds = timeNanoseconds * 1000 time :: DiffTime time = picosecondsToDiffTime $ fromIntegral timePicoseconds in UTCTime day time -- | Convert 'UTCTime' to 'SystemTime', matching zero 'SystemTime' to midnight of 'systemEpochDay' UTC. utcToSystemTime :: UTCTime -> SystemTime utcToSystemTime (UTCTime day time) = let days :: Int64 days = fromIntegral $ diffDays day systemEpochDay timePicoseconds :: Int64 timePicoseconds = fromIntegral $ diffTimeToPicoseconds time timeNanoseconds :: Int64 timeNanoseconds = timePicoseconds `div` 1000 timeSeconds :: Int64 nanoseconds :: Int64 (timeSeconds,nanoseconds) = if timeNanoseconds >= 86400000000000 then (86399,timeNanoseconds - 86399000000000) else timeNanoseconds `divMod` 1000000000 seconds :: Int64 seconds = days * 86400 + timeSeconds in MkSystemTime seconds $ fromIntegral nanoseconds systemEpochAbsolute :: AbsoluteTime systemEpochAbsolute = taiNominalDayStart systemEpochDay -- | Convert 'SystemTime' to 'AbsoluteTime', matching zero 'SystemTime' to midnight of 'systemEpochDay' TAI. systemToTAITime :: SystemTime -> AbsoluteTime systemToTAITime (MkSystemTime s ns) = let diff :: DiffTime diff = (fromIntegral s) + (fromIntegral ns) * 1E-9 in addAbsoluteTime diff systemEpochAbsolute -- | The day of the epoch of 'SystemTime', 1970-01-01 systemEpochDay :: Day systemEpochDay = ModifiedJulianDay 40587 #endif