hodatime-0.2.1.1: src/Data/HodaTime/Offset/Internal.hs
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)
-- | An 'Offset' from UTC in seconds.
newtype Offset = Offset { offsetSeconds :: Int } -- TODO: Any reason to make this 32 bit? We don't need more space than 32 bit
deriving (Eq, Ord, Show) -- TODO: Remove Show
-- Offset specific constants
maxOffsetHours :: Num a => a
maxOffsetHours = 18
maxOffsetSeconds :: Num a => a
maxOffsetSeconds = maxOffsetHours * secondsPerHour
minOffsetSeconds :: Num a => a
minOffsetSeconds = negate maxOffsetSeconds
-- | An 'Offset' with an offset of 0. This is equivalent to UTC
empty :: Offset
empty = Offset 0
-- TODO: temp solution until we deal with printing
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)
-- | Create an 'Offset' of (clamped) s seconds.
fromSeconds :: Integral a => a -> Offset
fromSeconds = Offset . secondsFromSeconds . clamp minOffsetSeconds maxOffsetSeconds
-- | Add one 'Offset' to another /NOTE: if the result of the addition is outside the accepted range it will be clamped/
addClamped :: Offset -> Offset -> Offset
addClamped (Offset lsecs) (Offset rsecs) = fromSeconds $ lsecs + rsecs
-- | Subtract one 'Offset' to another. /NOTE: See 'add' above/
minusClamped :: Offset -> Offset -> Offset
minusClamped (Offset lsecs) (Offset rsecs) = fromSeconds $ lsecs - rsecs
-- helper functions
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