module Data.HodaTime.TimeZone.Internal
(
   TZIdentifier(..)
  ,TransitionInfo(..)
  ,TransitionExpression(..)
  ,TransitionExpressionInfo(..)
  ,UtcTransitionsMap
  ,IntervalEntry(..)
  ,CalDateTransitionsMap
  ,TimeZone(..)
  ,emptyUtcTransitions
  ,addUtcTransition
  ,addUtcTransitionExpression
  ,activeTransitionFor
  ,nextTransition
  ,emptyCalDateTransitions
  ,addCalDateTransition
  ,addCalDateTransitionExpression
  ,calDateTransitionsFor
  ,aroundCalDateTransition
  ,fixedOffsetZone
  ,expressionToInstant
  ,yearExpressionToInstant
)
where

import Data.Maybe (fromMaybe)
import Data.HodaTime.Instant.Internal (Instant(..), minus, bigBang)
import Data.HodaTime.Offset.Internal (Offset(..), adjustInstant)
import Data.HodaTime.Duration.Internal (fromNanoseconds)
import Data.HodaTime.Calendar.Gregorian.Internal (nthDayToDayOfMonth, yearMonthDayToDays, instantToYearMonthDay)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.IntervalMap.FingerTree (IntervalMap, Interval(..))
import qualified Data.IntervalMap.FingerTree as IMap

data TZIdentifier = UTC | Zone String
  deriving (TZIdentifier -> TZIdentifier -> Bool
(TZIdentifier -> TZIdentifier -> Bool)
-> (TZIdentifier -> TZIdentifier -> Bool) -> Eq TZIdentifier
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TZIdentifier -> TZIdentifier -> Bool
== :: TZIdentifier -> TZIdentifier -> Bool
$c/= :: TZIdentifier -> TZIdentifier -> Bool
/= :: TZIdentifier -> TZIdentifier -> Bool
Eq, Int -> TZIdentifier -> ShowS
[TZIdentifier] -> ShowS
TZIdentifier -> String
(Int -> TZIdentifier -> ShowS)
-> (TZIdentifier -> String)
-> ([TZIdentifier] -> ShowS)
-> Show TZIdentifier
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TZIdentifier -> ShowS
showsPrec :: Int -> TZIdentifier -> ShowS
$cshow :: TZIdentifier -> String
show :: TZIdentifier -> String
$cshowList :: [TZIdentifier] -> ShowS
showList :: [TZIdentifier] -> ShowS
Show)

data TransitionInfo = TransitionInfo { TransitionInfo -> Offset
tiUtcOffset :: Offset, TransitionInfo -> Bool
tiIsDst :: Bool, TransitionInfo -> String
tiAbbreviation :: String }
  deriving (TransitionInfo -> TransitionInfo -> Bool
(TransitionInfo -> TransitionInfo -> Bool)
-> (TransitionInfo -> TransitionInfo -> Bool) -> Eq TransitionInfo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TransitionInfo -> TransitionInfo -> Bool
== :: TransitionInfo -> TransitionInfo -> Bool
$c/= :: TransitionInfo -> TransitionInfo -> Bool
/= :: TransitionInfo -> TransitionInfo -> Bool
Eq, Int -> TransitionInfo -> ShowS
[TransitionInfo] -> ShowS
TransitionInfo -> String
(Int -> TransitionInfo -> ShowS)
-> (TransitionInfo -> String)
-> ([TransitionInfo] -> ShowS)
-> Show TransitionInfo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TransitionInfo -> ShowS
showsPrec :: Int -> TransitionInfo -> ShowS
$cshow :: TransitionInfo -> String
show :: TransitionInfo -> String
$cshowList :: [TransitionInfo] -> ShowS
showList :: [TransitionInfo] -> ShowS
Show)

data TransitionExpression =
  NthDayExpression
  {
     TransitionExpression -> Int
teMonth :: Int
    ,TransitionExpression -> Int
teNthDay :: Int
    ,TransitionExpression -> Int
teDay :: Int
    ,TransitionExpression -> Int
teSeconds :: Int
  }
  | JulianExpression { TransitionExpression -> Bool
jeCountLeaps :: Bool, TransitionExpression -> Int
jeDay :: Int, TransitionExpression -> Int
jeSeconds :: Int }
  deriving (TransitionExpression -> TransitionExpression -> Bool
(TransitionExpression -> TransitionExpression -> Bool)
-> (TransitionExpression -> TransitionExpression -> Bool)
-> Eq TransitionExpression
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TransitionExpression -> TransitionExpression -> Bool
== :: TransitionExpression -> TransitionExpression -> Bool
$c/= :: TransitionExpression -> TransitionExpression -> Bool
/= :: TransitionExpression -> TransitionExpression -> Bool
Eq, Int -> TransitionExpression -> ShowS
[TransitionExpression] -> ShowS
TransitionExpression -> String
(Int -> TransitionExpression -> ShowS)
-> (TransitionExpression -> String)
-> ([TransitionExpression] -> ShowS)
-> Show TransitionExpression
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TransitionExpression -> ShowS
showsPrec :: Int -> TransitionExpression -> ShowS
$cshow :: TransitionExpression -> String
show :: TransitionExpression -> String
$cshowList :: [TransitionExpression] -> ShowS
showList :: [TransitionExpression] -> ShowS
Show)

data TransitionExpressionInfo = TransitionExpressionInfo
  {
     TransitionExpressionInfo -> TransitionExpression
startExpression :: TransitionExpression
    ,TransitionExpressionInfo -> TransitionExpression
endExpression :: TransitionExpression
    ,TransitionExpressionInfo -> TransitionInfo
stdTransInfo :: TransitionInfo
    ,TransitionExpressionInfo -> TransitionInfo
dstTransInfo :: TransitionInfo
  }
  deriving (TransitionExpressionInfo -> TransitionExpressionInfo -> Bool
(TransitionExpressionInfo -> TransitionExpressionInfo -> Bool)
-> (TransitionExpressionInfo -> TransitionExpressionInfo -> Bool)
-> Eq TransitionExpressionInfo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TransitionExpressionInfo -> TransitionExpressionInfo -> Bool
== :: TransitionExpressionInfo -> TransitionExpressionInfo -> Bool
$c/= :: TransitionExpressionInfo -> TransitionExpressionInfo -> Bool
/= :: TransitionExpressionInfo -> TransitionExpressionInfo -> Bool
Eq, Int -> TransitionExpressionInfo -> ShowS
[TransitionExpressionInfo] -> ShowS
TransitionExpressionInfo -> String
(Int -> TransitionExpressionInfo -> ShowS)
-> (TransitionExpressionInfo -> String)
-> ([TransitionExpressionInfo] -> ShowS)
-> Show TransitionExpressionInfo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TransitionExpressionInfo -> ShowS
showsPrec :: Int -> TransitionExpressionInfo -> ShowS
$cshow :: TransitionExpressionInfo -> String
show :: TransitionExpressionInfo -> String
$cshowList :: [TransitionExpressionInfo] -> ShowS
showList :: [TransitionExpressionInfo] -> ShowS
Show)

