{-# LANGUAGE Safe #-}
{-# OPTIONS -fno-warn-orphans #-}

module Data.Time.LocalTime.Internal.LocalTime
    (
    -- * Local Time
      LocalTime(..)
    , addLocalTime
    , diffLocalTime
    -- converting UTC and UT1 times to LocalTime
    , utcToLocalTime
    , localTimeToUTC
    , ut1ToLocalTime
    , localTimeToUT1
    ) where

import Control.DeepSeq
import Data.Data
import Data.Time.Calendar.Days
import Data.Time.Calendar.Gregorian
import Data.Time.Clock.Internal.NominalDiffTime
import Data.Time.Clock.Internal.UTCDiff
import Data.Time.Clock.Internal.UTCTime
import Data.Time.Clock.Internal.UniversalTime
import Data.Time.LocalTime.Internal.TimeOfDay
import Data.Time.LocalTime.Internal.TimeZone

-- | A simple day and time aggregate, where the day is of the specified parameter,
-- and the time is a TimeOfDay.
-- Conversion of this (as local civil time) to UTC depends on the time zone.
-- Conversion of this (as local mean time) to UT1 depends on the longitude.
data LocalTime = LocalTime
    { LocalTime -> Day
localDay :: Day
    , LocalTime -> TimeOfDay
localTimeOfDay :: TimeOfDay
    } deriving (LocalTime -> LocalTime -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LocalTime -> LocalTime -> Bool
$c/= :: LocalTime -> LocalTime -> Bool
== :: LocalTime -> LocalTime -> Bool
$c== :: LocalTime -> LocalTime -> Bool
Eq, Eq LocalTime
LocalTime -> LocalTime -> Bool
LocalTime -> LocalTime -> Ordering
LocalTime -> LocalTime -> LocalTime
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: LocalTime -> LocalTime -> LocalTime
$cmin :: LocalTime -> LocalTime -> LocalTime
max :: LocalTime -> LocalTime -> LocalTime
$cmax :: LocalTime -> LocalTime -> LocalTime
>= :: LocalTime -> LocalTime -> Bool
$c>= :: LocalTime -> LocalTime -> Bool
> :: LocalTime -> LocalTime -> Bool
$c> :: LocalTime -> LocalTime -> Bool
<= :: LocalTime -> LocalTime -> Bool
$c<= :: LocalTime -> LocalTime -> Bool
< :: LocalTime -> LocalTime -> Bool
$c< :: LocalTime -> LocalTime -> Bool
compare :: LocalTime -> LocalTime -> Ordering
$ccompare :: LocalTime -> LocalTime -> Ordering
Ord, Typeable LocalTime
LocalTime -> DataType
LocalTime -> Constr
(forall b. Data b => b -> b) -> LocalTime -> LocalTime
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> LocalTime -> u
forall u. (forall d. Data d => d -> u) -> LocalTime -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> LocalTime -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> LocalTime -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> LocalTime -> m LocalTime
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> LocalTime -> m LocalTime
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c LocalTime
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> LocalTime -> c LocalTime
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c LocalTime)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c LocalTime)
gmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> LocalTime -> m LocalTime
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> LocalTime -> m LocalTime
gmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> LocalTime -> m LocalTime
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> LocalTime -> m LocalTime
gmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> LocalTime -> m LocalTime
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> LocalTime -> m LocalTime
gmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> LocalTime -> u
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> LocalTime -> u
gmapQ :: forall u. (forall d. Data d => d -> u) -> LocalTime -> [u]
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> LocalTime -> [u]
gmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> LocalTime -> r
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> LocalTime -> r
gmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> LocalTime -> r
$cgmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> LocalTime -> r
gmapT :: (forall b. Data b => b -> b) -> LocalTime -> LocalTime
$cgmapT :: (forall b. Data b => b -> b) -> LocalTime -> LocalTime
dataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c LocalTime)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c LocalTime)
dataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c LocalTime)
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c LocalTime)
dataTypeOf :: LocalTime -> DataType
$cdataTypeOf :: LocalTime -> DataType
toConstr :: LocalTime -> Constr
$ctoConstr :: LocalTime -> Constr
gunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c LocalTime
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c LocalTime
gfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> LocalTime -> c LocalTime
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> LocalTime -> c LocalTime
Data, Typeable)

instance NFData LocalTime where
    rnf :: LocalTime -> ()
rnf (LocalTime Day
d TimeOfDay
t) = forall a. NFData a => a -> ()
rnf Day
d seq :: forall a b. a -> b -> b
`seq` forall a. NFData a => a -> ()
rnf TimeOfDay
t seq :: forall a b. a -> b -> b
`seq` ()

instance Show LocalTime where
    show :: LocalTime -> String
