packages feed

thyme-0.3.6: src/Data/Thyme/Time/Core.hs

{-# LANGUAGE CPP #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ViewPatterns #-}

#if HLINT
#include "cabal_macros.h"
#endif

-- | This module provides the 'Thyme' typeclass, and instances for
-- converting between "Data.Time" and "Data.Thyme" types. It also provides
-- compatibility wrappers for existing code using "Data.Time".
--
-- Note that we do not provide 'Num' hierarchy instances for 'DiffTime' nor
-- 'NominalDiffTime' here. If you want to use them anyway despite parts of
-- them being ill-defined (e.g. @('*')@ on 'DiffTime'), import
-- "Data.Thyme.Time" instead.

module Data.Thyme.Time.Core
    ( module Data.Thyme
    , module Data.Thyme.Time.Core
    ) where

import Prelude
import Control.Lens
import Data.AffineSpace
import Data.Fixed
import Data.Ratio
import Data.Thyme
import Data.Thyme.Clock.TAI
import qualified Data.Time.Calendar as T
import qualified Data.Time.Clock as T
import qualified Data.Time.Clock.TAI as T
import qualified Data.Time.LocalTime as T
import Data.Thyme.TrueName

------------------------------------------------------------------------
-- * Type conversion

-- | Typeclass for converting between "Data.Time" and "Data.Thyme" types.
class Thyme time thyme | thyme -> time where
    -- | Convert between "Data.Time" and "Data.Thyme" types.
    --
    -- @
    -- > :set -t
    -- > import qualified "Data.Time"
    --
    -- > 'thyme' 'Control.Lens.#' ('fromSeconds'' 10 :: 'DiffTime')
    -- 10s
    -- it :: 'Data.Time.DiffTime'
    --
    -- > 'Data.Time.secondsToDiffTime' 10 '^.' 'thyme' :: 'DiffTime'
    -- 10s
    -- it :: 'DiffTime'
    -- @
    thyme :: Iso' time thyme

instance Thyme T.Day Day where
    {-# INLINE thyme #-}
    thyme = iso
        (ModifiedJulianDay . fromInteger . T.toModifiedJulianDay)
        (T.ModifiedJulianDay . toInteger . toModifiedJulianDay)

instance Thyme T.UniversalTime UniversalTime where
    {-# INLINE thyme #-}
    thyme = iso T.getModJulianDate T.ModJulianDate . from modJulianDate

instance Thyme T.DiffTime DiffTime where
    {-# INLINE thyme #-}
    thyme = dt . fixed . from picoseconds where
        dt = iso (\ [truename| ''T.DiffTime MkDiffTime | ps |] -> ps )
            [truename| ''T.DiffTime MkDiffTime |]
#if MIN_VERSION_base(4,7,0)
        fixed = iso (\ (MkFixed n) -> n ) MkFixed
#else
        fixed = iso (\ [truename| ''Fixed MkFixed | n |] -> n )
            [truename| ''Fixed MkFixed |]
#endif

instance Thyme T.NominalDiffTime NominalDiffTime where
    {-# INLINE thyme #-}
    thyme = ndt . fixed . from picoseconds where
        ndt = iso (\ [truename| ''T.NominalDiffTime MkNominalDiffTime | ps |] -> ps )
            [truename| ''T.NominalDiffTime MkNominalDiffTime |]
#if MIN_VERSION_base(4,7,0)
        fixed = iso (\ (MkFixed n) -> n ) MkFixed
#else
        fixed = iso (\ [truename| ''Fixed MkFixed | n |] -> n )
            [truename| ''Fixed MkFixed |]
#endif

instance Thyme T.UTCTime UTCView where
    {-# INLINE thyme #-}
    thyme = iso
        (\ (T.UTCTime d t) -> UTCView (d ^. thyme) (t ^. thyme))
        (\ (UTCView d t) -> T.UTCTime (thyme # d) (thyme # t))

instance Thyme T.UTCTime UTCTime where
    {-# INLINE thyme #-}
    thyme = thyme . from utcTime

instance Thyme T.AbsoluteTime AbsoluteTime where
    {-# INLINE thyme #-}
    thyme = iso (`T.diffAbsoluteTime` T.taiEpoch)
            (`T.addAbsoluteTime` T.taiEpoch)
        . thyme . iso (taiEpoch .+^) (.-. taiEpoch)

instance Thyme T.TimeZone TimeZone where
    {-# INLINE thyme #-}
    thyme = iso (\ T.TimeZone {..} -> TimeZone {..})
        (\ TimeZone {..} -> T.TimeZone {..})

instance Thyme T.TimeOfDay TimeOfDay where
    {-# INLINE thyme #-}
    thyme = iso ( \ (T.TimeOfDay h m s) -> TimeOfDay h m $
            microseconds # round (s * 1000000) )
        ( \ (TimeOfDay h m s) -> T.TimeOfDay h m . fromRational $
            toInteger (s ^. microseconds) % 1000000 )

instance Thyme T.LocalTime LocalTime where
    {-# INLINE thyme #-}
    thyme = iso
        (\ (T.LocalTime d t) -> LocalTime (d ^. thyme) (t ^. thyme))
        (\ (LocalTime d t) -> T.LocalTime (thyme # d) (thyme # t))

instance Thyme T.ZonedTime ZonedTime where
    {-# INLINE thyme #-}
    thyme = iso
        (\ (T.ZonedTime t z) -> ZonedTime (t ^. thyme) (z ^. thyme))
        (\ (ZonedTime t z) -> T.ZonedTime (thyme # t) (thyme # z))

-- | Convert a "Data.Time" type to a "Data.Thyme" type, if you would rather
-- not use "Control.Lens" directly.
--
-- @
-- 'toThyme' = 'view' 'thyme'
-- 'toThyme' t ≡ t '^.' 'thyme'
-- @
{-# INLINE toThyme #-}
toThyme :: (Thyme time thyme) => time -> thyme
toThyme = view thyme

-- | Convert a "Data.Thyme" type to a "Data.Time" type, if you would rather
-- not use "Control.Lens" directly.
--
-- @
-- 'fromThyme' = 'review' 'thyme'
-- 'fromThyme' t ≡ 'thyme' 'Control.Lens.#' t
-- @
{-# INLINE fromThyme #-}
fromThyme :: (Thyme time thyme) => thyme -> time
fromThyme = review thyme