git.iko.soy/typeable/timezone-olson
on master help sign in
10 files changed+302−160
since splitsnapshots
unifiedsplit
.gitignore+16 .travis.yml+107 Data/Time/LocalTime/TimeZone/Olson.hs+2−2 Data/Time/LocalTime/TimeZone/Olson/Parse.hs+21−14 Data/Time/LocalTime/TimeZone/Olson/Render.hs+47−54 Data/Time/LocalTime/TimeZone/Olson/Types.hs+41−14 LICENSE+1−1 README → README.md+18−24 catTZ.hs+14 timezone-olson.cabal+35−51
.gitignorenew file+16
@@ -0,0 +1,16 @@
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.ymlnew file+107
@@ -0,0 +1,107 @@
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+2−2
@@ -1,7 +1,7 @@
11-----------------------------------------------------------------------------
22-- |
33-- Module : Data.Time.LocalTime.TimeZone.Olson
4−-- Copyright : Yitzchak Gale 2010
4+-- Copyright : Yitzchak Gale 2018
55--
66-- Maintainer : Yitzchak Gale <gale@sefer.org>
77-- Portability : portable
@@ -13,7 +13,7 @@
1313-- converting the parsed data into @TimeZoneSeries@ and @TimeZone@
1414-- objects.
1515
16−{- Copyright (c) 2010 Yitzchak Gale. All rights reserved.
16+{- Copyright (c) 2018 Yitzchak Gale. All rights reserved.
1717For licensing information, see the BSD3-style license in the file
1818LICENSE that was originally distributed by the author together with
1919this file. -}
Data/Time/LocalTime/TimeZone/Olson/Parse.hs+21−14
@@ -3,19 +3,18 @@
33-----------------------------------------------------------------------------
44-- |
55-- Module : Data.Time.LocalTime.TimeZone.Olson.Parse
6−-- Copyright : Yitzchak Gale 2010
6+-- Copyright : Yitzchak Gale 2018
77--
88-- Maintainer : Yitzchak Gale <gale@sefer.org>
99-- Portability : portable
1010--
11−-- A parser for binary Olson timezone files whose format are specified
11+-- A parser for binary Olson timezone files whose format is specified
1212-- by the tzfile(5) man page on Unix-like systems. For more
1313-- information about this format, see
1414-- <http://www.twinsun.com/tz/tz-link.htm>. Functions are provided for
15−-- converting the parsed data into @TimeZoneSeries@ and @TimeZone@
16−-- objects.
15+-- converting the parsed data into 'TimeZoneSeries' objects.
1716
18−{- Copyright (c) 2010 Yitzchak Gale. All rights reserved.
17+{- Copyright (c) 2018 Yitzchak Gale. All rights reserved.
1918For licensing information, see the BSD3-style license in the file
2019LICENSE that was originally distributed by the author together with
2120this file. -}
@@ -40,9 +39,12 @@ import Data.Binary.Get (Get, runGet, getWord8, getWord32be, getWord64be,
4039import qualified Data.ByteString as B
4140import qualified Data.ByteString.Lazy as L
4241import 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)
4648import Data.Typeable (Typeable)
4749import Control.Monad (guard, replicateM, replicateM_, when)
4850import Control.Exception.Extensible (try, throw, Exception, ErrorCall)
@@ -58,8 +60,8 @@ instance Exception OlsonError
5860-- | Convert parsed Olson timezone data into a @TimeZoneSeries@.
5961olsonToTimeZoneSeries :: OlsonData -> Maybe TimeZoneSeries
6062olsonToTimeZoneSeries (OlsonData ttimes ttinfos@(dflt0:_) _ _) =
61− fmap (TimeZoneSeries $ mkTZ dflt) . mapM (lookupTZ ttinfos) $
62− reverse ttimes
63+ fmap (TimeZoneSeries $ mkTZ dflt) . mapM (lookupTZ ttinfos) .
64+ uniqTimes . sortBy futureToPast $ ttimes
6365 where
6466 dflt = fromMaybe dflt0 . listToMaybe $ filter isStd ttinfos
6567 isStd (TtInfo _ isdst _ _) = not isdst
@@ -68,6 +70,8 @@ olsonToTimeZoneSeries (OlsonData ttimes ttinfos@(dflt0:_) _ _) =
6870 lookupTZ ttinfos ttime = fmap (((,) $ toUTC ttime) . mkTZ) . listToMaybe $
6971 drop (transIndex ttime) ttinfos
7072 toUTC = posixSecondsToUTCTime . fromIntegral . transTime
73+ uniqTimes = map last . groupBy ((==) `on` transTime)
74+ futureToPast = comparing $ negate . transTime
7175olsonToTimeZoneSeries _ = Nothing
7276
7377-- | Read timezone data from a binary Olson timezone file and convert
@@ -103,13 +107,16 @@ getOlson :: SizeLimits -> Get OlsonData
103107getOlson limits = do
104108 (version, part1) <- getOlsonPart True limits get32bitInteger
105109 -- There is one part for Version 1 format data, and two parts and a POSIX
106− -- TZ string for Version 2 format data
107− case version of
108− 0 -> return part1
109− 50 -> do (_, part2) <- getOlsonPart False limits get64bitInteger
110− posixTZ <- getPosixTZ
111− return $ part1 `mappend` part2 `mappend` posixTZ
112− _ -> verify (const False) "invalid version number" undefined
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
113120
114121-- Parse the part of an Olson file that contains timezone data
115122getOlsonPart :: Integral a => Bool -> SizeLimits -> Get a ->
Data/Time/LocalTime/TimeZone/Olson/Render.hs+47−54
@@ -2,7 +2,7 @@
22-----------------------------------------------------------------------------
33-- |
44-- Module : Data.Time.LocalTime.TimeZone.Olson.Render
5−-- Copyright : Yitzchak Gale 2010
5+-- Copyright : Yitzchak Gale 2018
66--
77-- Maintainer : Yitzchak Gale <gale@sefer.org>
88-- Portability : portable
@@ -12,7 +12,7 @@
1212-- Unix-like systems. For more information about this format, see
1313-- <http://www.twinsun.com/tz/tz-link.htm>.
1414
15−{- Copyright (c) 2010 Yitzchak Gale. All rights reserved.
15+{- Copyright (c) 2018ZZ Yitzchak Gale. All rights reserved.
1616For licensing information, see the BSD3-style license in the file
1717LICENSE that was originally distributed by the author together with
1818this file. -}
@@ -30,7 +30,7 @@ module Data.Time.LocalTime.TimeZone.Olson.Render
3030 renderOlsonToFile,
3131 verifyOlsonLimits,
3232 putOlson,
33− splitOlson
33+ extractOlsonV1
3434)
3535where
3636
@@ -69,9 +69,9 @@ timeZoneSeriesToOlson (TimeZoneSeries dflt pairs)
6969 | otherwise = Just $
7070 OlsonData
7171 [Transition secs ttinfo |
72− (t, tzs) <- reverse pairs,
72+ (t, tz) <- reverse pairs,
7373 let secs = round $ utcTimeToPOSIXSeconds t,
74− ttinfo <- maybeToList $ lookup (mkTT tzs) ttAssocs]
74+ ttinfo <- maybeToList $ lookup (mkTT tz) ttAssocs]
7575 ttinfos
7676 []
7777 Nothing
@@ -110,66 +110,52 @@ renderOlsonToFile fp olson = do
110110
111111-- | Render Olson timezone data in binary Olson timezone file format
112112-- as a lazy @ByteString@
113−putOlson :: OlsonData -> Put
114−putOlson olson = putOlsonParts version olson1 olson2 posix >> flush
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
115118 where
116− (olson1, olson2, posix) = splitOlson olson
117− version
118− | olson2 /= mempty = 50
119− | otherwise = maybe 0 (const 50) $ posix >>= guard . not . null
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−-- rendered using Version 2 format, and the POSIX-style TZ string
124−-- if specified
125−splitOlson :: OlsonData -> (OlsonData, OlsonData, Maybe String)
126−splitOlson (OlsonData transs ttinfos leaps posix) =
127− (OlsonData transs1 ttinfos1 leaps1 Nothing,
128− OlsonData transs2 ttinfos2 leaps2 Nothing,
129− posix)
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
130128 where
131129 cutoff = 0x80000000 -- 2^31
132130 fitsIn32bits x = x < cutoff && x >= negate cutoff
133− ( leaps1 , leaps2 ) = partition (fitsIn32bits . leapTime) leaps
134− (transs1', transs2') = partition (fitsIn32bits . transTime) transs
135− assoc1 = mkAssoc [0] transs1'
136− assoc2 = mkAssoc [] transs2'
137− transs1 = mkTranss transs1' assoc1
138− transs2 = mkTranss transs2' assoc2
139− ttinfos1 = mkTtinfos assoc1
140− ttinfos2 = mkTtinfos assoc2
141− mkAssoc prepend transs' = zip
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
142135 (sortBy (comparing $ fmap tt_ttype . listToMaybe . flip drop ttinfos) .
143− uniq . sort . (prepend ++) $ map transIndex transs')
136+ uniq . sort . (0 :) $ map transIndex transs1')
144137 [0..]
145− mkTranss transs' assoc = [t {transIndex = i} |
146− t <- transs', i <- maybeToList $ lookup (transIndex t) assoc]
147− mkTtinfos assoc = map snd . dropWhile (isNothing . fst) .
148− sortBy (comparing fst) $ zip (map (flip lookup assoc) [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
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
156142
157143putOlsonPart :: Word8 -> (Integer -> Put) -> OlsonData -> Put
158144putOlsonPart version putTime (OlsonData transs ttinfos leaps _) = do
159− putASCII "TZif"
145+ putASCII "magic number" "TZif"
160146 putWord8 version
161147 putByteString . B.pack $ replicate 15 0 -- padding nulls
162148 replicateM_ 2 $ putCount ttinfosWithTtype
163− -- tzh_ttisgmtcnt
164− -- tzh_ttisstdcnt
165− putCount leaps -- tzh_leapcnt
166− putCount transs -- tzh_timecnt
167− putCount ttinfos -- tzh_typecnt
168− putCount abbrChars -- tzh_charcnt
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
169155 mapM_ (putTime . transTime ) transs
170156 mapM_ (put8bitIntegral . transIndex) transs
171157 mapM_ putTtInfo ttinfosIndexed
172− putASCII abbrChars
158+ mapM_ putAbbr abbrStrings
173159 mapM_ (putLeapInfo putTime) leaps
174160 mapM_ (putBool . (== Std) . tt_ttype) ttinfosWithTtype -- isstd
175161 mapM_ (putBool . (== UTC) . tt_ttype) ttinfosWithTtype -- isgmt
@@ -177,7 +163,8 @@ putOlsonPart version putTime (OlsonData transs ttinfos leaps _) = do
177163 putCount = put32bitIntegral . length
178164 ttinfosWithTtype = takeWhile ((<= UTC) . tt_ttype) ttinfosIndexed
179165 abbrStrings = uniq . sort $ map tt_abbr ttinfos
180− abbrChars = concatMap (++ "\NUL") abbrStrings
166+ abbrChars = sum (map length abbrStrings) + length abbrStrings
167+ putAbbr abbr = putASCII "time zone abbreviation" abbr >> putWord8 0
181168 abbrAssocs = zip abbrStrings . scanl (+) 0 $
182169 map ((+ 1) . length) abbrStrings
183170 ttinfosIndexed = [TtInfo gmtoff isdst ttype i |
@@ -187,7 +174,7 @@ putOlsonPart version putTime (OlsonData transs ttinfos leaps _) = do
187174putPosixTZ :: Maybe String -> Put
188175putPosixTZ posix = do
189176 putWord8 10
190− putASCII $ fromMaybe "" posix
177+ putASCII "POSIX TZ string"$ fromMaybe "" posix
191178 putWord8 10
192179
193180putTtInfo :: TtInfo Int -> Put
@@ -220,5 +207,11 @@ putBool True = putWord8 1
220207uniq :: Eq a => [a] -> [a]
221208uniq = map head . group
222209
223−putASCII :: String -> Put
224−putASCII = putByteString . B.pack . map (fromIntegral . fromEnum)
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"
Data/Time/LocalTime/TimeZone/Olson/Types.hs+41−14
@@ -1,8 +1,9 @@
11{-# OPTIONS_HADDOCK hide #-}
2+{-# LANGUAGE CPP #-}
23-----------------------------------------------------------------------------
34-- |
45-- Module : Data.Time.LocalTime.TimeZone.Olson.Types
5−-- Copyright : Yitzchak Gale 2010
6+-- Copyright : Yitzchak Gale 2018
67--
78-- Maintainer : Yitzchak Gale <gale@sefer.org>
89-- Portability : portable
@@ -14,7 +15,7 @@
1415--
1516-- Both Version 1 and Version 2 timezone data can be represented.
1617
17−{- Copyright (c) 2010 Yitzchak Gale. All rights reserved.
18+{- Copyright (c) 2018 Yitzchak Gale. All rights reserved.
1819For licensing information, see the BSD3-style license in the file
1920LICENSE that was originally distributed by the author together with
2021this file. -}
@@ -36,22 +37,33 @@ module Data.Time.LocalTime.TimeZone.Olson.Types
3637)
3738where
3839
40+#if MIN_VERSION_base(4,11,0)
41+import Data.Semigroup (Semigroup(..))
42+#endif
3943import Data.Monoid (Monoid(..))
4044import Control.Monad (mplus)
4145
4246-- | @OlsonData@ represents a full set of timezone data for a location.
4347--
44−-- @OlsonData@ can represent timezone data from files in Version 1 format
45−-- or Version 2 format. Version 1 format files can only contain timestamp
46−-- values that can be represented in less than 32 bits, and cannot contain
47−-- a POSIX TZ string.
48+-- @OlsonData@ can represent timezone data from files in Version 1, 2,
49+-- or 3 format.
4850--
49−-- In a Version 2 format file, the timezone data is split into two parts.
50−-- The first part contains timezone data for which all timestamp values
51−-- can be represented in less than 32 bits, and the second part contains
52−-- timezone data for which 32 bits or more are required to represent
53−-- timestamp values. The POSIX TZ string, if present, can only be rendered
54−-- in a Version 2 file, and appears after both parts of the timezone data.
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.
62+--
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.
5567data OlsonData =
5668 OlsonData {
5769 olsonTransitions :: [Transition],
@@ -63,10 +75,25 @@ data OlsonData =
6375 }
6476 deriving (Eq, Show)
6577
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
6689instance Monoid OlsonData where
6790 mempty = OlsonData [] [] [] Nothing
68− mappend (OlsonData a b c d ) (OlsonData a' b' c' d')
69− = OlsonData (a++a') (b++b') (c++c') (d `mplus` d')
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
7097
7198-- | A @Transition@ represents a moment when the clocks change in a
7299-- timezone. It consists of a Unix timestamp value that indicates the
LICENSE+1−1
@@ -1,4 +1,4 @@
1−Copyright (c) 2010 Yitzchak Gale. All rights reserved.
1+Copyright (c) 2010-2018 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 → README.mdrenamed+18−24
@@ -1,39 +1,33 @@
1−timezone-olson version 0.1.0
1+# timezone-olson
2+
3+On Hackage: [timezone-olson](http://hackage.haskell.org/package/timezone-olson)
24
35This package provides a parser and renderer for binary Olson timezone
46files whose format is specified by the tzfile(5) man page on Unix-like
57systems. For more information about this format, see
6−<http://www.twinsun.com/tz/tz-link.htm>. Functions are provided for
7−converting the parsed data into 'TimeZoneSeries' objects from the
8−timezone-series package. On many platforms, binary Olson timezone
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
914files suitable for use with this package are available in the
10−directory /usr/share/zoneinfo and its subdirectories on your computer.
15+directory `/usr/share/zoneinfo` and its subdirectories on your computer.
1116
12−This version of timezone-olson is highly experimental. Expect there
13−to be bugs, and do not rely on any stability of the exposed
14−interfaces.
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.
1523
16−Copyright (c) 2010 Yitzchak Gale. All rights reserved.
1724For licensing information, see the BSD3-style license in the file
1825LICENSE that was originally distributed by the author together with
1926this file.
2027
21−This package is part of the time-ng project:
22−http://projects.haskell.org/time-ng/
23−
24−Send suggestions, bug reports, and patches to:
25−yitz@community.haskell.org
26−
27−INSTALLATION:
28−
29−To install the latest version of this package, make sure that
30−cabal-install is installed on your system (it is if you have installed
31−the Haskell Platform) and type the commands:
32−
33−cabal update
34−cabal install timezone-olson
28+This package is part of the [time-ng project](http://projects.haskell.org/time-ng/).
3529
36−TESTING UTILITIES:
30+## Testing utilities
3731
3832This package also provides two Haskell files, each of which can be
3933compiled into a command-line utility that might be helpful for testing
catTZ.hsnew file+14
@@ -0,0 +1,14 @@
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)
timezone-olson.cabal+35−51
@@ -1,61 +1,45 @@
1−-- timezone-olson.cabal auto-generated by cabal init. For additional
2−-- options, see
3−-- http://www.haskell.org/cabal/release/cabal-latest/doc/users-guide/authors.html#pkg-descr.
4−-- The name of the package.
51Name: timezone-olson
6−
7−-- The package version. See the Haskell package versioning policy
8−-- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for
9−-- standards guiding when and how versions should be incremented.
10−Version: 0.1
11−
12−-- A short (one-line) description of the package.
2+Version: 0.1.9
133Synopsis: A pure Haskell parser and renderer for binary Olson timezone files
14−
15−-- A longer description of the package.
16−-- Description:
17−
18−-- URL for the project homepage or repository.
19−Homepage: http://community.haskell.org/timezone
20−
21−-- The license under which the package is released.
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/
2219License: BSD3
23−
24−-- The file containing the license text.
2520License-file: LICENSE
26−
27−-- The package author(s).
2821Author: Yitzchak Gale
29−
30−-- An email address to which users can send suggestions, bug reports,
31−-- and patches.
32−Maintainer: gale@sefer.org
33−
34−-- A copyright notice.
35−-- Copyright:
36−
22+Maintainer: yitz@sefer.org
23+Copyright: Copyright (c) 2010-2018 Yitzchak Gale. All rights reserved.
3724Category: Data
38−
3925Build-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
4029
41−-- Extra files to be distributed with the package, such as examples or
42−-- a README.
43−-- Extra-source-files:
44−
45−-- Constraint on the version of Cabal needed to build this package.
46−Cabal-version: >=1.2
47−
30+Source-repository HEAD
31+ type: git
32+ location: https://github.com/ygale/timezone-olson.git
4833
4934Library
50− -- Modules exported by the library.
51− Exposed-modules: Data.Time.LocalTime.TimeZone.Olson, Data.Time.LocalTime.TimeZone.Olson.Parse, Data.Time.LocalTime.TimeZone.Olson.Render, Data.Time.LocalTime.TimeZone.Olson.Types
52−
53− -- Packages needed in order to build this package.
54− -- Build-depends:
55−
56− -- Modules not exported by this package.
57− -- Other-modules:
58−
59− -- Extra tools (e.g. alex, hsc2hs, ...) needed to build the source.
60− -- Build-tools:
61−
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