{-|
Module: Data.Astro.Time.Conv
Description: Julian Date
Copyright: Alexander Ignatyev, 2017


Conversion functions between datetime types defined in Data.Time and Data.Astro.Time modules.
-}
module Data.Astro.Time.Conv
(
  zonedTimeToLCT
  , zonedTimeToLCD
  , lctToZonedTime
)

where


import Data.Time.LocalTime (ZonedTime(..), LocalTime(..)
                           , TimeOfDay(..), TimeZone(..)
                           , minutesToTimeZone)
import Data.Time.Calendar (toGregorian, fromGregorian)

import Data.Astro.Types(DecimalHours(..))
import Data.Astro.Utils (fromFixed)
import Data.Astro.Time.JulianDate (JulianDate(..)
                                  , LocalCivilTime(..)
                                  , LocalCivilDate(..)
                                  , fromYMDHMS, toYMDHMS
                                  , lctFromYMDHMS, lcdFromYMD
                                  , lctToYMDHMS)


-----------------------------------------------------------

-- Data.Time types -> Data.Astro types

timeZoneToDH :: TimeZone -> DecimalHours
timeZoneToDH :: TimeZone -> DecimalHours
timeZoneToDH  TimeZone
tz = Double -> DecimalHours
DH Double
hours
  where toMinutes :: TimeZone -> Double
toMinutes = Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Double) -> (TimeZone -> Int) -> TimeZone -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimeZone -> Int
timeZoneMinutes
        hours :: Double
hours = (TimeZone -> Double
toMinutes TimeZone
tz) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
60.0


-- | Convert ZonedTime to LocalCivilTime

zonedTimeToLCT :: ZonedTime -> LocalCivilTime
zonedTimeToLCT :: ZonedTime -> LocalCivilTime
zonedTimeToLCT ZonedTime
zonedTime = DecimalHours
-> Integer -> Int -> Int -> Int -> Int -> Double -> LocalCivilTime
lctFromYMDHMS DecimalHours
tz Integer
y Int
m Int
d Int
hours Int
mins (Fixed E12 -> Double
forall a b. (Fractional a, HasResolution b) => Fixed b -> a
fromFixed Fixed E12
secs)
  where tz :: DecimalHours
tz = TimeZone -> DecimalHours
timeZoneToDH (ZonedTime -> TimeZone
zonedTimeZone ZonedTime
zonedTime)
        lt :: LocalTime
lt = ZonedTime -> LocalTime
zonedTimeToLocalTime ZonedTime
zonedTime
        (Integer
y, Int
m, Int
d) = Day -> (Integer, Int, Int)
toGregorian (LocalTime -> Day
localDay LocalTime
lt)
        TimeOfDay Int
hours Int
mins Fixed E12
secs = LocalTime -> TimeOfDay
localTimeOfDay LocalTime
lt


-- | Convert ZonedTime to LocalCivilDate

zonedTimeToLCD :: ZonedTime -> LocalCivilDate
zonedTimeToLCD :: ZonedTime -> LocalCivilDate
zonedTimeToLCD ZonedTime
zonedTime = DecimalHours -> Integer -> Int -> Int -> LocalCivilDate
lcdFromYMD DecimalHours
tz Integer
y Int
m Int
d
  where tz :: DecimalHours
tz = TimeZone -> DecimalHours
timeZoneToDH (ZonedTime -> TimeZone
zonedTimeZone ZonedTime
zonedTime)
        lt :: LocalTime
lt = ZonedTime -> LocalTime
zonedTimeToLocalTime ZonedTime
zonedTime
        (Integer
y, Int
m, Int
d) = Day -> (Integer, Int, Int)
toGregorian (LocalTime -> Day
localDay LocalTime
lt)


-----------------------------------------------------------

-- Data.Astro Types -> Data.Time types


dhToTimeZone :: DecimalHours -> TimeZone
dhToTimeZone :: DecimalHours -> TimeZone
dhToTimeZone (DH Double
hours) = Int -> TimeZone
minutesToTimeZone Int
minutes
  where minutes :: Int
minutes = Double -> Int
forall a b. (RealFrac a, Integral b) => a -> b
round (Double
60Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
hours)


-- | Convert LocalCivilTime to ZonedTime

lctToZonedTime :: LocalCivilTime -> ZonedTime
lctToZonedTime :: LocalCivilTime -> ZonedTime
lctToZonedTime LocalCivilTime
lct = ZonedTime :: LocalTime -> TimeZone -> ZonedTime
ZonedTime { zonedTimeToLocalTime :: LocalTime
zonedTimeToLocalTime = LocalTime
lt, zonedTimeZone :: TimeZone
zonedTimeZone = TimeZone
tz }
  where tz :: TimeZone
tz = DecimalHours -> TimeZone
dhToTimeZone (DecimalHours -> TimeZone) -> DecimalHours -> TimeZone
forall a b. (a -> b) -> a -> b
$ LocalCivilTime -> DecimalHours
lctTimeZone LocalCivilTime
lct
        (Integer
y, Int
m, Int
d, Int
hours, Int
mins, Double
secs) = LocalCivilTime -> (Integer, Int, Int, Int, Int, Double)
lctToYMDHMS LocalCivilTime
lct
        day :: Day
day = Integer -> Int -> Int -> Day
fromGregorian Integer
y Int
m Int
d
        time :: TimeOfDay
time = Int -> Int -> Fixed E12 -> TimeOfDay
TimeOfDay Int
hours Int
mins (Double -> Fixed E12
forall a b. (Real a, Fractional b) => a -> b
realToFrac Double
secs)
        lt :: LocalTime
lt = LocalTime :: Day -> TimeOfDay -> LocalTime
LocalTime { localDay :: Day
localDay = Day
day, localTimeOfDay :: TimeOfDay
localTimeOfDay = TimeOfDay
time }