{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE OverloadedStrings #-}
module Data.UnixTime.Conv (
formatUnixTime,
formatUnixTimeGMT,
parseUnixTime,
parseUnixTimeGMT,
webDateFormat,
mailDateFormat,
fromEpochTime,
toEpochTime,
fromClockTime,
toClockTime,
) where
import Control.Applicative
import Data.ByteString.Char8
import Data.ByteString.Unsafe
import Data.UnixTime.Types
import Foreign.C.String
import Foreign.C.Types
import Foreign.Marshal.Alloc
import System.IO.Unsafe (unsafePerformIO)
import System.Posix.Types (EpochTime)
import System.Time (ClockTime (..))
foreign import ccall unsafe "c_parse_unix_time"
c_parse_unix_time :: CString -> CString -> IO CTime
foreign import ccall unsafe "c_parse_unix_time_gmt"
c_parse_unix_time_gmt :: CString -> CString -> IO CTime
foreign import ccall unsafe "c_format_unix_time"
c_format_unix_time :: CString -> CTime -> CString -> CInt -> IO CSize
foreign import ccall unsafe "c_format_unix_time_gmt"
c_format_unix_time_gmt :: CString -> CTime -> CString -> CInt -> IO CSize
parseUnixTime :: Format -> ByteString -> UnixTime
parseUnixTime :: ByteString -> ByteString -> UnixTime
parseUnixTime ByteString
fmt ByteString
str = IO UnixTime -> UnixTime
forall a. IO a -> a
unsafePerformIO (IO UnixTime -> UnixTime) -> IO UnixTime -> UnixTime
forall a b. (a -> b) -> a -> b
$
ByteString -> (CString -> IO UnixTime) -> IO UnixTime
forall a. ByteString -> (CString -> IO a) -> IO a
useAsCString ByteString
fmt ((CString -> IO UnixTime) -> IO UnixTime)
-> (CString -> IO UnixTime) -> IO UnixTime
forall a b. (a -> b) -> a -> b
$ \CString
cfmt ->
ByteString -> (CString -> IO UnixTime) -> IO UnixTime
forall a. ByteString -> (CString -> IO a) -> IO a
useAsCString ByteString
str ((CString -> IO UnixTime) -> IO UnixTime)
-> (CString -> IO UnixTime) -> IO UnixTime
forall a b. (a -> b) -> a -> b
$ \CString
cstr -> do
sec <- CString -> CString -> IO CTime
c_parse_unix_time CString
cfmt CString
cstr
return $ UnixTime sec 0
parseUnixTimeGMT :: Format -> ByteString -> UnixTime
parseUnixTimeGMT :: ByteString -> ByteString -> UnixTime
parseUnixTimeGMT ByteString
fmt ByteString
str = IO UnixTime -> UnixTime
forall a. IO a -> a
unsafePerformIO (IO UnixTime -> UnixTime) -> IO UnixTime -> UnixTime
forall a b. (a -> b) -> a -> b
$
ByteString -> (CString -> IO UnixTime) -> IO UnixTime
forall a. ByteString -> (CString -> IO a) -> IO a
useAsCString ByteString
fmt ((CString -> IO UnixTime) -> IO UnixTime)
-> (CString -> IO UnixTime) -> IO UnixTime
forall a b. (a -> b) -> a -> b
$ \CString
cfmt ->
ByteString -> (CString -> IO UnixTime) -> IO UnixTime
forall a. ByteString -> (CString -> IO a) -> IO a
useAsCString ByteString
str ((CString -> IO UnixTime) -> IO UnixTime)
-> (CString -> IO UnixTime) -> IO UnixTime
forall a b. (a -> b) -> a -> b
$ \CString
cstr -> do
sec <- CString -> CString -> IO CTime
c_parse_unix_time_gmt CString
cfmt CString
cstr
return $ UnixTime sec 0
formatUnixTime :: Format -> UnixTime -> IO ByteString
formatUnixTime :: ByteString -> UnixTime -> IO ByteString
formatUnixTime ByteString
fmt UnixTime
t =
(CString -> CTime -> CString -> CInt -> IO CSize)
-> ByteString -> UnixTime -> IO ByteString
formatUnixTimeHelper CString -> CTime -> CString -> CInt -> IO CSize
c_format_unix_time ByteString
fmt UnixTime
t
{-# INLINE formatUnixTime #-}
formatUnixTimeGMT :: Format -> UnixTime -> ByteString
formatUnixTimeGMT :: ByteString -> UnixTime -> ByteString
formatUnixTimeGMT ByteString
fmt UnixTime
t =
IO ByteString -> ByteString
forall a. IO a -> a
unsafePerformIO (IO ByteString -> ByteString) -> IO ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ (CString -> CTime -> CString -> CInt -> IO CSize)
-> ByteString -> UnixTime -> IO ByteString
formatUnixTimeHelper CString -> CTime -> CString -> CInt -> IO CSize
c_format_unix_time_gmt ByteString
fmt UnixTime
t
{-# INLINE formatUnixTimeGMT #-}
formatUnixTimeHelper
:: (CString -> CTime -> CString -> CInt -> IO CSize)
-> Format
-> UnixTime
-> IO ByteString
formatUnixTimeHelper :: (CString -> CTime -> CString -> CInt -> IO CSize)
-> ByteString -> UnixTime -> IO ByteString
formatUnixTimeHelper CString -> CTime -> CString -> CInt -> IO CSize
formatFun ByteString
fmt (UnixTime CTime
sec Int32
_) =
ByteString -> (CString -> IO ByteString) -> IO ByteString
forall a. ByteString -> (CString -> IO a) -> IO a
useAsCString ByteString
fmt ((CString -> IO ByteString) -> IO ByteString)
-> (CString -> IO ByteString) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \CString
cfmt -> do
let siz :: Int
siz = Int
80
ptr <- Int -> IO CString
forall a. Int -> IO (Ptr a)
mallocBytes Int
siz
len <- fromIntegral <$> formatFun cfmt sec ptr (fromIntegral siz)
ptr' <- reallocBytes ptr (len + 1)
unsafePackMallocCString ptr'
webDateFormat :: Format
webDateFormat :: ByteString
webDateFormat = ByteString
"%a, %d %b %Y %H:%M:%S GMT"
mailDateFormat :: Format
mailDateFormat :: ByteString
mailDateFormat = ByteString
"%a, %d %b %Y %H:%M:%S %z"
fromEpochTime :: EpochTime -> UnixTime
fromEpochTime :: CTime -> UnixTime
fromEpochTime CTime
sec = CTime -> Int32 -> UnixTime
UnixTime CTime
sec Int32
0
toEpochTime :: UnixTime -> EpochTime
toEpochTime :: UnixTime -> CTime
toEpochTime (UnixTime CTime
sec Int32
_) = CTime
sec
fromClockTime :: ClockTime -> UnixTime
fromClockTime :: ClockTime -> UnixTime
fromClockTime (TOD Integer
sec Integer
psec) = CTime -> Int32 -> UnixTime
UnixTime CTime
sec' Int32
usec'
where
sec' :: CTime
sec' = Integer -> CTime
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
sec
usec' :: Int32
usec' = Integer -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Int32) -> Integer -> Int32
forall a b. (a -> b) -> a -> b
$ Integer
psec Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` Integer
1000000
toClockTime :: UnixTime -> ClockTime
toClockTime :: UnixTime -> ClockTime
toClockTime (UnixTime CTime
sec Int32
usec) = Integer -> Integer -> ClockTime
TOD Integer
sec' Integer
psec'
where
sec' :: Integer
sec' = Ratio Integer -> Integer
forall b. Integral b => Ratio Integer -> b
forall a b. (RealFrac a, Integral b) => a -> b
truncate (CTime -> Ratio Integer
forall a. Real a => a -> Ratio Integer
toRational CTime
sec)
psec' :: Integer
psec' = Int32 -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int32 -> Integer) -> Int32 -> Integer
forall a b. (a -> b) -> a -> b
$ Int32
usec Int32 -> Int32 -> Int32
forall a. Num a => a -> a -> a
* Int32
1000000