packages feed

timezone-detect-0.3.0.0: test/TimezoneDetectSpec.hs

module TimezoneDetectSpec (spec) where

import Data.Time
import Data.Time.LocalTime.TimeZone.Detect
import Test.Hspec

zoneFile :: FilePath
zoneFile = "./test/tz_db/timezone21.bin"

localTimeFromString :: String -> IO LocalTime
localTimeFromString = 
    parseTimeM True defaultTimeLocale "%Y-%-m-%-d %T"

utcFromString :: String -> IO UTCTime
utcFromString =
    parseTimeM True defaultTimeLocale "%Y-%-m-%-d %T"

spec :: Spec
spec = do
    -- 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 "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"
            utcSummer   <- utcFromString "2019-08-25 04:30:00"
            atPointSummer <- timeAtPointToUTCFromFile zoneFile 40.7831 (-73.9712) localSummer

            atPointSummer `shouldBe` utcSummer
    
    describe "timeInTimeZoneToUTC" $ do
        it "calculates a UTC instant given a timezone name" $ 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"
            alwaysSummer  <- utcFromString "2019-08-25 06:30:00"

            atTZWinter <- timeInTimeZoneToUTC "America/New_York" localWinter
            atTZSummer <- timeInTimeZoneToUTC "America/New_York" localSummer
            atTZNoDST  <- timeInTimeZoneToUTC "America/Tegucigalpa" localSummer

            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