-- | Perhaps this could be called @moment@, as it aims to identify a
-- moment in time. A DateTime is a combination of a LocalTime from
-- Data.Time and a TimeZoneOffset. Previously a DateTime was simply a
-- ZonedTime from Data.Time but ZonedTime has data that Penny does not
-- need.
module Penny.Lincoln.Bits.DateTime (
  DateTime
  , dateTime
  , localTime
  , timeZone
  , TimeZoneOffset
  , offsetToMins
  , minsToOffset
  , noOffset
  ) where

import qualified Data.Time as T

-- | The number of minutes that this timezone is offset from UTC. Can
-- be positive, negative, or zero.
newtype TimeZoneOffset = TimeZoneOffset { offsetToMins :: Int }
                         deriving (Eq, Ord, Show)

-- | Convert minutes to a time zone offset. I'm having a hard time
-- deciding whether to be liberal or strict in what to accept
-- here. Currently it is somewhat strict in that it will fail if
-- absolute value is greater than 840 minutes; currently the article
-- at http://en.wikipedia.org/wiki/List_of_time_zones_by_UTC_offset
-- says there is no offset greater than 14 hours, or 840 minutes.
minsToOffset :: Int -> Maybe TimeZoneOffset
minsToOffset m = if abs m > 840
                 then Nothing
                 else Just $ TimeZoneOffset m

noOffset :: TimeZoneOffset
noOffset = TimeZoneOffset 0

-- | A DateTime is a UTC time that also remembers the local time from
-- which it was set. The Eq and Ord instances will compare two
-- DateTimes based on their equivalent UTC times.
data DateTime = DateTime { localTime :: T.LocalTime
                         , timeZone :: TimeZoneOffset }
                   deriving Show

-- | Construct a DateTime.
dateTime :: T.LocalTime -> TimeZoneOffset -> DateTime
dateTime = DateTime

toUTC :: DateTime -> T.UTCTime
toUTC (DateTime lt (TimeZoneOffset tzo)) = T.localTimeToUTC tz lt where
  tz = T.minutesToTimeZone tzo

instance Eq DateTime where
  l == r = toUTC l == toUTC r

instance Ord DateTime where
  compare l r = compare (toUTC l) (toUTC r)