{-# LANGUAGE CPP #-}
{-# LANGUAGE Safe #-}

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

module Data.Time.LocalTime.Internal.LocalTime 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.CalendarDiffTime
import Data.Time.LocalTime.Internal.TimeOfDay
import Data.Time.LocalTime.Internal.TimeZone
import GHC.Generics
#if __GLASGOW_HASKELL__ >= 914
import qualified Language.Haskell.TH.Lift as TH
#else
import qualified Language.Haskell.TH.Syntax as TH
#endif

-- | 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
(LocalTime -> LocalTime -> Bool)
-> (LocalTime -> LocalTime -> Bool) -> Eq LocalTime
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: LocalTime -> LocalTime -> Bool
== :: LocalTime -> LocalTime -> Bool
$c/= :: LocalTime -> LocalTime -> Bool
/= :: LocalTime -> LocalTime -> Bool
Eq, Eq LocalTime
Eq LocalTime =>
(LocalTime -> LocalTime -> Ordering)
-> (LocalTime -> LocalTime -> Bool)
-> (LocalTime -> LocalTime -> Bool)
-> (LocalTime -> LocalTime -> Bool)
-> (LocalTime -> LocalTime -> Bool)
-> (LocalTime -> LocalTime -> LocalTime)
-> (LocalTime -> LocalTime -> LocalTime)
-> Ord 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
$ccompare :: LocalTime -> LocalTime -> Ordering
compare :: LocalTime -> LocalTime -> Ordering
$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
>= :: LocalTime -> LocalTime -> Bool
$cmax :: LocalTime -> LocalTime -> LocalTime
max :: LocalTime -> LocalTime -> LocalTime
$cmin :: LocalTime -> LocalTime -> LocalTime
min :: LocalTime -> LocalTime -> LocalTime
Ord, Typeable, Typeable LocalTime
Typeable LocalTime =>
(forall (c :: * -> *).
 (forall d b. Data d => c (d -> b) -> d -> c b)
 -> (forall g. g -> c g) -> LocalTime -> c LocalTime)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c LocalTime)
-> (LocalTime -> Constr)
-> (LocalTime -> DataType)
-> (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))
-> ((forall b. Data b => b -> b) -> LocalTime -> LocalTime)
-> (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 u. (forall d. Data d => d -> u) -> LocalTime -> [u])
-> (forall u.
    Int -> (forall d. Data d => d -> u) -> LocalTime -> u)
-> (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 (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> LocalTime -> m LocalTime)
-> Data LocalTime
LocalTime -> Constr
LocalTime -> DataType
(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)
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> LocalTime -> c LocalTime
gfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> LocalTime -> c LocalTime
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c LocalTime
gunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c LocalTime
$ctoConstr :: LocalTime -> Constr
toConstr :: LocalTime -> Constr
$cdataTypeOf :: LocalTime -> DataType
dataTypeOf :: LocalTime -> DataType
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c LocalTime)
dataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c LocalTime)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c LocalTime)
dataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c LocalTime)
$cgmapT :: (forall b. Data b => b -> b) -> LocalTime -> LocalTime
gmapT :: (forall b. Data b => b -> b) -> LocalTime -> LocalTime
$cgmapQl :: 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
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> LocalTime -> r
gmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> LocalTime -> r
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> LocalTime -> [u]
gmapQ :: forall u. (forall d. Data d => d -> u) -> LocalTime -> [u]
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> LocalTime -> u
gmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> LocalTime -> u
$cgmapM :: forall (m :: * -> *).
Monad 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
$cgmapMp :: 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
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> LocalTime -> m LocalTime
gmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> LocalTime -> m LocalTime
Data, (forall x. LocalTime -> Rep LocalTime x)
-> (forall x. Rep LocalTime x -> LocalTime) -> Generic LocalTime
forall x. Rep LocalTime x -> LocalTime
forall x. LocalTime -> Rep LocalTime x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. LocalTime -> Rep LocalTime x
from :: forall x. LocalTime -> Rep LocalTime x
$cto :: forall x. Rep LocalTime x -> LocalTime
to :: forall x. Rep LocalTime x -> LocalTime
Generic, (forall (m :: * -> *). Quote m => LocalTime -> m Exp)
-> (forall (m :: * -> *). Quote m => LocalTime -> Code m LocalTime)
-> Lift LocalTime
forall t.
(forall (m :: * -> *). Quote m => t -> m Exp)
-> (forall (m :: * -> *). Quote m => t -> Code m t) -> Lift t
forall (m :: * -> *). Quote m => LocalTime -> m Exp
forall (m :: * -> *). Quote m => LocalTime -> Code m LocalTime
$clift :: forall (m :: * -> *). Quote m => LocalTime -> m Exp
lift :: forall (m :: * -> *). Quote m => LocalTime -> m Exp
$cliftTyped :: forall (m :: * -> *). Quote m => LocalTime -> Code m LocalTime
liftTyped :: forall (m :: * -> *). Quote m => LocalTime -> Code m LocalTime
TH.Lift)

instance NFData LocalTime where
    rnf :: LocalTime -> ()
