on master help sign in
Add ToJSON and FromJSON instances for NominalDiffTime
faadca7Nikolay Amiantov
Data/Aeson/Types/Instances.hs+16−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 (Day, LocalTime, UTCTime, ZonedTime)
80+import Data.Time (Day, LocalTime, UTCTime, ZonedTime, NominalDiffTime)
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)
@@ -749,6 +749,21 @@ stringEncoding = String . T.decodeLatin1 . L.toStrict . encode
749instance FromJSON UTCTime where
749instance FromJSON UTCTime where
750 parseJSON = withText "UTCTime" (Time.run Time.utcTime)
750 parseJSON = withText "UTCTime" (Time.run Time.utcTime)
751
751
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+
752parseJSONElemAtIndex :: FromJSON a => Int -> Vector Value -> Parser a
767parseJSONElemAtIndex :: FromJSON a => Int -> Vector Value -> Parser a
753parseJSONElemAtIndex idx ary = parseJSON (V.unsafeIndex ary idx) <?> Index idx
768parseJSONElemAtIndex idx ary = parseJSON (V.unsafeIndex ary idx) <?> Index idx
754
769
tests/Instances.hs+6−1
@@ -8,8 +8,10 @@ import Data.Function (on)
8import Control.Monad
8import Control.Monad
9import Test.QuickCheck (Arbitrary(..), Gen, choose, oneof, elements)
9import Test.QuickCheck (Arbitrary(..), Gen, choose, oneof, elements)
10import Data.Time.Clock (DiffTime, UTCTime(..), picosecondsToDiffTime)
10import Data.Time.Clock (DiffTime, UTCTime(..), picosecondsToDiffTime)
11+import Data.Fixed (Pico)
11import Data.Time (ZonedTime(..), LocalTime(..), TimeZone(..),
12import Data.Time (ZonedTime(..), LocalTime(..), TimeZone(..),
12− hoursToTimeZone, Day(..), TimeOfDay(..))
13+ hoursToTimeZone, Day(..), TimeOfDay(..),
14+ NominalDiffTime)
13import qualified Data.Text as T
15import qualified Data.Text as T
14import qualified Data.Map as Map
16import qualified Data.Map as Map
15import Data.Text (Text)
17import Data.Text (Text)
@@ -49,6 +51,9 @@ instance Arbitrary DotNetTime where
49instance Arbitrary ZonedTime where
51instance Arbitrary ZonedTime where
50 arbitrary = liftM2 ZonedTime arbitrary arbitrary
52 arbitrary = liftM2 ZonedTime arbitrary arbitrary
51
53
54+instance Arbitrary NominalDiffTime where
55+ arbitrary = realToFrac <$> (arbitrary :: Gen Pico)
56+
52deriving instance Eq ZonedTime
57deriving instance Eq ZonedTime
53
58
54-- Compare equality to within a millisecond, allowing for rounding
59-- Compare equality to within a millisecond, allowing for rounding
tests/Properties.hs+2−1
@@ -9,7 +9,7 @@ import Data.Aeson.Parser (value)
9import Data.Aeson.Types
9import Data.Aeson.Types
10import Data.ByteString.Builder (toLazyByteString)
10import Data.ByteString.Builder (toLazyByteString)
11import Data.Int (Int8)
11import Data.Int (Int8)
12−import Data.Time (Day, LocalTime, UTCTime, ZonedTime)
12+import Data.Time (Day, LocalTime, UTCTime, ZonedTime, NominalDiffTime)
13import Encoders
13import Encoders
14import Instances ()
14import Instances ()
15import Test.Framework (Test, testGroup)
15import Test.Framework (Test, testGroup)
@@ -124,6 +124,7 @@ tests = testGroup "properties" [
124 , testProperty "LocalTime" $ roundTripEq (undefined :: LocalTime)
124 , testProperty "LocalTime" $ roundTripEq (undefined :: LocalTime)
125 , testProperty "UTCTime" $ roundTripEq (undefined :: UTCTime)
125 , testProperty "UTCTime" $ roundTripEq (undefined :: UTCTime)
126 , testProperty "ZonedTime" $ roundTripEq (undefined :: ZonedTime)
126 , testProperty "ZonedTime" $ roundTripEq (undefined :: ZonedTime)
127+ , testProperty "NominalDiffTime" $ roundTripEq (undefined :: NominalDiffTime)
127 , testGroup "ghcGenerics" [
128 , testGroup "ghcGenerics" [
128 testProperty "OneConstructor" $ roundTripEq OneConstructor
129 testProperty "OneConstructor" $ roundTripEq OneConstructor
129 , testProperty "Product2" $ roundTripEq (undefined :: Product2 Int Bool)
130 , testProperty "Product2" $ roundTripEq (undefined :: Product2 Int Bool)