{-# LANGUAGE OverloadedStrings #-}

module Data.Fmt.Time (
    time,

    -- * Time
    t,
    hm,
    hms,
    day,
    day',
    month,
    month',
    year,
    unix,
    zone,

    -- * Duration
    secs,
    mins,
    hours,
    days,
    years,
) where

import Data.Fmt
import Data.String
import Data.Time (FormatTime, defaultTimeLocale, formatTime)
import Data.Time.Format.ISO8601 (ISO8601, iso8601Show)
import Prelude hiding (min)
import qualified Data.Fmt.Code as Fmt

{- | A custom time formatter.

 For example, the E.U. formatting convention is  /time "%Y-%m-%d %T %z"/
-}
time :: (IsString m, FormatTime a) => String -> Fmt1 m s a
time :: forall m a s. (IsString m, FormatTime a) => String -> Fmt1 m s a
time String
s = (a -> m) -> Fmt1 m s a
forall a m s. (a -> m) -> Fmt1 m s a
fmt1 ((a -> m) -> Fmt1 m s a) -> (a -> m) -> Fmt1 m s a
forall a b. (a -> b) -> a -> b
$ String -> m
forall a. IsString a => String -> a
fromString (String -> m) -> (a -> String) -> a -> m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimeLocale -> String -> a -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale String
s

-- Time

-------------------------

-- | < https://en.wikipedia.org/wiki/ISO_8601 ISO-8601> time: /2021-06-05T01:46:46.173677-07:00/
t :: (IsString m, ISO8601 a) => Fmt1 m s a
t :: forall m a s. (IsString m, ISO8601 a) => Fmt1 m s a
t = (a -> m) -> Fmt1 m s a
forall a m s. (a -> m) -> Fmt1 m s a
fmt1 ((a -> m) -> Fmt1 m s a) -> (a -> m) -> Fmt1 m s a
forall a b. (a -> b) -> a -> b
$ String -> m
forall a. IsString a => String -> a
fromString (String -> m) -> (a -> String) -> a -> m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall t. ISO8601 t => t -> String
iso8601Show

-- | Hour-minute of day: @%H:%M@.
hm :: (IsString m, FormatTime a) => Fmt1 m s a
hm :: forall m a s. (IsString m, FormatTime a) => Fmt1 m s a
hm = String -> Fmt1 m s a
forall m a s. (IsString m, FormatTime a) => String -> Fmt1 m s a
time String
"%R"

-- | Hour-minute-second of day: @%H:%M:%S@.
hms :: (IsString m, FormatTime a) => Fmt1 m s a
hms :: forall m a s. (IsString m, FormatTime a) => Fmt1 m s a
hms = String -> Fmt1 m s a
forall m a s. (IsString m, FormatTime a) => String -> Fmt1 m s a
time String
"%T"

-- | Day of month: @01@ - @31@.
day :: (IsString m, FormatTime a) => Fmt1 m s a
day :: forall m a s. (IsString m, FormatTime a) => Fmt1 m s a
day = String -> Fmt1 m s a
forall m a s. (IsString m, FormatTime a) => String -> Fmt1 m s a
time String
"%d"

-- | Day of week: @Sun@ - @Sat@.
day' :: (IsString m, FormatTime a) => Fmt1 m s a
day' :: forall m a s. (IsString m, FormatTime a) => Fmt1 m s a
day' = String -> Fmt1 m s a
forall m a s. (IsString m, FormatTime a) => String -> Fmt1 m s a
time String
"%a"

-- | Month of year: @01@ - @12@.
month :: (IsString m, FormatTime a) => Fmt1 m s a
month :: forall m a s. (IsString m, FormatTime a) => Fmt1 m s a
month = String -> Fmt1 m s a
forall m a s. (IsString m, FormatTime a) => String -> Fmt1 m s a
time String
"%m"

-- | Month of year: @Jan@ - @Dec@.
month' :: (IsString m, FormatTime a) => Fmt1 m s a
month' :: forall m a s. (IsString m, FormatTime a) => Fmt1 m s a
month' = String -> Fmt1 m s a
forall m a s. (IsString m, FormatTime a) => String -> Fmt1 m s a
time String
"%b"

-- | Year.
year :: (IsString m, FormatTime a) => Fmt1 m s a
year :: forall m a s. (IsString m, FormatTime a) => Fmt1 m s a
year = String -> Fmt1 m s a
forall m a s. (IsString m, FormatTime a) => String -> Fmt1 m s a
time String
"%Y"

-- | Seconds from Unix epoch.
unix :: (IsString m, FormatTime a) => Fmt1 m s a
unix :: forall m a s. (IsString m, FormatTime a) => Fmt1 m s a
unix = String -> Fmt1 m s a
forall m a s. (IsString m, FormatTime a) => String -> Fmt1 m s a
time String
"%s"

-- | Timezone offset: @-HHMM@.
zone :: (IsString m, FormatTime a) => Fmt1 m s a
zone :: forall m a s. (IsString m, FormatTime a) => Fmt1 m s a
zone = String -> Fmt1 m s a
forall m a s. (IsString m, FormatTime a) => String -> Fmt1 m s a
time String
"%z"

-- Duration

-------------------------

-- | Display to a given precision the absolute value time span in seconds.
secs :: IsString m => Int -> Fmt1 m s Double
secs :: forall m s. IsString m => Int -> Fmt1 m s Double
secs Int
n = (Double -> m) -> Fmt1 m s Double
forall a m s. (a -> m) -> Fmt1 m s a
fmt1 (Fmt m m (Double -> m) -> Double -> m
forall m a. Fmt m m a -> a
runFmt (Int -> Fmt m m (Double -> m)
forall m a s. (IsString m, RealFloat a) => Int -> Fmt1 m s a
Fmt.f Int
n) (Double -> m) -> (Double -> Double) -> Double -> m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Double
forall a. Num a => a -> a
abs (Double -> Double) -> (Double -> Double) -> Double -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Double
forall {p}. p -> p
count) where count :: p -> p
count p
n' = p
n'

-- | Display to a given precision the absolute value time span in minutes.
mins :: IsString m => Int -> Fmt1 m s Double
mins :: forall m s. IsString m => Int -> Fmt1 m s Double
mins Int
n = (Double -> m) -> Fmt1 m s Double
forall a m s. (a -> m) -> Fmt1 m s a
fmt1 (Fmt m m (Double -> m) -> Double -> m
forall m a. Fmt m m a -> a
runFmt (Int -> Fmt m m (Double -> m)
forall m a s. (IsString m, RealFloat a) => Int -> Fmt1 m s a
Fmt.f Int
n) (Double -> m) -> (Double -> Double) -> Double -> m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Double
forall a. Num a => a -> a
abs (Double -> Double) -> (Double -> Double) -> Double -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Double
forall {a}. Fractional a => a -> a
count) where count :: a -> a
count a
n' = a
n' a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
60

-- | Display to a given precision the absolute value time span in hours.
hours :: IsString m => Int -> Fmt1 m s Double
hours :: forall m s. IsString m => Int -> Fmt1 m s Double
hours Int
n = (Double -> m) -> Fmt1 m s Double
forall a m s. (a -> m) -> Fmt1 m s a
fmt1 (Fmt m m (Double -> m) -> Double -> m
forall m a. Fmt m m a -> a
runFmt (Int -> Fmt m m (Double -> m)
forall m a s. (IsString m, RealFloat a) => Int -> Fmt1 m s a
Fmt.f Int
n) (Double -> m) -> (Double -> Double) -> Double -> m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Double
forall a. Num a => a -> a
abs (Double -> Double) -> (Double -> Double) -> Double -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Double
forall {a}. Fractional a => a -> a
count) where count :: a -> a
count a
n' = a
n' a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
60 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
60

-- | Display to a given precision the absolute value time span in days.
days :: (IsString m) => Int -> Fmt1 m s Double
days :: forall m s. IsString m => Int -> Fmt1 m s Double
days Int
n = (Double -> m) -> Fmt1 m s Double
forall a m s. (a -> m) -> Fmt1 m s a
fmt1 (Fmt m m (Double -> m) -> Double -> m
forall m a. Fmt m m a -> a
runFmt (Int -> Fmt m m (Double -> m)
forall m a s. (IsString m, RealFloat a) => Int -> Fmt1 m s a
Fmt.f Int
n) (Double -> m) -> (Double -> Double) -> Double -> m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Double
forall a. Num a => a -> a
abs (Double -> Double) -> (Double -> Double) -> Double -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Double
forall {a}. Fractional a => a -> a
count) where count :: a -> a
count a
n' = a
n' a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
24 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
60 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
60

-- | Display to a given precision the absolute value time span in years.
years :: IsString m => Int -> Fmt1 m s Double
years :: forall m s. IsString m => Int -> Fmt1 m s Double
years Int
n = (Double -> m) -> Fmt1 m s Double
forall a m s. (a -> m) -> Fmt1 m s a
fmt1 (Fmt m m (Double -> m) -> Double -> m
forall m a. Fmt m m a -> a
runFmt (Int -> Fmt m m (Double -> m)
forall m a s. (IsString m, RealFloat a) => Int -> Fmt1 m s a
Fmt.f Int
n) (Double -> m) -> (Double -> Double) -> Double -> m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Double
forall a. Num a => a -> a
abs (Double -> Double) -> (Double -> Double) -> Double -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Double
forall {a}. Fractional a => a -> a
count) where count :: a -> a
count a
n' = a
n' a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
365 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
24 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
60 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
60