{- |
Module      : Data.Time.Zones
Copyright   : (C) 2014 Mihaly Barasz
License     : Apache-2.0, see LICENSE
Maintainer  : Janus Troelsen <ysangkok@gmail.com>
Stability   : experimental
-}

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveDataTypeable #-}

module Data.Time.Zones (
  TZ,
  Data.Time.Zones.Types.utcTZ,
  -- * Universal -> Local direction
  diffForPOSIX,
  timeZoneForPOSIX,
  timeZoneForUTCTime,
  utcToLocalTimeTZ,
  -- * Local -> Universal direction
  LocalToUTCResult(..),
  localTimeToUTCFull,
  localTimeToUTCTZ,
  -- TODO(klao): do we want to export these?
  FromLocal(..),
  localToPOSIX,
  -- * Acquiring `TZ` information
  loadTZFromFile,
  loadTZFromDB,
  loadSystemTZ,
  loadLocalTZ,
  -- * Utilities
  diffForAbbr,
  ) where

import           Control.DeepSeq
import           Data.Bits (shiftR)
import           Data.Data
import           Data.Int (Int64)
import           Data.Time
import           Data.Time.Zones.Internal
import           Data.Time.Zones.Read
import           Data.Time.Zones.Types
import qualified Data.Vector as VB
import qualified Data.Vector.Unboxed as VU