data TransitionInfoOrExp = 
    TransitionInfoFixed TransitionInfo
  | TransitionInfoExpression TransitionExpressionInfo
    deriving (TransitionInfoOrExp -> TransitionInfoOrExp -> Bool
(TransitionInfoOrExp -> TransitionInfoOrExp -> Bool)
-> (TransitionInfoOrExp -> TransitionInfoOrExp -> Bool)
-> Eq TransitionInfoOrExp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TransitionInfoOrExp -> TransitionInfoOrExp -> Bool
== :: TransitionInfoOrExp -> TransitionInfoOrExp -> Bool
$c/= :: TransitionInfoOrExp -> TransitionInfoOrExp -> Bool
/= :: TransitionInfoOrExp -> TransitionInfoOrExp -> Bool
Eq, Int -> TransitionInfoOrExp -> ShowS
[TransitionInfoOrExp] -> ShowS
TransitionInfoOrExp -> String
(Int -> TransitionInfoOrExp -> ShowS)
-> (TransitionInfoOrExp -> String)
-> ([TransitionInfoOrExp] -> ShowS)
-> Show TransitionInfoOrExp
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TransitionInfoOrExp -> ShowS
showsPrec :: Int -> TransitionInfoOrExp -> ShowS
$cshow :: TransitionInfoOrExp -> String
show :: TransitionInfoOrExp -> String
$cshowList :: [TransitionInfoOrExp] -> ShowS
showList :: [TransitionInfoOrExp] -> ShowS
Show)

-- UTC instant to transition

type UtcTransitionsMap = Map Instant TransitionInfoOrExp

emptyUtcTransitions :: UtcTransitionsMap
emptyUtcTransitions :: UtcTransitionsMap
emptyUtcTransitions = UtcTransitionsMap
forall k a. Map k a
Map.empty

addUtcTransition :: Instant -> TransitionInfo -> UtcTransitionsMap -> UtcTransitionsMap
addUtcTransition :: Instant -> TransitionInfo -> UtcTransitionsMap -> UtcTransitionsMap
addUtcTransition Instant
i TransitionInfo
fti = Instant
-> TransitionInfoOrExp -> UtcTransitionsMap -> UtcTransitionsMap
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Instant
i (TransitionInfo -> TransitionInfoOrExp
TransitionInfoFixed TransitionInfo
fti)

addUtcTransitionExpression :: Instant -> TransitionExpressionInfo -> UtcTransitionsMap -> UtcTransitionsMap
addUtcTransitionExpression :: Instant
-> TransitionExpressionInfo
-> UtcTransitionsMap
-> UtcTransitionsMap
addUtcTransitionExpression Instant
i TransitionExpressionInfo
texp = Instant
-> TransitionInfoOrExp -> UtcTransitionsMap -> UtcTransitionsMap
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Instant
i (TransitionExpressionInfo -> TransitionInfoOrExp
TransitionInfoExpression TransitionExpressionInfo
texp)

activeTransitionFor :: Instant -> TimeZone -> TransitionInfo
activeTransitionFor :: Instant -> TimeZone -> TransitionInfo
activeTransitionFor Instant
i (TimeZone TZIdentifier
_ UtcTransitionsMap
utcM CalDateTransitionsMap
_) = Instant
-> ((Instant, Instant, TransitionInfo, TransitionInfo)
    -> TransitionInfo)
-> (TransitionInfo -> TransitionInfo)
-> TransitionInfoOrExp
-> TransitionInfo
forall a.
Instant
-> ((Instant, Instant, TransitionInfo, TransitionInfo) -> a)
-> (TransitionInfo -> a)
-> TransitionInfoOrExp
-> a
fromTransInfo Instant
i (Instant, Instant, TransitionInfo, TransitionInfo)
-> TransitionInfo
forall {c}. (Instant, Instant, c, c) -> c
f TransitionInfo -> TransitionInfo
forall a. a -> a
id (TransitionInfoOrExp -> TransitionInfo)
-> (Maybe (Instant, TransitionInfoOrExp) -> TransitionInfoOrExp)
-> Maybe (Instant, TransitionInfoOrExp)
-> TransitionInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Instant, TransitionInfoOrExp) -> TransitionInfoOrExp
forall a b. (a, b) -> b
snd ((Instant, TransitionInfoOrExp) -> TransitionInfoOrExp)
-> (Maybe (Instant, TransitionInfoOrExp)
    -> (Instant, TransitionInfoOrExp))
-> Maybe (Instant, TransitionInfoOrExp)
-> TransitionInfoOrExp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Instant, TransitionInfoOrExp)
-> Maybe (Instant, TransitionInfoOrExp)
-> (Instant, TransitionInfoOrExp)
forall a. a -> Maybe a -> a
fromMaybe (UtcTransitionsMap -> (Instant, TransitionInfoOrExp)
forall k a. Map k a -> (k, a)
Map.findMin UtcTransitionsMap
utcM) (Maybe (Instant, TransitionInfoOrExp) -> TransitionInfo)
-> Maybe (Instant, TransitionInfoOrExp) -> TransitionInfo
forall a b. (a -> b) -> a -> b
$ Instant
-> UtcTransitionsMap -> Maybe (Instant, TransitionInfoOrExp)
forall k v. Ord k => k -> Map k v -> Maybe (k, v)
Map.lookupLE Instant
i UtcTransitionsMap
utcM     -- NOTE: The findMin case should be impossible
  where
    f :: (Instant, Instant, c, c) -> c
