lib/Data/Time/Clock/Internal/SystemTime.hs

    #if __GLASGOW_HASKELL__ >= 710
    {-# OPTIONS -fno-warn-trustworthy-safe #-}
    #endif
    {-# LANGUAGE Trustworthy #-}
    module Data.Time.Clock.Internal.SystemTime
        (
        SystemTime(..),
        getSystemTime,
        getTime_resolution,
        getTAISystemTime,
        ) where

    import Data.Int (Int64)
    import Data.Word
    import Control.DeepSeq
    import Data.Time.Clock.Internal.DiffTime

    #include "HsTimeConfig.h"

    #ifdef mingw32_HOST_OS
    import qualified System.Win32.Time as Win32
    #elif defined(HAVE_CLOCK_GETTIME)
    import Data.Time.Clock.Internal.CTimespec
    import Foreign.C.Types (CTime(..), CLong(..))
    #else
    import Data.Time.Clock.Internal.CTimeval
    import Foreign.C.Types (CLong(..))
    #endif

    --------------------------------------------------------------------------------

    -- | '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)

    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

    -- | The resolution of 'getSystemTime', 'getCurrentTime', 'getPOSIXTime'
    getTime_resolution :: DiffTime

    -- | If supported, get TAI time, epoch start of 1970 TAI, with resolution.
    -- This is supported only on UNIX systems, and only those with CLOCK_TAI available at run-time.
    getTAISystemTime :: Maybe (DiffTime,IO SystemTime)

    #ifdef mingw32_HOST_OS
    -- On Windows, the equlvalent of POSIX time is "file time", defined as
    -- the number of 100-nanosecond intervals that have elapsed since
    -- 12:00 A.M. January 1, 1601 (UTC).  We can convert this into a POSIX
    -- time by adjusting the offset to be relative to the POSIX epoch.

    getSystemTime = do
        Win32.FILETIME ft <- Win32.getSystemTimeAsFileTime
        let (s, us) = (ft - win32_epoch_adjust) `divMod` 10000000
        return (MkSystemTime (fromIntegral s) (fromIntegral us * 100))
      where
        win32_epoch_adjust :: Word64
        win32_epoch_adjust = 116444736000000000
    getTime_resolution = 100E-9 -- 100ns
    getTAISystemTime = Nothing

    #elif defined(HAVE_CLOCK_GETTIME)
    -- Use hi-res clock_gettime

    timespecToSystemTime :: CTimespec -> SystemTime
    timespecToSystemTime (MkCTimespec (CTime s) (CLong ns)) = (MkSystemTime (fromIntegral s) (fromIntegral ns))

    timespecToDiffTime :: CTimespec -> DiffTime
    timespecToDiffTime (MkCTimespec (CTime s) ns) = (fromIntegral s) + (fromIntegral ns) * 1E-9

    clockGetSystemTime :: ClockID -> IO SystemTime
    clockGetSystemTime clock = fmap timespecToSystemTime $ clockGetTime clock

    getSystemTime = clockGetSystemTime clock_REALTIME
    getTime_resolution = timespecToDiffTime realtimeRes
    getTAISystemTime = fmap (\resolution -> (timespecToDiffTime resolution,clockGetSystemTime clock_TAI)) $ clockResolution clock_TAI

    #else
    -- Use gettimeofday
    getSystemTime = do
        MkCTimeval (CLong s) (CLong us) <- getCTimeval
        return (MkSystemTime (fromIntegral s) (fromIntegral us * 1000))
    getTime_resolution = 1E-6 -- microsecond
    getTAISystemTime = Nothing

    #endif