rnf (LocalTime Day
d TimeOfDay
t) = Day -> ()
forall a. NFData a => a -> ()
rnf Day
d () -> () -> ()
forall a b. a -> b -> b
`seq` TimeOfDay -> ()
forall a. NFData a => a -> ()
rnf TimeOfDay
t () -> () -> ()
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) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ (TimeOfDay -> String
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 (UTCTime -> LocalTime)
-> (LocalTime -> UTCTime) -> LocalTime -> LocalTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NominalDiffTime -> UTCTime -> UTCTime
addUTCTime NominalDiffTime
x (UTCTime -> UTCTime)
-> (LocalTime -> UTCTime) -> LocalTime -> UTCTime
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 Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
+ Rational
long Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Rational
360 :: Rational
    localMJD :: Integer
localMJD = Rational -> Integer
forall b. Integral b => Rational -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor Rational
localTime
    localToDOffset :: Rational
localToDOffset = Rational
localTime Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
- (Integer -> Rational
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 ((Integer -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
localMJD) Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
+ (TimeOfDay -> Rational
timeOfDayToDayFraction TimeOfDay
tod) Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
- (Rational
long Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Rational
360))

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

addLocalDurationClip :: CalendarDiffTime -> LocalTime -> LocalTime
addLocalDurationClip :: CalendarDiffTime -> LocalTime -> LocalTime
addLocalDurationClip (CalendarDiffTime Integer
m NominalDiffTime
d) (LocalTime Day
day TimeOfDay
t) =
    NominalDiffTime -> LocalTime -> LocalTime
addLocalTime NominalDiffTime
d (LocalTime -> LocalTime) -> LocalTime -> LocalTime
forall a b. (a -> b) -> a -> b
$ Day -> TimeOfDay -> LocalTime
LocalTime (Integer -> Day -> Day
addGregorianMonthsClip Integer
m Day
day) TimeOfDay
t

addLocalDurationRollOver :: CalendarDiffTime -> LocalTime -> LocalTime
addLocalDurationRollOver :: CalendarDiffTime -> LocalTime -> LocalTime
addLocalDurationRollOver (CalendarDiffTime Integer
m NominalDiffTime
d) (LocalTime Day
day TimeOfDay
t) =
    NominalDiffTime -> LocalTime -> LocalTime
addLocalTime NominalDiffTime
d (LocalTime -> LocalTime) -> LocalTime -> LocalTime
forall a b. (a -> b) -> a -> b
$ Day -> TimeOfDay -> LocalTime
LocalTime (Integer -> Day -> Day
addGregorianMonthsRollOver Integer
m Day
day) TimeOfDay
t

diffLocalDurationClip :: LocalTime -> LocalTime -> CalendarDiffTime
diffLocalDurationClip :: LocalTime -> LocalTime -> CalendarDiffTime
diffLocalDurationClip (LocalTime Day
day1 TimeOfDay
t1) (LocalTime Day
day2 TimeOfDay
t2) =
    let
        CalendarDiffTime Integer
m NominalDiffTime
t = CalendarDiffDays -> CalendarDiffTime
calendarTimeDays (CalendarDiffDays -> CalendarDiffTime)
-> CalendarDiffDays -> CalendarDiffTime
forall a b. (a -> b) -> a -> b
$ Day -> Day -> CalendarDiffDays
diffGregorianDurationClip Day
day1 Day
day2
    in
        Integer -> NominalDiffTime -> CalendarDiffTime
CalendarDiffTime Integer
m (NominalDiffTime -> CalendarDiffTime)
-> NominalDiffTime -> CalendarDiffTime
forall a b. (a -> b) -> a -> b
$ NominalDiffTime
t NominalDiffTime -> NominalDiffTime -> NominalDiffTime
forall a. Num a => a -> a -> a
+ TimeOfDay -> TimeOfDay -> NominalDiffTime
diffTimeOfDay TimeOfDay
t1 TimeOfDay
t2

diffLocalDurationRollOver :: LocalTime -> LocalTime -> CalendarDiffTime
diffLocalDurationRollOver :: LocalTime -> LocalTime -> CalendarDiffTime
diffLocalDurationRollOver (LocalTime Day
day1 TimeOfDay
t1) (LocalTime Day
day2 TimeOfDay
t2) =
    let
        CalendarDiffTime Integer
m NominalDiffTime
t = CalendarDiffDays -> CalendarDiffTime
calendarTimeDays (CalendarDiffDays -> CalendarDiffTime)
-> CalendarDiffDays -> CalendarDiffTime
forall a b. (a -> b) -> a -> b
$ Day -> Day -> CalendarDiffDays
diffGregorianDurationRollOver Day
day1 Day
day2
    in
        Integer -> NominalDiffTime -> CalendarDiffTime
CalendarDiffTime Integer
m (NominalDiffTime -> CalendarDiffTime)
-> NominalDiffTime -> CalendarDiffTime
forall a b. (a -> b) -> a -> b
$ NominalDiffTime
t NominalDiffTime -> NominalDiffTime -> NominalDiffTime
forall a. Num a => a -> a -> a
+ TimeOfDay -> TimeOfDay -> NominalDiffTime
diffTimeOfDay TimeOfDay
t1 TimeOfDay
t2