module PostgreSQL.Binary.Time where import PostgreSQL.Binary.Prelude hiding (second) {-# INLINEABLE dayToPostgresJulian #-} dayToPostgresJulian :: Day -> Integer dayToPostgresJulian = (+ (2400001 - 2451545)) . toModifiedJulianDay {-# INLINEABLE postgresJulianToDay #-} postgresJulianToDay :: (Integral a) => a -> Day postgresJulianToDay = ModifiedJulianDay . fromIntegral . subtract (2400001 - 2451545) {-# INLINEABLE microsToTimeOfDay #-} microsToTimeOfDay :: Int64 -> TimeOfDay microsToTimeOfDay = evalState $ do h <- state $ flip divMod $ 10 ^ 6 * 60 * 60 m <- state $ flip divMod $ 10 ^ 6 * 60 u <- get return $ TimeOfDay (fromIntegral h) (fromIntegral m) (microsToPico u) {-# INLINEABLE microsToUTC #-} microsToUTC :: Int64 -> UTCTime microsToUTC = evalState $ do d <- state $ flip divMod $ 10 ^ 6 * 60 * 60 * 24 u <- get return $ UTCTime (postgresJulianToDay d) (microsToDiffTime u) {-# INLINEABLE microsToPico #-} microsToPico :: Int64 -> Pico microsToPico = unsafeCoerce . (* (10 ^ 6)) . (fromIntegral :: Int64 -> Integer) {-# INLINEABLE microsToDiffTime #-} microsToDiffTime :: Int64 -> DiffTime microsToDiffTime = unsafeCoerce microsToPico {-# INLINEABLE microsToLocalTime #-} microsToLocalTime :: Int64 -> LocalTime microsToLocalTime = evalState $ do d <- state $ flip divMod $ 10 ^ 6 * 60 * 60 * 24 u <- get return $ LocalTime (postgresJulianToDay d) (microsToTimeOfDay u) {-# INLINEABLE secsToTimeOfDay #-} secsToTimeOfDay :: Double -> TimeOfDay secsToTimeOfDay = evalState $ do h <- state $ flip divMod' $ 60 * 60 m <- state $ flip divMod' $ 60 s <- get return $ TimeOfDay (fromIntegral h) (fromIntegral m) (secsToPico s) {-# INLINEABLE secsToUTC #-} secsToUTC :: Double -> UTCTime secsToUTC = evalState $ do d <- state $ flip divMod' $ 60 * 60 * 24 s <- get return $ UTCTime (postgresJulianToDay d) (secsToDiffTime s) {-# INLINEABLE secsToLocalTime #-} secsToLocalTime :: Double -> LocalTime secsToLocalTime = evalState $ do d <- state $ flip divMod' $ 60 * 60 * 24 s <- get return $ LocalTime (postgresJulianToDay d) (secsToTimeOfDay s) {-# INLINEABLE secsToPico #-} secsToPico :: Double -> Pico secsToPico s = unsafeCoerce (truncate $ toRational s * 10 ^ 12 :: Integer) {-# INLINEABLE secsToDiffTime #-} secsToDiffTime :: Double -> DiffTime secsToDiffTime = unsafeCoerce secsToPico {-# INLINEABLE localTimeToMicros #-} localTimeToMicros :: LocalTime -> Int64 localTimeToMicros (LocalTime dayX timeX) = let d = dayToPostgresJulian dayX p = unsafeCoerce $ timeOfDayToTime timeX in 10 ^ 6 * 60 * 60 * 24 * fromIntegral d + fromIntegral (div p (10 ^ 6)) {-# INLINEABLE localTimeToSecs #-} localTimeToSecs :: LocalTime -> Double localTimeToSecs (LocalTime dayX timeX) = let d = dayToPostgresJulian dayX p = unsafeCoerce $ timeOfDayToTime timeX in 60 * 60 * 24 * fromIntegral d + fromRational (p % (10 ^ 12)) {-# INLINEABLE utcToMicros #-} utcToMicros :: UTCTime -> Int64 utcToMicros (UTCTime dayX diffTimeX) = let d = dayToPostgresJulian dayX p = unsafeCoerce diffTimeX in 10 ^ 6 * 60 * 60 * 24 * fromIntegral d + fromIntegral (div p (10 ^ 6)) {-# INLINEABLE utcToSecs #-} utcToSecs :: UTCTime -> Double utcToSecs (UTCTime dayX diffTimeX) = let d = dayToPostgresJulian dayX p = unsafeCoerce diffTimeX in 60 * 60 * 24 * fromIntegral d + fromRational (p % (10 ^ 12)) -- * Constants in microseconds according to Julian dates standard -- According to -- http://www.postgresql.org/docs/9.1/static/datatype-datetime.html -- Postgres uses Julian dates internally yearMicros :: Int64 yearMicros = truncate (365.2425 * fromIntegral dayMicros :: Rational) dayMicros :: Int64 dayMicros = 24 * hourMicros hourMicros :: Int64 hourMicros = 60 * minuteMicros minuteMicros :: Int64 minuteMicros = 60 * secondMicros secondMicros :: Int64 secondMicros = 10 ^ 6