1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
module Seconds where
import Data.Aeson (FromJSON)
import Data.Aeson qualified as Json
import Data.Aeson.Types (FromJSON (parseJSON))
import Data.Scientific
import Data.Time (NominalDiffTime)
import FieldParser
import FieldParser qualified as Field
import MyPrelude
-- | A natural number of seconds.
newtype Seconds = Seconds {unSeconds :: Natural}
deriving stock (Eq, Show)
-- | Parse a decimal number as a number of seconds
textToSeconds :: FieldParser Text Seconds
textToSeconds = Seconds <$> Field.decimalNatural
scientificToSeconds :: FieldParser Scientific Seconds
scientificToSeconds =
( Field.boundedScientificIntegral @Int "Number of seconds"
>>> Field.integralToNatural
)
& rmap Seconds
-- Microseconds, represented internally with a 64 bit Int
newtype MicrosecondsInt = MicrosecondsInt {unMicrosecondsInt :: Int}
deriving stock (Eq, Show)
-- | Try to fit a number of seconds into a MicrosecondsInt
secondsToMicrosecondsInt :: FieldParser Seconds MicrosecondsInt
secondsToMicrosecondsInt =
lmap
(\sec -> naturalToInteger sec.unSeconds * 1_000_000)
(Field.bounded "Could not fit into an Int after multiplying with 1_000_000 (seconds to microseconds)")
& rmap MicrosecondsInt
secondsToNominalDiffTime :: Seconds -> NominalDiffTime
secondsToNominalDiffTime sec =
sec.unSeconds
& naturalToInteger
& fromInteger @NominalDiffTime
instance FromJSON Seconds where
parseJSON = Field.toParseJSON jsonNumberToSeconds
-- | Parse a json number as a number of seconds.
jsonNumberToSeconds :: FieldParser' Error Json.Value Seconds
jsonNumberToSeconds = Field.jsonNumber >>> scientificToSeconds
-- | Return the number of seconds in a week
secondsInAWeek :: Seconds
secondsInAWeek = Seconds (3600 * 24 * 7)
|