on master help sign in
Add ToJSON and FromJSON instances for NominalDiffTime
commitfaadca79b45ddf2ee3c6600e872b5330867e290f authorNikolay Amiantov <ab@fmap.me> dateThu 23 Jul 2015, 04:20 (11 years ago) parent8ab0959
3 files changed+24−3
Data/Aeson/Types/Instances.hs+16−1 tests/Instances.hs+6−1 tests/Properties.hs+2−1
Data/Aeson/Types/Instances.hs+16−1
@@ -77,7 +77,7 @@ import Data.Maybe (fromMaybe)
7777import Data.Monoid (Dual(..), First(..), Last(..))
7878import Data.Ratio (Ratio, (%), numerator, denominator)
7979import Data.Text (Text, pack, unpack)
80−import Data.Time (Day, LocalTime, UTCTime, ZonedTime)
80+import Data.Time (Day, LocalTime, UTCTime, ZonedTime, NominalDiffTime)
8181import Data.Time.Format (FormatTime, formatTime, parseTime)
8282import Data.Traversable as Tr (sequence, traverse)
8383import Data.Vector (Vector)
@@ -749,6 +749,21 @@ stringEncoding = String . T.decodeLatin1 . L.toStrict . encode
749749instance FromJSON UTCTime where
750750 parseJSON = withText "UTCTime" (Time.run Time.utcTime)
751751
752+instance ToJSON NominalDiffTime where
753+ toJSON = Number . realToFrac
754+ {-# INLINE toJSON #-}
755+
756+ toEncoding = Encoding . E.number . realToFrac
757+ {-# INLINE toEncoding #-}
758+
759+-- | /WARNING:/ Only parse lengths of time from trusted input
760+-- since an attacker could easily fill up the memory of the target
761+-- system by specifying a scientific number with a big exponent like
762+-- @1e1000000000@.
763+instance FromJSON NominalDiffTime where
764+ parseJSON = withScientific "NominalDiffTime" $ pure . realToFrac
765+ {-# INLINE parseJSON #-}
766+
752767parseJSONElemAtIndex :: FromJSON a => Int -> Vector Value -> Parser a
753768parseJSONElemAtIndex idx ary = parseJSON (V.unsafeIndex ary idx) <?> Index idx
754769
tests/Instances.hs+6−1
@@ -8,8 +8,10 @@ import Data.Function (on)
88import Control.Monad
99import Test.QuickCheck (Arbitrary(..), Gen, choose, oneof, elements)
1010import Data.Time.Clock (DiffTime, UTCTime(..), picosecondsToDiffTime)
11+import Data.Fixed (Pico)
1112import Data.Time (ZonedTime(..), LocalTime(..), TimeZone(..),
12− hoursToTimeZone, Day(..), TimeOfDay(..))
13+ hoursToTimeZone, Day(..), TimeOfDay(..),
14+ NominalDiffTime)
1315import qualified Data.Text as T
1416import qualified Data.Map as Map
1517import Data.Text (Text)
@@ -49,6 +51,9 @@ instance Arbitrary DotNetTime where
4951instance Arbitrary ZonedTime where
5052 arbitrary = liftM2 ZonedTime arbitrary arbitrary
5153
54+instance Arbitrary NominalDiffTime where
55+ arbitrary = realToFrac <$> (arbitrary :: Gen Pico)
56+
5257deriving instance Eq ZonedTime
5358
5459-- Compare equality to within a millisecond, allowing for rounding
tests/Properties.hs+2−1
@@ -9,7 +9,7 @@ import Data.Aeson.Parser (value)
99import Data.Aeson.Types
1010import Data.ByteString.Builder (toLazyByteString)
1111import Data.Int (Int8)
12−import Data.Time (Day, LocalTime, UTCTime, ZonedTime)
12+import Data.Time (Day, LocalTime, UTCTime, ZonedTime, NominalDiffTime)
1313import Encoders
1414import Instances ()
1515import Test.Framework (Test, testGroup)
@@ -124,6 +124,7 @@ tests = testGroup "properties" [
124124 , testProperty "LocalTime" $ roundTripEq (undefined :: LocalTime)
125125 , testProperty "UTCTime" $ roundTripEq (undefined :: UTCTime)
126126 , testProperty "ZonedTime" $ roundTripEq (undefined :: ZonedTime)
127+ , testProperty "NominalDiffTime" $ roundTripEq (undefined :: NominalDiffTime)
127128 , testGroup "ghcGenerics" [
128129 testProperty "OneConstructor" $ roundTripEq OneConstructor
129130 , testProperty "Product2" $ roundTripEq (undefined :: Product2 Int Bool)