-- | Returns the time difference (in seconds) for TZ at the given
-- POSIX time.
diffForPOSIX :: TZ -> Int64 -> Int
{-# INLINE diffForPOSIX #-}
diffForPOSIX :: TZ -> Int64 -> Int
diffForPOSIX (TZ Vector Int64
trans Vector Int
diffs Vector (Bool, String)
_) Int64
t = Vector Int -> Int -> Int
forall a. Unbox a => Vector a -> Int -> a
VU.unsafeIndex Vector Int
diffs (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Vector Int64 -> Int64 -> Int
forall a. (Unbox a, Ord a) => Vector a -> a -> Int
binarySearch Vector Int64
trans Int64
t

timeZoneForIx :: TZ -> Int -> TimeZone
{-# INLINE timeZoneForIx #-}
timeZoneForIx :: TZ -> Int -> TimeZone
timeZoneForIx (TZ Vector Int64
_ Vector Int
diffs Vector (Bool, String)
infos) Int
i = Int -> Bool -> String -> TimeZone
TimeZone Int
diffMins Bool
isDst String
name
  where
    diffMins :: Int
diffMins = Vector Int -> Int -> Int
forall a. Unbox a => Vector a -> Int -> a
VU.unsafeIndex Vector Int
diffs Int
i Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
60
    (Bool
isDst, String
name) = Vector (Bool, String) -> Int -> (Bool, String)
forall a. Vector a -> Int -> a
VB.unsafeIndex Vector (Bool, String)
infos Int
i

-- | Returns the `TimeZone` for the `TZ` at the given POSIX time.
timeZoneForPOSIX :: TZ -> Int64 -> TimeZone
{-# INLINABLE timeZoneForPOSIX #-}
timeZoneForPOSIX :: TZ -> Int64 -> TimeZone
timeZoneForPOSIX tz :: TZ
tz@(TZ Vector Int64
trans Vector Int
_ Vector (Bool, String)
_) Int64
t = TZ -> Int -> TimeZone
timeZoneForIx TZ
tz Int
i
  where
    i :: Int
i = Vector Int64 -> Int64 -> Int
forall a. (Unbox a, Ord a) => Vector a -> a -> Int
binarySearch Vector Int64
trans Int64
t

-- | Returns the `TimeZone` for the `TZ` at the given `UTCTime`.
timeZoneForUTCTime :: TZ -> UTCTime -> TimeZone
{-# INLINABLE timeZoneForUTCTime #-}
timeZoneForUTCTime :: TZ -> UTCTime -> TimeZone
timeZoneForUTCTime TZ
tz UTCTime
ut = TZ -> Int64 -> TimeZone
timeZoneForPOSIX TZ
tz (Int64 -> TimeZone) -> Int64 -> TimeZone
forall a b. (a -> b) -> a -> b
$ UTCTime -> Int64
utcTimeToInt64 UTCTime
ut

-- | Returns the `LocalTime` corresponding to the given `UTCTime` in `TZ`.
--
-- @utcToLocalTimeTZ tz ut@ is equivalent to @`utcToLocalTime`
-- (`timeZoneForPOSIX` tz ut) ut@ except when the time difference is not
-- an integral number of minutes
utcToLocalTimeTZ :: TZ -> UTCTime -> LocalTime
utcToLocalTimeTZ :: TZ -> UTCTime -> LocalTime
utcToLocalTimeTZ TZ
tz UTCTime
utcT = Int64 -> Int64 -> LocalTime
int64PairToLocalTime Int64
ut' Int64
ps
  where
    (Int64
ut, Int64
ps) = UTCTime -> (Int64, Int64)
utcTimeToInt64Pair UTCTime
utcT
    ut' :: Int64
ut' = Int64
ut Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
+ Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (TZ -> Int64 -> Int
diffForPOSIX TZ
tz Int64
ut)

-- | Returns the largest index `i` such that `v ! i <= t`.
--
-- Assumes that `v` is sorted, has at least one element and `v ! 0 <= t`.
binarySearch :: (VU.Unbox a, Ord a) => VU.Vector a -> a -> Int
{-# INLINE binarySearch #-}
binarySearch :: Vector a -> a -> Int
binarySearch Vector a
v a
t | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1    = Int
0
                 | Bool
otherwise = a
t a -> Int -> Int
`seq` Int -> Int -> Int
go Int
1 Int
n
  where
    n :: Int
n = Vector a -> Int
forall a. Unbox a => Vector a -> Int
VU.length Vector a
v
    go :: Int -> Int -> Int
go !Int
l !Int
u | Int
l Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
u = (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
             | Vector a -> Int -> a
forall a. Unbox a => Vector a -> Int -> a
VU.unsafeIndex Vector a
v Int
k a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
t  = Int -> Int -> Int
go (Int
kInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) Int
u
             | Bool
otherwise  = Int -> Int -> Int
go Int
l Int
k
      where
        k :: Int
k = (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
u) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftR` Int
1

--------------------------------------------------------------------------------
-- LocalTime to UTCTime

-- Representing LocalTimes as Int64s.
--
-- We want a simple and convenient mapping of
-- (year,month,day,hour,minutes,seconds) tuples onto a linear
-- scale. We adopt the following convention: an Int64 maps to the
-- tuple that a POSIX time represented by the same number would map in
-- UTC time zone. That is, 0 maps to '1970-01-01 00:00:00' and
-- 1395516860 maps to '2014-03-22 19:34:20'.
--
-- This is independent and without reference to any particular time
-- zone, it is completely analogous to LocalTime in that you need a
-- time zone to be able to interpret this as a point in time. And then
-- it may refer to an invalid time (spring time forward clock jump) or
-- two possible times (fall time backward jump).
--
-- So, it's basically another representation for LocalTimes (those
-- that can be represented within an Int64 and ignoring the fractional
-- seconds), except that LocalTime can contain invalid time-of-day
-- part (like 27:-05:107) and the Int64 representation can't and is
-- always unambiguous.
--
-- With that in mind, a UTCTime to LocalTime conversion can be seen as
-- 'TZ -> Int64 -> Int64', where the first Int64 is POSIX time and the
-- second is this kind of LocalTime representation.


-- | Internal representation of LocalTime -> UTCTime conversion result:
data FromLocal
  = FLGap    { FromLocal -> Int
_flIx :: {-# UNPACK #-} !Int
             , FromLocal -> Int64
_flRes :: {-# UNPACK #-} !Int64 }
  | FLUnique { _flIx :: {-# UNPACK #-} !Int
             , _flRes :: {-# UNPACK #-} !Int64 }
  | FLDouble { _flIx :: {-# UNPACK #-} !Int
             , FromLocal -> Int64
_flRes1 :: {-# UNPACK #-} !Int64
             , FromLocal -> Int64
_flRes2 :: {-# UNPACK #-} !Int64 }
  deriving (FromLocal -> FromLocal -> Bool
(FromLocal -> FromLocal -> Bool)
-> (FromLocal -> FromLocal -> Bool) -> Eq FromLocal
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: FromLocal -> FromLocal -> Bool
$c/= :: FromLocal -> FromLocal -> Bool
== :: FromLocal -> FromLocal -> Bool
$c== :: FromLocal -> FromLocal -> Bool
Eq, Int -> FromLocal -> ShowS
[FromLocal] -> ShowS
FromLocal -> String
(Int -> FromLocal -> ShowS)
-> (FromLocal -> String)
-> ([FromLocal] -> ShowS)
-> Show FromLocal
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FromLocal] -> ShowS
$cshowList :: [FromLocal] -> ShowS
show :: FromLocal -> String
$cshow :: FromLocal -> String
showsPrec :: Int -> FromLocal -> ShowS
$cshowsPrec :: Int -> FromLocal -> ShowS
Show, ReadPrec [FromLocal]
ReadPrec FromLocal
Int -> ReadS FromLocal
ReadS [FromLocal]
(Int -> ReadS FromLocal)
-> ReadS [FromLocal]
-> ReadPrec FromLocal
-> ReadPrec [FromLocal]
-> Read FromLocal
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [FromLocal]
$creadListPrec :: ReadPrec [FromLocal]
readPrec :: ReadPrec FromLocal
$creadPrec :: ReadPrec FromLocal
readList :: ReadS [FromLocal]
$creadList :: ReadS [FromLocal]
readsPrec :: Int -> ReadS FromLocal
$creadsPrec :: Int -> ReadS FromLocal
Read, Typeable, Typeable FromLocal
DataType
Constr
Typeable FromLocal
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> FromLocal -> c FromLocal)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c FromLocal)
-> (FromLocal -> Constr)
-> (FromLocal -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c FromLocal))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c FromLocal))
-> ((forall b. Data b => b -> b) -> FromLocal -> FromLocal)
-> (forall r r'.
    (r -> r' -> r)
    -> r -> (forall d. Data d => d -> r') -> FromLocal -> r)
-> (forall r r'.
    (r' -> r -> r)
    -> r -> (forall d. Data d => d -> r') -> FromLocal -> r)
-> (forall u. (forall d. Data d => d -> u) -> FromLocal -> [u])
-> (forall u.
    Int -> (forall d. Data d => d -> u) -> FromLocal -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> FromLocal -> m FromLocal)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> FromLocal -> m FromLocal)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> FromLocal -> m FromLocal)
-> Data FromLocal
FromLocal -> DataType
FromLocal -> Constr
(forall b. Data b => b -> b) -> FromLocal -> FromLocal
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> FromLocal -> c FromLocal
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c FromLocal
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> FromLocal -> u
forall u. (forall d. Data d => d -> u) -> FromLocal -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> FromLocal -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> FromLocal -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> FromLocal -> m FromLocal
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> FromLocal -> m FromLocal
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c FromLocal
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> FromLocal -> c FromLocal
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c FromLocal)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c FromLocal)
$cFLDouble :: Constr
$cFLUnique :: Constr
$cFLGap :: Constr
$tFromLocal :: DataType
gmapMo :: (forall d. Data d => d -> m d) -> FromLocal -> m FromLocal
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> FromLocal -> m FromLocal
gmapMp :: (forall d. Data d => d -> m d) -> FromLocal -> m FromLocal
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> FromLocal -> m FromLocal
gmapM :: (forall d. Data d => d -> m d) -> FromLocal -> m FromLocal
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> FromLocal -> m FromLocal
gmapQi :: Int -> (forall d. Data d => d -> u) -> FromLocal -> u
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> FromLocal -> u
gmapQ :: (forall d. Data d => d -> u) -> FromLocal -> [u]
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> FromLocal -> [u]
gmapQr :: (r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> FromLocal -> r
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> FromLocal -> r
gmapQl :: (r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> FromLocal -> r
$cgmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> FromLocal -> r
gmapT :: (forall b. Data b => b -> b) -> FromLocal -> FromLocal
$cgmapT :: (forall b. Data b => b -> b) -> FromLocal -> FromLocal
dataCast2 :: (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c FromLocal)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c FromLocal)
dataCast1 :: (forall d. Data d => c (t d)) -> Maybe (c FromLocal)
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c FromLocal)
dataTypeOf :: FromLocal -> DataType
$cdataTypeOf :: FromLocal -> DataType
toConstr :: FromLocal -> Constr
$ctoConstr :: FromLocal -> Constr
gunfold :: (forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c FromLocal
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c FromLocal
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> FromLocal -> c FromLocal
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> FromLocal -> c FromLocal
$cp1Data :: Typeable FromLocal
Data)

instance NFData FromLocal where
  rnf :: FromLocal -> ()
rnf !FromLocal
_ = ()

-- We make the following two assumptions here:
--
-- 1. No diff in any time zone is ever bigger than 24 hours.
--
-- 2. No two consecutive transitions in any zone file ever fall within
--    48 hours of each other.
--
-- As a consequence, a local time might correspond to two different
-- points in time, but never three.
--
-- TODO(klao): check that these assuptions hold.
localToPOSIX :: TZ -> Int64 -> FromLocal
{-# INLINABLE localToPOSIX #-}
localToPOSIX :: TZ -> Int64 -> FromLocal
localToPOSIX (TZ Vector Int64
trans Vector Int
diffs Vector (Bool, String)
_) !Int64
lTime = FromLocal
res
  where
    lBound :: Int64
lBound = Int64
lTime Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
- Int64
86400
    ix :: Int
ix = Vector Int64 -> Int64 -> Int
forall a. (Unbox a, Ord a) => Vector a -> a -> Int
binarySearch Vector Int64
trans Int64
lBound
    cand1 :: Int64
cand1 = Int64
lTime Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
- Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Vector Int -> Int -> Int
forall a. Unbox a => Vector a -> Int -> a
VU.unsafeIndex Vector Int
diffs Int
ix)
    res :: FromLocal
res = if Int
ix Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Vector Int64 -> Int
forall a. Unbox a => Vector a -> Int
VU.length Vector Int64
trans Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
          then Int -> Int64 -> FromLocal
FLUnique Int
ix Int64
cand1 -- TODO(klao): extend when rule handling is added
          else FromLocal
res'

    ix' :: Int
ix' = Int
ix Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
    nextTrans :: Int64
nextTrans = Vector Int64 -> Int -> Int64
forall a. Unbox a => Vector a -> Int -> a
VU.unsafeIndex Vector Int64
trans Int
ix'
    cand2 :: Int64
cand2 = Int64
lTime Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
- Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Vector Int -> Int -> Int
forall a. Unbox a => Vector a -> Int -> a
VU.unsafeIndex Vector Int
diffs Int
ix')
    res' :: FromLocal
res' = case (Int64
cand1 Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
< Int64
nextTrans, Int64
cand2 Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
nextTrans) of
      (Bool
False, Bool
False) -> Int -> Int64 -> FromLocal
FLGap Int
ix Int64
cand1
      (Bool
True,  Bool
False) -> Int -> Int64 -> FromLocal
FLUnique Int
ix Int64
cand1
      (Bool
False, Bool
True)  -> Int -> Int64 -> FromLocal
FLUnique Int
ix' Int64
cand2
      (Bool
True,  Bool
True)  -> Int -> Int64 -> Int64 -> FromLocal
FLDouble Int
ix Int64
cand1 Int64
cand2

-- | Fully descriptive result of a LocalTime to UTCTime conversion.
--
-- In case of LTUAmbiguous the first result is always earlier than the
-- second one. Generally this only happens during the daylight saving
-- -> standard time transition (ie. summer -> winter). So, the first
-- result corresponds to interpreting the LocalTime as a daylight
-- saving time and the second result as standard time in the given
-- location.
--
-- But, if the location had some kind of administrative time
-- transition during which the clocks jumped back, then both results
-- can correspond to standard times (or daylight saving times) just
-- before and after the transition. You can always inspect the
-- 'timeZoneSummerOnly' field of the returned 'TimeZone's to get an
-- idea what kind of transition was taking place.
--
-- TODO(klao): document the LTUNone behavior.
data LocalToUTCResult
  = LTUNone { LocalToUTCResult -> UTCTime
_ltuResult :: UTCTime
            , LocalToUTCResult -> TimeZone
_ltuZone :: TimeZone }
  | LTUUnique { _ltuResult :: UTCTime
              , _ltuZone :: TimeZone }
  | LTUAmbiguous { LocalToUTCResult -> UTCTime
_ltuFirst      :: UTCTime
                 , LocalToUTCResult -> UTCTime
_ltuSecond     :: UTCTime
                 , LocalToUTCResult -> TimeZone
_ltuFirstZone  :: TimeZone
                 , LocalToUTCResult -> TimeZone
_ltuSecondZone :: TimeZone
                 } deriving (LocalToUTCResult -> LocalToUTCResult -> Bool
(LocalToUTCResult -> LocalToUTCResult -> Bool)
-> (LocalToUTCResult -> LocalToUTCResult -> Bool)
-> Eq LocalToUTCResult
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LocalToUTCResult -> LocalToUTCResult -> Bool
$c/= :: LocalToUTCResult -> LocalToUTCResult -> Bool
== :: LocalToUTCResult -> LocalToUTCResult -> Bool
$c== :: LocalToUTCResult -> LocalToUTCResult -> Bool
Eq, Int -> LocalToUTCResult -> ShowS
[LocalToUTCResult] -> ShowS
LocalToUTCResult -> String
(Int -> LocalToUTCResult -> ShowS)
-> (LocalToUTCResult -> String)
-> ([LocalToUTCResult] -> ShowS)
-> Show LocalToUTCResult
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [LocalToUTCResult] -> ShowS
$cshowList :: [LocalToUTCResult] -> ShowS
show :: LocalToUTCResult -> String
$cshow :: LocalToUTCResult -> String
showsPrec :: Int -> LocalToUTCResult -> ShowS
$cshowsPrec :: Int -> LocalToUTCResult -> ShowS
Show, ReadPrec [LocalToUTCResult]
ReadPrec LocalToUTCResult
Int -> ReadS LocalToUTCResult
ReadS [LocalToUTCResult]
(Int -> ReadS LocalToUTCResult)
-> ReadS [LocalToUTCResult]
-> ReadPrec LocalToUTCResult
-> ReadPrec [LocalToUTCResult]
-> Read LocalToUTCResult
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [LocalToUTCResult]
$creadListPrec :: ReadPrec [LocalToUTCResult]
readPrec :: ReadPrec LocalToUTCResult
$creadPrec :: ReadPrec LocalToUTCResult
readList :: ReadS [LocalToUTCResult]
$creadList :: ReadS [LocalToUTCResult]
readsPrec :: Int -> ReadS LocalToUTCResult
$creadsPrec :: Int -> ReadS LocalToUTCResult
Read, Typeable, Typeable LocalToUTCResult
DataType
Constr
Typeable LocalToUTCResult
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> LocalToUTCResult -> c LocalToUTCResult)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c LocalToUTCResult)
-> (LocalToUTCResult -> Constr)
-> (LocalToUTCResult -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c LocalToUTCResult))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e))
    -> Maybe (c LocalToUTCResult))
-> ((forall b. Data b => b -> b)
    -> LocalToUTCResult -> LocalToUTCResult)
-> (forall r r'.
    (r -> r' -> r)
    -> r -> (forall d. Data d => d -> r') -> LocalToUTCResult -> r)
-> (forall r r'.
    (r' -> r -> r)
    -> r -> (forall d. Data d => d -> r') -> LocalToUTCResult -> r)
-> (forall u.
    (forall d. Data d => d -> u) -> LocalToUTCResult -> [u])
-> (forall u.
    Int -> (forall d. Data d => d -> u) -> LocalToUTCResult -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d)
    -> LocalToUTCResult -> m LocalToUTCResult)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d)
    -> LocalToUTCResult -> m LocalToUTCResult)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d)
    -> LocalToUTCResult -> m LocalToUTCResult)
-> Data LocalToUTCResult
LocalToUTCResult -> DataType
LocalToUTCResult -> Constr
(forall b. Data b => b -> b)
-> LocalToUTCResult -> LocalToUTCResult
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> LocalToUTCResult -> c LocalToUTCResult
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c LocalToUTCResult
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u.
Int -> (forall d. Data d => d -> u) -> LocalToUTCResult -> u
forall u. (forall d. Data d => d -> u) -> LocalToUTCResult -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> LocalToUTCResult -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> LocalToUTCResult -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d)
-> LocalToUTCResult -> m LocalToUTCResult
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d)
-> LocalToUTCResult -> m LocalToUTCResult
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c LocalToUTCResult
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> LocalToUTCResult -> c LocalToUTCResult
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c LocalToUTCResult)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c LocalToUTCResult)
$cLTUAmbiguous :: Constr
$cLTUUnique :: Constr
$cLTUNone :: Constr
$tLocalToUTCResult :: DataType
gmapMo :: (forall d. Data d => d -> m d)
-> LocalToUTCResult -> m LocalToUTCResult
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d)
-> LocalToUTCResult -> m LocalToUTCResult
gmapMp :: (forall d. Data d => d -> m d)
-> LocalToUTCResult -> m LocalToUTCResult
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d)
-> LocalToUTCResult -> m LocalToUTCResult
gmapM :: (forall d. Data d => d -> m d)
-> LocalToUTCResult -> m LocalToUTCResult
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d)
-> LocalToUTCResult -> m LocalToUTCResult
gmapQi :: Int -> (forall d. Data d => d -> u) -> LocalToUTCResult -> u
$cgmapQi :: forall u.
Int -> (forall d. Data d => d -> u) -> LocalToUTCResult -> u
gmapQ :: (forall d. Data d => d -> u) -> LocalToUTCResult -> [u]
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> LocalToUTCResult -> [u]
gmapQr :: (r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> LocalToUTCResult -> r
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> LocalToUTCResult -> r
gmapQl :: (r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> LocalToUTCResult -> r
$cgmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> LocalToUTCResult -> r
gmapT :: (forall b. Data b => b -> b)
-> LocalToUTCResult -> LocalToUTCResult
$cgmapT :: (forall b. Data b => b -> b)
-> LocalToUTCResult -> LocalToUTCResult
dataCast2 :: (forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c LocalToUTCResult)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c LocalToUTCResult)
dataCast1 :: (forall d. Data d => c (t d)) -> Maybe (c LocalToUTCResult)
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c LocalToUTCResult)
dataTypeOf :: LocalToUTCResult -> DataType
$cdataTypeOf :: LocalToUTCResult -> DataType
toConstr :: LocalToUTCResult -> Constr
$ctoConstr :: LocalToUTCResult -> Constr
gunfold :: (forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c LocalToUTCResult
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c LocalToUTCResult
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> LocalToUTCResult -> c LocalToUTCResult
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> LocalToUTCResult -> c LocalToUTCResult
$cp1Data :: Typeable LocalToUTCResult
Data)

instance NFData LocalToUTCResult where
  rnf :: LocalToUTCResult -> ()
rnf !LocalToUTCResult
_ = ()

-- TODO(klao): better name
localTimeToUTCFull :: TZ -> LocalTime -> LocalToUTCResult
localTimeToUTCFull :: TZ -> LocalTime -> LocalToUTCResult
localTimeToUTCFull tz :: TZ
tz@(TZ Vector Int64
_ Vector Int
diffs Vector (Bool, String)
_) LocalTime
localT = LocalToUTCResult
res
  where
    (Int64
t,Int64
ps) = LocalTime -> (Int64, Int64)
localTimeToInt64Pair LocalTime
localT
    addDiff :: Int -> UTCTime
addDiff Int
i = Int64 -> Int64 -> UTCTime
int64PairToUTCTime Int64
t' Int64
ps
      where
        diff :: Int
diff = Vector Int -> Int -> Int
forall a. Unbox a => Vector a -> Int -> a
VU.unsafeIndex Vector Int
diffs Int
i
        t' :: Int64
t' = Int64
t Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
- Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
diff
    res :: LocalToUTCResult
res = case TZ -> Int64 -> FromLocal
localToPOSIX TZ
tz Int64
t of
      FLGap Int
i Int64
_ -> UTCTime -> TimeZone -> LocalToUTCResult
LTUNone (Int -> UTCTime
addDiff Int
i) (TZ -> Int -> TimeZone
timeZoneForIx TZ
tz Int
i)
      FLUnique Int
i Int64
_ -> UTCTime -> TimeZone -> LocalToUTCResult
LTUUnique (Int -> UTCTime
addDiff Int
i) (TZ -> Int -> TimeZone
timeZoneForIx TZ
tz Int
i)
      FLDouble Int
i Int64
_ Int64
_ -> UTCTime -> UTCTime -> TimeZone -> TimeZone -> LocalToUTCResult
LTUAmbiguous (Int -> UTCTime
addDiff Int
i) (Int -> UTCTime
addDiff (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1))
                          (TZ -> Int -> TimeZone
timeZoneForIx TZ
tz Int
i) (TZ -> Int -> TimeZone
timeZoneForIx TZ
tz (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1))

localTimeToUTCTZ :: TZ -> LocalTime -> UTCTime
localTimeToUTCTZ :: TZ -> LocalTime -> UTCTime
localTimeToUTCTZ TZ
tz LocalTime
lt =
  case TZ -> LocalTime -> LocalToUTCResult
localTimeToUTCFull TZ
tz LocalTime
lt of
    LTUNone UTCTime
ut TimeZone
_ -> UTCTime
ut
    LTUUnique UTCTime
ut TimeZone
_ -> UTCTime
ut
    LTUAmbiguous UTCTime
_ UTCTime
ut TimeZone
_ TimeZone
_ -> UTCTime
ut

--------------------------------------------------------------------------------
-- Random utility functions

-- | Returns /a/ time difference (in seconds) corresponding to the
-- abbreviation in the given time zone.
--
-- If there are multiple time differences associated with the same
-- abbreviation, the one corresponding to the latest use is
-- returned. (The latest use might be in the past or the future
-- depending on whether the abbreviation is still in use.)
--
-- This function is here for informational purpose only, do not use it
-- for time conversion. (Instead, use 'localTimeToUTCFull', and if the
-- result is ambiguous disambiguate between the possible results based
-- on the abbreviation.)
diffForAbbr :: TZ -> String -> Maybe Int
{-# INLINABLE diffForAbbr #-}
diffForAbbr :: TZ -> String -> Maybe Int
diffForAbbr (TZ Vector Int64
_ Vector Int
diffs Vector (Bool, String)
infos) String
s =
  case ((Bool, String) -> Bool) -> Vector (Bool, String) -> Maybe Int
forall a. (a -> Bool) -> Vector a -> Maybe Int
VB.findIndex (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
(==) String
s (String -> Bool)
-> ((Bool, String) -> String) -> (Bool, String) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool, String) -> String
forall a b. (a, b) -> b
snd) (Vector (Bool, String) -> Maybe Int)
-> Vector (Bool, String) -> Maybe Int
forall a b. (a -> b) -> a -> b
$ Vector (Bool, String) -> Vector (Bool, String)
forall a. Vector a -> Vector a
VB.reverse Vector (Bool, String)
infos of
    Maybe Int
Nothing -> Maybe Int
forall a. Maybe a
Nothing
    Just Int
i -> Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$ Vector Int -> Int -> Int
forall a. Unbox a => Vector a -> Int -> a
VU.unsafeIndex Vector Int
diffs (Vector Int -> Int
forall a. Unbox a => Vector a -> Int
VU.length Vector Int
diffs Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
i)