{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
module Data.Time.ToText (
buildDay,
buildLocalTime,
buildTimeOfDay,
buildTimeZone,
buildUTCTime,
buildZonedTime,
buildYear,
buildMonth,
buildQuarter,
buildQuarterOfYear,
) where
import Data.Char (chr)
import Data.Fixed (Fixed (..))
import Data.Int (Int64)
import Data.Text.Lazy.Builder (Builder)
import Data.Time (TimeOfDay (..))
import Data.Time.Calendar (Day, toGregorian)
import Data.Time.Calendar.Compat (Year)
import Data.Time.Calendar.Month.Compat (Month, toYearMonth)
import Data.Time.Calendar.Quarter.Compat (Quarter, QuarterOfYear (..),
toYearQuarter)
import Data.Time.Clock (UTCTime (..))
import qualified Data.Text.Lazy.Builder as B
import qualified Data.Text.Lazy.Builder.Int as B (decimal)
import qualified Data.Time.LocalTime as Local
#if !MIN_VERSION_base(4,11,0)
import Data.Semigroup ((<>))
#endif
buildDay :: Day -> Builder
buildDay :: Day -> Builder
buildDay Day
dd = Year -> Builder
buildYear Year
yr Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
char7 Char
'-' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
digits2 Int
m Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
char7 Char
'-' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
digits2 Int
d
where (Year
yr,Int
m,Int
d) = Day -> (Year, Int, Int)
toGregorian Day
dd
{-# INLINE buildDay #-}
buildMonth :: Month -> Builder
buildMonth :: Month -> Builder
buildMonth Month
mm = Year -> Builder
buildYear Year
yr Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
char7 Char
'-' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
digits2 Int
m
where (Year
yr,Int
m) = Month -> (Year, Int)
toYearMonth Month
mm
{-# INLINE buildMonth #-}
buildQuarter :: Quarter -> Builder
buildQuarter :: Quarter -> Builder
buildQuarter Quarter
qq = Year -> Builder
buildYear Year
yr Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
char7 Char
'-' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> QuarterOfYear -> Builder
buildQuarterOfYear QuarterOfYear
q
where (Year
yr,QuarterOfYear
q) = Quarter -> (Year, QuarterOfYear)
toYearQuarter Quarter
qq
{-# INLINE buildQuarter #-}
buildQuarterOfYear :: QuarterOfYear -> Builder
buildQuarterOfYear :: QuarterOfYear -> Builder
buildQuarterOfYear QuarterOfYear
q = Char -> Builder
char7 Char
'q' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> case QuarterOfYear
q of
QuarterOfYear
Q1 -> Char -> Builder
char7 Char
'1'
QuarterOfYear
Q2 -> Char -> Builder
char7 Char
'2'
QuarterOfYear
Q3 -> Char -> Builder
char7 Char
'3'
QuarterOfYear
Q4 -> Char -> Builder
char7 Char
'4'
buildYear :: Year -> Builder
buildYear :: Year -> Builder
buildYear Year
y
| Year
y Year -> Year -> Bool
forall a. Ord a => a -> a -> Bool
>= Year
1000 = Year -> Builder
forall a. Integral a => a -> Builder
B.decimal Year
y
| Year
y Year -> Year -> Bool
forall a. Ord a => a -> a -> Bool
>= Year
0 = Year -> Builder
forall a. Integral a => a -> Builder
padYear Year
y
| Year
y Year -> Year -> Bool
forall a. Ord a => a -> a -> Bool
>= -Year
999 = Char -> Builder
char7 Char
'-' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Year -> Builder
forall a. Integral a => a -> Builder
padYear (Year -> Year
forall a. Num a => a -> a
negate Year
y)
| Bool
otherwise = Year -> Builder
forall a. Integral a => a -> Builder
B.decimal Year
y
where
padYear :: p -> Builder
padYear p
y' =
let (Int
ab,Int
c) = p -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral p
y' Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
10
(Int
a,Int
b) = Int
ab Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
10
in Char -> Builder
char7 Char
'0' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
digit Int
a Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
digit Int
b Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
digit Int
c
{-# INLINE buildYear #-}
buildTimeOfDay :: TimeOfDay -> Builder
buildTimeOfDay :: TimeOfDay -> Builder
buildTimeOfDay (TimeOfDay Int
h Int
m (MkFixed Year
s)) =
Int -> Builder
digits2 Int
h Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
char7 Char
':' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
Int -> Builder
digits2 Int
m Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
char7 Char
':' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
Int -> Builder
digits2 (Year -> Int
forall a. Num a => Year -> a
fromInteger Year
real) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int64 -> Builder
buildFrac (Year -> Int64
forall a. Num a => Year -> a
fromInteger Year
frac)
where
(Year
real,Year
frac) = Year
s Year -> Year -> (Year, Year)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Year
pico
buildFrac :: Int64 -> Builder
buildFrac :: Int64 -> Builder
buildFrac Int64
0 = Builder
forall a. Monoid a => a
mempty
buildFrac Int64
i = Char -> Builder
char7 Char
'.' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> case Int64
i Int64 -> Int64 -> (Int64, Int64)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int64
micro of
(Int64
hi, Int64
0) -> Int64 -> Builder
buildFrac6 Int64
hi
(Int64
hi, Int64
lo) -> Int64 -> Builder
digits6 Int64
hi Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int64 -> Builder
buildFrac6 Int64
lo
buildFrac6 :: Int64 -> Builder
buildFrac6 :: Int64 -> Builder
buildFrac6 Int64
i = case Int64
i Int64 -> Int64 -> (Int64, Int64)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int64
milli of
(Int64
hi, Int64
0) -> Int64 -> Builder
digits3 Int64
hi
(Int64
hi, Int64
lo) -> Int64 -> Builder
digits3 Int64
hi Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int64 -> Builder
digits3 Int64
lo
digits6 :: Int64 -> Builder
digits6 Int64
i = case Int64
i Int64 -> Int64 -> (Int64, Int64)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int64
milli of
(Int64
hi, Int64
lo) -> Int64 -> Builder
digits3 Int64
hi Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int64 -> Builder
digits3 Int64
lo
digits3 :: Int64 -> Builder
digits3 Int64
i = Int64 -> Builder
digit64 Int64
a Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int64 -> Builder
digit64 Int64
b Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int64 -> Builder
digit64 Int64
c
where
(Int64
ab, Int64
c) = Int64
i Int64 -> Int64 -> (Int64, Int64)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int64
10
(Int64
a, Int64
b) = Int64
ab Int64 -> Int64 -> (Int64, Int64)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int64
10
pico :: Year
pico = Year
1000000000000
micro :: Int64
micro = Int64
1000000
milli :: Int64
milli = Int64
1000
{-# INLINE buildTimeOfDay #-}
buildTimeZone :: Local.TimeZone -> Builder
buildTimeZone :: TimeZone -> Builder
buildTimeZone (Local.TimeZone Int
off Bool
_ String
_)
| Int
off Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Char -> Builder
char7 Char
'Z'
| Bool
otherwise = Char -> Builder
char7 Char
s Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
digits2 Int
h Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
char7 Char
':' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
digits2 Int
m
where !s :: Char
s = if Int
off Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 then Char
'-' else Char
'+'
(Int
h,Int
m) = Int -> Int
forall a. Num a => a -> a
abs Int
off Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
60
{-# INLINE buildTimeZone #-}
dayTime :: Day -> TimeOfDay -> Builder
dayTime :: Day -> TimeOfDay -> Builder
dayTime Day
d TimeOfDay
t = Day -> Builder
buildDay Day
d Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
char7 Char
'T' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> TimeOfDay -> Builder
buildTimeOfDay TimeOfDay
t
{-# INLINE dayTime #-}
buildUTCTime :: UTCTime -> B.Builder
buildUTCTime :: UTCTime -> Builder
buildUTCTime (UTCTime Day
d DiffTime
s) = Day -> TimeOfDay -> Builder
dayTime Day
d (DiffTime -> TimeOfDay
Local.timeToTimeOfDay DiffTime
s) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
char7 Char
'Z'
{-# INLINE buildUTCTime #-}
buildLocalTime :: Local.LocalTime -> Builder
buildLocalTime :: LocalTime -> Builder
buildLocalTime (Local.LocalTime Day
d TimeOfDay
t) = Day -> TimeOfDay -> Builder
dayTime Day
d TimeOfDay
t
{-# INLINE buildLocalTime #-}
buildZonedTime :: Local.ZonedTime -> Builder
buildZonedTime :: ZonedTime -> Builder
buildZonedTime (Local.ZonedTime LocalTime
t TimeZone
z) = LocalTime -> Builder
buildLocalTime LocalTime
t Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> TimeZone -> Builder
buildTimeZone TimeZone
z
{-# INLINE buildZonedTime #-}
digits2 :: Int -> Builder
digits2 :: Int -> Builder
digits2 Int
a = Int -> Builder
digit Int
hi Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
digit Int
lo
where (Int
hi,Int
lo) = Int
a Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
10
digit :: Int -> Builder
digit :: Int -> Builder
digit Int
x = Char -> Builder
char7 (Int -> Char
chr (Int
x Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
48))
digit64 :: Int64 -> Builder
digit64 :: Int64 -> Builder
digit64 = Int -> Builder
digit (Int -> Builder) -> (Int64 -> Int) -> Int64 -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral
char7 :: Char -> Builder
char7 :: Char -> Builder
char7 = Char -> Builder
B.singleton