module Data.HodaTime.Offset.Internal
(
Offset(..)
,maxOffsetHours
,maxOffsetSeconds
,minOffsetSeconds
,empty
,toStringRep
,fromSeconds
,adjustInstant
,addClamped
,minusClamped
)
where
import Data.HodaTime.Instant.Internal (Instant, add, minus)
import qualified Data.HodaTime.Duration.Internal as D (fromSeconds)
import Data.HodaTime.Constants (secondsPerHour)
import Data.HodaTime.Internal (secondsFromSeconds, clamp)
newtype Offset = Offset { offsetSeconds :: Int }
deriving (Eq, Ord, Show)
maxOffsetHours :: Num a => a
maxOffsetHours = 18
maxOffsetSeconds :: Num a => a
maxOffsetSeconds = maxOffsetHours * secondsPerHour
minOffsetSeconds :: Num a => a
minOffsetSeconds = negate maxOffsetSeconds
empty :: Offset
empty = Offset 0
toStringRep :: Offset -> String
toStringRep (Offset secs) = rep
where
utc = "UTC"
rep = if secs == 0 then utc else utc ++ sign ++ show h ++ ":" ++ show s
sign = if secs < 0 then "-" else "+"
h = secs `div` secondsPerHour
s = secs - (h*secondsPerHour)
fromSeconds :: Integral a => a -> Offset
fromSeconds = Offset . secondsFromSeconds . clamp minOffsetSeconds maxOffsetSeconds
addClamped :: Offset -> Offset -> Offset
addClamped (Offset lsecs) (Offset rsecs) = fromSeconds $ lsecs + rsecs
minusClamped :: Offset -> Offset -> Offset
minusClamped (Offset lsecs) (Offset rsecs) = fromSeconds $ lsecs - rsecs
adjustInstant :: Offset -> Instant -> Instant
adjustInstant (Offset secs) instant = instant'
where
op = if secs < 0 then minus else add
duration = D.fromSeconds . abs $ secs
instant' = instant `op` duration