show (LocalTime Day
d TimeOfDay
t) = (Day -> String
showGregorian Day
d) forall a. [a] -> [a] -> [a]
++ String
" " forall a. [a] -> [a] -> [a]
++ (forall a. Show a => a -> String
show TimeOfDay
t)

-- | addLocalTime a b = a + b
addLocalTime :: NominalDiffTime -> LocalTime -> LocalTime
addLocalTime :: NominalDiffTime -> LocalTime -> LocalTime
addLocalTime NominalDiffTime
x = TimeZone -> UTCTime -> LocalTime
utcToLocalTime TimeZone
utc forall b c a. (b -> c) -> (a -> b) -> a -> c
. NominalDiffTime -> UTCTime -> UTCTime
addUTCTime NominalDiffTime
x forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimeZone -> LocalTime -> UTCTime
localTimeToUTC TimeZone
utc

-- | diffLocalTime a b = a - b
diffLocalTime :: LocalTime -> LocalTime -> NominalDiffTime
diffLocalTime :: LocalTime -> LocalTime -> NominalDiffTime
diffLocalTime LocalTime
a LocalTime
b = UTCTime -> UTCTime -> NominalDiffTime
diffUTCTime (TimeZone -> LocalTime -> UTCTime
localTimeToUTC TimeZone
utc LocalTime
a) (TimeZone -> LocalTime -> UTCTime
localTimeToUTC TimeZone
utc LocalTime
b)

-- | Get the local time of a UTC time in a time zone.
utcToLocalTime :: TimeZone -> UTCTime -> LocalTime
utcToLocalTime :: TimeZone -> UTCTime -> LocalTime
utcToLocalTime TimeZone
tz (UTCTime Day
day DiffTime
dt) = Day -> TimeOfDay -> LocalTime
LocalTime (Integer -> Day -> Day
addDays Integer
i Day
day) TimeOfDay
tod
  where
    (Integer
i, TimeOfDay
tod) = TimeZone -> TimeOfDay -> (Integer, TimeOfDay)
utcToLocalTimeOfDay TimeZone
tz (DiffTime -> TimeOfDay
timeToTimeOfDay DiffTime
dt)

-- | Get the UTC time of a local time in a time zone.
localTimeToUTC :: TimeZone -> LocalTime -> UTCTime
localTimeToUTC :: TimeZone -> LocalTime -> UTCTime
localTimeToUTC TimeZone
tz (LocalTime Day
day TimeOfDay
tod) = Day -> DiffTime -> UTCTime
UTCTime (Integer -> Day -> Day
addDays Integer
i Day
day) (TimeOfDay -> DiffTime
timeOfDayToTime TimeOfDay
todUTC)
  where
    (Integer
i, TimeOfDay
todUTC) = TimeZone -> TimeOfDay -> (Integer, TimeOfDay)
localToUTCTimeOfDay TimeZone
tz TimeOfDay
tod

-- | Get the local time of a UT1 time on a particular meridian (in degrees, positive is East).
ut1ToLocalTime :: Rational -> UniversalTime -> LocalTime
ut1ToLocalTime :: Rational -> UniversalTime -> LocalTime
ut1ToLocalTime Rational
long (ModJulianDate Rational
date) =
    Day -> TimeOfDay -> LocalTime
LocalTime (Integer -> Day
ModifiedJulianDay Integer
localMJD) (Rational -> TimeOfDay
dayFractionToTimeOfDay Rational
localToDOffset)
  where
    localTime :: Rational
localTime = Rational
date forall a. Num a => a -> a -> a
+ Rational
long forall a. Fractional a => a -> a -> a
/ Rational
360 :: Rational
    localMJD :: Integer
localMJD = forall a b. (RealFrac a, Integral b) => a -> b
floor Rational
localTime
    localToDOffset :: Rational
localToDOffset = Rational
localTime forall a. Num a => a -> a -> a
- (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
localMJD)

-- | Get the UT1 time of a local time on a particular meridian (in degrees, positive is East).
localTimeToUT1 :: Rational -> LocalTime -> UniversalTime
localTimeToUT1 :: Rational -> LocalTime -> UniversalTime
localTimeToUT1 Rational
long (LocalTime (ModifiedJulianDay Integer
localMJD) TimeOfDay
tod) =
    Rational -> UniversalTime
ModJulianDate ((forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
localMJD) forall a. Num a => a -> a -> a
+ (TimeOfDay -> Rational
timeOfDayToDayFraction TimeOfDay
tod) forall a. Num a => a -> a -> a
- (Rational
long forall a. Fractional a => a -> a -> a
/ Rational
360))

-- orphan instance
instance Show UniversalTime where
    show :: UniversalTime -> String
show UniversalTime
t = forall a. Show a => a -> String
show (Rational -> UniversalTime -> LocalTime
ut1ToLocalTime Rational
0 UniversalTime
t)