f (Instant
dstStart, Instant
dstEnd, c
stdTI, c
dstTI) = if Instant
i Instant -> Instant -> Bool
forall a. Ord a => a -> a -> Bool
<= Instant
dstStart Bool -> Bool -> Bool
|| Instant
i Instant -> Instant -> Bool
forall a. Ord a => a -> a -> Bool
>= Instant
dstEnd then c
stdTI else c
dstTI

-- TODO: We would need to get the next year to complete this function but let's see if it's actually used before doing more work
nextTransition :: Instant -> TimeZone -> (Instant, TransitionInfo)
nextTransition :: Instant -> TimeZone -> (Instant, TransitionInfo)
nextTransition Instant
i (TimeZone TZIdentifier
_ UtcTransitionsMap
utcM CalDateTransitionsMap
_) = (Instant, TransitionInfoOrExp) -> (Instant, TransitionInfo)
f ((Instant, TransitionInfoOrExp) -> (Instant, TransitionInfo))
-> (Maybe (Instant, TransitionInfoOrExp)
    -> (Instant, TransitionInfoOrExp))
-> Maybe (Instant, TransitionInfoOrExp)
-> (Instant, TransitionInfo)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Instant, TransitionInfoOrExp)
-> Maybe (Instant, TransitionInfoOrExp)
-> (Instant, TransitionInfoOrExp)
forall a. a -> Maybe a -> a
fromMaybe (UtcTransitionsMap -> (Instant, TransitionInfoOrExp)
forall k a. Map k a -> (k, a)
Map.findMax UtcTransitionsMap
utcM) (Maybe (Instant, TransitionInfoOrExp) -> (Instant, TransitionInfo))
-> Maybe (Instant, TransitionInfoOrExp)
-> (Instant, TransitionInfo)
forall a b. (a -> b) -> a -> b
$ Instant
-> UtcTransitionsMap -> Maybe (Instant, TransitionInfoOrExp)
forall k v. Ord k => k -> Map k v -> Maybe (k, v)
Map.lookupGT Instant
i UtcTransitionsMap
utcM
  where
    f :: (Instant, TransitionInfoOrExp) -> (Instant, TransitionInfo)
f (Instant
i', TransitionInfoOrExp
ti) = Instant
-> ((Instant, Instant, TransitionInfo, TransitionInfo)
    -> (Instant, TransitionInfo))
