{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE OverloadedStrings #-}
module Data.UnixTime.Conv (
formatUnixTime,
formatUnixTimeGMT,
parseUnixTime,
parseUnixTimeGMT,
webDateFormat,
mailDateFormat,
fromEpochTime,
toEpochTime
) 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)
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