{-# LANGUAGE DataKinds #-}

{-| Functions for encoding common time formats in RFC 8259 JSONs.
 -}

module Codec.JSON.Encoder.Time
  ( -- * Calendar
    year
  , quarter

    -- ** Month
  , month
  , monthDate

    -- ** Week
  , weekDate

    -- ** Ordinal
  , ordinalDate

    -- * Time of day
  , timeOfDay

    -- ** Local
  , localTime

    -- ** Zoned
  , utcTime
  , timeZone
  , zonedTime
  ) where

import           Codec.JSON.Encoder.Unsafe

import qualified Builder.Lathe.Time as Builder
import           Data.ByteString.Builder
import           Data.Time.Calendar
import           Data.Time.Calendar.Month
import           Data.Time.Calendar.Quarter
import           Data.Time.Clock
import           Data.Time.LocalTime



-- | Encode a year as a JSON string in ISO 8601 extended @[-…y]yyyy@ format
--
--   Compatible with RFC 3339 if the year is in the \([0,10000)\) interval.
year :: Year -> Encoder
year :: Year -> Encoder
year Year
y = Builder -> Encoder
Encoder (Builder -> Encoder) -> Builder -> Encoder
forall a b. (a -> b) -> a -> b
$ Word8 -> Builder
word8 Word8
0x22 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Year -> Builder
Builder.year Year
y Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
word8 Word8
0x22



-- | Encode a year quarter as a JSON string in @[-…y]yyyy-Qq@ format.
--
--   Note that year quarters are not defined by ISO 8601, this is an informal convention.
quarter :: Quarter -> Encoder
quarter :: Quarter -> Encoder
quarter Quarter
q = Builder -> Encoder
Encoder (Builder -> Encoder) -> Builder -> Encoder
forall a b. (a -> b) -> a -> b
$ Word8 -> Builder
word8 Word8
0x22 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Quarter -> Builder
Builder.quarter Quarter
q Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
word8 Word8
0x22



-- | Encode a month date as a JSON string, in ISO 8601 extended @[-…y]yyyy-mm@ format.
--
--   RFC 3339 compatibility matches that of the 'year' function.
month :: Month -> Encoder
month :: Month -> Encoder
month Month
m = Builder -> Encoder
Encoder (Builder -> Encoder) -> Builder -> Encoder
forall a b. (a -> b) -> a -> b
$ Word8 -> Builder
word8 Word8
0x22 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Month -> Builder
Builder.month Month
m Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
word8 Word8
0x22



-- | Encode a month date as a JSON string in ISO 8601 extended @[-…y]yyyy-mm-dd@ format.
--
--   RFC 3339 compatibility matches that of the 'year' function.
monthDate :: Day -> Encoder
monthDate :: Day -> Encoder
monthDate Day
d = Builder -> Encoder
Encoder (Builder -> Encoder) -> Builder -> Encoder
forall a b. (a -> b) -> a -> b
$ Word8 -> Builder
word8 Word8
0x22 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Day -> Builder
Builder.monthDate Day
d Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
word8 Word8
0x22



-- | Encode a week date as a JSON string in ISO 8601 extended @[-…y]yyyy-Www-d@ format.
weekDate :: Day -> Encoder
weekDate :: Day -> Encoder
weekDate Day
d = Builder -> Encoder
Encoder (Builder -> Encoder) -> Builder -> Encoder
forall a b. (a -> b) -> a -> b
$ Word8 -> Builder
word8 Word8
0x22 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Day -> Builder
Builder.weekDate Day
d Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
word8 Word8
0x22



-- | Encode an ordinal date as a JSON string in ISO 8601 extended @[-…y]yyyy-ddd@ format.
ordinalDate :: Day -> Encoder
ordinalDate :: Day -> Encoder
ordinalDate Day
d = Builder -> Encoder
Encoder (Builder -> Encoder) -> Builder -> Encoder
forall a b. (a -> b) -> a -> b
$ Word8 -> Builder
word8 Word8
0x22 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Day -> Builder
Builder.ordinalDate Day
d Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
word8 Word8
0x22



-- | Encode a time of day as a JSON string in RFC 3339 @hh:mm:ss[.s…]@ format.
timeOfDay :: TimeOfDay -> Encoder
timeOfDay :: TimeOfDay -> Encoder
timeOfDay TimeOfDay
t = Builder -> Encoder
Encoder (Builder -> Encoder) -> Builder -> Encoder
forall a b. (a -> b) -> a -> b
$ Word8 -> Builder
word8 Word8
0x22 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> TimeOfDay -> Builder
Builder.timeOfDay TimeOfDay
t Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
word8 Word8
0x22



-- | Encode a local time as a JSON string in ISO 8601 extended
--   @[-…y]yyyy-mm-ddThh:mm:ss[.s…]@ format.
--
--   RFC 3339 compatibility matches that of the 'year' function.
localTime :: LocalTime -> Encoder
localTime :: LocalTime -> Encoder
localTime LocalTime
l = Builder -> Encoder
Encoder (Builder -> Encoder) -> Builder -> Encoder
forall a b. (a -> b) -> a -> b
$ Word8 -> Builder
word8 Word8
0x22 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> LocalTime -> Builder
Builder.localTime LocalTime
l Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
word8 Word8
0x22



-- | Encode a UTC time as a JSON string in ISO 8601 extended
--   @[-…y]yyyy-mm-ddThh:mm:ss[.s…]Z@ format.
--
--   RFC 3339 compatibility matches that of the 'year' function.
utcTime :: UTCTime -> Encoder
utcTime :: UTCTime -> Encoder
utcTime UTCTime
u = Builder -> Encoder
Encoder (Builder -> Encoder) -> Builder -> Encoder
forall a b. (a -> b) -> a -> b
$ Word8 -> Builder
word8 Word8
0x22 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> UTCTime -> Builder
Builder.utcTime UTCTime
u Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
word8 Word8
0x22



-- | Encode a time zone as a JSON string in ISO 8601 extended @±[…h]hh:mm@ format.
--
--   Compatible with RFC 3339 if the minute offset from UTC is
--   in the \((-24 \cdot 60, 24 \cdot 60)\) interval.
timeZone :: TimeZone -> Encoder
timeZone :: TimeZone -> Encoder
timeZone TimeZone
t = Builder -> Encoder
Encoder (Builder -> Encoder) -> Builder -> Encoder
forall a b. (a -> b) -> a -> b
$ Word8 -> Builder
word8 Word8
0x22 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> TimeZone -> Builder
Builder.timeZone TimeZone
t Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
word8 Word8
0x22



-- | Encode a zoned time as a JSON string in ISO 8601 extended
--   @[-…y]yyyy-mm-ddThh:mm:ss[.s…]±[…h]hh:mm@ format.
--
--   RFC 3339 compatibility matches that of both the 'year' and 'timeZone' functions.
zonedTime :: ZonedTime -> Encoder
zonedTime :: ZonedTime -> Encoder
zonedTime ZonedTime
z = Builder -> Encoder
Encoder (Builder -> Encoder) -> Builder -> Encoder
forall a b. (a -> b) -> a -> b
$ Word8 -> Builder
word8 Word8
0x22 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ZonedTime -> Builder
Builder.zonedTime ZonedTime
z Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
word8 Word8
0x22