{-# LANGUAGE NumericUnderscores #-}

{-| Functions for encoding data using common time formats.
 -}

module Builder.Lathe.Time
  ( -- * Calendar
    year
  , quarter

    -- ** Month
  , month
  , monthDate

    -- ** Week
  , weekDate

    -- ** Ordinal
  , ordinalDate

    -- * Time of day
  , timeOfDay

    -- ** Local
  , localTime

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

import           Data.ByteString.Builder
import qualified Data.ByteString.Builder.Prim as Prim

import           Data.Bits
import           Data.Fixed
import           Data.Time.Calendar
import           Data.Time.Calendar.Month
import           Data.Time.Calendar.OrdinalDate
import           Data.Time.Calendar.Quarter
import           Data.Time.Calendar.WeekDate
import           Data.Time.Clock
import           Data.Time.LocalTime



{-# INLINE oneDec #-}
oneDec :: Prim.FixedPrim Int
oneDec :: FixedPrim Int
oneDec =
  (\Int
x -> Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
x Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8
0x30
   )
     (Int -> Word8) -> FixedPrim Word8 -> FixedPrim Int
forall (f :: * -> *) b a. Contravariant f => (b -> a) -> f a -> f b
Prim.>$< FixedPrim Word8
Prim.word8

{-# INLINE twoDec #-}
twoDec :: Prim.FixedPrim Int
twoDec :: FixedPrim Int
twoDec =
  (\Int
xx -> let (Int
x1, Int
x0) = Int
xx Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
10
          in (Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
unsafeShiftL (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
x1) Int
8 Word16 -> Word16 -> Word16
forall a. Num a => a -> a -> a
+ Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
x0 Word16 -> Word16 -> Word16
forall a. Num a => a -> a -> a
+ Word16
0x3030)
   )
     (Int -> Word16) -> FixedPrim Word16 -> FixedPrim Int
forall (f :: * -> *) b a. Contravariant f => (b -> a) -> f a -> f b
Prim.>$< FixedPrim Word16
Prim.word16BE

{-# INLINE threeDec #-}
threeDec :: Prim.FixedPrim Int
threeDec :: FixedPrim Int
threeDec =
  (Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
100)
     (Int -> (Int, Int)) -> FixedPrim (Int, Int) -> FixedPrim Int
forall (f :: * -> *) b a. Contravariant f => (b -> a) -> f a -> f b
Prim.>$< FixedPrim Int
oneDec
     FixedPrim Int -> FixedPrim Int -> FixedPrim (Int, Int)
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Int
twoDec



trimmedSeconds :: Pico -> Builder
trimmedSeconds :: Pico -> Builder
trimmedSeconds (MkFixed Year
ssms) =
  let double :: Double
double = Year -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Year
ssms Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
1_000_000_000_000
      ss :: Int
ss     = Double -> Int
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
truncate Double
double
      ms :: Double
ms     = Double
double Double -> Double -> Double
forall a. Num a => a -> a -> a
- Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
ss

  in if Double
ms Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double
0
       then FixedPrim Int -> Int -> Builder
forall a. FixedPrim a -> a -> Builder
Prim.primFixed FixedPrim Int
twoDec Int
ss
       else ( if Int
ss Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
10
                then Builder
forall a. Monoid a => a
mempty
                else Word8 -> Builder
word8 Word8
0x30
            )
         Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> FloatFormat -> Double -> Builder
formatDouble FloatFormat
standardDefaultPrecision Double
double



{-# INLINE withYear #-}
withYear :: Year -> (Prim.FixedPrim Int -> Int -> Builder) -> Builder
withYear :: Year -> (FixedPrim Int -> Int -> Builder) -> Builder
withYear Year
yyyy FixedPrim Int -> Int -> Builder
f =
  let (Bool
m, Year
y, Year
yyy) | Year
yyyy Year -> Year -> Bool
forall a. Ord a => a -> a -> Bool
>= Year
0 = let (Year
x, Year
xxx) = Year
yyyy Year -> Year -> (Year, Year)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Year
1_000
                                in (Bool
False, Year
x, Year
xxx)
                  | Bool
otherwise = let (Year
x, Year
xxx) = Year -> Year
forall a. Num a => a -> a
negate Year
yyyy Year -> Year -> (Year, Year)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Year
1_000
                                in (Bool
True, Year
x, Year
xxx)

  in    ( if Bool
m
            then Word8 -> Builder
word8 Word8
0x2D
            else Builder
forall a. Monoid a => a
mempty
        )
     Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Year -> Builder
integerDec Year
y
     Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> FixedPrim Int -> Int -> Builder
f FixedPrim Int
threeDec (Year -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Year
yyy)



-- | Encode a year in ISO 8601 extended @[-…y]yyyy@ format. At least 4 bytes wide.
--
--  Compatible with RFC 3339 if the year is in the \([0,10000)\) interval.
year :: Year -> Builder
year :: Year -> Builder
year Year
yyyy = Year -> (FixedPrim Int -> Int -> Builder) -> Builder
withYear Year
yyyy FixedPrim Int -> Int -> Builder
forall a. FixedPrim a -> a -> Builder
Prim.primFixed



-- | Encode a year quarter in @[-…y]yyyy-Qq@ format. At least 7 bytes wide.
--
--   Note that year quarters are not defined by ISO 8601, this is an informal convention.
quarter :: Quarter -> Builder
quarter :: Quarter -> Builder
quarter (YearQuarter Year
yyyy QuarterOfYear
q) =
  let i :: Word8
i = case QuarterOfYear
q of
            QuarterOfYear
Q1 -> Word8
0x31
            QuarterOfYear
Q2 -> Word8
0x32
            QuarterOfYear
Q3 -> Word8
0x33
            QuarterOfYear
Q4 -> Word8
0x34

  in Year -> (FixedPrim Int -> Int -> Builder) -> Builder
withYear Year
yyyy ((FixedPrim Int -> Int -> Builder) -> Builder)
-> (FixedPrim Int -> Int -> Builder) -> Builder
forall a b. (a -> b) -> a -> b
$ \FixedPrim Int
yearDec Int
yyy ->
       FixedPrim (Int, (Word16, Word8))
-> (Int, (Word16, Word8)) -> Builder
forall a. FixedPrim a -> a -> Builder
Prim.primFixed
         ( (Int, (Word16, Word8)) -> (Int, (Word16, Word8))
forall a. a -> a
id
             ((Int, (Word16, Word8)) -> (Int, (Word16, Word8)))
-> FixedPrim (Int, (Word16, Word8))
-> FixedPrim (Int, (Word16, Word8))
forall (f :: * -> *) b a. Contravariant f => (b -> a) -> f a -> f b
Prim.>$< FixedPrim Int
yearDec
             FixedPrim Int
-> FixedPrim (Word16, Word8) -> FixedPrim (Int, (Word16, Word8))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word16
Prim.word16BE
             FixedPrim Word16 -> FixedPrim Word8 -> FixedPrim (Word16, Word8)
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word8
Prim.word8
         )
         (Int
yyy, (Word16
0x2D51, Word8
i))



-- | Encode a month in ISO 8601 extended @[-…y]yyyy-mm@ format. At least 7 bytes wide.
--
--   RFC 3339 compatibility matches that of the 'year' function.
month :: Month -> Builder
month :: Month -> Builder
month (YearMonth Year
yyyy Int
mm) =
  Year -> (FixedPrim Int -> Int -> Builder) -> Builder
withYear Year
yyyy ((FixedPrim Int -> Int -> Builder) -> Builder)
-> (FixedPrim Int -> Int -> Builder) -> Builder
forall a b. (a -> b) -> a -> b
$ \FixedPrim Int
yearDec Int
yyy ->
    FixedPrim (Int, (Word8, Int)) -> (Int, (Word8, Int)) -> Builder
forall a. FixedPrim a -> a -> Builder
Prim.primFixed
      ( (Int, (Word8, Int)) -> (Int, (Word8, Int))
forall a. a -> a
id
          ((Int, (Word8, Int)) -> (Int, (Word8, Int)))
-> FixedPrim (Int, (Word8, Int)) -> FixedPrim (Int, (Word8, Int))
forall (f :: * -> *) b a. Contravariant f => (b -> a) -> f a -> f b
Prim.>$< FixedPrim Int
yearDec
          FixedPrim Int
-> FixedPrim (Word8, Int) -> FixedPrim (Int, (Word8, Int))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word8
Prim.word8
          FixedPrim Word8 -> FixedPrim Int -> FixedPrim (Word8, Int)
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Int
twoDec
      )
      (Int
yyy, (Word8
0x2D, Int
mm))



-- | Encode a month date in ISO 8601 extended @[-…y]yyyy-mm-dd@ format.
--   At least 10 bytes wide.
--
--   RFC 3339 compatibility matches that of the 'year' function.
monthDate :: Day -> Builder
monthDate :: Day -> Builder
monthDate (YearMonthDay Year
yyyy Int
mm Int
dd) =
  Year -> (FixedPrim Int -> Int -> Builder) -> Builder
withYear Year
yyyy ((FixedPrim Int -> Int -> Builder) -> Builder)
-> (FixedPrim Int -> Int -> Builder) -> Builder
forall a b. (a -> b) -> a -> b
$ \FixedPrim Int
yearDec Int
yyy ->
    FixedPrim (Int, (Word8, (Int, (Word8, Int))))
-> (Int, (Word8, (Int, (Word8, Int)))) -> Builder
forall a. FixedPrim a -> a -> Builder
Prim.primFixed
      ( (Int, (Word8, (Int, (Word8, Int))))
-> (Int, (Word8, (Int, (Word8, Int))))
forall a. a -> a
id
          ((Int, (Word8, (Int, (Word8, Int))))
 -> (Int, (Word8, (Int, (Word8, Int)))))
-> FixedPrim (Int, (Word8, (Int, (Word8, Int))))
-> FixedPrim (Int, (Word8, (Int, (Word8, Int))))
forall (f :: * -> *) b a. Contravariant f => (b -> a) -> f a -> f b
Prim.>$< FixedPrim Int
yearDec
          FixedPrim Int
-> FixedPrim (Word8, (Int, (Word8, Int)))
-> FixedPrim (Int, (Word8, (Int, (Word8, Int))))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word8
Prim.word8
          FixedPrim Word8
-> FixedPrim (Int, (Word8, Int))
-> FixedPrim (Word8, (Int, (Word8, Int)))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Int
twoDec
          FixedPrim Int
-> FixedPrim (Word8, Int) -> FixedPrim (Int, (Word8, Int))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word8
Prim.word8
          FixedPrim Word8 -> FixedPrim Int -> FixedPrim (Word8, Int)
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Int
twoDec
      )
      (Int
yyy, (Word8
0x2D, (Int
mm, (Word8
0x2D, Int
dd))))



-- | Encode an ordinal date in ISO 8601 extended @[-…y]yyyy-ddd@ format.
--   At least 8 bytes wide.
ordinalDate :: Day -> Builder
ordinalDate :: Day -> Builder
ordinalDate Day
x =
  let (Year
yyyy, Int
ddd) = Day -> (Year, Int)
toOrdinalDate Day
x
  in Year -> (FixedPrim Int -> Int -> Builder) -> Builder
withYear Year
yyyy ((FixedPrim Int -> Int -> Builder) -> Builder)
-> (FixedPrim Int -> Int -> Builder) -> Builder
forall a b. (a -> b) -> a -> b
$ \FixedPrim Int
yearDec Int
yyy ->
       FixedPrim (Int, (Word8, Int)) -> (Int, (Word8, Int)) -> Builder
forall a. FixedPrim a -> a -> Builder
Prim.primFixed
         ( (Int, (Word8, Int)) -> (Int, (Word8, Int))
forall a. a -> a
id
             ((Int, (Word8, Int)) -> (Int, (Word8, Int)))
-> FixedPrim (Int, (Word8, Int)) -> FixedPrim (Int, (Word8, Int))
forall (f :: * -> *) b a. Contravariant f => (b -> a) -> f a -> f b
Prim.>$< FixedPrim Int
yearDec
             FixedPrim Int
-> FixedPrim (Word8, Int) -> FixedPrim (Int, (Word8, Int))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word8
Prim.word8
             FixedPrim Word8 -> FixedPrim Int -> FixedPrim (Word8, Int)
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Int
threeDec
         )
         (Int
yyy, (Word8
0x2D, Int
ddd))



-- | Encode a week date in ISO 8601 extended @[-…y]yyyy-Www-d@ format.
--   At least 10 bytes wide.
weekDate :: Day -> Builder
weekDate :: Day -> Builder
weekDate Day
x =
  let (Year
yyyy, Int
ww, Int
d) = Day -> (Year, Int, Int)
toWeekDate Day
x
  in Year -> (FixedPrim Int -> Int -> Builder) -> Builder
withYear Year
yyyy ((FixedPrim Int -> Int -> Builder) -> Builder)
-> (FixedPrim Int -> Int -> Builder) -> Builder
forall a b. (a -> b) -> a -> b
$ \FixedPrim Int
yearDec Int
yyy ->
       FixedPrim (Int, (Word16, (Int, (Word8, Int))))
-> (Int, (Word16, (Int, (Word8, Int)))) -> Builder
forall a. FixedPrim a -> a -> Builder
Prim.primFixed
         ( (Int, (Word16, (Int, (Word8, Int))))
-> (Int, (Word16, (Int, (Word8, Int))))
forall a. a -> a
id
             ((Int, (Word16, (Int, (Word8, Int))))
 -> (Int, (Word16, (Int, (Word8, Int)))))
-> FixedPrim (Int, (Word16, (Int, (Word8, Int))))
-> FixedPrim (Int, (Word16, (Int, (Word8, Int))))
forall (f :: * -> *) b a. Contravariant f => (b -> a) -> f a -> f b
Prim.>$< FixedPrim Int
yearDec
             FixedPrim Int
-> FixedPrim (Word16, (Int, (Word8, Int)))
-> FixedPrim (Int, (Word16, (Int, (Word8, Int))))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word16
Prim.word16BE
             FixedPrim Word16
-> FixedPrim (Int, (Word8, Int))
-> FixedPrim (Word16, (Int, (Word8, Int)))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Int
twoDec
             FixedPrim Int
-> FixedPrim (Word8, Int) -> FixedPrim (Int, (Word8, Int))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word8
Prim.word8
             FixedPrim Word8 -> FixedPrim Int -> FixedPrim (Word8, Int)
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Int
oneDec
         )
         (Int
yyy, (Word16
0x2D57, (Int
ww, (Word8
0x2D, Int
d))))



-- | Encode a time of day in RFC 3339 @hh:mm:ss[.s…]@ format.
--   8 to 21 bytes wide.
timeOfDay :: TimeOfDay -> Builder
timeOfDay :: TimeOfDay -> Builder
timeOfDay (TimeOfDay Int
hh Int
mm Pico
ssms) =
     FixedPrim (Int, (Word8, (Int, Word8)))
-> (Int, (Word8, (Int, Word8))) -> Builder
forall a. FixedPrim a -> a -> Builder
Prim.primFixed
       ( (Int, (Word8, (Int, Word8))) -> (Int, (Word8, (Int, Word8)))
forall a. a -> a
id
           ((Int, (Word8, (Int, Word8))) -> (Int, (Word8, (Int, Word8))))
-> FixedPrim (Int, (Word8, (Int, Word8)))
-> FixedPrim (Int, (Word8, (Int, Word8)))
forall (f :: * -> *) b a. Contravariant f => (b -> a) -> f a -> f b
Prim.>$< FixedPrim Int
twoDec
           FixedPrim Int
-> FixedPrim (Word8, (Int, Word8))
-> FixedPrim (Int, (Word8, (Int, Word8)))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word8
Prim.word8
           FixedPrim Word8
-> FixedPrim (Int, Word8) -> FixedPrim (Word8, (Int, Word8))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Int
twoDec
           FixedPrim Int -> FixedPrim Word8 -> FixedPrim (Int, Word8)
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word8
Prim.word8
       )
       (Int
hh, (Word8
0x3A, (Int
mm, Word8
0x3A)))

  Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Pico -> Builder
trimmedSeconds Pico
ssms



-- | Encode a local time in ISO 8601 extended @[-…y]yyyy-mm-ddThh:mm:ss[.s…]@ format.
--   At least 19 bytes wide.
--
--   RFC 3339 compatibility matches that of the 'year' function.
localTime :: LocalTime -> Builder
localTime :: LocalTime -> Builder
localTime (LocalTime (YearMonthDay Year
yyyy Int
mm Int
dd) (TimeOfDay Int
hh Int
nn Pico
ssms)) =
     Year -> (FixedPrim Int -> Int -> Builder) -> Builder
withYear Year
yyyy ((FixedPrim Int -> Int -> Builder) -> Builder)
-> (FixedPrim Int -> Int -> Builder) -> Builder
forall a b. (a -> b) -> a -> b
$ \FixedPrim Int
yearDec Int
yyy -> do
       FixedPrim
  (Int,
   (Word8,
    (Int, (Word8, (Int, (Word8, (Int, (Word8, (Int, Word8)))))))))
-> (Int,
    (Word8,
     (Int, (Word8, (Int, (Word8, (Int, (Word8, (Int, Word8)))))))))
-> Builder
forall a. FixedPrim a -> a -> Builder
Prim.primFixed
         ( (Int,
 (Word8,
  (Int, (Word8, (Int, (Word8, (Int, (Word8, (Int, Word8)))))))))
-> (Int,
    (Word8,
     (Int, (Word8, (Int, (Word8, (Int, (Word8, (Int, Word8)))))))))
forall a. a -> a
id
             ((Int,
  (Word8,
   (Int, (Word8, (Int, (Word8, (Int, (Word8, (Int, Word8)))))))))
 -> (Int,
     (Word8,
      (Int, (Word8, (Int, (Word8, (Int, (Word8, (Int, Word8))))))))))
-> FixedPrim
     (Int,
      (Word8,
       (Int, (Word8, (Int, (Word8, (Int, (Word8, (Int, Word8)))))))))
-> FixedPrim
     (Int,
      (Word8,
       (Int, (Word8, (Int, (Word8, (Int, (Word8, (Int, Word8)))))))))
forall (f :: * -> *) b a. Contravariant f => (b -> a) -> f a -> f b
Prim.>$< FixedPrim Int
yearDec
             FixedPrim Int
-> FixedPrim
     (Word8,
      (Int, (Word8, (Int, (Word8, (Int, (Word8, (Int, Word8))))))))
-> FixedPrim
     (Int,
      (Word8,
       (Int, (Word8, (Int, (Word8, (Int, (Word8, (Int, Word8)))))))))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word8
Prim.word8
             FixedPrim Word8
-> FixedPrim
     (Int, (Word8, (Int, (Word8, (Int, (Word8, (Int, Word8)))))))
-> FixedPrim
     (Word8,
      (Int, (Word8, (Int, (Word8, (Int, (Word8, (Int, Word8))))))))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Int
twoDec
             FixedPrim Int
-> FixedPrim (Word8, (Int, (Word8, (Int, (Word8, (Int, Word8))))))
-> FixedPrim
     (Int, (Word8, (Int, (Word8, (Int, (Word8, (Int, Word8)))))))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word8
Prim.word8
             FixedPrim Word8
-> FixedPrim (Int, (Word8, (Int, (Word8, (Int, Word8)))))
-> FixedPrim (Word8, (Int, (Word8, (Int, (Word8, (Int, Word8))))))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Int
twoDec
             FixedPrim Int
-> FixedPrim (Word8, (Int, (Word8, (Int, Word8))))
-> FixedPrim (Int, (Word8, (Int, (Word8, (Int, Word8)))))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word8
Prim.word8
             FixedPrim Word8
-> FixedPrim (Int, (Word8, (Int, Word8)))
-> FixedPrim (Word8, (Int, (Word8, (Int, Word8))))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Int
twoDec
             FixedPrim Int
-> FixedPrim (Word8, (Int, Word8))
-> FixedPrim (Int, (Word8, (Int, Word8)))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word8
Prim.word8
             FixedPrim Word8
-> FixedPrim (Int, Word8) -> FixedPrim (Word8, (Int, Word8))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Int
twoDec
             FixedPrim Int -> FixedPrim Word8 -> FixedPrim (Int, Word8)
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word8
Prim.word8
         )
         (Int
yyy, (Word8
0x2D, (Int
mm, (Word8
0x2D, (Int
dd, (Word8
0x54, (Int
hh, (Word8
0x3A, (Int
nn, Word8
0x3A)))))))))

  Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Pico -> Builder
trimmedSeconds Pico
ssms



-- | Encode a UTC time in ISO 8601 extended @[-…y]yyyy-mm-ddThh:mm:ss[.s…]Z@ format.
--   At least 20 bytes wide.
--
--   RFC 3339 compatibility matches that of the 'year' function.
utcTime :: UTCTime -> Builder
utcTime :: UTCTime -> Builder
utcTime UTCTime
time = LocalTime -> Builder
localTime (TimeZone -> UTCTime -> LocalTime
utcToLocalTime TimeZone
utc UTCTime
time) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
word8 Word8
0x5A



-- | Encode a time zone in ISO 8601 extended @±[…h]hh:mm@ format.
--   At least 6 bytes wide.
--
--   Compatible with RFC 3339 if the minute offset from UTC is
--   in the \((-24 \cdot 60, 24 \cdot 60)\) interval.
timeZone :: TimeZone -> Builder
timeZone :: TimeZone -> Builder
timeZone TimeZone
zone =
  let hhmm :: Int
hhmm = TimeZone -> Int
timeZoneMinutes TimeZone
zone

      (Word8
m, Int
hh, Int
mm) = if Int
hhmm Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
                      then let (Int
yy, Int
zz) = Int
hhmm Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
60
                           in (Word8
0x2B, Int
yy, Int
zz)

                      else let (Int
yy, Int
zz) = Int -> Int
forall a. Num a => a -> a
negate Int
hhmm Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
60
                           in (Word8
0x2D, Int
yy, Int
zz)

  in FixedPrim (Word8, (Int, (Word8, Int)))
-> (Word8, (Int, (Word8, Int))) -> Builder
forall a. FixedPrim a -> a -> Builder
Prim.primFixed
       ( (Word8, (Int, (Word8, Int))) -> (Word8, (Int, (Word8, Int)))
forall a. a -> a
id
           ((Word8, (Int, (Word8, Int))) -> (Word8, (Int, (Word8, Int))))
-> FixedPrim (Word8, (Int, (Word8, Int)))
-> FixedPrim (Word8, (Int, (Word8, Int)))
forall (f :: * -> *) b a. Contravariant f => (b -> a) -> f a -> f b
Prim.>$< FixedPrim Word8
Prim.word8
           FixedPrim Word8
-> FixedPrim (Int, (Word8, Int))
-> FixedPrim (Word8, (Int, (Word8, Int)))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Int
twoDec
           FixedPrim Int
-> FixedPrim (Word8, Int) -> FixedPrim (Int, (Word8, Int))
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word8
Prim.word8
           FixedPrim Word8 -> FixedPrim Int -> FixedPrim (Word8, Int)
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Int
twoDec
       )
       (Word8
m, (Int
hh, (Word8
0x3A, Int
mm)))



-- | Encode a zoned time in ISO 8601 extended
--   @[-…y]yyyy-mm-ddThh:mm:ss[.s…]±[…h]hh:mm@ format.
--   At least 25 bytes wide.
--
--   RFC 3339 compatibility matches that of both the 'year' and 'timeZone' functions.
zonedTime :: ZonedTime -> Builder
zonedTime :: ZonedTime -> Builder
zonedTime (ZonedTime LocalTime
local TimeZone
zone) = LocalTime -> Builder
localTime LocalTime
local Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> TimeZone -> Builder
timeZone TimeZone
zone