on master help sign in
Make UTCTime encoding 3x faster
27f250bBryan O'Sullivan
Data/Aeson/Encode/Builder.hs+23−10
@@ -25,8 +25,6 @@ module Data.Aeson.Encode.Builder
25 , unquoted
25 , unquoted
26 , number
26 , number
27 , day
27 , day
28− , timeOfDay
29− , timeZone
30 , utcTime
28 , utcTime
31 , zonedTime
29 , zonedTime
32 , ascii2
30 , ascii2
@@ -41,12 +39,14 @@ import Data.ByteString.Builder.Prim as BP
41import Data.ByteString.Builder.Scientific (scientificBuilder)
39import Data.ByteString.Builder.Scientific (scientificBuilder)
42import Data.Char (chr, ord)
40import Data.Char (chr, ord)
43import Data.Foldable (foldMap)
41import Data.Foldable (foldMap)
42+import Data.Int (Int64)
44import Data.Monoid ((<>))
43import Data.Monoid ((<>))
45import Data.Scientific (Scientific, base10Exponent, coefficient)
44import Data.Scientific (Scientific, base10Exponent, coefficient)
46−import Data.Time (UTCTime(..))
45+import Data.Time (DiffTime, UTCTime(..))
47import Data.Time.Calendar (Day(..), toGregorian)
46import Data.Time.Calendar (Day(..), toGregorian)
48import Data.Time.LocalTime
47import Data.Time.LocalTime
49import Data.Word (Word8)
48import Data.Word (Word8)
49+import Unsafe.Coerce (unsafeCoerce)
50import qualified Data.HashMap.Strict as HMS
50import qualified Data.HashMap.Strict as HMS
51import qualified Data.Text as T
51import qualified Data.Text as T
52import qualified Data.Text.Encoding as TE
52import qualified Data.Text.Encoding as TE
@@ -177,8 +177,8 @@ day dd = B.integerDec y <>
177 !(T dh dl) = twoDigits d
177 !(T dh dl) = twoDigits d
178{-# INLINE day #-}
178{-# INLINE day #-}
179
179
180−timeOfDay :: TimeOfDay -> Builder
180+timeOfDay :: TimeOfDay64 -> Builder
181−timeOfDay (TimeOfDay h m s)
181+timeOfDay (TOD h m s)
182 | micro100 < 5 = hhmmss -- omit trailing milliseconds if zero
182 | micro100 < 5 = hhmmss -- omit trailing milliseconds if zero
183 | otherwise = hhmmss <> BP.primBounded (ascii4 ('.',(a,(b,c)))) ()
183 | otherwise = hhmmss <> BP.primBounded (ascii4 ('.',(a,(b,c)))) ()
184 where
184 where
@@ -186,8 +186,7 @@ timeOfDay (TimeOfDay h m s)
186 !(T hh hl) = twoDigits h
186 !(T hh hl) = twoDigits h
187 !(T mh ml) = twoDigits m
187 !(T mh ml) = twoDigits m
188 !(T sh sl) = twoDigits (fromIntegral real)
188 !(T sh sl) = twoDigits (fromIntegral real)
189− picos = fromPico s
190− (real,frac) = picos `quotRem` 1000000000000
189+ (real,frac) = s `quotRem` 1000000000000
191 -- Units of 100 microseconds (tenths of a millisecond), which we
190 -- Units of 100 microseconds (tenths of a millisecond), which we
192 -- round up so that milliseconds >= 0.5 render correctly.
191 -- round up so that milliseconds >= 0.5 render correctly.
193 micro100
192 micro100
@@ -209,16 +208,30 @@ timeZone (TimeZone off _ _)
209 (h,m) = abs off `quotRem` 60
208 (h,m) = abs off `quotRem` 60
210{-# INLINE timeZone #-}
209{-# INLINE timeZone #-}
211
210
212−dayTime :: Day -> TimeOfDay -> Builder
211+dayTime :: Day -> TimeOfDay64 -> Builder
213dayTime d t = day d <> B.char7 'T' <> timeOfDay t
212dayTime d t = day d <> B.char7 'T' <> timeOfDay t
214{-# INLINE dayTime #-}
213{-# INLINE dayTime #-}
215
214
216utcTime :: UTCTime -> B.Builder
215utcTime :: UTCTime -> B.Builder
217−utcTime (UTCTime d s) = dayTime d (timeToTimeOfDay s) <> B.char7 'Z'
216+utcTime (UTCTime d s) = dayTime d (diffTimeOfDay64 s) <> B.char7 'Z'
218{-# INLINE utcTime #-}
217{-# INLINE utcTime #-}
219
218
219+data TimeOfDay64 = TOD {-# UNPACK #-} !Int
220+ {-# UNPACK #-} !Int
221+ {-# UNPACK #-} !Int64
222+
223+diffTimeOfDay64 :: DiffTime -> TimeOfDay64
224+diffTimeOfDay64 t = TOD (fromIntegral h) (fromIntegral m) s
225+ where (h,mp) = fromIntegral pico `quotRem` 3600000000000000
226+ (m,s) = mp `quotRem` 60000000000000
227+ pico = unsafeCoerce t :: Integer
228+
229+toTimeOfDay64 :: TimeOfDay -> TimeOfDay64
230+toTimeOfDay64 (TimeOfDay h m s) = TOD h m (fromIntegral (fromPico s))
231+
220zonedTime :: ZonedTime -> Builder
232zonedTime :: ZonedTime -> Builder
221−zonedTime (ZonedTime (LocalTime d t) z) = dayTime d t <> timeZone z
233+zonedTime (ZonedTime (LocalTime d t) z) =
234+ dayTime d (toTimeOfDay64 t) <> timeZone z
222{-# INLINE zonedTime #-}
235{-# INLINE zonedTime #-}
223
236
224data T = T {-# UNPACK #-} !Char {-# UNPACK #-} !Char
237data T = T {-# UNPACK #-} !Char {-# UNPACK #-} !Char
Data/Aeson/Types/Instances.hs+1−1
@@ -77,7 +77,7 @@ import Data.Maybe (fromMaybe)
77import Data.Monoid (Dual(..), First(..), Last(..))
77import Data.Monoid (Dual(..), First(..), Last(..))
78import Data.Ratio (Ratio, (%), numerator, denominator)
78import Data.Ratio (Ratio, (%), numerator, denominator)
79import Data.Text (Text, pack, unpack)
79import Data.Text (Text, pack, unpack)
80−import Data.Time (UTCTime(..), ZonedTime(..), TimeZone(..))
80+import Data.Time (UTCTime, ZonedTime)
81import Data.Time.Format (FormatTime, formatTime, parseTime)
81import Data.Time.Format (FormatTime, formatTime, parseTime)
82import Data.Traversable as Tr (sequence, traverse)
82import Data.Traversable as Tr (sequence, traverse)
83import Data.Vector (Vector)
83import Data.Vector (Vector)