diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,17 @@
 # Changelog for timezone-detect
 
+## v0.3.0.0 (2020-09-02)
+
+**Breaking Changes!**
+
+* Introduce `openTimeZoneDatabase` and `closeTimeZoneDatabase` to hew closer to
+  the underlying library's intended usage. And `withTimeZoneDatabase` to manage the
+  opening and closing of the TZ file around an IO computation with it.
+* Changes the signature of `lookupTimeZoneName` to take a timezone database, not
+  a file, same with `timeAtPointToUTC`. Introduces `*FromFile` variants that
+  work with the path to the DB file and manage the opening/closing.
+
+
 ## v0.2.2.0 (2020-08-30)
 
 * Explicitly import `MonadFail` and `fail`; hide the `fail` from `Prelude`.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -9,27 +9,47 @@
 ## Usage
 
 You'll need timezone database files to work with this library, see instructions [in the original repository](https://github.com/BertoldVdb/ZoneDetect/tree/master/database).
+A copy is provided in the `test` directory of this repository, but it's intentionally not bundled in the package. We make no guarantees of its correctness,
+we recommend you use the original authors' files!
 
+
+### Timezone Name Lookup
+
 Once you have those files in hand, you'll be able to get a timezone from a given latitude and longitude:
 
 ```haskell
->>> lookupTimeZoneName "./test/tz_db/timezone21.bin" 40.7831 (-73.9712) :: Maybe TimeZoneName
+>>> db <- openTimeZoneDatabase "./test/tz_db/timezone21.bin" 
+>>> let tz = lookupTimeZoneName db 40.7831 (-73.9712) :: Maybe TimeZoneName
 Just "America/New_York"
+>>> closeTimeZoneDatabase db
 ```
 
