@@ -13,23 +13,18 @@
13module Database.PostgreSQL.Simple.Time.Implementation where
13module Database.PostgreSQL.Simple.Time.Implementation where
15import Prelude hiding (take)
15import Prelude hiding (take)
16−import Data.ByteString.Builder(Builder, byteString, char8, integerDec)
16+import Data.ByteString.Builder(Builder, byteString)
17+import Data.ByteString.Builder.Prim(primBounded)
17import Control.Arrow((***))
18import Control.Arrow((***))
18import Control.Applicative
19import Control.Applicative
19−import Data.Bits((.&.))
20import qualified Data.ByteString as B
20import qualified Data.ByteString as B
21−import Data.ByteString.Internal (c2w, w2c)
22import Data.Time hiding (getTimeZone, getZonedTime)
21import Data.Time hiding (getTimeZone, getZonedTime)
23import Data.Typeable
22import Data.Typeable
24−import Data.Word(Word8)
25import Data.Maybe (fromMaybe)
23import Data.Maybe (fromMaybe)
26import qualified Data.Attoparsec.ByteString.Char8 as A
24import qualified Data.Attoparsec.ByteString.Char8 as A
27import Database.PostgreSQL.Simple.Compat ((<>))
25import Database.PostgreSQL.Simple.Compat ((<>))
28−import Data.Monoid(Monoid(..))
29−import Data.Fixed (Pico)
31−import qualified Database.PostgreSQL.Simple.Time.Internal.Parser as TP
26+import qualified Database.PostgreSQL.Simple.Time.Internal.Parser as TP
32−import Database.PostgreSQL.Simple.Compat (fromPico)
27+import qualified Database.PostgreSQL.Simple.Time.Internal.Printer as TPP
34data Unbounded a
29data Unbounded a
35 = NegInfinity
30 = NegInfinity
@@ -115,7 +110,7 @@ getTimeZoneHMS = munge <$> TP.timeZoneHMS
115 munge (Just (TP.UTCOffsetHMS h m s)) = (h,m,s)
110 munge (Just (TP.UTCOffsetHMS h m s)) = (h,m,s)
117localToUTCTimeOfDayHMS :: TimeZoneHMS -> TimeOfDay -> (Integer, TimeOfDay)
112localToUTCTimeOfDayHMS :: TimeZoneHMS -> TimeOfDay -> (Integer, TimeOfDay)
118−localToUTCTimeOfDayHMS (dh, dm, ds) tod =
113+localToUTCTimeOfDayHMS (dh, dm, ds) tod =
119 TP.localToUTCTimeOfDayHMS (TP.UTCOffsetHMS dh dm ds) tod
114 TP.localToUTCTimeOfDayHMS (TP.UTCOffsetHMS dh dm ds) tod
121getZonedTime :: A.Parser ZonedTime
116getZonedTime :: A.Parser ZonedTime
@@ -130,57 +125,23 @@ getUTCTime = TP.utcTime
130getUTCTimestamp :: A.Parser UTCTimestamp
125getUTCTimestamp :: A.Parser UTCTimestamp
131getUTCTimestamp = getUnbounded getUTCTime
126getUTCTimestamp = getUnbounded getUTCTime
134−toNum :: Num n => B.ByteString -> n
138−toNum_ :: Num n => n -> B.ByteString -> n
139−toNum_ = B.foldl' (\a c -> 10*a + digit c)
141−digit :: Num n => Word8 -> n
142−digit c = fromIntegral (c .&. 0x0f)
145−digits :: Num n => String -> A.Parser n
149− if A.isDigit x && A.isDigit y
150− then return $! (10 * digit (c2w x) + digit (c2w y))
151− else fail (msg <> " is not 2 digits")
152−{-# INLINE digits #-}
155dayToBuilder :: Day -> Builder
128dayToBuilder :: Day -> Builder
156−dayToBuilder (toGregorian -> (y,m,d)) = do
129+dayToBuilder = primBounded TPP.day
157− pad4 y <> char8 '-' <> pad2 m <> char8 '-' <> pad2 d
159timeOfDayToBuilder :: TimeOfDay -> Builder
131timeOfDayToBuilder :: TimeOfDay -> Builder
160−timeOfDayToBuilder (TimeOfDay h m s) = do
132+timeOfDayToBuilder = primBounded TPP.timeOfDay
161− pad2 h <> char8 ':' <> pad2 m <> char8 ':' <> showSeconds s
163timeZoneToBuilder :: TimeZone -> Builder
134timeZoneToBuilder :: TimeZone -> Builder
164−timeZoneToBuilder tz
135+timeZoneToBuilder = primBounded TPP.timeZone
165− | m == 0 = sign h <> pad2 (abs h)
166− | otherwise = sign h <> pad2 (abs h) <> char8 ':' <> pad2 (abs m)
168− (h,m) = timeZoneMinutes tz `quotRem` 60
169− sign h | h >= 0 = char8 '+'
170− | otherwise = char8 '-'
172utcTimeToBuilder :: UTCTime -> Builder
137utcTimeToBuilder :: UTCTime -> Builder
173−utcTimeToBuilder (UTCTime day time) =
138+utcTimeToBuilder = primBounded TPP.utcTime
174− dayToBuilder day <> char8 ' '
175− <> timeOfDayToBuilder (timeToTimeOfDay time) <> byteString "+00"
177zonedTimeToBuilder :: ZonedTime -> Builder
140zonedTimeToBuilder :: ZonedTime -> Builder
178−zonedTimeToBuilder (ZonedTime localTime tz) =
141+zonedTimeToBuilder = primBounded TPP.zonedTime
179− localTimeToBuilder localTime <> timeZoneToBuilder tz
181localTimeToBuilder :: LocalTime -> Builder
143localTimeToBuilder :: LocalTime -> Builder
182−localTimeToBuilder (LocalTime day tod) =
144+localTimeToBuilder = primBounded TPP.localTime
183− dayToBuilder day <> char8 ' ' <> timeOfDayToBuilder tod
185unboundedToBuilder :: (a -> Builder) -> (Unbounded a -> Builder)
146unboundedToBuilder :: (a -> Builder) -> (Unbounded a -> Builder)
186unboundedToBuilder finiteToBuilder unbounded
147unboundedToBuilder finiteToBuilder unbounded
@@ -202,62 +163,4 @@ dateToBuilder :: Date -> Builder
202dateToBuilder = unboundedToBuilder dayToBuilder
163dateToBuilder = unboundedToBuilder dayToBuilder
204nominalDiffTimeToBuilder :: NominalDiffTime -> Builder
165nominalDiffTimeToBuilder :: NominalDiffTime -> Builder
205−nominalDiffTimeToBuilder xyz
166+nominalDiffTimeToBuilder = TPP.nominalDiffTime
206− | yz < 500000 = sign <> integerDec x
207− | otherwise = sign <> integerDec x <> char8 '.' <> showD6 y
209− sign = if xyz >= 0 then mempty else char8 '-'
210− -- A kludge to work around the fact that Data.Fixed isn't very fast and
211− -- NominalDiffTime doesn't give the MkNominalDiffTime constructor.
212− (x,yz) = ((unsafeCoerce (abs xyz) :: Integer) + 500000) `quotRem` 1000000000000
213− (fromIntegral -> y, _z) = yz `quotRem` 1000000
215−showSeconds :: Pico -> Builder
218− | z == 0 = pad2 x <> char8 '.' <> showD6 y
219− | otherwise = pad2 x <> char8 '.' <> pad6 y <> showD6 z
221− (x_,yz) = fromPico xyz `quotRem` 1000000000000
222− x = fromIntegral x_ :: Int
223− (fromIntegral -> y, fromIntegral -> z) = yz `quotRem` 1000000
225−pad6 :: Int -> Builder
226−pad6 xy = let (x,y) = xy `quotRem` 1000
229−showD6 :: Int -> Builder
230−showD6 xy = case xy `quotRem` 1000 of
232− (x,y) -> pad3 x <> showD3 y
234−pad3 :: Int -> Builder
235−pad3 abc = let (ab,c) = abc `quotRem` 10
236− (a,b) = ab `quotRem` 10
237− in p a <> p b <> p c
239−showD3 :: Int -> Builder
240−showD3 abc = case abc `quotRem` 100 of
242− (a,bc) -> case bc `quotRem` 10 of
244− (b,c) -> p a <> p b <> p c
246−-- | p assumes its input is in the range [0..9]
247−p :: Integral n => n -> Builder
248−p n = char8 (w2c (fromIntegral (n + 48)))
251−-- | pad2 assumes its input is in the range [0..99]
252−pad2 :: Integral n => n -> Builder
253−pad2 n = let (a,b) = n `quotRem` 10 in p a <> p b
256−-- | pad4 assumes its input is positive
257−pad4 :: Integer -> Builder
258−pad4 abcd | abcd >= 10000 = integerDec abcd
259− | otherwise = p a <> p b <> p c <> p d
260− where (ab,cd) = abcd `quotRem` 100
261− (a,b) = ab `quotRem` 10
262− (c,d) = cd `quotRem` 10