-> (TransitionInfo -> (Instant, TransitionInfo))
-> TransitionInfoOrExp
-> (Instant, TransitionInfo)
forall a.
Instant
-> ((Instant, Instant, TransitionInfo, TransitionInfo) -> a)
-> (TransitionInfo -> a)
-> TransitionInfoOrExp
-> a
fromTransInfo Instant
i (Instant, Instant, TransitionInfo, TransitionInfo)
-> (Instant, TransitionInfo)
forall {b}. (Instant, Instant, b, b) -> (Instant, b)
g (\TransitionInfo
ti' -> (Instant
i', TransitionInfo
ti')) TransitionInfoOrExp
ti
    g :: (Instant, Instant, b, b) -> (Instant, b)
g (Instant
dstStart, Instant
dstEnd, b
stdTI, b
dstTI) = if Instant
i Instant -> Instant -> Bool
forall a. Ord a => a -> a -> Bool
< Instant
dstStart then (Instant
dstStart, b
dstTI) else if Instant
i Instant -> Instant -> Bool
forall a. Ord a => a -> a -> Bool
< Instant
dstEnd then (Instant
dstEnd, b
stdTI) else String -> (Instant, b)
forall a. HasCallStack => String -> a
error String
"nextTransition: need next year"

-- CalendarDate to transition

data IntervalEntry a =
    Smallest
  | Entry a
  | Largest
  deriving (IntervalEntry a -> IntervalEntry a -> Bool
(IntervalEntry a -> IntervalEntry a -> Bool)
-> (IntervalEntry a -> IntervalEntry a -> Bool)
-> Eq (IntervalEntry a)
forall a. Eq a => IntervalEntry a -> IntervalEntry a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => IntervalEntry a -> IntervalEntry a -> Bool
== :: IntervalEntry a -> IntervalEntry a -> Bool
$c/= :: forall a. Eq a => IntervalEntry a -> IntervalEntry a -> Bool
/= :: IntervalEntry a -> IntervalEntry a -> Bool
Eq, Eq (IntervalEntry a)
Eq (IntervalEntry a) =>
(IntervalEntry a -> IntervalEntry a -> Ordering)
-> (IntervalEntry a -> IntervalEntry a -> Bool)
-> (IntervalEntry a -> IntervalEntry a -> Bool)
-> (IntervalEntry a -> IntervalEntry a -> Bool)
-> (IntervalEntry a -> IntervalEntry a -> Bool)
-> (IntervalEntry a -> IntervalEntry a -> IntervalEntry a)
-> (IntervalEntry a -> IntervalEntry a -> IntervalEntry a)
-> Ord (IntervalEntry a)
IntervalEntry a -> IntervalEntry a -> Bool
IntervalEntry a -> IntervalEntry a -> Ordering
IntervalEntry a -> IntervalEntry a -> IntervalEntry a
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. Ord a => Eq (IntervalEntry a)
forall a. Ord a => IntervalEntry a -> IntervalEntry a -> Bool
forall a. Ord a => IntervalEntry a -> IntervalEntry a -> Ordering
forall a.
Ord a =>
IntervalEntry a -> IntervalEntry a -> IntervalEntry a
$ccompare :: forall a. Ord a => IntervalEntry a -> IntervalEntry a -> Ordering
compare :: IntervalEntry a -> IntervalEntry a -> Ordering
$c< :: forall a. Ord a => IntervalEntry a -> IntervalEntry a -> Bool
< :: IntervalEntry a -> IntervalEntry a -> Bool
$c<= :: forall a. Ord a => IntervalEntry a -> IntervalEntry a -> Bool
<= :: IntervalEntry a -> IntervalEntry a -> Bool
$c> :: forall a. Ord a => IntervalEntry a -> IntervalEntry a -> Bool
> :: IntervalEntry a -> IntervalEntry a -> Bool
$c>= :: forall a. Ord a => IntervalEntry a -> IntervalEntry a -> Bool
>= :: IntervalEntry a -> IntervalEntry a -> Bool
$cmax :: forall a.
Ord a =>
IntervalEntry a -> IntervalEntry a -> IntervalEntry a
max :: IntervalEntry a -> IntervalEntry a -> IntervalEntry a
$cmin :: forall a.
Ord a =>
IntervalEntry a -> IntervalEntry a -> IntervalEntry a
min :: IntervalEntry a -> IntervalEntry a -> IntervalEntry a
Ord, Int -> IntervalEntry a -> ShowS
[IntervalEntry a] -> ShowS
IntervalEntry a -> String
(Int -> IntervalEntry a -> ShowS)
-> (IntervalEntry a -> String)
-> ([IntervalEntry a] -> ShowS)
-> Show (IntervalEntry a)
forall a. Show a => Int -> IntervalEntry a -> ShowS
forall a. Show a => [IntervalEntry a] -> ShowS
forall a. Show a => IntervalEntry a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Show a => Int -> IntervalEntry a -> ShowS
showsPrec :: Int -> IntervalEntry a -> ShowS
$cshow :: forall a. Show a => IntervalEntry a -> String
show :: IntervalEntry a -> String
$cshowList :: forall a. Show a => [IntervalEntry a] -> ShowS
showList :: [IntervalEntry a] -> ShowS
Show)

type CalDateTransitionsMap = IntervalMap (IntervalEntry Instant) TransitionInfoOrExp

emptyCalDateTransitions :: CalDateTransitionsMap
emptyCalDateTransitions :: CalDateTransitionsMap
emptyCalDateTransitions = CalDateTransitionsMap
forall v a. Ord v => IntervalMap v a
IMap.empty

addCalDateTransition :: IntervalEntry Instant -> IntervalEntry Instant -> TransitionInfo -> CalDateTransitionsMap -> CalDateTransitionsMap
addCalDateTransition :: IntervalEntry Instant
-> IntervalEntry Instant
-> TransitionInfo
-> CalDateTransitionsMap
-> CalDateTransitionsMap
addCalDateTransition IntervalEntry Instant
b IntervalEntry Instant
e TransitionInfo
fti = Interval (IntervalEntry Instant)
-> TransitionInfoOrExp
-> CalDateTransitionsMap
-> CalDateTransitionsMap
forall v a.
Ord v =>
Interval v -> a -> IntervalMap v a -> IntervalMap v a
IMap.insert Interval (IntervalEntry Instant)
interval (TransitionInfo -> TransitionInfoOrExp
TransitionInfoFixed TransitionInfo
fti)
  where
    interval :: Interval (IntervalEntry Instant)
interval = IntervalEntry Instant
-> IntervalEntry Instant -> Interval (IntervalEntry Instant)
forall v. v -> v -> Interval v
Interval IntervalEntry Instant
b IntervalEntry Instant
e

addCalDateTransitionExpression :: IntervalEntry Instant -> IntervalEntry Instant -> TransitionExpressionInfo -> CalDateTransitionsMap -> CalDateTransitionsMap
addCalDateTransitionExpression :: IntervalEntry Instant
-> IntervalEntry Instant
-> TransitionExpressionInfo
-> CalDateTransitionsMap
-> CalDateTransitionsMap
addCalDateTransitionExpression IntervalEntry Instant
b IntervalEntry Instant
e TransitionExpressionInfo
texp = Interval (IntervalEntry Instant)
-> TransitionInfoOrExp
-> CalDateTransitionsMap
-> CalDateTransitionsMap
forall v a.
Ord v =>
Interval v -> a -> IntervalMap v a -> IntervalMap v a
IMap.insert Interval (IntervalEntry Instant)
interval (TransitionExpressionInfo -> TransitionInfoOrExp
TransitionInfoExpression TransitionExpressionInfo
texp)
  where
    interval :: Interval (IntervalEntry Instant)
interval = IntervalEntry Instant
-> IntervalEntry Instant -> Interval (IntervalEntry Instant)
forall v. v -> v -> Interval v
Interval IntervalEntry Instant
b IntervalEntry Instant
e

calDateTransitionsFor :: Instant -> TimeZone -> [TransitionInfo]
calDateTransitionsFor :: Instant -> TimeZone -> [TransitionInfo]
calDateTransitionsFor Instant
i (TimeZone TZIdentifier
_ UtcTransitionsMap
_ CalDateTransitionsMap
cdtMap) = ((Interval (IntervalEntry Instant), TransitionInfoOrExp)
 -> [TransitionInfo])
-> [(Interval (IntervalEntry Instant), TransitionInfoOrExp)]
-> [TransitionInfo]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (Instant
-> ((Instant, Instant, TransitionInfo, TransitionInfo)
    -> [TransitionInfo])
-> (TransitionInfo -> [TransitionInfo])
-> TransitionInfoOrExp
-> [TransitionInfo]
forall a.
Instant
-> ((Instant, Instant, TransitionInfo, TransitionInfo) -> a)
-> (TransitionInfo -> a)
-> TransitionInfoOrExp
-> a
fromTransInfo Instant
i (Instant, Instant, TransitionInfo, TransitionInfo)
-> [TransitionInfo]
f (TransitionInfo -> [TransitionInfo] -> [TransitionInfo]
forall a. a -> [a] -> [a]
:[]) (TransitionInfoOrExp -> [TransitionInfo])
-> ((Interval (IntervalEntry Instant), TransitionInfoOrExp)
    -> TransitionInfoOrExp)
-> (Interval (IntervalEntry Instant), TransitionInfoOrExp)
-> [TransitionInfo]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Interval (IntervalEntry Instant), TransitionInfoOrExp)
-> TransitionInfoOrExp
forall a b. (a, b) -> b
snd) ([(Interval (IntervalEntry Instant), TransitionInfoOrExp)]
 -> [TransitionInfo])
-> (CalDateTransitionsMap
    -> [(Interval (IntervalEntry Instant), TransitionInfoOrExp)])
