hourglass-0.2.0: Data/Hourglass/Local.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
-- |
-- Module : Data.Hourglass.Local
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : unknown
--
-- Local time = global time + timezone
--
module Data.Hourglass.Local
(
-- * Local time
-- ** Local time type
LocalTime
-- ** Local time creation and manipulation
, localTime
, localTimeUnwrap
, localTimeToGlobal
, localTimeFromGlobal
, localTimeGetTimezone
, localTimeSetTimezone
, localTimeConvert
) where
import Data.Hourglass.Types
import Data.Hourglass.Time
import Data.Hourglass.Diff
-- | Local time representation
--
-- this is a time representation augmented by a timezone
-- to get back to a global time, the timezoneOffset needed to be added to the local time.
--
data LocalTime t = LocalTime
{ localTimeUnwrap :: t -- ^ unwrap the LocalTime value. the time value is local.
, localTimeGetTimezone :: TimezoneOffset -- ^ get the timezone associated with LocalTime
}
-- FIXME add instance Read too.
instance Show t => Show (LocalTime t) where
show (LocalTime t tz) = show t ++ show tz
instance Eq t => Eq (LocalTime t) where
LocalTime t1 tz1 == LocalTime t2 tz2 = tz1 == tz2 && t1 == t2
instance (Ord t, Time t) => Ord (LocalTime t) where
compare l1@(LocalTime g1 tz1) l2@(LocalTime g2 tz2) =
case compare tz1 tz2 of
EQ -> compare g1 g2
_ -> let t1 = localTimeToGlobal l1
t2 = localTimeToGlobal l2
in compare t1 t2
instance Functor LocalTime where
fmap f (LocalTime t tz) = LocalTime (f t) tz
-- | Create a local time type from a timezone and a time type.
--
-- The time value is assumed to be local to the timezone offset set,
-- so no transformation is done.
localTime :: Time t => TimezoneOffset -> t -> LocalTime t
localTime tz t = LocalTime t tz
-- | Get back a global time value
localTimeToGlobal :: Time t => LocalTime t -> t
localTimeToGlobal (LocalTime local tz)
| tz == TimezoneOffset 0 = local
| otherwise = timeConvert $ elapsedTimeAddSecondsP (timeGetElapsedP local) tzSecs
where tzSecs = negate $ timezoneOffsetToSeconds tz
-- | create a local time value from a global one
localTimeFromGlobal :: Time t => t -> LocalTime t
localTimeFromGlobal t = localTime (TimezoneOffset 0) t
-- | Change the timezone, and adjust the local value to represent the new local value.
localTimeSetTimezone :: Time t => TimezoneOffset -> LocalTime t -> LocalTime t
localTimeSetTimezone tz currentLocal@(LocalTime t currentTz)
| diffTz == 0 = currentLocal
| otherwise = LocalTime (timeConvert t') tz
where t' = elapsedTimeAddSecondsP (timeGetElapsedP t) diffTz
diffTz = timezoneOffsetToSeconds tz - timezoneOffsetToSeconds currentTz
-- | convert the local time representation to another time representation determined by context.
localTimeConvert :: (Time t1, Time t2) => LocalTime t1 -> LocalTime t2
localTimeConvert = fmap timeConvert