packages feed

rel8-1.0.0.0: src/Rel8/Expr/Time.hs

module Rel8.Expr.Time
  ( -- * Working with @Day@
    today
  , toDay
  , fromDay
  , addDays
  , diffDays
  , subtractDays

    -- * Working with @UTCTime@
  , now
  , addTime
  , diffTime
  , subtractTime

  -- * Working with @CalendarDiffTime@
  , scaleInterval
  , second, seconds
  , minute, minutes
  , hour, hours
  , day, days
  , week, weeks
  , month, months
  , year, years
  ) where

-- base
import Data.Int ( Int32 )
import Prelude

-- rel8
import Rel8.Expr ( Expr )
import Rel8.Expr.Function ( binaryOperator, nullaryFunction )
import Rel8.Expr.Opaleye ( castExpr, unsafeCastExpr, unsafeLiteral )

-- time
import Data.Time.Calendar ( Day )
import Data.Time.Clock ( UTCTime )
import Data.Time.LocalTime ( CalendarDiffTime )


-- | Corresponds to @date(now())@.
today :: Expr Day
today = toDay now


-- | Corresponds to calling the @date@ function with a given time.
toDay :: Expr UTCTime -> Expr Day
toDay = unsafeCastExpr


-- | Corresponds to @x::timestamptz@.
fromDay :: Expr Day -> Expr UTCTime
fromDay = unsafeCastExpr


-- | Move forward a given number of days from a particular day.
addDays :: Expr Int32 -> Expr Day -> Expr Day
addDays = flip (binaryOperator "+")


-- | Find the number of days between two days. Corresponds to the @-@ operator.
diffDays :: Expr Day -> Expr Day -> Expr Int32
diffDays = binaryOperator "-"


-- | Subtract a given number of days from a particular 'Day'. 
subtractDays :: Expr Int32 -> Expr Day -> Expr Day
subtractDays = flip (binaryOperator "-")


-- | Corresponds to @now()@.
now :: Expr UTCTime
now = nullaryFunction "now"


-- | Add a time interval to a point in time, yielding a new point in time.
addTime :: Expr CalendarDiffTime -> Expr UTCTime -> Expr UTCTime
addTime = flip (binaryOperator "+")


-- | Find the duration between two times.
diffTime :: Expr UTCTime -> Expr UTCTime -> Expr CalendarDiffTime
diffTime = binaryOperator "-"


-- | Subtract a time interval from a point in time, yielding a new point in time.
subtractTime :: Expr CalendarDiffTime -> Expr UTCTime -> Expr UTCTime
subtractTime = flip (binaryOperator "-")


scaleInterval :: Expr Double -> Expr CalendarDiffTime -> Expr CalendarDiffTime
scaleInterval = binaryOperator "*"


-- | An interval of one second.
second :: Expr CalendarDiffTime
second = singleton "second"


-- | Create a literal interval from a number of seconds.
seconds :: Expr Double -> Expr CalendarDiffTime
seconds = (`scaleInterval` second)


-- | An interval of one minute.
minute :: Expr CalendarDiffTime
minute = singleton "minute"


-- | Create a literal interval from a number of minutes.
minutes :: Expr Double -> Expr CalendarDiffTime
minutes = (`scaleInterval` minute)


-- | An interval of one hour.
hour :: Expr CalendarDiffTime
hour = singleton "hour"


-- | Create a literal interval from a number of hours.
hours :: Expr Double -> Expr CalendarDiffTime
hours = (`scaleInterval` hour)


-- | An interval of one day.
day :: Expr CalendarDiffTime
day = singleton "day"


-- | Create a literal interval from a number of days.
days ::  Expr Double -> Expr CalendarDiffTime
days = (`scaleInterval` day)


-- | An interval of one week.
week :: Expr CalendarDiffTime
week = singleton "week"


-- | Create a literal interval from a number of weeks.
weeks ::  Expr Double -> Expr CalendarDiffTime
weeks = (`scaleInterval` week)


-- | An interval of one month.
month :: Expr CalendarDiffTime
month = singleton "month"


-- | Create a literal interval from a number of months.
months ::  Expr Double -> Expr CalendarDiffTime
months = (`scaleInterval` month)


-- | An interval of one year.
year :: Expr CalendarDiffTime
year = singleton "year"


-- | Create a literal interval from a number of years.
years ::  Expr Double -> Expr CalendarDiffTime
years = (`scaleInterval` year)


singleton :: String -> Expr CalendarDiffTime
singleton unit = castExpr $ unsafeLiteral $ "'1 " ++ unit ++ "'"