-> CalDateTransitionsMap
-> [TransitionInfo]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CalDateTransitionsMap
-> [(Interval (IntervalEntry Instant), TransitionInfoOrExp)]
forall {a}.
IntervalMap (IntervalEntry Instant) a
-> [(Interval (IntervalEntry Instant), a)]
search (CalDateTransitionsMap -> [TransitionInfo])
-> CalDateTransitionsMap -> [TransitionInfo]
forall a b. (a -> b) -> a -> b
$ CalDateTransitionsMap
cdtMap
  where
    search :: IntervalMap (IntervalEntry Instant) a
-> [(Interval (IntervalEntry Instant), a)]
search = IntervalEntry Instant
-> IntervalMap (IntervalEntry Instant) a
-> [(Interval (IntervalEntry Instant), a)]
forall v a. Ord v => v -> IntervalMap v a -> [(Interval v, a)]
IMap.search (Instant -> IntervalEntry Instant
forall a. a -> IntervalEntry a
Entry Instant
i)
    f :: (Instant, Instant, TransitionInfo, TransitionInfo)
-> [TransitionInfo]
f = ((Interval (IntervalEntry Instant), TransitionInfo)
 -> TransitionInfo)
-> [(Interval (IntervalEntry Instant), TransitionInfo)]
-> [TransitionInfo]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Interval (IntervalEntry Instant), TransitionInfo)
-> TransitionInfo
forall a b. (a, b) -> b
snd ([(Interval (IntervalEntry Instant), TransitionInfo)]
 -> [TransitionInfo])
-> ((Instant, Instant, TransitionInfo, TransitionInfo)
    -> [(Interval (IntervalEntry Instant), TransitionInfo)])
-> (Instant, Instant, TransitionInfo, TransitionInfo)
-> [TransitionInfo]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IntervalMap (IntervalEntry Instant) TransitionInfo
-> [(Interval (IntervalEntry Instant), TransitionInfo)]
forall {a}.
IntervalMap (IntervalEntry Instant) a
-> [(Interval (IntervalEntry Instant), a)]
search (IntervalMap (IntervalEntry Instant) TransitionInfo
 -> [(Interval (IntervalEntry Instant), TransitionInfo)])
-> ((Instant, Instant, TransitionInfo, TransitionInfo)
    -> IntervalMap (IntervalEntry Instant) TransitionInfo)
-> (Instant, Instant, TransitionInfo, TransitionInfo)
-> [(Interval (IntervalEntry Instant), TransitionInfo)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Instant, Instant, TransitionInfo, TransitionInfo)
-> IntervalMap (IntervalEntry Instant) TransitionInfo
buildFixedTransIMap

-- TODO: this function need major cleanup, this implementation is really nasty and almost certainly unsafe
aroundCalDateTransition :: Instant -> TimeZone -> (TransitionInfo, TransitionInfo)
aroundCalDateTransition :: Instant -> TimeZone -> (TransitionInfo, TransitionInfo)
aroundCalDateTransition Instant
i (TimeZone TZIdentifier
_ UtcTransitionsMap
_ CalDateTransitionsMap
cdtMap) = [TransitionInfoOrExp] -> (TransitionInfo, TransitionInfo)
go ([TransitionInfoOrExp] -> (TransitionInfo, TransitionInfo))
-> (CalDateTransitionsMap -> [TransitionInfoOrExp])
-> CalDateTransitionsMap
-> (TransitionInfo, TransitionInfo)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Interval (IntervalEntry Instant), TransitionInfoOrExp)
 -> TransitionInfoOrExp)
-> [(Interval (IntervalEntry Instant), TransitionInfoOrExp)]
-> [TransitionInfoOrExp]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Interval (IntervalEntry Instant), TransitionInfoOrExp)
-> TransitionInfoOrExp
forall a b. (a, b) -> b
snd ([(Interval (IntervalEntry Instant), TransitionInfoOrExp)]
 -> [TransitionInfoOrExp])
-> (CalDateTransitionsMap
    -> [(Interval (IntervalEntry Instant), TransitionInfoOrExp)])
-> CalDateTransitionsMap
-> [TransitionInfoOrExp]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IntervalEntry Instant
-> CalDateTransitionsMap
-> [(Interval (IntervalEntry Instant), TransitionInfoOrExp)]
forall v a. Ord v => v -> IntervalMap v a -> [(Interval v, a)]
IMap.search (Instant -> IntervalEntry Instant
forall a. a -> IntervalEntry a
Entry Instant
i) (CalDateTransitionsMap -> (TransitionInfo, TransitionInfo))
-> CalDateTransitionsMap -> (TransitionInfo, TransitionInfo)
forall a b. (a -> b) -> a -> b
$ CalDateTransitionsMap
cdtMap
    where
      go :: [TransitionInfoOrExp] -> (TransitionInfo, TransitionInfo)
go [] = (TransitionInfo
before, TransitionInfo
after)
      go [(TransitionInfoExpression (TransitionExpressionInfo TransitionExpression
_ TransitionExpression
_ TransitionInfo
stdTI TransitionInfo
dstTI))] = (TransitionInfo
stdTI, TransitionInfo
dstTI) -- NOTE: Should be the only way this happens
      go [TransitionInfoOrExp]
x = String -> (TransitionInfo, TransitionInfo)
forall a. HasCallStack => String -> a
error (String -> (TransitionInfo, TransitionInfo))
-> String -> (TransitionInfo, TransitionInfo)
forall a b. (a -> b) -> a -> b
$ String
"aroundCalDateTransition: unexpected search result" String -> ShowS
forall a. [a] -> [a] -> [a]
++ [TransitionInfoOrExp] -> String
forall a. Show a => a -> String
show [TransitionInfoOrExp]
x
      before :: TransitionInfo
before = Instant
-> ((Instant, Instant, TransitionInfo, TransitionInfo)
    -> TransitionInfo)
