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