canteven-parsedate-1.0.1.2: src/Canteven/ParseDate/Types.hs
{-# LANGUAGE NamedFieldPuns #-}
module Canteven.ParseDate.Types (
LocalTimeAndOffset(..),
ltaoInTimeZone,
ltaoInTimeZoneTZ
) where
import Data.Time (UTCTime, ParseTime (buildTime))
import Data.Time.LocalTime (LocalTime, TimeZone, localTimeToUTC)
import Data.Time.LocalTime.TimeZone.Series (TimeZoneSeries, utcToLocalTime')
import Data.Time.Zones (TZ, utcToLocalTimeTZ)
-- | A data type for parsing ISO8601 and distinguishing between with-offset or
-- without-offset formats.
data LocalTimeAndOffset = LocalTimeAndOffset {
ltaoLocalTime :: LocalTime
, ltaoOffset :: Maybe TimeZone
} deriving (Read, Show, Eq)
instance ParseTime LocalTimeAndOffset where
buildTime l xs =
LocalTimeAndOffset (buildTime l $ filter (not . isZoneInfo) xs)
maybeZone
where
-- Apparently "%Z" matches even the empty string and parses it as 00:00.
-- "%z" might do this too but I haven't tested it.
isZoneInfo ('z',_) = True
isZoneInfo ('Z',"") = False
isZoneInfo ('Z',_) = True
isZoneInfo _ = False
zoneLetters = filter isZoneInfo xs
maybeZone | null zoneLetters = Nothing
| otherwise = Just $ buildTime l zoneLetters
-- | Get the localtime represented by this LTAO in the given timezone.
ltaoInTimeZone :: TimeZoneSeries -> LocalTimeAndOffset -> LocalTime
ltaoInTimeZone = ltaoInTimeZoneConvert utcToLocalTime'
-- | same as @ltaoInTimeZone@ but for TZ
ltaoInTimeZoneTZ :: TZ -> LocalTimeAndOffset -> LocalTime
ltaoInTimeZoneTZ = ltaoInTimeZoneConvert utcToLocalTimeTZ
ltaoInTimeZoneConvert :: (a -> UTCTime -> LocalTime) -> a -> LocalTimeAndOffset -> LocalTime
-- If the LTAO doesn't specify an offset, it must be local time, so just use it
-- directly.
ltaoInTimeZoneConvert _ _ (LocalTimeAndOffset lTime Nothing) = lTime
-- Otherwise, this LTAO specifies a UTCTime, so convert that UTCTime to LocalTime.
ltaoInTimeZoneConvert convert tz (LocalTimeAndOffset lTime (Just off)) =
convert tz utc
where
utc = localTimeToUTC off lTime