-> (TransitionInfo -> TransitionInfo)
-> TransitionInfoOrExp
-> TransitionInfo
forall a.
Instant
-> ((Instant, Instant, TransitionInfo, TransitionInfo) -> a)
-> (TransitionInfo -> a)
-> TransitionInfoOrExp
-> a
fromTransInfo Instant
i (Instant, Instant, TransitionInfo, TransitionInfo)
-> TransitionInfo
forall {a}. a
bomb TransitionInfo -> TransitionInfo
forall a. a -> a
id (TransitionInfoOrExp -> TransitionInfo)
-> (CalDateTransitionsMap -> TransitionInfoOrExp)
-> CalDateTransitionsMap
-> TransitionInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Interval (IntervalEntry Instant), TransitionInfoOrExp)
-> TransitionInfoOrExp
forall a b. (a, b) -> b
snd ((Interval (IntervalEntry Instant), TransitionInfoOrExp)
 -> TransitionInfoOrExp)
-> (CalDateTransitionsMap
    -> (Interval (IntervalEntry Instant), TransitionInfoOrExp))
-> CalDateTransitionsMap
-> TransitionInfoOrExp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(Interval (IntervalEntry Instant), TransitionInfoOrExp)]
-> (Interval (IntervalEntry Instant), TransitionInfoOrExp)
forall {a}. [a] -> a
go' ([(Interval (IntervalEntry Instant), TransitionInfoOrExp)]
 -> (Interval (IntervalEntry Instant), TransitionInfoOrExp))
-> (CalDateTransitionsMap
    -> [(Interval (IntervalEntry Instant), TransitionInfoOrExp)])
-> CalDateTransitionsMap
-> (Interval (IntervalEntry Instant), TransitionInfoOrExp)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (IntervalEntry Instant
 -> CalDateTransitionsMap
 -> [(Interval (IntervalEntry Instant), TransitionInfoOrExp)])
-> CalDateTransitionsMap
-> IntervalEntry Instant
-> [(Interval (IntervalEntry Instant), TransitionInfoOrExp)]
forall a b c. (a -> b -> c) -> b -> a -> c
flip IntervalEntry Instant
-> CalDateTransitionsMap
-> [(Interval (IntervalEntry Instant), TransitionInfoOrExp)]
forall v a. Ord v => v -> IntervalMap v a -> [(Interval v, a)]
IMap.search CalDateTransitionsMap
cdtMap (IntervalEntry Instant
 -> [(Interval (IntervalEntry Instant), TransitionInfoOrExp)])
-> (CalDateTransitionsMap -> IntervalEntry Instant)
-> CalDateTransitionsMap
-> [(Interval (IntervalEntry Instant), TransitionInfoOrExp)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Interval (IntervalEntry Instant) -> IntervalEntry Instant
forall v. Interval v -> v
IMap.high (Interval (IntervalEntry Instant) -> IntervalEntry Instant)
-> (CalDateTransitionsMap -> Interval (IntervalEntry Instant))
-> CalDateTransitionsMap
-> IntervalEntry Instant
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Interval (IntervalEntry Instant)
-> Maybe (Interval (IntervalEntry Instant))
-> Interval (IntervalEntry Instant)
forall a. a -> Maybe a -> a
fromMaybe (String -> Interval (IntervalEntry Instant)
forall a. HasCallStack => String -> a
error String
"around.before: fixme") (Maybe (Interval (IntervalEntry Instant))
 -> Interval (IntervalEntry Instant))
-> (CalDateTransitionsMap
    -> Maybe (Interval (IntervalEntry Instant)))
-> CalDateTransitionsMap
-> Interval (IntervalEntry Instant)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CalDateTransitionsMap -> Maybe (Interval (IntervalEntry Instant))
forall v a. Ord v => IntervalMap v a -> Maybe (Interval v)
IMap.bounds (CalDateTransitionsMap -> TransitionInfo)
-> CalDateTransitionsMap -> TransitionInfo
forall a b. (a -> b) -> a -> b
$ CalDateTransitionsMap
front
      after :: TransitionInfo
after = Instant
-> ((Instant, Instant, TransitionInfo, TransitionInfo)
    -> TransitionInfo)
-> (TransitionInfo -> TransitionInfo)
-> TransitionInfoOrExp
-> TransitionInfo
forall a.
Instant
-> ((Instant, Instant, TransitionInfo, TransitionInfo) -> a)
-> (TransitionInfo -> a)
-> TransitionInfoOrExp
-> a
fromTransInfo Instant
i (Instant, Instant, TransitionInfo, TransitionInfo)
-> TransitionInfo
forall {a}. a
bomb TransitionInfo -> TransitionInfo
forall a. a -> a
id (TransitionInfoOrExp -> TransitionInfo)
-> (CalDateTransitionsMap -> TransitionInfoOrExp)
-> CalDateTransitionsMap
-> TransitionInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Interval (IntervalEntry Instant), TransitionInfoOrExp)
-> TransitionInfoOrExp
forall a b. (a, b) -> b
snd ((Interval (IntervalEntry Instant), TransitionInfoOrExp)
 -> TransitionInfoOrExp)
-> (CalDateTransitionsMap
    -> (Interval (IntervalEntry Instant), TransitionInfoOrExp))
-> CalDateTransitionsMap
-> TransitionInfoOrExp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Interval (IntervalEntry Instant), TransitionInfoOrExp),
 CalDateTransitionsMap)
-> (Interval (IntervalEntry Instant), TransitionInfoOrExp)
forall a b. (a, b) -> a
fst (((Interval (IntervalEntry Instant), TransitionInfoOrExp),
  CalDateTransitionsMap)
 -> (Interval (IntervalEntry Instant), TransitionInfoOrExp))
-> (CalDateTransitionsMap
    -> ((Interval (IntervalEntry Instant), TransitionInfoOrExp),
        CalDateTransitionsMap))
-> CalDateTransitionsMap
-> (Interval (IntervalEntry Instant), TransitionInfoOrExp)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Interval (IntervalEntry Instant), TransitionInfoOrExp),
 CalDateTransitionsMap)
-> Maybe
     ((Interval (IntervalEntry Instant), TransitionInfoOrExp),
      CalDateTransitionsMap)
-> ((Interval (IntervalEntry Instant), TransitionInfoOrExp),
    CalDateTransitionsMap)
forall a. a -> Maybe a -> a
fromMaybe (String
-> ((Interval (IntervalEntry Instant), TransitionInfoOrExp),
    CalDateTransitionsMap)
forall a. HasCallStack => String -> a
error String
"around.after: fixme") (Maybe
   ((Interval (IntervalEntry Instant), TransitionInfoOrExp),
    CalDateTransitionsMap)
 -> ((Interval (IntervalEntry Instant), TransitionInfoOrExp),
     CalDateTransitionsMap))
