@@ -25,8 +25,6 @@ module Data.Aeson.Encode.Builder
2525 , unquoted
2626 , number
2727 , day
28− , timeOfDay
29− , timeZone
3028 , utcTime
3129 , zonedTime
3230 , ascii2
@@ -41,12 +39,14 @@ import Data.ByteString.Builder.Prim as BP
4139import Data.ByteString.Builder.Scientific (scientificBuilder)
4240import Data.Char (chr, ord)
4341import Data.Foldable (foldMap)
42+import Data.Int (Int64)
4443import Data.Monoid ((<>))
4544import Data.Scientific (Scientific, base10Exponent, coefficient)
46−import Data.Time (UTCTime(..))
45+import Data.Time (DiffTime, UTCTime(..))
4746import Data.Time.Calendar (Day(..), toGregorian)
4847import Data.Time.LocalTime
4948import Data.Word (Word8)
49+import Unsafe.Coerce (unsafeCoerce)
5050import qualified Data.HashMap.Strict as HMS
5151import qualified Data.Text as T
5252import qualified Data.Text.Encoding as TE
@@ -177,8 +177,8 @@ day dd = B.integerDec y <>
177177 !(T dh dl) = twoDigits d
178178{-# INLINE day #-}
179179
180−timeOfDay :: TimeOfDay -> Builder
181−timeOfDay (TimeOfDay h m s)
180+timeOfDay :: TimeOfDay64 -> Builder
181+timeOfDay (TOD h m s)
182182 | micro100 < 5 = hhmmss -- omit trailing milliseconds if zero
183183 | otherwise = hhmmss <> BP.primBounded (ascii4 ('.',(a,(b,c)))) ()
184184 where
@@ -186,8 +186,7 @@ timeOfDay (TimeOfDay h m s)
186186 !(T hh hl) = twoDigits h
187187 !(T mh ml) = twoDigits m
188188 !(T sh sl) = twoDigits (fromIntegral real)
189− picos = fromPico s
190− (real,frac) = picos `quotRem` 1000000000000
189+ (real,frac) = s `quotRem` 1000000000000
191190 -- Units of 100 microseconds (tenths of a millisecond), which we
192191 -- round up so that milliseconds >= 0.5 render correctly.
193192 micro100
@@ -209,16 +208,30 @@ timeZone (TimeZone off _ _)
209208 (h,m) = abs off `quotRem` 60
210209{-# INLINE timeZone #-}
211210
212−dayTime :: Day -> TimeOfDay -> Builder
211+dayTime :: Day -> TimeOfDay64 -> Builder
213212dayTime d t = day d <> B.char7 'T' <> timeOfDay t
214213{-# INLINE dayTime #-}
215214
216215utcTime :: 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'
218217{-# INLINE utcTime #-}
219218
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+
220232zonedTime :: 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
222235{-# INLINE zonedTime #-}
223236
224237data T = T {-# UNPACK #-} !Char {-# UNPACK #-} !Char