-Additionally, we now depend on the [timezone-series](https://hackage.haskell.org/package/timezone-series) and [timezone-olson](https://hackage.haskell.org/package/timezone-olson) packages to add awareness of `tz database` information.
+You can use `withTimeZoneDatabase` to "bracket" access to the file (take care of opening and closing,)
+but if all you want to do is do a one-off lookup, a convenience function that opens and closes the file when done
+is also provided, specialized to `IO`:
 
+```haskell
+>>> tz <- lookupTimeZoneNameFromFile "./test/tz_db/timezone21.bin" 40.7831 (-73.9712)
+"America/New_York"
+```
+
+### LocalTime to UTCTime conversion
+
+Additionally, we depend on the [timezone-series](https://hackage.haskell.org/package/timezone-series) and [timezone-olson](https://hackage.haskell.org/package/timezone-olson) packages to add awareness of `tz database` information.
+
 With that, you can look up the UTC time at a point in time and space:
 
 ```haskell
 >>> import Data.Time
+>> db <- openTimeZoneDatabase "./test/tz_db/timezone21.bin"
 >>> localWinter <- parseTimeM True defaultTimeLocale "%Y-%-m-%-d %T" "2019-12-25 00:30:00"
->>> utcTime <- timeAtPointToUTC "./test/tz_db/timezone21.bin" 40.7831 (-73.9712) localWinter
+>>> utcTime <- timeAtPointToUTC db 40.7831 (-73.9712) localWinter
 2019-12-25 05:30:00 UTC
 
 >>> localSummer <- parseTimeM True defaultTimeLocale "%Y-%-m-%-d %T" "2019-07-25 00:30:00"
->>> utcTime <- timeAtPointToUTC "./test/tz_db/timezone21.bin" 40.7831 (-73.9712) localWinter
+>>> utcTime <- timeAtPointToUTC db 40.7831 (-73.9712) localWinter
 2019-07-25 04:30:00 UTC
+>>> closeTimeZoneDatabase db
 ```
 
 You can also opt to obtain the timezone name separately (if you wanted to isolate that as a failure scenario,)
@@ -40,3 +60,31 @@
 >>> utcTime <- timeInTimeZoneToUTC "America/New_York" localSummer
 2019-07-25 04:30:00 UTC
 ```
+
+## Copyright
+
+This library is released under the GPL v2; but the license for the underlying C library bears the following copyright:
+
+> Copyright (c) 2018, Bertold Van den Bergh (vandenbergh@bertold.org) 
+> All rights reserved.
+> Redistribution and use in source and binary forms, with or without
+> modification, are permitted provided that the following conditions are met:
+>    * Redistributions of source code must retain the above copyright
+>       notice, this list of conditions and the following disclaimer.
+>    * Redistributions in binary form must reproduce the above copyright
+>       notice, this list of conditions and the following disclaimer in the
+>       documentation and/or other materials provided with the distribution.
+>    * Neither the name of the author nor the
+>       names of its contributors may be used to endorse or promote products
+>       derived from this software without specific prior written permission.
+>
+> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+> ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+> WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+> DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTOR BE LIABLE FOR ANY
+> DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+> (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+> ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+> (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+> SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/Data/Time/LocalTime/TimeZone/Detect.hs b/src/Data/Time/LocalTime/TimeZone/Detect.hs
--- a/src/Data/Time/LocalTime/TimeZone/Detect.hs
+++ b/src/Data/Time/LocalTime/TimeZone/Detect.hs
@@ -12,19 +12,30 @@
 
 The only relevant binding to ZoneDetect is 'lookupTimeZoneName', richer information that plays neatly
 with the notion of 'TimeZone' could be derived, but I didn't have a personal need for that yet.
+
+Functions to open, close, and work with an open database (from a valid file) are provided.
 -}
 
 module Data.Time.LocalTime.TimeZone.Detect 
-    ( lookupTimeZoneName
+    ( TimeZoneName
+    , TimeZoneDatabase
+    -- for managing the database info pointer:
+    , openTimeZoneDatabase
+    , closeTimeZoneDatabase
+    , withTimeZoneDatabase
+    -- timezone lookup:
+    , lookupTimeZoneName
+    , lookupTimeZoneNameFromFile
+    -- (local time, place) -> UTC "instant"
     , timeAtPointToUTC
+    , timeAtPointToUTCFromFile
+    -- (local time, timezone name) -> UTC "instant"
     , timeInTimeZoneToUTC
-    , getTimeZoneSeriesFromOlsonFileUNIX
-    , TimeZoneName
 ) where
 
 import Foreign.ZoneDetect
 import Foreign.C.String (peekCAString, withCAString)
-import Foreign (nullPtr)
+import Foreign (Ptr, nullPtr)
 import Data.Time
 import Data.Time.LocalTime.TimeZone.Olson
 import Data.Time.LocalTime.TimeZone.Series
@@ -32,6 +43,7 @@
 import Control.Monad.IO.Class (MonadIO(liftIO))
 import Control.Monad.Fail (MonadFail, fail)
 import Prelude hiding (fail)
+import Control.Exception (bracket)
 
 -- | Alias for clarity, timezones are path-like strings that follow the IANA conventions
 -- documented here:
@@ -40,31 +52,31 @@
 -- <https://en.wikipedia.org/wiki/Tz_database#Names_of_time_zones>
 type TimeZoneName = FilePath
 
--- | Gets timezone info from the standard location in UNIX systems.
--- The name should be one of the standard tz database names, as returned
--- by `lookupTimeZoneName`.
--- See: <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones>
-getTimeZoneSeriesFromOlsonFileUNIX :: TimeZoneName -> IO TimeZoneSeries
-getTimeZoneSeriesFromOlsonFileUNIX tzName =
-    getTimeZoneSeriesFromOlsonFile $ "/usr/share/zoneinfo/" ++ tzName
+-- | A reference to a timezone database.
+type TimeZoneDatabase = Ptr ZoneDetectInfo
 
 -- | Given a timezone database, latitude and longitude, try to determine the
 -- timezone name. Follow the instructions in the C library's repository
 -- to obtain timezone database files (<https://github.com/BertoldVdb/ZoneDetect/tree/05567e367576d7f3efa00083b7661a01e43dc8ca/database>)
 -- Once in possesion of said files, the lookup looks as follows:
 -- 
--- >>> tz <- lookupTimeZoneName "./test/tz_db/timezone21.bin" 40.7831 (-73.9712) :: Maybe TimeZoneName
+-- >>> db <- openTimeZoneDatabase "./test/tz_db/timezone21.bin" 
+-- >>> let tz = lookupTimeZoneName db 40.7831 (-73.9712) :: Maybe TimeZoneName
 -- Just "America/New_York"
+-- >>> closeTimeZoneDatabase db
 -- 
--- An invalid database file, or invalid coordinates, will cause the given monad to `fail`.
-lookupTimeZoneName :: MonadFail m => FilePath -> Double -> Double -> m TimeZoneName
-lookupTimeZoneName databaseLocation lat lng = 
+-- An invalid database pointer, or invalid coordinates, will cause the given monad to `fail`.
+-- Note that we follow the original library's pattern of obtaining the `TimeZoneDatabase`
+-- separately (which could prove advantageous in e.g a web server.) If you're doing
+-- a one-off lookup, or are okay with the IO cost of opening the DB file, see
+-- `lookupTimeZoneNameFromFile`.
+lookupTimeZoneName :: MonadFail m => TimeZoneDatabase -> Double -> Double -> m TimeZoneName
+lookupTimeZoneName database lat lng =
     unsafePerformIO $ do
-        zdPtr <- withCAString databaseLocation $ \dbl -> c_ZDOpenDatabase dbl
-        if zdPtr == nullPtr then
-            pure $ fail (databaseLocation ++ " is not a valid timezone database.")
+        if database == nullPtr then
+            pure $ fail "Invalid timezone database."
         else do
-            tzName <- c_ZDHelperSimpleLookupString zdPtr
+            tzName <- c_ZDHelperSimpleLookupString database
                                                    (realToFrac lat)
                                                    (realToFrac lng)
             if tzName == nullPtr then
@@ -72,6 +84,11 @@
             else
                 peekCAString tzName >>= (pure . return)
 
+-- | Same as `lookupTimeZoneName`, but takes the path to the database file and only works in `IO`.
+lookupTimeZoneNameFromFile :: FilePath -> Double -> Double -> IO TimeZoneName
+lookupTimeZoneNameFromFile databaseLocation lat lng =
+    withTimeZoneDatabase databaseLocation
+        (\db -> lookupTimeZoneName db lat lng) 
 
 -- | Given a timezone name (presumably obtained via `lookupTimeZoneName`,)
 -- and a reference time in `LocalTime`, find the UTC equivalent.
@@ -85,7 +102,39 @@
 -- which offset was in effect, since daylight savings, historical circumstances, political revisions
 -- and other circumstances (documented in the olson tz database) may have been in effect
 -- at that point in spacetime.
-timeAtPointToUTC :: FilePath -> Double -> Double -> LocalTime -> IO UTCTime
-timeAtPointToUTC databaseLocation lat lng referenceTime = do
-    tzName <- lookupTimeZoneName databaseLocation lat lng
+timeAtPointToUTC :: TimeZoneDatabase -> Double -> Double -> LocalTime -> IO UTCTime
+timeAtPointToUTC database lat lng referenceTime = do
+    tzName <- lookupTimeZoneName database lat lng
     timeInTimeZoneToUTC tzName referenceTime
+
+-- | Same as `timeAtPointToUTC`, but takes the path to the timezone database file
+-- and takes care of opening and closing the file.
+timeAtPointToUTCFromFile :: FilePath -> Double -> Double -> LocalTime -> IO UTCTime
+timeAtPointToUTCFromFile databaseLocation lat lng referenceTime =
+    withTimeZoneDatabase databaseLocation
+        (\db -> timeAtPointToUTC db lat lng referenceTime) 
+
+-- | Gets timezone info from the standard location in UNIX systems.
+-- The name should be one of the standard tz database names, as returned
+-- by `lookupTimeZoneName`.
+-- See: <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones>
+getTimeZoneSeriesFromOlsonFileUNIX :: TimeZoneName -> IO TimeZoneSeries
+getTimeZoneSeriesFromOlsonFileUNIX tzName =
+    getTimeZoneSeriesFromOlsonFile $ "/usr/share/zoneinfo/" ++ tzName
+
+-- | Open a timezone database file and obtain a pointer to the database,
+-- as interpreted by the underlying C code.
+openTimeZoneDatabase :: FilePath -> IO TimeZoneDatabase
+openTimeZoneDatabase databaseLocation = 
+    withCAString databaseLocation $ \dbl -> c_ZDOpenDatabase dbl
+
+-- | Given a pointer to a timezone database, close any allocated resources.
+closeTimeZoneDatabase :: TimeZoneDatabase -> IO ()
+closeTimeZoneDatabase = c_ZDCloseDatabase
+
+-- | Given a path to a timezone database file, and a computation to run with it,
+-- takes care of opening the file, running the computation and then closing it.
+withTimeZoneDatabase :: FilePath -> (TimeZoneDatabase -> IO a) -> IO a
+withTimeZoneDatabase databaseLocation = 
+    bracket (openTimeZoneDatabase databaseLocation)
+            (closeTimeZoneDatabase)
diff --git a/src/Foreign/ZoneDetect.hsc b/src/Foreign/ZoneDetect.hsc
--- a/src/Foreign/ZoneDetect.hsc
+++ b/src/Foreign/ZoneDetect.hsc
@@ -8,27 +8,16 @@
 
 #include <zonedetect.h>
 
--- https://github.com/BertoldVdb/ZoneDetect/blob/05567e367576d7f3efa00083b7661a01e43dc8ca/library/zonedetect.c#L61
--- note that we define the non-Windows version. This library will not compile in Windows systems! (sorry, I just
--- don't know enough Haskell CPP directive-fu yet!)
+-- | Opaque pointer to the underlying C struct:
+-- https://wiki.haskell.org/FFI_cook_book#Passing_opaque_structures.2Ftypes
+-- https://github.com/BertoldVdb/ZoneDetect/blob/05567e367576d7f3efa00083b7661a01e43dc8ca/library/zonedetect.h
 data ZoneDetectInfo = ZoneDetectInfo
-    { fd :: Int
-    , length :: CInt -- as per: https://hackage.haskell.org/package/bindings-posix-1.2.4/docs/Bindings-Posix-Sys-Types.html
-    , closeType :: Word8
-    , mapping :: Ptr Word8
-    , tableType :: Word8
-    , version :: Word8
-    , precision :: Word8
-    , numFields :: Word8
-    , notice :: CString
-    , fieldNames :: Ptr CString
-    , bboxOffset :: Word32
-    , metadataOffset :: Word32
-    , dataOffset :: Word32
-    }
 
 foreign import ccall unsafe "zonedetect.h ZDOpenDatabase"
     c_ZDOpenDatabase :: CString -> IO (Ptr ZoneDetectInfo)
+
+foreign import ccall unsafe "zonedetect.hs ZDCloseDatabase"
+    c_ZDCloseDatabase :: Ptr ZoneDetectInfo -> IO ()
 
 foreign import ccall unsafe "zonedetect.h ZDHelperSimpleLookupString"
     c_ZDHelperSimpleLookupString :: Ptr ZoneDetectInfo -> CFloat -> CFloat -> IO CString
diff --git a/test/TimezoneDetectSpec.hs b/test/TimezoneDetectSpec.hs
--- a/test/TimezoneDetectSpec.hs
+++ b/test/TimezoneDetectSpec.hs
@@ -7,9 +7,6 @@
 zoneFile :: FilePath
 zoneFile = "./test/tz_db/timezone21.bin"
 
-lookupTimeZoneName' :: Double -> Double -> Maybe TimeZoneName
-lookupTimeZoneName' = lookupTimeZoneName zoneFile
-
 localTimeFromString :: String -> IO LocalTime
 localTimeFromString = 
     parseTimeM True defaultTimeLocale "%Y-%-m-%-d %T"
@@ -18,51 +15,22 @@
 utcFromString =
     parseTimeM True defaultTimeLocale "%Y-%-m-%-d %T"
 
-timeAtPointToUTC' :: Double -> Double -> LocalTime -> IO UTCTime
-timeAtPointToUTC' = timeAtPointToUTC zoneFile
-
 spec :: Spec
 spec = do
-    describe "lookupTimeZoneName" $ do
-        it "calculates coordinates for known locations" $ do
-            let newYork = lookupTimeZoneName' 40.7831 (-73.9712)
-            let tegucigalpa = lookupTimeZoneName' 14.0650 (-87.1715)
-            newYork `shouldBe` (Just "America/New_York")
-            tegucigalpa `shouldBe` (Just "America/Tegucigalpa")
-
-        it "returns an error value when given an invalid timezone file path" $ do
-            let wrong = lookupTimeZoneName "bogus" 0.0 0.0
-            wrong `shouldBe` Nothing -- invalid DB file
-
-        it "returns an error value when given invalid coordinates" $ do
-            let outOfThisWorld = lookupTimeZoneName' 40000000.7 (-73.97)
-            outOfThisWorld `shouldBe` Nothing -- invalid coordinates
+    -- Simplistic functions: only work in IO, need a path to the TZ file, manage resources on their own.
+    describe "lookupTimeZoneNameFromFile" $ do
+        it "doesn't need a timezone db, just a path to the file, to detect the timezone." $ do
+            newYork <- lookupTimeZoneNameFromFile zoneFile 40.7831 (-73.9712)
+            newYork `shouldBe` "America/New_York"
 
-    describe "timeAtPointToUTC" $ do
-        it "calculates a UTC instant at a point in time and space in New York" $ do
-            localWinter <- localTimeFromString "2019-12-25 00:30:00"
+    describe "timeAtPointToUTCFromFile" $ do
+        it "doesn't need a timezone db, just a path to the file, to detect the UTC instant in a point and time" $ do
             localSummer <- localTimeFromString "2019-08-25 00:30:00"
-            utcWinter <- utcFromString "2019-12-25 05:30:00"
-            utcSummer <- utcFromString "2019-08-25 04:30:00"
-            
-            atPointWinter <- timeAtPointToUTC' 40.7831 (-73.9712) localWinter
-            atPointSummer <- timeAtPointToUTC' 40.7831 (-73.9712) localSummer
+            utcSummer   <- utcFromString "2019-08-25 04:30:00"
+            atPointSummer <- timeAtPointToUTCFromFile zoneFile 40.7831 (-73.9712) localSummer
 
-            atPointWinter `shouldBe` utcWinter
             atPointSummer `shouldBe` utcSummer
-
-        it "calculates a UTC instant at a point in time and space in Tegucigalpa (no DST)" $ do
-            localWinter <- localTimeFromString "2019-12-25 00:30:00"
-            localSummer <- localTimeFromString "2019-08-25 00:30:00"
-            utcWinter <- utcFromString "2019-12-25 06:30:00"
-            utcSummer <- utcFromString "2019-08-25 06:30:00"
-            
-            atPointWinter <- timeAtPointToUTC' 14.0650 (-87.1715) localWinter
-            atPointSummer <- timeAtPointToUTC' 14.0650 (-87.1715) localSummer
-
-            atPointWinter `shouldBe` utcWinter
-            atPointSummer `shouldBe` utcSummer
-
+    
     describe "timeInTimeZoneToUTC" $ do
         it "calculates a UTC instant given a timezone name" $ do
             localWinter <- localTimeFromString "2019-12-25 00:30:00"
@@ -78,3 +46,47 @@
             atTZWinter `shouldBe` utcWinter
             atTZSummer `shouldBe` utcSummer
             atTZNoDST  `shouldBe` alwaysSummer
+
+    -- More general functions: work with a reference to an open TZ DB. You can use `withTimeZoneDatabase`
+    -- for resource management (opens the file, does the computation, closes.)
+    around (withTimeZoneDatabase zoneFile) $ do
+        describe "lookupTimeZoneName" $ do
+            it "returns the expected timezones for known locations" $ \db -> do
+                let newYork = lookupTimeZoneName db 40.7831 (-73.9712)
+                    tegucigalpa = lookupTimeZoneName db 14.0650 (-87.1715)
+                newYork `shouldBe` (Just "America/New_York")
+                tegucigalpa `shouldBe` (Just "America/Tegucigalpa")
+
+            it "returns an error value when given invalid coordinates" $ \db -> do
+                let outOfThisWorld = lookupTimeZoneName db 40000000.7 (-73.97)
+                outOfThisWorld `shouldBe` Nothing -- invalid coordinates
+
+            it "returns an error value when given a bogus database" $ \_ -> do
+                badDb <- openTimeZoneDatabase "bogus"
+                let bogus = lookupTimeZoneName badDb 40.7831 (-73.9712)
+                bogus `shouldBe` Nothing
+
+        describe "timeAtPointToUTC" $ do
+            it "calculates a UTC instant at a point in time and space in New York" $ \db -> do
+                localWinter <- localTimeFromString "2019-12-25 00:30:00"
+                localSummer <- localTimeFromString "2019-08-25 00:30:00"
+                utcWinter <- utcFromString "2019-12-25 05:30:00"
+                utcSummer <- utcFromString "2019-08-25 04:30:00"
+
+                atPointWinter <- timeAtPointToUTC db 40.7831 (-73.9712) localWinter
+                atPointSummer <- timeAtPointToUTC  db 40.7831 (-73.9712) localSummer
+
+                atPointWinter `shouldBe` utcWinter
+                atPointSummer `shouldBe` utcSummer
+
+            it "calculates a UTC instant at a point in time and space in Tegucigalpa (no DST)" $ \db -> do
+                localWinter <- localTimeFromString "2019-12-25 00:30:00"
+                localSummer <- localTimeFromString "2019-08-25 00:30:00"
+                utcWinter <- utcFromString "2019-12-25 06:30:00"
+                utcSummer <- utcFromString "2019-08-25 06:30:00"
+
+                atPointWinter <- timeAtPointToUTC db 14.0650 (-87.1715) localWinter
+                atPointSummer <- timeAtPointToUTC db 14.0650 (-87.1715) localSummer
+
+                atPointWinter `shouldBe` utcWinter
+                atPointSummer `shouldBe` utcSummer
diff --git a/timezone-detect.cabal b/timezone-detect.cabal
--- a/timezone-detect.cabal
+++ b/timezone-detect.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 03ea7e2e9760969e8b6c4e2a5f8cb5a17b448db1b6b3d5749e18cf3f7336553a
+-- hash: cada8fe310ed1ed1c85911dc9e3b40c06e5e111b2984429f42aa5a762a956c9a
 
 name:           timezone-detect
-version:        0.2.2.0
+version:        0.3.0.0
 synopsis:       Haskell bindings for the zone-detect C library; plus tz-aware utils.
 description:    Please see the README on GitHub at <https://github.com/lfborjas/timezone-detect#readme>
 category:       Data, Foreign, Time
