module Data.HodaTime.ZonedDateTime
(
ZonedDateTime
,fromCalendarDateTimeLeniently
,fromCalendarDateTimeStrictly
,fromInstant
,toCalendarDateTime
,toCalendarDate
,toLocalTime
,inDst
,zoneAbbreviation
,fromCalendarDateTimeAll
,resolve
,DateTimeDoesNotExistException(..)
,DateTimeAmbiguousException(..)
)
where
import Data.HodaTime.ZonedDateTime.Internal
import Data.HodaTime.CalendarDateTime.Internal (CalendarDateTime(..), CalendarDate(..), IsCalendarDateTime(..), IsCalendar(..), LocalTime)
import Data.HodaTime.LocalTime.Internal (second)
import Data.HodaTime.Instant.Internal (Instant)
import Data.HodaTime.Offset.Internal (Offset(..), adjustInstant)
import Data.HodaTime.TimeZone.Internal (TimeZone, TransitionInfo(..), calDateTransitionsFor, aroundCalDateTransition, activeTransitionFor)
import Control.Exception (Exception)
import Control.Monad.Catch (MonadThrow, throwM)
import Data.Typeable (Typeable)
data DateTimeDoesNotExistException = DateTimeDoesNotExistException
deriving (Typeable, Show)
instance Exception DateTimeDoesNotExistException
data DateTimeAmbiguousException = DateTimeAmbiguousException
deriving (Typeable, Show)
instance Exception DateTimeAmbiguousException
fromCalendarDateTimeLeniently :: (IsCalendar cal, IsCalendarDateTime cal) => CalendarDateTime cal -> TimeZone -> ZonedDateTime cal
fromCalendarDateTimeLeniently = resolve ambiguous skipped
where
ambiguous zdt _ = zdt
skipped (ZonedDateTime _ _ (TransitionInfo (Offset bOff) _ _)) (ZonedDateTime cdt tz ti@(TransitionInfo (Offset aOff) _ _)) = ZonedDateTime cdt' tz ti
where
cdt' = modify (\s -> s + aOff - bOff) second cdt
modify f l = head . l ((:[]) . f)
fromCalendarDateTimeStrictly :: (MonadThrow m, IsCalendarDateTime cal) => CalendarDateTime cal -> TimeZone -> m (ZonedDateTime cal)
fromCalendarDateTimeStrictly cdt = go . fromCalendarDateTimeAll cdt
where
go [] = throwM $ DateTimeDoesNotExistException
go [zdt] = return zdt
go _ = throwM $ DateTimeAmbiguousException
fromCalendarDateTimeAll :: IsCalendarDateTime cal => CalendarDateTime cal -> TimeZone -> [ZonedDateTime cal]
fromCalendarDateTimeAll cdt tz = zdts
where
instant = toUnadjustedInstant cdt
zdts = fmap mkZdt . calDateTransitionsFor instant $ tz
mkZdt = ZonedDateTime cdt tz
fromInstant :: IsCalendarDateTime cal => Instant -> TimeZone -> ZonedDateTime cal
fromInstant instant tz = ZonedDateTime cdt tz ti
where
ti = activeTransitionFor instant tz
offset = tiUtcOffset ti
instant' = adjustInstant offset instant
cdt = fromAdjustedInstant instant'
resolve ::
IsCalendarDateTime cal =>
(ZonedDateTime cal -> ZonedDateTime cal -> ZonedDateTime cal) ->
(ZonedDateTime cal -> ZonedDateTime cal -> ZonedDateTime cal) ->
CalendarDateTime cal ->
TimeZone ->
ZonedDateTime cal
resolve ambiguous skipped cdt tz = go . fmap mkZdt . calDateTransitionsFor instant $ tz
where
instant = toUnadjustedInstant cdt
(before, after) = aroundCalDateTransition instant $ tz
mkZdt = ZonedDateTime cdt tz
go [] = skipped (mkZdt before) (mkZdt after)
go [zdt] = zdt
go (zdt1:zdt2:[]) = ambiguous zdt1 zdt2
go _ = error "misconfiguration: more than 2 dates returns from calDateTransitionsFor"
toCalendarDateTime :: ZonedDateTime cal -> CalendarDateTime cal
toCalendarDateTime (ZonedDateTime cdt _ _) = cdt
toCalendarDate :: ZonedDateTime cal -> CalendarDate cal
toCalendarDate (ZonedDateTime (CalendarDateTime cd _) _ _) = cd
toLocalTime :: ZonedDateTime cal -> LocalTime
toLocalTime (ZonedDateTime (CalendarDateTime _ lt) _ _) = lt
inDst :: ZonedDateTime cal -> Bool
inDst (ZonedDateTime _ _ (TransitionInfo _ isInDst _)) = isInDst
zoneAbbreviation :: ZonedDateTime cal -> String
zoneAbbreviation (ZonedDateTime _ _ (TransitionInfo _ _ abbr)) = abbr