git.iko.soy/typeable/timezone-olson
on master help sign in
Version 2 Olson files repeat all TZ transitions from the Version 1 section also in the Version 2 section.
9ec84adYitzchak Gale
Data/Time/LocalTime/TimeZone/Olson/Parse.hs+7−2
@@ -39,9 +39,12 @@ import Data.Binary.Get (Get, runGet, getWord8, getWord32be, getWord64be,
39import qualified Data.ByteString as B
39import qualified Data.ByteString as B
40import qualified Data.ByteString.Lazy as L
40import qualified Data.ByteString.Lazy as L
41import Data.Monoid (mappend)
41import Data.Monoid (mappend)
42+import Data.List (sortBy, groupBy)
42import Data.Maybe (listToMaybe, fromMaybe)
43import Data.Maybe (listToMaybe, fromMaybe)
43import Data.Word (Word8)
44import Data.Word (Word8)
44import Data.Int (Int32, Int64)
45import Data.Int (Int32, Int64)
46+import Data.Ord (comparing)
47+import Data.Function (on)
45import Data.Typeable (Typeable)
48import Data.Typeable (Typeable)
46import Control.Monad (guard, replicateM, replicateM_, when)
49import Control.Monad (guard, replicateM, replicateM_, when)
47import Control.Exception.Extensible (try, throw, Exception, ErrorCall)
50import Control.Exception.Extensible (try, throw, Exception, ErrorCall)
@@ -57,8 +60,8 @@ instance Exception OlsonError
57-- | Convert parsed Olson timezone data into a @TimeZoneSeries@.
60-- | Convert parsed Olson timezone data into a @TimeZoneSeries@.
58olsonToTimeZoneSeries :: OlsonData -> Maybe TimeZoneSeries
61olsonToTimeZoneSeries :: OlsonData -> Maybe TimeZoneSeries
59olsonToTimeZoneSeries (OlsonData ttimes ttinfos@(dflt0:_) _ _) =
62olsonToTimeZoneSeries (OlsonData ttimes ttinfos@(dflt0:_) _ _) =
60− fmap (TimeZoneSeries $ mkTZ dflt) . mapM (lookupTZ ttinfos) $
63+ fmap (TimeZoneSeries $ mkTZ dflt) . mapM (lookupTZ ttinfos) .
61− reverse ttimes
64+ uniqTimes . sortBy futureToPast $ ttimes
62 where
65 where
63 dflt = fromMaybe dflt0 . listToMaybe $ filter isStd ttinfos
66 dflt = fromMaybe dflt0 . listToMaybe $ filter isStd ttinfos
64 isStd (TtInfo _ isdst _ _) = not isdst
67 isStd (TtInfo _ isdst _ _) = not isdst
@@ -67,6 +70,8 @@ olsonToTimeZoneSeries (OlsonData ttimes ttinfos@(dflt0:_) _ _) =
67 lookupTZ ttinfos ttime = fmap (((,) $ toUTC ttime) . mkTZ) . listToMaybe $
70 lookupTZ ttinfos ttime = fmap (((,) $ toUTC ttime) . mkTZ) . listToMaybe $
68 drop (transIndex ttime) ttinfos
71 drop (transIndex ttime) ttinfos
69 toUTC = posixSecondsToUTCTime . fromIntegral . transTime
72 toUTC = posixSecondsToUTCTime . fromIntegral . transTime
73+ uniqTimes = map last . groupBy ((==) `on` transTime)
74+ futureToPast = comparing $ negate . transTime
70olsonToTimeZoneSeries _ = Nothing
75olsonToTimeZoneSeries _ = Nothing
71
76
72-- | Read timezone data from a binary Olson timezone file and convert
77-- | Read timezone data from a binary Olson timezone file and convert
Data/Time/LocalTime/TimeZone/Olson/Render.hs+24−38
@@ -30,7 +30,7 @@ module Data.Time.LocalTime.TimeZone.Olson.Render
30 renderOlsonToFile,
30 renderOlsonToFile,
31 verifyOlsonLimits,
31 verifyOlsonLimits,
32 putOlson,
32 putOlson,
33− splitOlson
33+ extractOlsonV1
34)
34)
35where
35where
36
36
@@ -110,49 +110,35 @@ renderOlsonToFile fp olson = do
110
110
111-- | Render Olson timezone data in binary Olson timezone file format
111-- | Render Olson timezone data in binary Olson timezone file format
112-- as a lazy @ByteString@
112-- as a lazy @ByteString@
113−putOlson :: OlsonData -> Put
113+putOlson olson@(OlsonData _ _ _ posix)
114−putOlson olson = putOlsonParts version olson1 olson2 posix >> flush
114+ | fitsInVersion1 = putOlsonPart 0 put32bitIntegral olson
115+ | otherwise = do putOlsonPart 50 put32bitIntegral olson1
116+ putOlsonPart 50 put64bitIntegral olson
117+ putPosixTZ posix
115 where
118 where
116− (olson1, olson2, posix) = splitOlson olson
119+ olson1 = extractOlsonV1 olson
117− version
120+ fitsInVersion1 = fmap null posix /= Just False &&
118− | olson2 /= mempty = 50
121+ olson1 == olson {olsonPosixTZ = Nothing}
119− | otherwise = maybe 0 (const 50) $ posix >>= guard . not . null
122+
120−
121−-- | Split Olson timezone data into three parts: timezone data that can
122−-- be rendered using Version 1 format, timezone data that can only be
123+-- | Extract Olson timezone data that can be rendered using Version 1 format
123−-- rendered using Version 2 format, and the POSIX-style TZ string
124−-- if specified
125−splitOlson :: OlsonData -> (OlsonData, OlsonData, Maybe String)
124+extractOlsonV1 :: OlsonData -> OlsonData
125+extractOlsonV1 (OlsonData transs ttinfos leaps _)
126−splitOlson (OlsonData transs ttinfos leaps posix) =
126+ | allV1 = OlsonData transs ttinfos leaps Nothing
127− (OlsonData transs1 ttinfos1 leaps1 Nothing,
127+ | otherwise = OlsonData transs1 ttinfos1 leaps1 Nothing
128− OlsonData transs2 ttinfos2 leaps2 Nothing,
129− posix)
130 where
128 where
131 cutoff = 0x80000000 -- 2^31
129 cutoff = 0x80000000 -- 2^31
132 fitsIn32bits x = x < cutoff && x >= negate cutoff
130 fitsIn32bits x = x < cutoff && x >= negate cutoff
133− ( leaps1 , leaps2 ) = partition (fitsIn32bits . leapTime) leaps
131+ leaps1 = filter (fitsIn32bits . leapTime) leaps
134− (transs1', transs2') = partition (fitsIn32bits . transTime) transs
132+ transs1' = filter (fitsIn32bits . transTime) transs
135− assoc1 = mkAssoc [0] transs1'
133+ allV1 = length leaps1 == length leaps && length transs1' == length transs
136− assoc2 = mkAssoc [] transs2'
134+ assoc1 = zip
137− transs1 = mkTranss transs1' assoc1
138− transs2 = mkTranss transs2' assoc2
139− ttinfos1 = mkTtinfos assoc1
140− ttinfos2 = mkTtinfos assoc2
141− mkAssoc prepend transs' = zip
142 (sortBy (comparing $ fmap tt_ttype . listToMaybe . flip drop ttinfos) .
135 (sortBy (comparing $ fmap tt_ttype . listToMaybe . flip drop ttinfos) .
143− uniq . sort . (prepend ++) $ map transIndex transs')
136+ uniq . sort . (0 :) $ map transIndex transs1')
144 [0..]
137 [0..]
145− mkTranss transs' assoc = [t {transIndex = i} |
138+ transs1 = [t {transIndex = i} |
146− t <- transs', i <- maybeToList $ lookup (transIndex t) assoc]
139+ t <- transs1', i <- maybeToList $ lookup (transIndex t) assoc1]
147− mkTtinfos assoc = map snd . dropWhile (isNothing . fst) .
140+ ttinfos1 = map snd . dropWhile (isNothing . fst) .
148− sortBy (comparing fst) $ zip (map (flip lookup assoc) [0..]) ttinfos
141+ sortBy (comparing fst) $ zip (map (flip lookup assoc1) [0..]) ttinfos
149−
150−putOlsonParts :: Word8 -> OlsonData -> OlsonData -> Maybe String -> Put
151−putOlsonParts 0 olson1 _ _ = putOlsonPart 0 put32bitIntegral olson1
152−putOlsonParts v2 olson1 olson2 posix = do
153− putOlsonPart v2 put32bitIntegral olson1
154− putOlsonPart v2 put64bitIntegral olson2
155− putPosixTZ posix
156
142
157putOlsonPart :: Word8 -> (Integer -> Put) -> OlsonData -> Put
143putOlsonPart :: Word8 -> (Integer -> Put) -> OlsonData -> Put
158putOlsonPart version putTime (OlsonData transs ttinfos leaps _) = do
144putOlsonPart version putTime (OlsonData transs ttinfos leaps _) = do