format everything with hindent
[packages/time.git] / lib / Data / Time / LocalTime / Internal / TimeOfDay.hs
1 {-# OPTIONS -fno-warn-unused-imports #-}
2
3 module Data.Time.LocalTime.Internal.TimeOfDay
4 (
5 -- * Time of day
6 TimeOfDay(..)
7 , midnight
8 , midday
9 , makeTimeOfDayValid
10 , timeToDaysAndTimeOfDay
11 , daysAndTimeOfDayToTime
12 , utcToLocalTimeOfDay
13 , localToUTCTimeOfDay
14 , timeToTimeOfDay
15 , timeOfDayToTime
16 , dayFractionToTimeOfDay
17 , timeOfDayToDayFraction
18 ) where
19
20 import Control.DeepSeq
21 import Data.Data
22 import Data.Fixed
23 import Data.Time.Calendar.Private
24 import Data.Time.Clock.Internal.DiffTime
25 import Data.Time.Clock.Internal.NominalDiffTime
26 import Data.Time.LocalTime.Internal.TimeZone
27 import Data.Typeable
28
29 -- | Time of day as represented in hour, minute and second (with picoseconds), typically used to express local time of day.
30 data TimeOfDay = TimeOfDay
31 { todHour :: Int
32 -- ^ range 0 - 23
33 , todMin :: Int
34 -- ^ range 0 - 59
35 , todSec :: Pico
36 -- ^ Note that 0 <= 'todSec' < 61, accomodating leap seconds.
37 -- Any local minute may have a leap second, since leap seconds happen in all zones simultaneously
38 } deriving (Eq, Ord, Data, Typeable)
39
40 instance NFData TimeOfDay where
41 rnf (TimeOfDay h m s) = rnf h `seq` rnf m `seq` s `seq` () -- FIXME: Data.Fixed had no NFData instances yet at time of writing
42
43 -- | Hour zero
44 midnight :: TimeOfDay
45 midnight = TimeOfDay 0 0 0
46
47 -- | Hour twelve
48 midday :: TimeOfDay
49 midday = TimeOfDay 12 0 0
50
51 instance Show TimeOfDay where
52 show (TimeOfDay h m s) = (show2 h) ++ ":" ++ (show2 m) ++ ":" ++ (show2Fixed s)
53
54 makeTimeOfDayValid :: Int -> Int -> Pico -> Maybe TimeOfDay
55 makeTimeOfDayValid h m s = do
56 _ <- clipValid 0 23 h
57 _ <- clipValid 0 59 m
58 _ <- clipValid 0 60.999999999999 s
59 return (TimeOfDay h m s)
60
61 -- | Convert a period of time into a count of days and a time of day since midnight.
62 -- The time of day will never have a leap second.
63 timeToDaysAndTimeOfDay :: NominalDiffTime -> (Integer, TimeOfDay)
64 timeToDaysAndTimeOfDay dt = let
65 s = realToFrac dt
66 (m, ms) = divMod' s 60
67 (h, hm) = divMod' m 60
68 (d, dh) = divMod' h 24
69 in (d, TimeOfDay dh hm ms)
70
71 -- | Convert a count of days and a time of day since midnight into a period of time.
72 daysAndTimeOfDayToTime :: Integer -> TimeOfDay -> NominalDiffTime
73 daysAndTimeOfDayToTime d (TimeOfDay dh hm ms) =
74 (+) (realToFrac ms) $ (*) 60 $ (+) (realToFrac hm) $ (*) 60 $ (+) (realToFrac dh) $ (*) 24 $ realToFrac d
75
76 -- | Convert a time of day in UTC to a time of day in some timezone, together with a day adjustment.
77 utcToLocalTimeOfDay :: TimeZone -> TimeOfDay -> (Integer, TimeOfDay)
78 utcToLocalTimeOfDay zone (TimeOfDay h m s) = (fromIntegral (div h' 24), TimeOfDay (mod h' 24) (mod m' 60) s)
79 where
80 m' = m + timeZoneMinutes zone
81 h' = h + (div m' 60)
82
83 -- | Convert a time of day in some timezone to a time of day in UTC, together with a day adjustment.
84 localToUTCTimeOfDay :: TimeZone -> TimeOfDay -> (Integer, TimeOfDay)
85 localToUTCTimeOfDay zone = utcToLocalTimeOfDay (minutesToTimeZone (negate (timeZoneMinutes zone)))
86
87 posixDayLength :: DiffTime
88 posixDayLength = fromInteger 86400
89
90 -- | Get the time of day given a time since midnight.
91 -- Time more than 24h will be converted to leap-seconds.
92 timeToTimeOfDay :: DiffTime -> TimeOfDay
93 timeToTimeOfDay dt
94 | dt >= posixDayLength = TimeOfDay 23 59 (60 + (realToFrac (dt - posixDayLength)))
95 timeToTimeOfDay dt = TimeOfDay (fromInteger h) (fromInteger m) s
96 where
97 s' = realToFrac dt
98 s = mod' s' 60
99 m' = div' s' 60
100 m = mod' m' 60
101 h = div' m' 60
102
103 -- | Get the time since midnight for a given time of day.
104 timeOfDayToTime :: TimeOfDay -> DiffTime
105 timeOfDayToTime (TimeOfDay h m s) = ((fromIntegral h) * 60 + (fromIntegral m)) * 60 + (realToFrac s)
106
107 -- | Get the time of day given the fraction of a day since midnight.
108 dayFractionToTimeOfDay :: Rational -> TimeOfDay
109 dayFractionToTimeOfDay df = timeToTimeOfDay (realToFrac (df * 86400))
110
111 -- | Get the fraction of a day since midnight given a time of day.
112 timeOfDayToDayFraction :: TimeOfDay -> Rational
113 timeOfDayToDayFraction tod = realToFrac (timeOfDayToTime tod) / realToFrac posixDayLength