2018-10-30 03:13:36 +00:00
|
|
|
{- timestamp parsing and formatting
|
2015-05-10 19:23:38 +00:00
|
|
|
-
|
2019-01-02 16:26:07 +00:00
|
|
|
- Copyright 2015-2019 Joey Hess <id@joeyh.name>
|
2015-05-10 19:23:38 +00:00
|
|
|
-
|
2018-10-30 03:13:36 +00:00
|
|
|
- License: BSD-2-clause
|
2015-05-10 19:23:38 +00:00
|
|
|
-}
|
|
|
|
|
2019-11-23 15:07:22 +00:00
|
|
|
module Utility.TimeStamp (
|
|
|
|
parserPOSIXTime,
|
|
|
|
parsePOSIXTime,
|
|
|
|
formatPOSIXTime,
|
|
|
|
) where
|
2015-05-10 19:23:38 +00:00
|
|
|
|
2019-01-02 17:13:17 +00:00
|
|
|
import Utility.Data
|
2016-09-29 18:04:53 +00:00
|
|
|
|
2015-05-10 19:23:38 +00:00
|
|
|
import Data.Time.Clock.POSIX
|
|
|
|
import Data.Time
|
2016-09-29 18:04:53 +00:00
|
|
|
import Data.Ratio
|
2019-01-02 16:26:07 +00:00
|
|
|
import Control.Applicative
|
|
|
|
import qualified Data.ByteString as B
|
2019-01-02 17:13:17 +00:00
|
|
|
import qualified Data.ByteString.Char8 as B8
|
2019-01-02 16:26:07 +00:00
|
|
|
import qualified Data.Attoparsec.ByteString as A
|
|
|
|
import Data.Attoparsec.ByteString.Char8 (char, decimal, signed, isDigit_w8)
|
2015-05-10 19:23:38 +00:00
|
|
|
|
2019-01-02 16:26:07 +00:00
|
|
|
{- Parses how POSIXTime shows itself: "1431286201.113452s"
|
|
|
|
- (The "s" is included for historical reasons and is optional.)
|
|
|
|
- Also handles the format with no decimal seconds. -}
|
|
|
|
parserPOSIXTime :: A.Parser POSIXTime
|
|
|
|
parserPOSIXTime = mkPOSIXTime
|
|
|
|
<$> signed decimal
|
|
|
|
<*> (declen <|> pure (0, 0))
|
|
|
|
<* optional (char 's')
|
|
|
|
where
|
|
|
|
declen :: A.Parser (Integer, Int)
|
|
|
|
declen = do
|
|
|
|
_ <- char '.'
|
|
|
|
b <- A.takeWhile isDigit_w8
|
|
|
|
let len = B.length b
|
|
|
|
d <- either fail pure $
|
|
|
|
A.parseOnly (decimal <* A.endOfInput) b
|
|
|
|
return (d, len)
|
|
|
|
|
2015-05-10 19:23:38 +00:00
|
|
|
parsePOSIXTime :: String -> Maybe POSIXTime
|
2019-01-02 17:13:17 +00:00
|
|
|
parsePOSIXTime s = eitherToMaybe $
|
|
|
|
A.parseOnly (parserPOSIXTime <* A.endOfInput) (B8.pack s)
|
2015-05-10 19:36:58 +00:00
|
|
|
|
2019-01-02 16:26:07 +00:00
|
|
|
{- This implementation allows for higher precision in a POSIXTime than
|
|
|
|
- supported by the system's Double, and avoids the complications of
|
|
|
|
- floating point. -}
|
|
|
|
mkPOSIXTime :: Integer -> (Integer, Int) -> POSIXTime
|
|
|
|
mkPOSIXTime n (d, dlen)
|
|
|
|
| n < 0 = fromIntegral n - fromRational r
|
|
|
|
| otherwise = fromIntegral n + fromRational r
|
|
|
|
where
|
|
|
|
r = d % (10 ^ dlen)
|
|
|
|
|
2015-05-10 19:36:58 +00:00
|
|
|
formatPOSIXTime :: String -> POSIXTime -> String
|
|
|
|
formatPOSIXTime fmt t = formatTime defaultTimeLocale fmt (posixSecondsToUTCTime t)
|