@@ -24,19 +24,24 @@ module Data.Aeson.Encode.Builder
2424 , string
2525 , unquoted
2626 , number
27+ , day
28+ , timeOfDay
2729 , ascii2
2830 , ascii4
2931 , ascii5
3032 ) where
3133
34+import Data.Aeson.Functions (fromPico)
3235import Data.Aeson.Types.Internal (Encoding(..), Value(..))
3336import Data.ByteString.Builder as B
3437import Data.ByteString.Builder.Prim as BP
3538import Data.ByteString.Builder.Scientific (scientificBuilder)
36−import Data.Char (ord)
39+import Data.Char (chr, ord)
3740import Data.Foldable (foldMap)
3841import Data.Monoid ((<>))
3942import Data.Scientific (Scientific, base10Exponent, coefficient)
43+import Data.Time.Calendar (Day(..), toGregorian)
44+import Data.Time.LocalTime (TimeOfDay(..))
4045import Data.Word (Word8)
4146import qualified Data.HashMap.Strict as HMS
4247import qualified Data.Text as T
@@ -147,3 +152,54 @@ ascii5 :: (Char, (Char, (Char, (Char, Char)))) -> BP.BoundedPrim a
147152ascii5 cs = BP.liftFixedToBounded $ (const cs) >$<
148153 BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7
149154{-# INLINE ascii5 #-}
155+
156+ascii6 :: (Char, (Char, (Char, (Char, (Char, Char))))) -> BP.BoundedPrim a
157+ascii6 cs = BP.liftFixedToBounded $ (const cs) >$<
158+ BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7
159+{-# INLINE ascii6 #-}
160+
161+ascii8 :: (Char, (Char, (Char, (Char, (Char, (Char, (Char, Char)))))))
162+ -> BP.BoundedPrim a
163+ascii8 cs = BP.liftFixedToBounded $ (const cs) >$<
164+ BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7 >*<
165+ BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7
166+{-# INLINE ascii8 #-}
167+
168+day :: Day -> Builder
169+day dd = B.integerDec y <>
170+ BP.primBounded (ascii6 ('-',(mh,(ml,('-',(dh,dl)))))) ()
171+ where (y,m,d) = toGregorian dd
172+ !(T mh ml) = twoDigits m
173+ !(T dh dl) = twoDigits d
174+{-# INLINE day #-}
175+
176+timeOfDay :: TimeOfDay -> Builder
177+timeOfDay (TimeOfDay h m s)
178+ | micro100 < 5 = hhmmss -- omit trailing milliseconds if zero
179+ | otherwise = hhmmss <> BP.primBounded (ascii4 ('.',(a,(b,c)))) ()
180+ where
181+ hhmmss = BP.primBounded (ascii8 (hh,(hl,(':',(mh,(ml,(':',(sh,sl)))))))) ()
182+ !(T hh hl) = twoDigits h
183+ !(T mh ml) = twoDigits m
184+ !(T sh sl) = twoDigits (fromIntegral real)
185+ picos = fromPico s
186+ (real,frac) = picos `quotRem` 1000000000000
187+ -- Units of 100 microseconds (tenths of a millisecond), which we
188+ -- round up so that milliseconds >= 0.5 render correctly.
189+ micro100
190+ | d `rem` 10 < 5 = d
191+ | otherwise = d + 10
192+ where d = fromIntegral (frac `quot` 100000000)
193+ !(T a b) = twoDigits ab
194+ (ab,cc) = micro100 `quotRem` 100
195+ !c = digit (cc `quot` 10)
196+{-# INLINE timeOfDay #-}
197+
198+data T = T {-# UNPACK #-} !Char {-# UNPACK #-} !Char
199+
200+twoDigits :: Int -> T
201+twoDigits a = T (digit hi) (digit lo)
202+ where (hi,lo) = a `quotRem` 10
203+
204+digit :: Int -> Char
205+digit x = chr (x + 48)