-> (CalDateTransitionsMap
    -> Maybe
         ((Interval (IntervalEntry Instant), TransitionInfoOrExp),
          CalDateTransitionsMap))
-> CalDateTransitionsMap
-> ((Interval (IntervalEntry Instant), TransitionInfoOrExp),
    CalDateTransitionsMap)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CalDateTransitionsMap
-> Maybe
     ((Interval (IntervalEntry Instant), TransitionInfoOrExp),
      CalDateTransitionsMap)
forall v a.
Ord v =>
IntervalMap v a -> Maybe ((Interval v, a), IntervalMap v a)
IMap.leastView (CalDateTransitionsMap -> TransitionInfo)
-> CalDateTransitionsMap -> TransitionInfo
forall a b. (a -> b) -> a -> b
$ CalDateTransitionsMap
back
      (CalDateTransitionsMap
front, CalDateTransitionsMap
back) = IntervalEntry Instant
-> CalDateTransitionsMap
-> (CalDateTransitionsMap, CalDateTransitionsMap)
forall v a.
Ord v =>
v -> IntervalMap v a -> (IntervalMap v a, IntervalMap v a)
IMap.splitAfter (Instant -> IntervalEntry Instant
forall a. a -> IntervalEntry a
Entry Instant
i) CalDateTransitionsMap
cdtMap
      go' :: [a] -> a
go' [] = String -> a
forall a. HasCallStack => String -> a
error String
"aroundCalDateTransition: no before transitions"
      go' [a
tei] = a
tei
      go' [a]
_ = String -> a
forall a. HasCallStack => String -> a
error String
"aroundCalDateTransition: too many before transitions"
      bomb :: a
bomb = String -> a
forall a. HasCallStack => String -> a
error String
"aroundCalDateTransition: got expression when fixed expected"

-- | Represents a time zone.  A 'TimeZone' can be used to instanciate a 'ZoneDateTime' from either and 'Instant' or a 'CalendarDateTime'
data TimeZone =
  TimeZone
    {
       TimeZone -> TZIdentifier
zoneName :: TZIdentifier
      ,TimeZone -> UtcTransitionsMap
utcTransitionsMap :: UtcTransitionsMap
      ,TimeZone -> CalDateTransitionsMap
calDateTransitionsMap :: CalDateTransitionsMap
    }
  deriving (TimeZone -> TimeZone -> Bool
(TimeZone -> TimeZone -> Bool)
-> (TimeZone -> TimeZone -> Bool) -> Eq TimeZone
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TimeZone -> TimeZone -> Bool
== :: TimeZone -> TimeZone -> Bool
$c/= :: TimeZone -> TimeZone -> Bool
/= :: TimeZone -> TimeZone -> Bool
Eq, Int -> TimeZone -> ShowS
[TimeZone] -> ShowS
TimeZone -> String
(Int -> TimeZone -> ShowS)
-> (TimeZone -> String) -> ([TimeZone] -> ShowS) -> Show TimeZone
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TimeZone -> ShowS
showsPrec :: Int -> TimeZone -> ShowS
$cshow :: TimeZone -> String
show :: TimeZone -> String
$cshowList :: [TimeZone] -> ShowS
showList :: [TimeZone] -> ShowS
Show)

-- constructors

fixedOffsetZone :: String -> Offset -> (UtcTransitionsMap, CalDateTransitionsMap, TransitionInfo)
fixedOffsetZone :: String
-> Offset
-> (UtcTransitionsMap, CalDateTransitionsMap, TransitionInfo)
fixedOffsetZone String
tzName Offset
offset = (UtcTransitionsMap
utcM, CalDateTransitionsMap
calDateM, TransitionInfo
tInfo)
    where
      utcM :: UtcTransitionsMap
utcM = Instant -> TransitionInfo -> UtcTransitionsMap -> UtcTransitionsMap
addUtcTransition Instant
bigBang TransitionInfo
tInfo UtcTransitionsMap
emptyUtcTransitions
      calDateM :: CalDateTransitionsMap
calDateM = IntervalEntry Instant
-> IntervalEntry Instant
-> TransitionInfo
-> CalDateTransitionsMap
-> CalDateTransitionsMap
addCalDateTransition IntervalEntry Instant
forall a. IntervalEntry a
Smallest IntervalEntry Instant
forall a. IntervalEntry a
Largest TransitionInfo
tInfo CalDateTransitionsMap
emptyCalDateTransitions
      tInfo :: TransitionInfo
tInfo = Offset -> Bool -> String -> TransitionInfo
TransitionInfo Offset
offset Bool
False String
tzName

-- helper functions

fromTransInfo :: Instant -> ((Instant, Instant, TransitionInfo, TransitionInfo) -> a) -> (TransitionInfo -> a) -> TransitionInfoOrExp -> a
fromTransInfo :: forall a.
Instant
-> ((Instant, Instant, TransitionInfo, TransitionInfo) -> a)
-> (TransitionInfo -> a)
-> TransitionInfoOrExp
-> a
fromTransInfo Instant
_ (Instant, Instant, TransitionInfo, TransitionInfo) -> a
_ TransitionInfo -> a
f (TransitionInfoFixed TransitionInfo
ti) = TransitionInfo -> a
f TransitionInfo
ti
fromTransInfo Instant
i (Instant, Instant, TransitionInfo, TransitionInfo) -> a
f TransitionInfo -> a
_ (TransitionInfoExpression (TransitionExpressionInfo TransitionExpression
startExpr TransitionExpression
endExpr TransitionInfo
stdTI TransitionInfo
dstTI)) = (Instant, Instant, TransitionInfo, TransitionInfo) -> a
f (Instant
dstStart, Instant
dstEnd, TransitionInfo
stdTI, TransitionInfo
dstTI)
  where
    dstStart :: Instant
dstStart = Instant -> TransitionExpression -> Instant
expressionToInstant Instant
i TransitionExpression
startExpr
    dstEnd :: Instant
dstEnd = Instant -> TransitionExpression -> Instant
expressionToInstant Instant
i TransitionExpression
endExpr

