{- | Module : Data.Convertible.Instances.Time Copyright : Copyright (C) 2009-2011 John Goerzen License : BSD3 Maintainer : John Goerzen Stability : provisional Portability: portable Instances to convert between various time structures, both old- and new-style. At present, this module does not do full input validation. That is, it is possible to get an exception rather than a Left result from these functions if your input is invalid, particularly when converting from the old-style System.Time structures. Copyright (C) 2009-2011 John Goerzen All rights reserved. For license and copyright information, see the file LICENSE -} module Data.Convertible.Instances.Time() where import Data.Convertible.Base import Data.Convertible.Utils import Data.Convertible.Instances.Num() import qualified System.Time as ST import Data.Time import Data.Time.Clock.POSIX import Data.Time.Calendar.OrdinalDate import Data.Ratio import Foreign.C.Types ---------------------------------------------------------------------- -- Intra-System.Time stuff ---------------------------------------------------------------------- instance Convertible ST.ClockTime ST.CalendarTime where safeConvert = return . ST.toUTCTime instance Convertible ST.CalendarTime ST.ClockTime where safeConvert = return . ST.toClockTime instance Convertible ST.ClockTime Integer where safeConvert (ST.TOD x _) = return x instance Convertible Integer ST.ClockTime where safeConvert x = return $ ST.TOD x 0 ---------------------------------------------------------------------- -- Intra-Data.Time stuff ---------------------------------------------------------------------- ------------------------------ POSIX and UTC times {- Covered under Real a instance Convertible Rational POSIXTime where safeConvert = return . fromRational -} instance Convertible Rational POSIXTime where safeConvert = return . fromRational instance Convertible Integer POSIXTime where safeConvert = return . fromInteger instance Convertible Int POSIXTime where safeConvert = return . fromIntegral instance Convertible Double POSIXTime where safeConvert = return . realToFrac instance Convertible POSIXTime Integer where safeConvert = return . truncate instance Convertible POSIXTime Rational where safeConvert = return . toRational instance Convertible POSIXTime Double where safeConvert = return . realToFrac instance Convertible POSIXTime Int where safeConvert = boundedConversion (return . truncate) instance Convertible POSIXTime UTCTime where safeConvert = return . posixSecondsToUTCTime instance Convertible UTCTime POSIXTime where safeConvert = return . utcTimeToPOSIXSeconds instance Convertible Rational UTCTime where safeConvert a = safeConvert a >>= return . posixSecondsToUTCTime instance Convertible Integer UTCTime where safeConvert a = safeConvert a >>= return . posixSecondsToUTCTime instance Convertible Int UTCTime where safeConvert a = safeConvert a >>= return . posixSecondsToUTCTime instance Convertible Double UTCTime where safeConvert a = safeConvert a >>= return . posixSecondsToUTCTime instance Convertible UTCTime Rational where safeConvert = safeConvert . utcTimeToPOSIXSeconds instance Convertible UTCTime Integer where safeConvert = safeConvert . utcTimeToPOSIXSeconds instance Convertible UTCTime Double where safeConvert = safeConvert . utcTimeToPOSIXSeconds instance Convertible UTCTime Int where safeConvert = boundedConversion (safeConvert . utcTimeToPOSIXSeconds) ------------------------------ LocalTime stuff instance Convertible UTCTime ZonedTime where safeConvert = return . utcToZonedTime utc instance Convertible POSIXTime ZonedTime where safeConvert = return . utcToZonedTime utc . posixSecondsToUTCTime instance Convertible ZonedTime UTCTime where safeConvert = return . zonedTimeToUTC instance Convertible ZonedTime POSIXTime where safeConvert = return . utcTimeToPOSIXSeconds . zonedTimeToUTC {- Too obvious? instance Convertible LocalTime Day where safeConvert = return . localDay instance Convertible LocalTime TimeOfDay where safeConvert = return . localTimeOfDay -} ---------------------------------------------------------------------- -- Conversions between old and new time ---------------------------------------------------------------------- instance Convertible ST.CalendarTime ZonedTime where safeConvert ct = return $ ZonedTime { zonedTimeToLocalTime = LocalTime { localDay = fromGregorian (fromIntegral $ ST.ctYear ct) (1 + (fromEnum $ ST.ctMonth ct)) (ST.ctDay ct), localTimeOfDay = TimeOfDay { todHour = ST.ctHour ct, todMin = ST.ctMin ct, todSec = (fromIntegral $ ST.ctSec ct) + fromRational (ST.ctPicosec ct % 1000000000000) } }, zonedTimeZone = TimeZone { timeZoneMinutes = ST.ctTZ ct `div` 60, timeZoneSummerOnly = ST.ctIsDST ct, timeZoneName = ST.ctTZName ct} } instance Convertible ST.CalendarTime POSIXTime where safeConvert = convertVia (undefined::ST.ClockTime) instance Convertible ST.CalendarTime UTCTime where safeConvert = convertVia (undefined::POSIXTime) instance Convertible ST.ClockTime POSIXTime where safeConvert (ST.TOD x y) = return $ fromRational $ fromInteger x + fromRational (y % 1000000000000) instance Convertible ST.ClockTime UTCTime where safeConvert = convertVia (undefined::POSIXTime) instance Convertible ST.ClockTime ZonedTime where safeConvert = convertVia (undefined::UTCTime) instance Convertible ZonedTime ST.ClockTime where safeConvert = convertVia (undefined::POSIXTime) instance Convertible POSIXTime ST.ClockTime where safeConvert x = return $ ST.TOD rsecs rpico where rsecs = floor x rpico = truncate $ abs $ 1000000000000 * (x - (fromIntegral rsecs)) instance Convertible UTCTime ST.ClockTime where safeConvert = safeConvert . utcTimeToPOSIXSeconds instance Convertible ZonedTime ST.CalendarTime where safeConvert zt = return $ ST.CalendarTime { ST.ctYear = fromIntegral year, ST.ctMonth = toEnum (month - 1), ST.ctDay = day, ST.ctHour = todHour ltod, ST.ctMin = todMin ltod, ST.ctSec = secs, ST.ctPicosec = pico, ST.ctWDay = toEnum . snd . sundayStartWeek . localDay . zonedTimeToLocalTime $ zt, ST.ctYDay = (snd . toOrdinalDate . localDay . zonedTimeToLocalTime $ zt) - 1, ST.ctTZName = timeZoneName . zonedTimeZone $ zt, ST.ctTZ = (timeZoneMinutes . zonedTimeZone $ zt) * 60, ST.ctIsDST = timeZoneSummerOnly . zonedTimeZone $ zt } where (year, month, day) = toGregorian . localDay . zonedTimeToLocalTime $ zt ltod = localTimeOfDay . zonedTimeToLocalTime $ zt secs = (truncate . todSec $ ltod)::Int picoRational = toRational (todSec ltod) - toRational secs pico = truncate (picoRational * 1000000000000) instance Convertible POSIXTime ST.CalendarTime where safeConvert = convertVia (undefined::ZonedTime) instance Convertible UTCTime ST.CalendarTime where safeConvert = safeConvert . utcTimeToPOSIXSeconds instance Convertible ST.TimeDiff NominalDiffTime where {- This is a clever hack. We convert the TimeDiff to a ClockTime, applying it as a diff vs. the epoch. Converting this ClockTime to a POSIXTime yiels the NominalDiffTime we want, since a POSIXTime is a NominalDiffTime vs. the epoch. -} safeConvert td = safeConvert clockTime where clockTime = ST.addToClockTime td (ST.TOD 0 0) instance Convertible NominalDiffTime ST.TimeDiff where {- Similar clever hack as above. -} safeConvert ndt = do clockt <- safeConvert ndt return (ST.diffClockTimes clockt (ST.TOD 0 0)) instance Convertible Integer ST.TimeDiff where safeConvert = convertVia (undefined::NominalDiffTime) instance Convertible Double ST.TimeDiff where safeConvert = convertVia (undefined::NominalDiffTime) instance Convertible ST.TimeDiff Integer where safeConvert = convertVia (undefined :: NominalDiffTime) instance Convertible ST.TimeDiff Rational where safeConvert = convertVia (undefined :: NominalDiffTime) instance Convertible ST.TimeDiff Double where safeConvert = convertVia (undefined :: NominalDiffTime) ---------------------------------------------------------------------- -- Foreign.C Types ---------------------------------------------------------------------- instance Convertible CTime POSIXTime where safeConvert = return . realToFrac instance Convertible POSIXTime CTime where safeConvert = return . fromInteger . truncate instance Convertible CTime Integer where safeConvert = return . truncate . toRational instance Convertible Integer CTime where safeConvert = return . fromInteger instance Convertible CTime Double where safeConvert = return . realToFrac instance Convertible Double CTime where safeConvert = return . fromInteger . truncate instance Convertible CTime Int where safeConvert x = do r1 <- safeConvert x boundedConversion (return . fromInteger) r1 instance Convertible Int CTime where safeConvert = safeConvert . toInteger instance Convertible CTime UTCTime where safeConvert = convertVia (undefined :: POSIXTime) instance Convertible UTCTime CTime where safeConvert = convertVia (undefined :: POSIXTime) instance Convertible CTime ST.ClockTime where safeConvert = convertVia (undefined :: POSIXTime) instance Convertible ST.ClockTime CTime where safeConvert = convertVia (undefined :: POSIXTime) instance Convertible CTime ST.CalendarTime where safeConvert = convertVia (undefined::POSIXTime) instance Convertible ST.CalendarTime CTime where safeConvert = convertVia (undefined::POSIXTime) instance Convertible CTime ZonedTime where safeConvert = convertVia (undefined::POSIXTime) instance Convertible ZonedTime CTime where safeConvert = convertVia (undefined::POSIXTime)