{-# LANGUAGE CPP #-}
module Katip.Format.Time
( formatAsLogTime,
formatAsIso8601,
)
where
import Control.Monad.ST (ST)
import Data.Int (Int64)
import Data.Text (Text)
import qualified Data.Text.Array as TA
import Data.Text.Internal (Text (..))
import Data.Time (Day, DiffTime, UTCTime (..), toGregorian)
import Data.Word
#if MIN_VERSION_text(2,0,0)
(Word8)
#else
(Word16)
#endif
import Unsafe.Coerce (unsafeCoerce)
formatAsLogTime :: UTCTime -> Text
formatAsLogTime :: UTCTime -> Text
formatAsLogTime (UTCTime Day
day DiffTime
time) = (Array, Int) -> Text
toText forall a b. (a -> b) -> a -> b
$
forall a. (forall s. ST s (MArray s, a)) -> (Array, a)
TA.run2 forall a b. (a -> b) -> a -> b
$ do
MArray s
buf <- forall s. Int -> ST s (MArray s)
TA.new Int
19
Int
_ <- forall s. MArray s -> Int -> Day -> ST s Int
writeDay MArray s
buf Int
0 Day
day
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf Int
10 Word8
0x20
Int
_ <- forall s. Bool -> MArray s -> Int -> TimeOfDay64 -> ST s Int
writeTimeOfDay Bool
False MArray s
buf Int
11 (DiffTime -> TimeOfDay64
diffTimeOfDay64 DiffTime
time)
forall (m :: * -> *) a. Monad m => a -> m a
return (MArray s
buf, Int
19)
where
toText :: (Array, Int) -> Text
toText (Array
arr, Int
len) = Array -> Int -> Int -> Text
Text Array
arr Int
0 Int
len
{-# INLINEABLE formatAsLogTime #-}
formatAsIso8601 :: UTCTime -> Text
formatAsIso8601 :: UTCTime -> Text
formatAsIso8601 (UTCTime Day
day DiffTime
time) = (Array, Int) -> Text
toText forall a b. (a -> b) -> a -> b
$
forall a. (forall s. ST s (MArray s, a)) -> (Array, a)
TA.run2 forall a b. (a -> b) -> a -> b
$ do
MArray s
buf <- forall s. Int -> ST s (MArray s)
TA.new Int
33
Int
_ <- forall s. MArray s -> Int -> Day -> ST s Int
writeDay MArray s
buf Int
0 Day
day
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf Int
10 Word8
0x54
Int
next <- forall s. Bool -> MArray s -> Int -> TimeOfDay64 -> ST s Int
writeTimeOfDay Bool
True MArray s
buf Int
11 (DiffTime -> TimeOfDay64
diffTimeOfDay64 DiffTime
time)
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf Int
next Word8
0x5A
forall (m :: * -> *) a. Monad m => a -> m a
return (MArray s
buf, Int
next forall a. Num a => a -> a -> a
+ Int
1)
where
toText :: (Array, Int) -> Text
toText (Array
arr, Int
len) = Array -> Int -> Int -> Text
Text Array
arr Int
0 Int
len
{-# INLINEABLE formatAsIso8601 #-}
writeDay :: TA.MArray s -> Int -> Day -> ST s Int
writeDay :: forall s. MArray s -> Int -> Day -> ST s Int
writeDay MArray s
buf Int
off Day
day =
do
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
0) (Int -> Word8
digit Int
y1)
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
1) (Int -> Word8
digit Int
y2)
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
2) (Int -> Word8
digit Int
y3)
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
3) (Int -> Word8
digit Int
y4)
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
4) Word8
0x2d
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
5) Word8
m1
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
6) Word8
m2
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
7) Word8
0x2d
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
8) Word8
d1
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
9) Word8
d2
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
off forall a. Num a => a -> a -> a
+ Int
10)
where
(Year
yr, Int
m, Int
d) = Day -> (Year, Int, Int)
toGregorian Day
day
(Int
y1, Int
ya) = forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Num a => a -> a
abs Year
yr) forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
1000
(Int
y2, Int
yb) = Int
ya forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
100
(Int
y3, Int
y4) = Int
yb forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
10
T Word8
m1 Word8
m2 = Int -> T
twoDigits Int
m
T Word8
d1 Word8
d2 = Int -> T
twoDigits Int
d
{-# INLINE writeDay #-}
writeTimeOfDay :: Bool -> TA.MArray s -> Int -> TimeOfDay64 -> ST s Int
writeTimeOfDay :: forall s. Bool -> MArray s -> Int -> TimeOfDay64 -> ST s Int
writeTimeOfDay Bool
doSubSeconds MArray s
buf Int
off (TOD Int
hh Int
mm Int64
ss) =
do
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf Int
off Word8
h1
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
1) Word8
h2
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
2) Word8
0x3A
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
3) Word8
m1
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
4) Word8
m2
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
5) Word8
0x3A
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
6) Word8
s1
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
7) Word8
s2
if Bool
doSubSeconds Bool -> Bool -> Bool
&& Int64
frac forall a. Eq a => a -> a -> Bool
/= Int64
0
then forall s. MArray s -> Int -> Int64 -> ST s Int
writeFracSeconds MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
8) Int64
frac
else forall (m :: * -> *) a. Monad m => a -> m a
return (Int
off forall a. Num a => a -> a -> a
+ Int
8)
where
T Word8
h1 Word8
h2 = Int -> T
twoDigits Int
hh
T Word8
m1 Word8
m2 = Int -> T
twoDigits Int
mm
T Word8
s1 Word8
s2 = Int -> T
twoDigits (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
real)
(Int64
real, Int64
frac) = Int64
ss forall a. Integral a => a -> a -> (a, a)
`quotRem` Int64
pico
pico :: Int64
pico = Int64
1000000000000
writeFracSeconds :: TA.MArray s -> Int -> Int64 -> ST s Int
writeFracSeconds :: forall s. MArray s -> Int -> Int64 -> ST s Int
writeFracSeconds MArray s
buf Int
off Int64
frac =
do
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf Int
off Word8
0x2e
if Int64
mills forall a. Eq a => a -> a -> Bool
== Int64
0
then do
forall s. MArray s -> Int -> Int -> ST s Int
writeTrunc6 MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
1) (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
mics)
else do
forall s. MArray s -> Int -> Int -> ST s ()
writeDigit6 MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
1) (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
mics)
forall s. MArray s -> Int -> Int -> ST s Int
writeTrunc6 MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
7) (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
mills)
where
(Int64
mics, Int64
mills) = Int64
frac forall a. Integral a => a -> a -> (a, a)
`quotRem` Int64
micro
micro :: Int64
micro = Int64
1000000
writeDigit6 :: TA.MArray s -> Int -> Int -> ST s ()
writeDigit6 :: forall s. MArray s -> Int -> Int -> ST s ()
writeDigit6 MArray s
buf Int
off Int
i =
do
forall s. MArray s -> Int -> Int -> ST s ()
writeDigit3 MArray s
buf Int
off Int
f1
forall s. MArray s -> Int -> Int -> ST s ()
writeDigit3 MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
3) Int
f2
where
(Int
f1, Int
f2) = Int
i forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
1000
{-# INLINE writeDigit6 #-}
writeDigit3 :: TA.MArray s -> Int -> Int -> ST s ()
writeDigit3 :: forall s. MArray s -> Int -> Int -> ST s ()
writeDigit3 MArray s
buf Int
off Int
i =
do
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf Int
off (Int -> Word8
digit Int
d1)
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
1) (Int -> Word8
digit Int
d2)
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
2) (Int -> Word8
digit Int
d3)
where
(Int
d1, Int
d) = Int
i forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
100
(Int
d2, Int
d3) = Int
d forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
10
{-# INLINE writeDigit3 #-}
writeTrunc6 :: TA.MArray s -> Int -> Int -> ST s Int
writeTrunc6 :: forall s. MArray s -> Int -> Int -> ST s Int
writeTrunc6 MArray s
buf Int
off Int
i =
if Int
f2 forall a. Eq a => a -> a -> Bool
== Int
0
then forall s. MArray s -> Int -> Int -> ST s Int
writeTrunc3 MArray s
buf Int
off Int
f1
else do
forall s. MArray s -> Int -> Int -> ST s ()
writeDigit3 MArray s
buf Int
off Int
f1
forall s. MArray s -> Int -> Int -> ST s Int
writeTrunc3 MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
3) Int
f2
where
(Int
f1, Int
f2) = Int
i forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
1000
{-# INLINE writeTrunc6 #-}
writeTrunc3 :: TA.MArray s -> Int -> Int -> ST s Int
writeTrunc3 :: forall s. MArray s -> Int -> Int -> ST s Int
writeTrunc3 MArray s
buf Int
off Int
i
| Int
d forall a. Eq a => a -> a -> Bool
== Int
0 = do
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf Int
off (Int -> Word8
digit Int
d1)
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
off forall a. Num a => a -> a -> a
+ Int
1)
| Int
d3 forall a. Eq a => a -> a -> Bool
== Int
0 = do
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf Int
off (Int -> Word8
digit Int
d1)
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
1) (Int -> Word8
digit Int
d2)
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
off forall a. Num a => a -> a -> a
+ Int
2)
| Bool
otherwise = do
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf Int
off (Int -> Word8
digit Int
d1)
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
1) (Int -> Word8
digit Int
d2)
forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
buf (Int
off forall a. Num a => a -> a -> a
+ Int
2) (Int -> Word8
digit Int
d3)
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
off forall a. Num a => a -> a -> a
+ Int
3)
where
(Int
d1, Int
d) = Int
i forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
100
(Int
d2, Int
d3) = Int
d forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
10
{-# INLINE writeTrunc3 #-}
data T = T
#if MIN_VERSION_text(2,0,0)
{-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8
#else
{-# UNPACK #-} !Word16 {-# UNPACK #-} !Word16
#endif
twoDigits :: Int -> T
twoDigits :: Int -> T
twoDigits Int
a = Word8 -> Word8 -> T
T (Int -> Word8
digit Int
hi) (Int -> Word8
digit Int
lo)
where
(Int
hi, Int
lo) = Int
a forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
10
digit :: Int ->
#if MIN_VERSION_text(2,0,0)
Word8
#else
Word16
#endif
digit :: Int -> Word8
digit Int
x = forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
x forall a. Num a => a -> a -> a
+ Int
48)
data TimeOfDay64
= TOD
{-# UNPACK #-} !Int
{-# UNPACK #-} !Int
{-# UNPACK #-} !Int64
diffTimeOfDay64 :: DiffTime -> TimeOfDay64
diffTimeOfDay64 :: DiffTime -> TimeOfDay64
diffTimeOfDay64 DiffTime
t = Int -> Int -> Int64 -> TimeOfDay64
TOD (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
h) (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
m) Int64
s
where
(Int64
h, Int64
mp) = forall a b. (Integral a, Num b) => a -> b
fromIntegral Year
pico forall a. Integral a => a -> a -> (a, a)
`quotRem` Int64
3600000000000000
(Int64
m, Int64
s) = Int64
mp forall a. Integral a => a -> a -> (a, a)
`quotRem` Int64
60000000000000
pico :: Year
pico = forall a b. a -> b
unsafeCoerce DiffTime
t :: Integer