-- |
-- Module      : Data.Hourglass.Internal.Unix
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : unknown
--
-- Time lowlevel helpers for the unix operating system
--
-- depend on localtime_r and gmtime_r.
-- Some obscure unix system might not support them.
--
module Data.Hourglass.Internal.Unix
    ( dateTimeFromUnixEpochP
    , dateTimeFromUnixEpoch
    , systemGetTimezone
    , systemGetElapsed
    , systemGetElapsedP
    ) where

import Data.Hourglass.Types
import Data.Time.Calendar.MonthDay
import Data.Time.Calendar.OrdinalDate
import Data.Time.LocalTime hiding (TimeOfDay(..))
import qualified Data.Time.LocalTime as DTLocalTime
import Data.Time.Clock.System

-- | convert a unix epoch precise to DateTime
dateTimeFromUnixEpochP :: ElapsedP -> DateTime
dateTimeFromUnixEpochP :: ElapsedP -> DateTime
dateTimeFromUnixEpochP (ElapsedP (Elapsed Seconds
sec) (NanoSeconds Int64
ns)) =
    Date -> TimeOfDay -> DateTime
DateTime Date
date TimeOfDay
time
  where systime :: SystemTime
systime = Int64 -> Word32 -> SystemTime
MkSystemTime (Seconds -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Seconds
sec) (Int64 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
ns)
        utctime :: UTCTime
utctime = SystemTime -> UTCTime
systemToUTCTime SystemTime
systime
        LocalTime Day
day TimeOfDay
timeofday = TimeZone -> UTCTime -> LocalTime
utcToLocalTime TimeZone
utc UTCTime
utctime
        (Year
year, DayOfYear
dayofyear) = Day -> (Year, DayOfYear)
toOrdinalDate Day
day
        (DayOfYear
monthofyear, DayOfYear
dayofmonth) = Bool -> DayOfYear -> (DayOfYear, DayOfYear)
dayOfYearToMonthAndDay (Year -> Bool
isLeapYear Year
year) DayOfYear
dayofyear
        date :: Date
date = Date
            { dateYear :: DayOfYear
dateYear  = Year -> DayOfYear
forall a b. (Integral a, Num b) => a -> b
fromIntegral Year
year
            , dateMonth :: Month
dateMonth = DayOfYear -> Month
forall a. Enum a => DayOfYear -> a
toEnum (DayOfYear
monthofyear DayOfYear -> DayOfYear -> DayOfYear
forall a. Num a => a -> a -> a
- DayOfYear
1)
            , dateDay :: DayOfYear
dateDay   = DayOfYear
dayofmonth
            }
        time :: TimeOfDay
time = TimeOfDay
            { todHour :: Hours
todHour = DayOfYear -> Hours
forall a b. (Integral a, Num b) => a -> b
fromIntegral (DayOfYear -> Hours) -> DayOfYear -> Hours
forall a b. (a -> b) -> a -> b
$ TimeOfDay -> DayOfYear
DTLocalTime.todHour TimeOfDay
timeofday
            , todMin :: Minutes
todMin  = DayOfYear -> Minutes
forall a b. (Integral a, Num b) => a -> b
fromIntegral (DayOfYear -> Minutes) -> DayOfYear -> Minutes
forall a b. (a -> b) -> a -> b
$ TimeOfDay -> DayOfYear
DTLocalTime.todMin TimeOfDay
timeofday
            , todSec :: Seconds
todSec  = Pico -> Seconds
forall b. Integral b => Pico -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor (Pico -> Seconds) -> Pico -> Seconds
forall a b. (a -> b) -> a -> b
$ TimeOfDay -> Pico
DTLocalTime.todSec TimeOfDay
timeofday
            , todNSec :: NanoSeconds
todNSec = Int64 -> NanoSeconds
NanoSeconds Int64
ns
            }

-- | convert a unix epoch to DateTime
dateTimeFromUnixEpoch :: Elapsed -> DateTime
dateTimeFromUnixEpoch :: Elapsed -> DateTime
dateTimeFromUnixEpoch Elapsed
e = ElapsedP -> DateTime
dateTimeFromUnixEpochP (ElapsedP -> DateTime) -> ElapsedP -> DateTime
forall a b. (a -> b) -> a -> b
$ Elapsed -> NanoSeconds -> ElapsedP
ElapsedP Elapsed
e NanoSeconds
0

-- | return the timezone offset in minutes
systemGetTimezone :: IO TimezoneOffset
systemGetTimezone :: IO TimezoneOffset
systemGetTimezone = do
    TimeZone DayOfYear
tzm Bool
_ String
_ <- IO TimeZone
getCurrentTimeZone
    TimezoneOffset -> IO TimezoneOffset
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (TimezoneOffset -> IO TimezoneOffset)
-> TimezoneOffset -> IO TimezoneOffset
forall a b. (a -> b) -> a -> b
$ DayOfYear -> TimezoneOffset
TimezoneOffset DayOfYear
tzm

----------------------------------------------------------------------------------------
-- | return the current elapsedP
systemGetElapsedP :: IO ElapsedP
systemGetElapsedP :: IO ElapsedP
systemGetElapsedP = do
    MkSystemTime Int64
sec Word32
nsec <- IO SystemTime
getSystemTime
    ElapsedP -> IO ElapsedP
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (ElapsedP -> IO ElapsedP) -> ElapsedP -> IO ElapsedP
forall a b. (a -> b) -> a -> b
$ Elapsed -> NanoSeconds -> ElapsedP
ElapsedP (Int64 -> Elapsed
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
sec) (Word32 -> NanoSeconds
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
nsec)

-- | return the current elapsed
systemGetElapsed :: IO Elapsed
systemGetElapsed :: IO Elapsed
systemGetElapsed = do
    ElapsedP Elapsed
e NanoSeconds
_ <- IO ElapsedP
systemGetElapsedP
    Elapsed -> IO Elapsed
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Elapsed
e