git.iko.soy/typeable/timezone-olson
on ffcf005 help sign in
12 files changed+168−571
since splitsnapshots
unifiedsplit
.gitignore−16 .travis.yml−107 Data/Time/LocalTime/TimeZone/Olson.hs+7−6 Data/Time/LocalTime/TimeZone/Olson/Parse.hs+47−85 Data/Time/LocalTime/TimeZone/Olson/Render.hs+71−124 Data/Time/LocalTime/TimeZone/Olson/Types.hs+30−100 LICENSE+1−1 README.md−43 Setup.hs−2 catTZ.hs−14 hzdump.hs+12−28 timezone-olson.cabal−45
.gitignoredeleted−16
@@ -1,16 +0,0 @@
1−dist
2−cabal-dev
3−*.o
4−*.hi
5−*.chi
6−*.chs.h
7−*.dyn_o
8−*.dyn_hi
9−.virtualenv
10−.hpc
11−.hsenv
12−.cabal-sandbox/
13−cabal.sandbox.config
14−*.prof
15−*.aux
16−*.hp
.travis.ymldeleted−107
@@ -1,107 +0,0 @@
1−# This Travis job script has been generated by a script via
2−#
3−# runghc make_travis_yml_2.hs 'timezone-olson.cabal'
4−#
5−# For more information, see https://github.com/hvr/multi-ghc-travis
6−#
7−language: c
8−sudo: false
9−
10−git:
11− submodules: false # whether to recursively clone submodules
12−
13−cache:
14− directories:
15− - $HOME/.cabal/packages
16− - $HOME/.cabal/store
17−
18−before_cache:
19− - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
20− # remove files that are regenerated by 'cabal update'
21− - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*
22− - rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json
23− - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache
24− - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar
25− - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx
26−
27− - rm -rfv $HOME/.cabal/packages/head.hackage
28−
29−matrix:
30− include:
31− - compiler: "ghc-8.0.1"
32− # env: TEST=--disable-tests BENCH=--disable-benchmarks
33− addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.0.1], sources: [hvr-ghc]}}
34− - compiler: "ghc-8.0.2"
35− # env: TEST=--disable-tests BENCH=--disable-benchmarks
36− addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.0.2], sources: [hvr-ghc]}}
37− - compiler: "ghc-8.2.1"
38− # env: TEST=--disable-tests BENCH=--disable-benchmarks
39− addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.2.1], sources: [hvr-ghc]}}
40− - compiler: "ghc-8.2.2"
41− # env: TEST=--disable-tests BENCH=--disable-benchmarks
42− addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.2.2], sources: [hvr-ghc]}}
43− - compiler: "ghc-8.4.1"
44− # env: TEST=--disable-tests BENCH=--disable-benchmarks
45− addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.4.1], sources: [hvr-ghc]}}
46−
47−before_install:
48− - HC=${CC}
49− - HCPKG=${HC/ghc/ghc-pkg}
50− - unset CC
51− - ROOTDIR=$(pwd)
52− - mkdir -p $HOME/.local/bin
53− - "PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH"
54− - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))
55− - echo $HCNUMVER
56−
57−install:
58− - cabal --version
59− - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
60− - BENCH=${BENCH---enable-benchmarks}
61− - TEST=${TEST---enable-tests}
62− - HADDOCK=${HADDOCK-true}
63− - INSTALLED=${INSTALLED-true}
64− - GHCHEAD=${GHCHEAD-false}
65− - travis_retry cabal update -v
66− - "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"
67− - rm -fv cabal.project cabal.project.local
68− - grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'
69− - "printf 'packages: \".\"\\n' > cabal.project"
70− - cat cabal.project
71− - if [ -f "./configure.ac" ]; then
72− (cd "." && autoreconf -i);
73− fi
74− - rm -f cabal.project.freeze
75− - cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project" --dep -j2 all
76− - cabal new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project" --dep -j2 all
77− - rm -rf .ghc.environment.* "."/dist
78− - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
79−
80−# Here starts the actual work to be performed for the package under test;
81−# any command which exits with a non-zero exit code causes the build to fail.
82−script:
83− # test that source-distributions can be generated
84− - (cd "." && cabal sdist)
85− - mv "."/dist/timezone-olson-*.tar.gz ${DISTDIR}/
86− - cd ${DISTDIR} || false
87− - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;
88− - "printf 'packages: timezone-olson-*/*.cabal\\n' > cabal.project"
89− - cat cabal.project
90− # this builds all libraries and executables (without tests/benchmarks)
91− - cabal new-build -w ${HC} --disable-tests --disable-benchmarks all
92−
93− # Build with installed constraints for packages in global-db
94− - if $INSTALLED; then echo cabal new-build -w ${HC} --disable-tests --disable-benchmarks $(${HCPKG} list --global --simple-output --names-only | sed 's/\([a-zA-Z0-9-]\{1,\}\) */--constraint="\1 installed" /g') all | sh; else echo "Not building with installed constraints"; fi
95−
96− # build & run tests, build benchmarks
97− - cabal new-build -w ${HC} ${TEST} ${BENCH} all
98−
99− # cabal check
100− - (cd timezone-olson-* && cabal check)
101−
102− # haddock
103− - rm -rf ./dist-newstyle
104− - if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo "Skipping haddock generation";fi
105−
106−# REGENDATA ["timezone-olson.cabal"]
107−# EOF
Data/Time/LocalTime/TimeZone/Olson.hs+7−6
@@ -1,7 +1,7 @@
11-----------------------------------------------------------------------------
22-- |
33-- Module : Data.Time.LocalTime.TimeZone.Olson
4−-- Copyright : Yitzchak Gale 2018
4+-- Copyright : Yitzchak Gale 2010
55--
66-- Maintainer : Yitzchak Gale <gale@sefer.org>
77-- Portability : portable
@@ -9,14 +9,15 @@
99-- A parser and renderer for binary Olson timezone files whose format
1010-- are specified by the tzfile(5) man page on Unix-like systems. For
1111-- more information about this format, see
12−-- <http://www.twinsun.com/tz/tz-link.htm>. Functions are provided for
12+-- http://www.twinsun.com/tz/tz-link.htm. Functions are provided for
1313-- converting the parsed data into @TimeZoneSeries@ and @TimeZone@
1414-- objects.
1515
16−{- Copyright (c) 2018 Yitzchak Gale. All rights reserved.
17−For licensing information, see the BSD3-style license in the file
18−LICENSE that was originally distributed by the author together with
19−this file. -}
16+{-
17+Copyright (c) 2010 Yitzchak Gale. All rights reserved.
18+For licensing information, see the file LICENSE that was
19+originally distributed by the author together with this file.
20+-}
2021
2122module Data.Time.LocalTime.TimeZone.Olson
2223(
Data/Time/LocalTime/TimeZone/Olson/Parse.hs+47−85
@@ -3,21 +3,22 @@
33-----------------------------------------------------------------------------
44-- |
55-- Module : Data.Time.LocalTime.TimeZone.Olson.Parse
6−-- Copyright : Yitzchak Gale 2018
6+-- Copyright : Yitzchak Gale 2010
77--
88-- Maintainer : Yitzchak Gale <gale@sefer.org>
99-- Portability : portable
1010--
11−-- A parser for binary Olson timezone files whose format is specified
11+-- A parser for binary Olson timezone files whose format are specified
1212-- by the tzfile(5) man page on Unix-like systems. For more
1313-- information about this format, see
14−-- <http://www.twinsun.com/tz/tz-link.htm>. Functions are provided for
15−-- converting the parsed data into 'TimeZoneSeries' objects.
14+-- http://www.twinsun.com/tz/tz-link.htm. Functions are provided for
15+-- converting the parsed data into @TimeZoneSeries@ and @TimeZone@
16+-- objects.
1617
17−{- Copyright (c) 2018 Yitzchak Gale. All rights reserved.
18−For licensing information, see the BSD3-style license in the file
19−LICENSE that was originally distributed by the author together with
20−this file. -}
18+{- Copyright (c) 2010 Yitzchak Gale. All rights reserved. For
19+licensing information, see the BSD3-style license in the file LICENSE
20+that was originally distributed by the author together with this file.
21+-}
2122
2223module Data.Time.LocalTime.TimeZone.Olson.Parse
2324(
@@ -39,14 +40,11 @@ import Data.Binary.Get (Get, runGet, getWord8, getWord32be, getWord64be,
3940import qualified Data.ByteString as B
4041import qualified Data.ByteString.Lazy as L
4142import Data.Monoid (mappend)
42−import Data.List (sortBy, groupBy)
4343import Data.Maybe (listToMaybe, fromMaybe)
4444import Data.Word (Word8)
4545import Data.Int (Int32, Int64)
46−import Data.Ord (comparing)
47−import Data.Function (on)
4846import Data.Typeable (Typeable)
49−import Control.Monad (guard, replicateM, replicateM_, when)
47+import Control.Monad (guard, replicateM, replicateM_)
5048import Control.Exception.Extensible (try, throw, Exception, ErrorCall)
5149
5250-- | An exception indicating that the binary data being parsed was not
@@ -60,8 +58,8 @@ instance Exception OlsonError
6058-- | Convert parsed Olson timezone data into a @TimeZoneSeries@.
6159olsonToTimeZoneSeries :: OlsonData -> Maybe TimeZoneSeries
6260olsonToTimeZoneSeries (OlsonData ttimes ttinfos@(dflt0:_) _ _) =
63− fmap (TimeZoneSeries $ mkTZ dflt) . mapM (lookupTZ ttinfos) .
64− uniqTimes . sortBy futureToPast $ ttimes
61+ fmap (TimeZoneSeries $ mkTZ dflt) . mapM (lookupTZ ttinfos) $
62+ reverse ttimes
6563 where
6664 dflt = fromMaybe dflt0 . listToMaybe $ filter isStd ttinfos
6765 isStd (TtInfo _ isdst _ _) = not isdst
@@ -70,74 +68,53 @@ olsonToTimeZoneSeries (OlsonData ttimes ttinfos@(dflt0:_) _ _) =
7068 lookupTZ ttinfos ttime = fmap (((,) $ toUTC ttime) . mkTZ) . listToMaybe $
7169 drop (transIndex ttime) ttinfos
7270 toUTC = posixSecondsToUTCTime . fromIntegral . transTime
73− uniqTimes = map last . groupBy ((==) `on` transTime)
74− futureToPast = comparing $ negate . transTime
7571olsonToTimeZoneSeries _ = Nothing
7672
7773-- | Read timezone data from a binary Olson timezone file and convert
78−-- it into a @TimeZoneSeries@ for use together with the types and
79−-- fucntions of "Data.Time". This is the function from this module
80−-- for which you are most likely to have use.
81−--
82−-- If the values in the Olson timezone file exceed the standard size
83−-- limits (see 'defaultLimits'), this function throws an
84−-- exception. For other behavior, use 'getOlson' and
85−-- 'Data.Binary.Get.runGet' directly.
74+-- it into a @TimeZoneSeries@.
8675getTimeZoneSeriesFromOlsonFile :: FilePath -> IO TimeZoneSeries
8776getTimeZoneSeriesFromOlsonFile fp = getOlsonFromFile fp >>=
8877 maybe (throwOlson fp "no timezone found in OlsonData") return .
8978 olsonToTimeZoneSeries
9079
9180-- | Parse a binary Olson timezone file.
92−--
93−-- If the values in the Olson timezone file exceed the standard size
94−-- limits (see 'defaultLimits'), this function throws an
95−-- exception. For other behavior, use 'getOlson' and
96−-- 'Data.Binary.Get.runGet' directly.
9781getOlsonFromFile :: FilePath -> IO OlsonData
9882getOlsonFromFile fp = do
99− e <- try . fmap (runGet $ getOlson defaultLimits) $ L.readFile fp
83+ e <- try . fmap (runGet getOlson) $ L.readFile fp
10084 either (formatError fp) return e
10185
10286formatError :: FilePath -> ErrorCall -> IO a
10387formatError fp e = throwOlson fp $ show e
10488
10589-- | A binary parser for binary Olson timezone files
106−getOlson :: SizeLimits -> Get OlsonData
107−getOlson limits = do
108− (version, part1) <- getOlsonPart True limits get32bitInteger
109− -- There is one part for Version 1 format data, and two parts and a POSIX
110− -- TZ string for Version 2 or 3 format data
111− case () of
112− _ | version == 0 -> return part1
113− | version == 50 || version == 51 -> do
114− (_, part2) <- getOlsonPart False limits get64bitInteger
115− posixTZ <- getPosixTZ
116− return $ part1 `mappend` part2 `mappend` posixTZ
117− | otherwise -> do
118− let msg = "getOlson: invalid tzfile version " ++ toASCII [version]
119− verify (const False) msg undefined
120−
121−-- Parse the part of an Olson file that contains timezone data
122−getOlsonPart :: Integral a => Bool -> SizeLimits -> Get a ->
123− Get (Word8, OlsonData)
124−getOlsonPart verifyMagic limits getTime = do
125− magic <- fmap (toASCII . B.unpack) $ getByteString 4
126− when verifyMagic $ verify_ (== "TZif") "missing magic number" magic
90+getOlson :: Get OlsonData
91+getOlson = do
92+ getByteString 4
93+ >>= verify ((== "TZif") . toASCII . B.unpack) "missing magic number"
12794 version <- getWord8
95+ >>= verify (`elem` [0, 50]) "invalid version number"
12896 replicateM_ 15 getWord8 -- padding nulls
97+ getOlsonParts version
98+
99+-- There is one part for Version 1 format data, and two parts and a POSIX
100+-- TZ string for Version 2 format data
101+getOlsonParts :: Word8 -> Get OlsonData
102+getOlsonParts 0 = getOlsonPart get32bitInteger
103+getOlsonParts 50 = do part1 <- getOlsonPart get32bitInteger
104+ part2 <- getOlsonPart get64bitInteger
105+ posixTZ <- getPosixTZ
106+ return $ part1 `mappend` part2 `mappend` posixTZ
107+getOlsonParts _ = error "Invalid version number" -- never reached
108+
109+-- Parse the part of an Olson file that contains timezone data
110+getOlsonPart :: Integral a => Get a -> Get OlsonData
111+getOlsonPart getTime = do
129112 tzh_ttisgmtcnt <- get32bitInt
130113 tzh_ttisstdcnt <- get32bitInt
131114 tzh_leapcnt <- get32bitInt
132− >>= verify (withinLimit maxLeaps) "too many leap second specifications"
133115 tzh_timecnt <- get32bitInt
134− >>= verify (withinLimit maxTimes) "too many timezone transitions"
135116 tzh_typecnt <- get32bitInt
136− >>= verify (withinLimit maxTypes) "too many timezone type specifications"
137− verify (withinLimit maxTypes) "too many isgmt specifiers" tzh_ttisgmtcnt
138− verify (withinLimit maxTypes) "too many isstd specifiers" tzh_ttisstdcnt
139117 tzh_charcnt <- get32bitInt
140− >>= verify (withinLimit maxAbbrChars) "too many tilezone specifiers"
141118 times <- fmap (map toInteger) $ replicateM tzh_timecnt getTime
142119 indexes <- replicateM tzh_timecnt get8bitInt
143120 ttinfos <- replicateM tzh_typecnt getTtInfo
@@ -145,32 +122,22 @@ getOlsonPart verifyMagic limits getTime = do
145122 leaps <- replicateM tzh_leapcnt $ getLeapInfo getTime
146123 isstds <- replicateM tzh_ttisstdcnt getBool
147124 isgmts <- replicateM tzh_ttisgmtcnt getBool
148− return
149− (version,
150− OlsonData
151− (zipWith Transition times indexes)
152− (map (flip lookupAbbr abbr_chars) . zipWith setTtype ttinfos $
153− zipWithExtend boolsToTType False False isstds isgmts)
154− leaps
155− Nothing
156− )
125+ return $ OlsonData
126+ (zipWith Transition times indexes)
127+ (map (flip lookupAbbr abbr_chars) . zipWith setTtype ttinfos .
128+ (++ repeat UnknownType) $
129+ zipWith boolsToTType (map Just isstds ++ repeat Nothing) isgmts)
130+ leaps
131+ Nothing
157132 where
158− withinLimit limit value = maybe True (value <=) $ limit limits
159133 lookupAbbr (TtInfo gmtoff isdst ttype abbrind) =
160134 TtInfo gmtoff isdst ttype . takeWhile (/= '\NUL') . drop abbrind
161135 setTtype ttinfo ttype = ttinfo {tt_ttype = ttype}
162− boolsToTType _ isgmt | isgmt = UTC
163− boolsToTType isstd _
164− | isstd = Std
165− | otherwise = Wall
166−
167−-- A variant of zipWith whose result is the length of the longer
168−-- rather than the shorter list, by extending the shorter list with
169−-- a default value
170−zipWithExtend :: (a -> b -> c) -> a -> b -> [a] -> [b] -> [c]
171−zipWithExtend f x0 y0 (x:xs) (y:ys) = f x y : zipWithExtend f x0 y0 xs ys
172−zipWithExtend f x0 _ [] ys = map (f x0) ys
173−zipWithExtend f _ y0 xs _ = map (flip f y0) xs
136+ boolsToTType _ isgmt | isgmt = UTC
137+ boolsToTType isstd _ = maybe UnknownType stdOrWall isstd
138+ stdOrWall isstd
139+ | isstd = Std
140+ | otherwise = Wall
174141
175142-- Parse a POSIX-style TZ string.
176143-- We don't try to understand the TZ string, we just pass it along whole.
@@ -191,7 +158,7 @@ getTtInfo = do
191158 gmtoff <- get32bitInt
192159 isdst <- getBool
193160 abbrind <- get8bitInt
194− return $ TtInfo gmtoff isdst Wall abbrind
161+ return $ TtInfo gmtoff isdst UnknownType abbrind
195162
196163-- Parse leap second info. (usually not used)
197164getLeapInfo :: Integral a => Get a -> Get LeapInfo
@@ -234,11 +201,6 @@ verify pred msg val
234201 | pred val = return val
235202 | otherwise = error msg
236203
237−verify_ :: Monad m => (a -> Bool) -> String -> a -> m ()
238−verify_ pred msg val
239− | pred val = return ()
240− | otherwise = error msg
241−
242204throwOlson :: FilePath -> String -> IO a
243205throwOlson fp msg = throw . OlsonError $
244206 fp ++ ": invalid timezone file: " ++ msg
Data/Time/LocalTime/TimeZone/Olson/Render.hs+71−124
@@ -2,20 +2,20 @@
22-----------------------------------------------------------------------------
33-- |
44-- Module : Data.Time.LocalTime.TimeZone.Olson.Render
5−-- Copyright : Yitzchak Gale 2018
5+-- Copyright : Yitzchak Gale 2010
66--
77-- Maintainer : Yitzchak Gale <gale@sefer.org>
88-- Portability : portable
99--
10−-- Render Olson timezone data in the standard binary format as used in
11−-- Olson timezone files, and as specified by the tzfile(5) man page on
12−-- Unix-like systems. For more information about this format, see
13−-- <http://www.twinsun.com/tz/tz-link.htm>.
10+-- Render Olson timezone data in the standard binary format as
11+-- used in Olson timezone files, and as specified by the
12+-- tzfile(5) man page on Unix-like systems. For more information
13+-- about this format, see http://www.twinsun.com/tz/tz-link.htm.
1414
15−{- Copyright (c) 2018ZZ Yitzchak Gale. All rights reserved.
16−For licensing information, see the BSD3-style license in the file
17−LICENSE that was originally distributed by the author together with
18−this file. -}
15+{- Copyright (c) 2010 Yitzchak Gale. All rights reserved. For
16+licensing information, see the BSD3-style license in the file LICENSE
17+that was originally distributed by the author together with this file.
18+-}
1919
2020module Data.Time.LocalTime.TimeZone.Olson.Render
2121(
@@ -25,19 +25,13 @@ module Data.Time.LocalTime.TimeZone.Olson.Render
2525 -- timestamp, or if a POSIX-style TZ string is specified, timezone
2626 -- data is rendered using Version 2 format. Otherwise, the timezone data
2727 -- is rendered using Version 1 format.
28− renderTimeZoneSeriesToOlsonFile,
29− timeZoneSeriesToOlson,
3028 renderOlsonToFile,
31− verifyOlsonLimits,
3229 putOlson,
33− extractOlsonV1
30+ splitOlson
3431)
3532where
3633
3734import Data.Time.LocalTime.TimeZone.Olson.Types
38−import Data.Time.LocalTime.TimeZone.Series (TimeZoneSeries(TimeZoneSeries))
39−import Data.Time (TimeZone(TimeZone, timeZoneSummerOnly, timeZoneName))
40−import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds)
4135import Data.Binary.Put (Put, runPut, putByteString, putWord8, flush,
4236 putWord32be, putWord64be)
4337import qualified Data.ByteString as B
@@ -45,117 +39,78 @@ import qualified Data.ByteString.Lazy as L
4539import Data.List (partition, sortBy, sort, group)
4640import Data.Ord (comparing)
4741import Data.Word (Word8)
48−import Data.Maybe (listToMaybe, maybeToList, isNothing, fromMaybe, catMaybes)
42+import Data.Maybe (listToMaybe, maybeToList, isNothing, fromMaybe)
4943import Data.Monoid (mempty)
50−import Control.Monad (guard, replicateM_, unless)
44+import Control.Monad (guard, replicateM_)
5145
52−-- | Render a @TimeZoneSeries@ as a binary Olson timezone file.
53−--
54−-- If the values in the Olson timezone data exceed the standard size
55−-- limits (see 'defaultLimits'), this function throws an
56−-- exception. For other behavior, use 'timeZoneSeriesToOlson',
57−-- 'verifyOlsonLimits', 'putOlson' and 'Data.Binary.Put.runPut'
58−-- directly.
59−renderTimeZoneSeriesToOlsonFile :: FilePath -> TimeZoneSeries -> IO ()
60−renderTimeZoneSeriesToOlsonFile fp = renderOlsonToFile fp .
61− fromMaybe (error "Cannot render TimeZoneSeries: default is summer time") .
62− timeZoneSeriesToOlson
63−
64−-- | Convert a @TimeZoneSeries@ to @OlsonData@ for rendering.
65−timeZoneSeriesToOlson :: TimeZoneSeries -> Maybe OlsonData
66−timeZoneSeriesToOlson (TimeZoneSeries dflt pairs)
67− | timeZoneSummerOnly dflt && not (all timeZoneSummerOnly $ map snd pairs)
68− = Nothing
69− | otherwise = Just $
70− OlsonData
71− [Transition secs ttinfo |
72− (t, tz) <- reverse pairs,
73− let secs = round $ utcTimeToPOSIXSeconds t,
74− ttinfo <- maybeToList $ lookup (mkTT tz) ttAssocs]
75− ttinfos
76− []
77− Nothing
78− where
79− mkTT (TimeZone offset isdst abbr) =
80− TtInfo (offset*60) isdst Wall abbr
81− dfltTT = mkTT dflt
82− ttAssocs = (dfltTT, 0) :
83− zip (uniq . sort . filter (/= dfltTT) $ map (mkTT . snd) pairs) [1..]
84− ttinfos = map fst ttAssocs
85−
86−-- | Check whether @OlsonData@ is within size limits.
87−verifyOlsonLimits :: SizeLimits -> OlsonData -> Bool
88−verifyOlsonLimits limits (OlsonData transs ttinfos leaps _) =
89− withinLimit maxTimes transs &&
90− withinLimit maxTypes ttinfos &&
91− withinLimit maxLeaps leaps &&
92− withinLimit maxAbbrChars abbrChars
93− where
94− withinLimit limit items = maybe True (null . flip drop items) $
95− limit limits
96− abbrChars = concat abbrStrs ++ map (const '\NUL') abbrStrs
97− abbrStrs = map tt_abbr ttinfos
9846
9947-- | Render Olson timezone data as a binary Olson timezone file
100−--
101−-- If the values in the Olson timezone data exceed the standard size
102−-- limits (see 'defaultLimits'), this function throws an
103−-- exception. For other behavior, use 'verifyOlsonLimits', 'putOlson'
104−-- and 'Data.Binary.Put.runPut' directly.
10548renderOlsonToFile :: FilePath -> OlsonData -> IO ()
106−renderOlsonToFile fp olson = do
107− unless (verifyOlsonLimits defaultLimits olson) $
108− error "Olson timezone data exceeds size limits"
109− L.writeFile fp . runPut . putOlson $ olson
49+renderOlsonToFile fp = L.writeFile fp . runPut . putOlson
11050
11151-- | Render Olson timezone data in binary Olson timezone file format
11252-- as a lazy @ByteString@
113−putOlson olson@(OlsonData _ _ _ posix)
114− | fitsInVersion1 = putOlsonPart 0 put32bitIntegral olson
115− | otherwise = do putOlsonPart 50 put32bitIntegral olson1
116− putOlsonPart 50 put64bitIntegral olson
117− putPosixTZ posix
53+putOlson :: OlsonData -> Put
54+putOlson olson = do
55+ putASCII "TZif"
56+ putWord8 version
57+ putByteString . B.pack $ replicate 15 0 -- padding nulls
58+ putOlsonParts version olson1 olson2 posix
59+ flush
11860 where
119− olson1 = extractOlsonV1 olson
120− fitsInVersion1 = fmap null posix /= Just False &&
121− olson1 == olson {olsonPosixTZ = Nothing}
122−
123−-- | Extract Olson timezone data that can be rendered using Version 1 format
124−extractOlsonV1 :: OlsonData -> OlsonData
125−extractOlsonV1 (OlsonData transs ttinfos leaps _)
126− | allV1 = OlsonData transs ttinfos leaps Nothing
127− | otherwise = OlsonData transs1 ttinfos1 leaps1 Nothing
61+ (olson1, olson2, posix) = splitOlson olson
62+ version
63+ | olson2 /= mempty = 50
64+ | otherwise = maybe 0 (const 50) $ posix >>= guard . not . null
65+
66+-- | Split Olson timezone data into three parts: timezone data that can
67+-- be rendered using Version 1 format, timezone data that can only be
68+-- rendered using Version 2 format, and the POSIX-style TZ string
69+-- if specified
70+splitOlson :: OlsonData -> (OlsonData, OlsonData, Maybe String)
71+splitOlson (OlsonData transs ttinfos leaps posix) =
72+ (OlsonData transs1 ttinfos1 leaps1 Nothing,
73+ OlsonData transs2 ttinfos2 leaps2 Nothing,
74+ posix)
12875 where
12976 cutoff = 0x80000000 -- 2^31
130− fitsIn32bits x = x < cutoff && x >= negate cutoff
131− leaps1 = filter (fitsIn32bits . leapTime) leaps
132− transs1' = filter (fitsIn32bits . transTime) transs
133− allV1 = length leaps1 == length leaps && length transs1' == length transs
134− assoc1 = zip
77+ ( leaps1 , leaps2 ) = partition ((>= cutoff) . leapTime) leaps
78+ (transs1', transs2') = partition ((>= cutoff) . transTime) transs
79+ assoc1 = mkAssoc [0] transs1'
80+ assoc2 = mkAssoc [] transs2'
81+ transs1 = mkTranss transs1' assoc1
82+ transs2 = mkTranss transs2' assoc2
83+ ttinfos1 = mkTtinfos assoc1
84+ ttinfos2 = mkTtinfos assoc2
85+ mkAssoc prepend transs' = zip
13586 (sortBy (comparing $ fmap tt_ttype . listToMaybe . flip drop ttinfos) .
136− uniq . sort . (0 :) $ map transIndex transs1')
87+ uniq . sort . (prepend ++) $ map transIndex transs')
13788 [0..]
138− transs1 = [t {transIndex = i} |
139− t <- transs1', i <- maybeToList $ lookup (transIndex t) assoc1]
140− ttinfos1 = map snd . dropWhile (isNothing . fst) .
141− sortBy (comparing fst) $ zip (map (flip lookup assoc1) [0..]) ttinfos
142−
143−putOlsonPart :: Word8 -> (Integer -> Put) -> OlsonData -> Put
144−putOlsonPart version putTime (OlsonData transs ttinfos leaps _) = do
145− putASCII "magic number" "TZif"
146− putWord8 version
147− putByteString . B.pack $ replicate 15 0 -- padding nulls
89+ mkTranss transs' assoc = [t {transIndex = i} |
90+ t <- transs', i <- maybeToList $ lookup (transIndex t) assoc]
91+ mkTtinfos assoc = map snd . dropWhile (isNothing . fst) .
92+ sortBy (comparing fst) $ zip (map (flip lookup assoc) [0..]) ttinfos
93+
94+putOlsonParts :: Word8 -> OlsonData -> OlsonData -> Maybe String -> Put
95+putOlsonParts 0 olson1 _ _ = putOlsonPart put32bitIntegral olson1
96+putOlsonParts _ olson1 olson2 posix = do
97+ putOlsonPart put32bitIntegral olson1
98+ putOlsonPart put64bitIntegral olson2
99+ putPosixTZ posix
100+
101+putOlsonPart :: (Integer -> Put) -> OlsonData -> Put
102+putOlsonPart putTime (OlsonData transs ttinfos leaps _) = do
148103 replicateM_ 2 $ putCount ttinfosWithTtype
149− -- tzh_ttisgmtcnt
150− -- tzh_ttisstdcnt
151− putCount leaps -- tzh_leapcnt
152− putCount transs -- tzh_timecnt
153− putCount ttinfos -- tzh_typecnt
154− put32bitIntegral abbrChars -- tzh_charcnt
104+ -- tzh_ttisgmtcnt
105+ -- tzh_ttisstdcnt
106+ putCount leaps -- tzh_leapcnt
107+ putCount transs -- tzh_timecnt
108+ putCount ttinfos -- tzh_typecnt
109+ putCount abbrChars -- tzh_charcnt
155110 mapM_ (putTime . transTime ) transs
156111 mapM_ (put8bitIntegral . transIndex) transs
157112 mapM_ putTtInfo ttinfosIndexed
158− mapM_ putAbbr abbrStrings
113+ putASCII abbrChars
159114 mapM_ (putLeapInfo putTime) leaps
160115 mapM_ (putBool . (== Std) . tt_ttype) ttinfosWithTtype -- isstd
161116 mapM_ (putBool . (== UTC) . tt_ttype) ttinfosWithTtype -- isgmt
@@ -163,18 +118,16 @@ putOlsonPart version putTime (OlsonData transs ttinfos leaps _) = do
163118 putCount = put32bitIntegral . length
164119 ttinfosWithTtype = takeWhile ((<= UTC) . tt_ttype) ttinfosIndexed
165120 abbrStrings = uniq . sort $ map tt_abbr ttinfos
166− abbrChars = sum (map length abbrStrings) + length abbrStrings
167− putAbbr abbr = putASCII "time zone abbreviation" abbr >> putWord8 0
168− abbrAssocs = zip abbrStrings . scanl (+) 0 $
169− map ((+ 1) . length) abbrStrings
121+ abbrChars = concatMap (++ "\NUL") abbrStrings
170122 ttinfosIndexed = [TtInfo gmtoff isdst ttype i |
171123 TtInfo gmtoff isdst ttype abbr <- ttinfos,
172− i <- maybeToList $ lookup abbr abbrAssocs]
124+ i <- maybeToList . lookup abbr . zip abbrStrings .
125+ scanl (+) 0 $ map ((+ 1) . length) abbrStrings]
173126
174127putPosixTZ :: Maybe String -> Put
175128putPosixTZ posix = do
176129 putWord8 10
177− putASCII "POSIX TZ string"$ fromMaybe "" posix
130+ putASCII $ fromMaybe "" posix
178131 putWord8 10
179132
180133putTtInfo :: TtInfo Int -> Put
@@ -207,11 +160,5 @@ putBool True = putWord8 1
207160uniq :: Eq a => [a] -> [a]
208161uniq = map head . group
209162
210−putASCII :: String -> String -> Put
211−putASCII what =
212− putByteString . B.pack . map (fromIntegral . verify . fromEnum)
213− where
214− verify c
215− | c >= 32 && c <= 126 = c
216− | otherwise = error $ "Cannot render TimeZoneSeries: " ++
217− what ++ " contains non-ASCII characters"
163+putASCII :: String -> Put
164+putASCII = putByteString . B.pack . map (fromIntegral . fromEnum)
Data/Time/LocalTime/TimeZone/Olson/Types.hs+30−100
@@ -1,9 +1,8 @@
11{-# OPTIONS_HADDOCK hide #-}
2−{-# LANGUAGE CPP #-}
32-----------------------------------------------------------------------------
43-- |
54-- Module : Data.Time.LocalTime.TimeZone.Olson.Types
6−-- Copyright : Yitzchak Gale 2018
5+-- Copyright : Yitzchak Gale 2010
76--
87-- Maintainer : Yitzchak Gale <gale@sefer.org>
98-- Portability : portable
@@ -11,14 +10,14 @@
1110-- Data types to represent timezone data as used in Olson timezone
1211-- files, and as specified by the tzfile(5) man page on Unix-like
1312-- systems. For more information about this format, see
14−-- <http://www.twinsun.com/tz/tz-link.htm>.
13+-- http://www.twinsun.com/tz/tz-link.htm.
1514--
1615-- Both Version 1 and Version 2 timezone data can be represented.
1716
18−{- Copyright (c) 2018 Yitzchak Gale. All rights reserved.
19−For licensing information, see the BSD3-style license in the file
20−LICENSE that was originally distributed by the author together with
21−this file. -}
17+{- Copyright (c) 2010 Yitzchak Gale. All rights reserved. For
18+licensing information, see the BSD3-style license in the file LICENSE
19+that was originally distributed by the author together with this file.
20+-}
2221
2322module Data.Time.LocalTime.TimeZone.Olson.Types
2423(
@@ -27,73 +26,38 @@ module Data.Time.LocalTime.TimeZone.Olson.Types
2726 Transition(..),
2827 TransitionType(..),
2928 TtInfo(..),
30− LeapInfo(..),
31−
32− -- ** Size limits for Olson timezone data
33− SizeLimits(..),
34− defaultLimits,
35− limitsNoSolar,
36− noLimits
29+ LeapInfo(..)
3730)
3831where
3932
40−#if MIN_VERSION_base(4,11,0)
41−import Data.Semigroup (Semigroup(..))
42−#endif
4333import Data.Monoid (Monoid(..))
4434import Control.Monad (mplus)
4535
4636-- | @OlsonData@ represents a full set of timezone data for a location.
4737--
48−-- @OlsonData@ can represent timezone data from files in Version 1, 2,
49−-- or 3 format.
50−--
51−-- Version 1 format files can only contain timestamp values that can
52−-- be represented in less than 32 bits, and cannot contain a POSIX TZ
53−-- string.
54−--
55−-- In a Version 2 format file, the timezone data is split into two
56−-- parts. The first part contains timezone data for which all
57−-- timestamp values can be represented in less than 32 bits, and the
58−-- second part contains timezone data for which 32 bits or more are
59−-- required to represent timestamp values. The POSIX TZ string, if
60−-- present, can only be rendered in a Version 2 file, and appears
61−-- after both parts of the timezone data.
38+-- @OlsonData@ can represent timezone data from files in Version 1 format
39+-- or Version 2 format. Version 1 format files can only contain timestamp
40+-- values that can be represented in less than 32 bits, and cannot contain
41+-- a POSIX TZ string.
6242--
63−-- Version 3 format files relax certain syntax requirements for the
64−-- POSIX TZ string. Since we represent the POSIX TZ string as an
65−-- unparsed 'String', Version 3 is identical to Version 2 for our
66−-- purposes.
43+-- In a Version 2 format file, the timezone data is split into two parts.
44+-- The first part contains timezone data for which all timestamp values
45+-- can be represented in less than 32 bits, and the second part contains
46+-- timezone data for which 32 bits or more are required to represent
47+-- timestamp values. The POSIX TZ string, if present, can only be rendered
48+-- in a Version 2 file, and appears after both parts of the timezone data.
6749data OlsonData =
68− OlsonData {
69− olsonTransitions :: [Transition],
70− olsonTypes :: [TtInfo String],
71− olsonLeaps :: [LeapInfo],
72− olsonPosixTZ :: (Maybe String)
73− -- ^ Optional POSIX TZ string for
74− -- times after the last @Transition@
75− }
50+ OlsonData
51+ [Transition]
52+ [TtInfo String]
53+ [LeapInfo]
54+ (Maybe String) -- ^ Optional POSIX TZ string for the last @Transition@
7655 deriving (Eq, Show)
7756
78−#if MIN_VERSION_base(4,11,0)
79−instance Semigroup OlsonData where
80− OlsonData a b c d <> OlsonData a' b' c' d' =
81− OlsonData (a ++ map (shiftBy $ length b) a')
82− (b ++ b') (c ++ c') (d `mplus` d')
83− where
84− shiftBy n trans = trans {transIndex = n + transIndex trans}
85−
86−instance Monoid OlsonData where
87− mempty = OlsonData [] [] [] Nothing
88−#else
8957instance Monoid OlsonData where
9058 mempty = OlsonData [] [] [] Nothing
91− mappend (OlsonData a b c d ) (OlsonData a' b' c' d') =
92− OlsonData (a ++ map (shiftBy $ length b) a')
93− (b ++ b') (c ++ c') (d `mplus` d')
94− where
95− shiftBy n trans = trans {transIndex = n + transIndex trans}
96−#endif
59+ mappend (OlsonData a b c d ) (OlsonData a' b' c' d')
60+ = OlsonData (a++a') (b++b') (c++c') (d `mplus` d')
9761
9862-- | A @Transition@ represents a moment when the clocks change in a
9963-- timezone. It consists of a Unix timestamp value that indicates the
@@ -104,9 +68,8 @@ data Transition =
10468 Transition
10569 {transTime :: Integer, -- ^ Unix timestamp indicating the time
10670 -- when the clocks change
107− transIndex :: Int -- ^ 0-based index in the list of @TtInfo@
71+ transIndex :: Int} -- ^ 0-based index in the list of @TtInfo@
10872 -- that describes the new time
109− }
11073 deriving (Eq, Show)
11174
11275-- | A @TransitionType@ is historical information about whether the
@@ -116,7 +79,7 @@ data Transition =
11679-- zone. This historical trivia may seem rather boring, but
11780-- unfortunately it is needed to interpret a POSIX-style TZ string
11881-- timezone specification correctly.
119−data TransitionType = Std | Wall | UTC
82+data TransitionType = Std | Wall | UTC | UnknownType
12083 deriving (Eq, Ord, Show)
12184
12285-- | A @TtInfo@ is a specification of local time in a timezone for
@@ -131,48 +94,15 @@ data TtInfo abbr =
13194 -- in seconds
13295 tt_isdst :: Bool, -- ^ True if local clocks are summer time
13396 tt_ttype :: TransitionType,
134− tt_abbr :: abbr -- ^ The timezone abbreviation string.
135− }
136− deriving (Eq, Ord, Show)
97+ tt_abbr :: abbr} -- ^ The timezone abbreviation string.
98+ deriving (Eq, Show)
13799
138100-- | Olson timezone files can contain leap second specifications, though
139−-- most do not.
101+-- the official files have not done so since the late 1980s.
140102data LeapInfo =
141103 LeapInfo
142104 {leapTime :: Integer, -- ^ A Unix timestamp indicating the time
143105 -- that the leap second occurred
144− leapOffset :: Int -- ^ The new total offset of UTC from UT1
106+ leapOffset :: Int} -- ^ The new total offset of UTC from UT1
145107 -- after this leap second
146− }
147108 deriving (Eq, Show)
148−
149−-- | The reference C implentation imposes size limits on the data
150−-- structures in a timezone file.
151−data SizeLimits = SizeLimits
152− {maxTimes :: Maybe Int, -- ^ The maximum number of transition times
153− maxTypes :: Maybe Int, -- ^ The maximum number of TtInfo
154− -- clock settings
155− maxAbbrChars :: Maybe Int, -- ^ The maximum total number of bytes in
156− -- all timezone abbreviations.
157− maxLeaps :: Maybe Int -- ^ The maximum number of leap second
158− -- specifications.
159− }
160−
161−-- | The size limits in @defaultLimits@ are taken from the file
162−-- tzfile.h from tzcode version 2010f. These are the limits for the C
163−-- implementation on many platforms.
164−defaultLimits :: SizeLimits
165−defaultLimits = SizeLimits { maxTimes = Just 1200, maxTypes = Just 256,
166− maxAbbrChars = Just 50, maxLeaps = Just 50 }
167−
168−-- | @limitsNoSolar@ contains the tighter size limits imposed on some
169−-- platforms that do not allow timezones that are based on solar time.
170−limitsNoSolar :: SizeLimits
171−limitsNoSolar = defaultLimits { maxTypes = Just 20 }
172−
173−-- | @noLimits@ imposes no size limits. If you use @noLimits@ when
174−-- parsing, you may exhaust all available memory when reading a faulty
175−-- or malicious timezone file. If you use @noLimits@ when rendering,
176−-- the rendered timezone file might not be readable on some systems.
177−noLimits :: SizeLimits
178−noLimits = SizeLimits Nothing Nothing Nothing Nothing
LICENSE+1−1
@@ -1,4 +1,4 @@
1−Copyright (c) 2010-2018 Yitzchak Gale. All rights reserved.
1+Copyright (c) 2010 Yitzchak Gale. All rights reserved.
22
33Redistribution and use in source and binary forms, with or without
44modification, are permitted provided that the following conditions are
README.mddeleted−43
@@ -1,43 +0,0 @@
1−# timezone-olson
2−
3−On Hackage: [timezone-olson](http://hackage.haskell.org/package/timezone-olson)
4−
5−This package provides a parser and renderer for binary Olson timezone
6−files whose format is specified by the tzfile(5) man page on Unix-like
7−systems. For more information about this format, see
8−[the IANA timezone database site](https://www.iana.org/time-zones).
9−
10−Functions are provided for
11−converting the parsed data into `TimeZoneSeries` objects from the
12−[timezone-series](http://hackage.haskell.org/package/timezone-series)
13−package. On many platforms, binary Olson timezone
14−files suitable for use with this package are available in the
15−directory `/usr/share/zoneinfo` and its subdirectories on your computer.
16−
17−See also the
18−[timezone-olson-th](http://hackage.haskell.org/package/timezone-olson-th)
19−package for a way to include timezone informaton from a binary Olson
20−timezone file at compile time.
21−
22−Copyright (c) 2010-2018 Yitzchak Gale. All rights reserved.
23−
24−For licensing information, see the BSD3-style license in the file
25−LICENSE that was originally distributed by the author together with
26−this file.
27−
28−This package is part of the [time-ng project](http://projects.haskell.org/time-ng/).
29−
30−## Testing utilities
31−
32−This package also provides two Haskell files, each of which can be
33−compiled into a command-line utility that might be helpful for testing
34−purposes.
35−
36−zhdump.hs: A clone of zdump(8), including most of its bugs, that
37− is usually present on systems that have an Olson timezone
38− database, except hzdump takes paths to timezone files
39− instead of timezone identifiers on the command line.
40−
41−catTZ: Read and parse a timezone file, then render it. With the
42− -i flag, interprets the timezone data as a TimeZoneSeries
43− object before rendering.
Setup.hsdeleted−2
@@ -1,2 +0,0 @@
1−import Distribution.Simple
2−main = defaultMain
catTZ.hsdeleted−14
@@ -1,14 +0,0 @@
1−-- | Parse an Olson timezone file, then render it.
2−-- If -i is specified, interpret it as a TimeZoneSeries before rendering.
3−module Main where
4−
5−import Data.Time.LocalTime.TimeZone.Olson
6−import Data.Time.LocalTime.TimeZone.Series
7−import System.Environment
8−
9−main = do
10− args <- getArgs
11− if head args == "-i"
12− then getTimeZoneSeriesFromOlsonFile (args !! 1) >>=
13− renderTimeZoneSeriesToOlsonFile (args !! 2)
14− else getOlsonFromFile (args !! 0) >>= renderOlsonToFile (args !! 1)
hzdump.hs+12−28
@@ -1,6 +1,5 @@
11-- | A clone in Haskell of the zdump(8) command, including most of
2−-- the bugs, that takes paths to Olson files instead of timezone
3−-- names. This is useful for testing the Haskell implementation
2+-- the bugs. This is useful for testing the Haskell implementation
43-- of the Olson timezone parser and renderer against the reference
54-- implementation in C. But less useful than it might seem at first,
65-- because Haskell rounds historical solar mean timezones to the
@@ -15,18 +14,15 @@ import Data.Maybe (listToMaybe)
1514import System.Environment (getArgs)
1615import System.Exit (exitWith, exitSuccess, ExitCode(ExitFailure))
1716import System.Locale (defaultTimeLocale)
18−import Control.Monad (guard)
1917
2018version :: IO a
2119version = do
22− putStrLn "hzdump version 0.1, clone of zdump 1.7 -c option fixed,"
23− putStrLn "takes zone file paths instead of zone specifications"
20+ putStrLn "hzdump version 0.1, clone of zdump 1.7 with -c option fixed"
2421 exitSuccess
2522
2623usage :: IO a
2724usage = do
28− putStrLn "usage: hzdump [--version] [-v] [-c cutoff] zone-file-path ..."
29− putStrLn " where cutoff is lo-year,hi-year or hi-year"
25+ putStrLn "usage: hzdump [--version] [-v] [-c cutoff] zonename ..."
3026 exitWith $ ExitFailure 1
3127
3228illegalOpt :: Char -> IO a -- sic
@@ -34,8 +30,7 @@ illegalOpt opt = do
3430 putStrLn $ "hzdump: illegal option -- " ++ [opt]
3531 usage
3632
37−data Option = Version | Illegal Char |
38− Verbose (Maybe Integer, Maybe Integer) | Now
33+data Option = Version | Illegal Char | Verbose (Maybe Integer) | Now
3934 deriving (Eq, Ord, Show)
4035
4136main = do
@@ -43,7 +38,7 @@ main = do
4338 (getTimes, displayTime) <- case opts of
4439 Version -> version
4540 Illegal opt -> illegalOpt opt
46− Verbose rng -> return (transitionTimes rng, displayVerbose)
41+ Verbose yr -> return (transitionTimesUntil yr, displayVerbose)
4742 _ -> do now <- getCurrentTime
4843 return (const [now], displayConcise)
4944 tzss <- mapM getZone zones
@@ -58,26 +53,17 @@ main = do
5853
5954parseArgs :: [String] -> (Option, [FilePath])
6055parseArgs args | "--version" `elem` args = (Version, [])
61−parseArgs args = getOpts False (Nothing, Nothing) args
56+parseArgs args = getOpts False Nothing args
6257 where
6358 getOpts _ cutoff ("-v":args) = getOpts True cutoff args
64− getOpts v _ ("-c":c:args) = maybe (Illegal 'c', [])
65− (\y -> getOpts v y args) $
66− parseCutoff c
59+ getOpts v Nothing ("-c":c:args) = maybe (Illegal 'c', [])
60+ (\y -> getOpts v (Just y) args) $
61+ maybeRead c
6762 getOpts v cutoff ("--":zones ) = (opts v cutoff, zones)
6863 getOpts _ _ (('-':x:_):_) = (Illegal x, [])
6964 getOpts v cutoff zones = (opts v cutoff, zones)
70−
7165 opts v cutoff = if v then Verbose cutoff else Now
7266
73− parseCutoff c = let p0 = listToMaybe $ reads c
74− los = fmap fst p0
75− his = do str <- fmap snd p0
76− let (comma, str1) = splitAt 1 str
77− guard $ comma == ","
78− maybeRead str1
79− in los >> Just (maybe (Nothing, los) ((,) los . Just) his)
80−
8167displayConcise :: TimeZoneSeries -> UTCTime -> String
8268displayConcise tzs t = formatTime defaultTimeLocale format $
8369 ZoneSeriesTime t tzs
@@ -90,11 +76,9 @@ displayVerbose tzs t = concat [displayConcise utcTZ t, " = ",
9076 where
9177 isdst = timeZoneSummerOnly $ timeZoneFromSeries tzs t
9278
93−transitionTimes :: (Maybe Integer, Maybe Integer) -> TimeZoneSeries ->
94− [UTCTime]
95−transitionTimes (lo, hi) =
96− maybe id (takeWhile . (>)) (fmap happyNewYear hi) .
97− maybe id (dropWhile . (>)) (fmap happyNewYear lo) .
79+transitionTimesUntil :: Maybe Integer -> TimeZoneSeries -> [UTCTime]
80+transitionTimesUntil yr =
81+ maybe id (dropWhile . (>=)) (fmap happyNewYear yr) .
9882 addBugs . addPrevSecond . actualTransitions
9983 where
10084 happyNewYear y = UTCTime (fromGregorian y 1 1) 0
timezone-olson.cabaldeleted−45
@@ -1,45 +0,0 @@
1−Name: timezone-olson
2−Version: 0.1.9
3−Synopsis: A pure Haskell parser and renderer for binary Olson timezone files
4−Description: A parser and renderer for binary Olson timezone
5− files whose format is specified by the tzfile(5)
6− man page on Unix-like systems. For more
7− information about this format, see
8− <http://www.iana.org/time-zones/repository/tz-link.html>.
9− Functions are provided for converting the parsed data into
10− 'TimeZoneSeries' objects from the timezone-series
11− package. On many platforms, binary Olson timezone
12− files suitable for use with this package are
13− available in the directory /usr/share/zoneinfo
14− and its subdirectories on your computer.
15− For a way to read binary Olson timezone files at compile
16− time, see the timezone-olson-th package
17− (<http://hackage.haskell.org/package/timezone-olson-th>).
18−Homepage: http://projects.haskell.org/time-ng/
19−License: BSD3
20−License-file: LICENSE
21−Author: Yitzchak Gale
22−Maintainer: yitz@sefer.org
23−Copyright: Copyright (c) 2010-2018 Yitzchak Gale. All rights reserved.
24−Category: Data
25−Build-type: Simple
26−Extra-source-files: README.md, catTZ.hs, hzdump.hs
27−Cabal-version: >=1.10
28−Tested-with: GHC > 8.0 && < 8.5
29−
30−Source-repository HEAD
31− type: git
32− location: https://github.com/ygale/timezone-olson.git
33−
34−Library
35− Default-language: Haskell2010
36− Exposed-modules: Data.Time.LocalTime.TimeZone.Olson
37− , Data.Time.LocalTime.TimeZone.Olson.Parse
38− , Data.Time.LocalTime.TimeZone.Olson.Render
39− , Data.Time.LocalTime.TimeZone.Olson.Types
40− Build-depends: base >= 3.0 && < 5.0,
41− timezone-series >= 0.1.0 && < 0.2,
42− time >= 1.6 && < 1.10,
43− binary >= 0.4.1 && < 0.9,
44− bytestring >= 0.9 && < 1.0,
45− extensible-exceptions >= 0.1.0 && < 0.2