thyme-0.1.0.0: Data/Thyme/LocalTime.hs
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
module Data.Thyme.LocalTime (
-- * Time zones
T.TimeZone (..)
, T.timeZoneOffsetString
, T.timeZoneOffsetString'
, T.minutesToTimeZone
, T.hoursToTimeZone
, T.utc
, T.getCurrentTimeZone
, module Data.Thyme.LocalTime
) where
import Prelude hiding ((.))
import Control.Applicative
import Control.Category
import Control.Lens
import Control.Monad
import Data.AffineSpace
import Data.Data
import Data.Micro
import qualified Data.Time as T
import Data.Thyme.Calendar.Day
import Data.Thyme.Clock
import Data.Thyme.Clock.Scale
import Data.Thyme.Clock.UTC
import Data.Thyme.TH
import Data.VectorSpace
getTimeZone :: UTCTime -> IO T.TimeZone
getTimeZone time = T.getTimeZone (T.UTCTime day dayTime) where
day = T.ModifiedJulianDay (fromIntegral mjd)
dayTime = fromRational $ dt ^/^ DiffTime (toMicro 1)
UTCTime (ModifiedJulianDay mjd) dt = view utcTime time
------------------------------------------------------------------------
-- * Time of day
type Hour = Int
type Minute = Int
data TimeOfDay = TimeOfDay
{ todHour :: {-# UNPACK #-}!Hour
, todMin :: {-# UNPACK #-}!Minute
, todSec :: {-# UNPACK #-}!DiffTime
} deriving (Eq, Ord, Data, Typeable, Show)
{-# INLINE makeTimeOfDayValid #-}
makeTimeOfDayValid :: Hour -> Minute -> DiffTime -> Maybe TimeOfDay
makeTimeOfDayValid h m s = TimeOfDay h m s
<$ guard (0 <= h && h <= 23 && 0 <= m && m <= 59 && 0 <= s && s < 61)
{-# INLINE timeOfDay #-}
timeOfDay :: Simple Iso DiffTime TimeOfDay
timeOfDay = iso fromDiff toDiff where
{-# INLINEABLE fromDiff #-}
fromDiff :: DiffTime -> TimeOfDay
fromDiff (DiffTime t) = TimeOfDay
(fromIntegral h) (fromIntegral m) (DiffTime s) where
(h, ms) = microQuotRem t (toMicro 3600)
(m, s) = microQuotRem ms (toMicro 60)
{-# INLINEABLE toDiff #-}
toDiff :: TimeOfDay -> DiffTime
toDiff (TimeOfDay h m s) = s
^+^ fromIntegral m *^ DiffTime (toMicro 60)
^+^ fromIntegral h *^ DiffTime (toMicro 3600)
type Minutes = Int
type Days = Int
-- | Add some minutes to a 'TimeOfDay'; result comes with a day adjustment.
{-# INLINE addMinutes #-}
addMinutes :: Minutes -> TimeOfDay -> (Days, TimeOfDay)
addMinutes dm (TimeOfDay h m s) = (dd, TimeOfDay h' m' s) where
(dd, h') = divMod (h + dh) 24
(dh, m') = divMod (m + dm) 60
{-# INLINE timeOfDayFraction #-}
timeOfDayFraction :: Simple Iso Rational TimeOfDay
timeOfDayFraction = iso fromRatio toRatio . timeOfDay where
NominalDiffTime posixDay = posixDayLength
fromRatio :: Rational -> DiffTime
fromRatio r = DiffTime (r *^ posixDay) where
toRatio :: DiffTime -> Rational
toRatio (DiffTime t) = t ^/^ posixDay
------------------------------------------------------------------------
-- * Local Time
data LocalTime = LocalTime
{ localDay :: {-# UNPACK #-}!Day
, localTimeOfDay :: {-only 3 words…-} {-# UNPACK #-}!TimeOfDay
} deriving (Eq, Ord, Data, Typeable, Show)
{-# INLINE utcLocalTime #-}
utcLocalTime :: T.TimeZone -> Simple Iso UTCTime LocalTime
utcLocalTime T.TimeZone {..} = utcTime . iso localise globalise where
{-# INLINEABLE localise #-}
localise :: UTCView -> LocalTime
localise (UTCTime day dt) = LocalTime (day .+^ dd) tod where
(dd, tod) = addMinutes timeZoneMinutes (view timeOfDay dt)
{-# INLINEABLE globalise #-}
globalise :: LocalTime -> UTCView
globalise (LocalTime day tod) = UTCTime (day .+^ dd)
(review timeOfDay utcToD) where
(dd, utcToD) = addMinutes (negate timeZoneMinutes) tod
-- TODO: ut1LocalTime
------------------------------------------------------------------------
-- * Zoned Time
data ZonedTime = ZonedTime
{ zonedTimeToLocalTime :: {-only 4 words…-} {-# UNPACK #-}!LocalTime
, zonedTimeZone :: !T.TimeZone
} deriving (Eq, Ord, Data, Typeable, Show)
{-# INLINE zonedTime #-}
zonedTime :: Simple Iso (T.TimeZone, UTCTime) ZonedTime
zonedTime = iso toZoned fromZoned where
{-# INLINE toZoned #-}
toZoned :: (T.TimeZone, UTCTime) -> ZonedTime
toZoned (tz, time) = ZonedTime (view (utcLocalTime tz) time) tz
{-# INLINE fromZoned #-}
fromZoned :: ZonedTime -> (T.TimeZone, UTCTime)
fromZoned (ZonedTime lt tz) = (tz, review (utcLocalTime tz) lt)
{-# INLINE getZonedTime #-}
getZonedTime :: IO ZonedTime
getZonedTime = utcToLocalZonedTime =<< getCurrentTime
{-# INLINEABLE utcToLocalZonedTime #-}
utcToLocalZonedTime :: UTCTime -> IO ZonedTime
utcToLocalZonedTime time = do
tz <- getTimeZone time
return (view zonedTime (tz, time))
------------------------------------------------------------------------
-- * Lenses
thymeLenses ''T.TimeZone
thymeLenses ''TimeOfDay
thymeLenses ''LocalTime
thymeLenses ''ZonedTime