-- NOTE: We have to store expressions in the year they take effect so this is the first place we can resolve
--       the actual map.  Otherwise we'd have to create two per year
buildFixedTransIMap :: (Instant, Instant, TransitionInfo, TransitionInfo) -> IntervalMap (IntervalEntry Instant) TransitionInfo
buildFixedTransIMap :: (Instant, Instant, TransitionInfo, TransitionInfo)
-> IntervalMap (IntervalEntry Instant) TransitionInfo
buildFixedTransIMap (Instant
start, Instant
end, TransitionInfo
stdTI, TransitionInfo
dstTI) = [(IntervalEntry Instant, IntervalEntry Instant, TransitionInfo)]
-> IntervalMap (IntervalEntry Instant) TransitionInfo
-> IntervalMap (IntervalEntry Instant) TransitionInfo
forall {v} {a}.
Ord v =>
[(v, v, a)] -> IntervalMap v a -> IntervalMap v a
mkMap [(IntervalEntry Instant, IntervalEntry Instant, TransitionInfo)]
entries IntervalMap (IntervalEntry Instant) TransitionInfo
forall a. Monoid a => a
mempty
  where
    mkMap :: [(v, v, a)] -> IntervalMap v a -> IntervalMap v a
mkMap [] IntervalMap v a
m = IntervalMap v a
m
    mkMap ((v
b, v
e, a
ti):[(v, v, a)]
xs) IntervalMap v a
m = [(v, v, a)] -> IntervalMap v a -> IntervalMap v a
mkMap [(v, v, a)]
xs (IntervalMap v a -> IntervalMap v a)
-> IntervalMap v a -> IntervalMap v a
forall a b. (a -> b) -> a -> b
$ v -> v -> a -> IntervalMap v a -> IntervalMap v a
forall {v} {a}.
Ord v =>
v -> v -> a -> IntervalMap v a -> IntervalMap v a
addEntry v
b v
e a
ti IntervalMap v a
m
    addEntry :: v -> v -> a -> IntervalMap v a -> IntervalMap v a
addEntry v
b v
e a
ti = Interval v -> a -> IntervalMap v a -> IntervalMap v a
forall v a.
Ord v =>
Interval v -> a -> IntervalMap v a -> IntervalMap v a
IMap.insert (v -> v -> Interval v
forall v. v -> v -> Interval v
Interval v
b v
e) a
ti
    entries :: [(IntervalEntry Instant, IntervalEntry Instant, TransitionInfo)]
entries = [(IntervalEntry Instant
forall a. IntervalEntry a
Smallest, Instant -> IntervalEntry Instant
forall a. a -> IntervalEntry a
Entry Instant
beforeStart, TransitionInfo
stdTI), (Instant -> IntervalEntry Instant
forall a. a -> IntervalEntry a
Entry Instant
start', Instant -> IntervalEntry Instant
forall a. a -> IntervalEntry a
Entry Instant
beforeEnd, TransitionInfo
dstTI), (Instant -> IntervalEntry Instant
forall a. a -> IntervalEntry a
Entry Instant
end', IntervalEntry Instant
forall a. IntervalEntry a
Largest, TransitionInfo
stdTI)]
    (Instant
start', Instant
beforeStart) = Instant -> TransitionInfo -> TransitionInfo -> (Instant, Instant)
adjust Instant
start TransitionInfo
dstTI TransitionInfo
stdTI
    (Instant
end', Instant
beforeEnd) = Instant -> TransitionInfo -> TransitionInfo -> (Instant, Instant)
adjust Instant
end TransitionInfo
stdTI TransitionInfo
dstTI
    adjust :: Instant -> TransitionInfo -> TransitionInfo -> (Instant, Instant)
adjust Instant
tran TransitionInfo
ti TransitionInfo
prevTI = (Instant
x, Instant
beforeX)
      where
        x :: Instant
x = Offset -> Instant -> Instant
adjustInstant (TransitionInfo -> Offset
tiUtcOffset TransitionInfo
ti) Instant
tran
        beforeX :: Instant
beforeX = (Instant -> Duration -> Instant) -> Duration -> Instant -> Instant
forall a b c. (a -> b -> c) -> b -> a -> c
flip Instant -> Duration -> Instant
minus (Int -> Duration
fromNanoseconds Int
1) (Instant -> Instant) -> (Instant -> Instant) -> Instant -> Instant
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Offset -> Instant -> Instant
adjustInstant (TransitionInfo -> Offset
tiUtcOffset TransitionInfo
prevTI) (Instant -> Instant) -> Instant -> Instant
forall a b. (a -> b) -> a -> b
$ Instant
tran

expressionToInstant :: Instant -> TransitionExpression -> Instant
expressionToInstant :: Instant -> TransitionExpression -> Instant
expressionToInstant Instant
instant = Int -> TransitionExpression -> Instant
yearExpressionToInstant Int
y
  where
    y :: Int
y = let (Word32
yr, Word8
_, Word8
_) = Instant -> (Word32, Word8, Word8)
instantToYearMonthDay Instant
instant in Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
yr

yearExpressionToInstant :: Int -> TransitionExpression -> Instant
yearExpressionToInstant :: Int -> TransitionExpression -> Instant
yearExpressionToInstant Int
y = TransitionExpression -> Instant
go
  where
    go :: TransitionExpression -> Instant
go (NthDayExpression Int
m Int
nth Int
day Int
s) = Int32 -> Word32 -> Word32 -> Instant
Instant Int32
days' (Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
s) Word32
0
      where
        m' :: Month Gregorian
m' = Int -> Month Gregorian
forall a. Enum a => Int -> a
toEnum Int
m
        d :: Int
d = Int -> Int -> Month Gregorian -> Int -> Int
nthDayToDayOfMonth Int
nth Int
day Month Gregorian
m' Int
y
        days' :: Int32
days' = Int -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int32) -> Int -> Int32
forall a b. (a -> b) -> a -> b
$ Int -> Month Gregorian -> Int -> Int
yearMonthDayToDays Int
y Month Gregorian
m' Int
d
    go (JulianExpression Bool
_cly Int
_d Int
_s) = String -> Instant
forall a. HasCallStack => String -> a
error String
"need julian year day function"