packages feed

time 1.16 → 1.16.0.1

raw patch · 25 files changed

+1203/−148 lines, 25 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

changelog.md view
@@ -1,5 +1,15 @@ # Change Log +## [1.16.0.1] - 2026-07-20++- fix gregorianPaschalMoon and gregorianEaster+- fix negative rollover differences in diffGregorianDurationRollOver and diffJulianDurationRollOver+- fix case-insensitive parsing for AM/PM markers, UTC, and known timezone names+- fix Unix timezone fallback offset sign and DST abbreviation+- fix JavaScript getTimeZone offsets and summer flag around DST transitions+- fix numeric parsers accepting overflowing bounded values+- fix systemToPOSIXTime for SystemTime leap-second values+ ## [1.16] - 2026-05-03  - add periodIn
configure view
@@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles.-# Generated by GNU Autoconf 2.71 for Haskell time package 1.16.+# Generated by GNU Autoconf 2.71 for Haskell time package 1.16.0.1. # # Report bugs to <ashley@semantic.org>. #@@ -610,8 +610,8 @@ # Identity of this package. PACKAGE_NAME='Haskell time package' PACKAGE_TARNAME='time'-PACKAGE_VERSION='1.16'-PACKAGE_STRING='Haskell time package 1.16'+PACKAGE_VERSION='1.16.0.1'+PACKAGE_STRING='Haskell time package 1.16.0.1' PACKAGE_BUGREPORT='ashley@semantic.org' PACKAGE_URL='' @@ -1258,7 +1258,7 @@   # Omit some internal or obsolete options to make the list less imposing.   # This message is too long to be a string in the A/UX 3.1 sh.   cat <<_ACEOF-\`configure' configures Haskell time package 1.16 to adapt to many kinds of systems.+\`configure' configures Haskell time package 1.16.0.1 to adapt to many kinds of systems.  Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1320,7 +1320,7 @@  if test -n "$ac_init_help"; then   case $ac_init_help in-     short | recursive ) echo "Configuration of Haskell time package 1.16:";;+     short | recursive ) echo "Configuration of Haskell time package 1.16.0.1:";;    esac   cat <<\_ACEOF @@ -1406,7 +1406,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then   cat <<\_ACEOF-Haskell time package configure 1.16+Haskell time package configure 1.16.0.1 generated by GNU Autoconf 2.71  Copyright (C) 2021 Free Software Foundation, Inc.@@ -1736,7 +1736,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by Haskell time package $as_me 1.16, which was+It was created by Haskell time package $as_me 1.16.0.1, which was generated by GNU Autoconf 2.71.  Invocation command line was    $ $0$ac_configure_args_raw@@ -4334,7 +4334,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log="-This file was extended by Haskell time package $as_me 1.16, which was+This file was extended by Haskell time package $as_me 1.16.0.1, which was generated by GNU Autoconf 2.71.  Invocation command line was    CONFIG_FILES    = $CONFIG_FILES@@ -4389,7 +4389,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\-Haskell time package config.status 1.16+Haskell time package config.status 1.16.0.1 configured by $0, generated by GNU Autoconf 2.71,   with options \\"\$ac_cs_config\\" 
configure.ac view
@@ -1,4 +1,4 @@-AC_INIT([Haskell time package],[1.16],[ashley@semantic.org],[time])+AC_INIT([Haskell time package],[1.16.0.1],[ashley@semantic.org],[time])  # Safety check: Ensure that we are in the correct source directory. AC_CONFIG_SRCDIR([lib/include/HsTime.h])
lib/Data/Format.hs view
@@ -29,6 +29,7 @@ import Data.Char import Data.Void import Text.ParserCombinators.ReadP+import Text.Read (readMaybe) import Prelude hiding (fail)  class IsoVariant f where@@ -213,13 +214,40 @@ readSign NegSign = option id $ char '-' >> return negate readSign PosNegSign = (char '+' >> return id) +++ (char '-' >> return negate) +readDigits :: Maybe Int -> ReadP String+readDigits mdigitcount =+    case mdigitcount of+        Just digitcount -> count digitcount $ satisfy isDigit+        Nothing -> munch1 isDigit++readMaybeP :: Read t => String -> ReadP t+readMaybeP str =+    case readMaybe str of+        Just t -> return t+        Nothing -> pfail++fromIntegerExact :: Integral t => Integer -> Maybe t+fromIntegerExact i =+    let+        t = fromInteger i+    in+        if toInteger t == i+            then Just t+            else Nothing++readIntegerNumber :: Integral t => SignOption -> Maybe Int -> ReadP t+readIntegerNumber signOpt mdigitcount = do+    sign <- readSign signOpt+    digits <- readDigits mdigitcount+    i <- readMaybeP digits+    case fromIntegerExact $ sign i of+        Just t -> return t+        Nothing -> pfail+ readNumber :: (Num t, Read t) => SignOption -> Maybe Int -> Bool -> ReadP t readNumber signOpt mdigitcount allowDecimal = do     sign <- readSign signOpt-    digits <--        case mdigitcount of-            Just digitcount -> count digitcount $ satisfy isDigit-            Nothing -> munch1 isDigit+    digits <- readDigits mdigitcount     moredigits <-         case allowDecimal of             False -> return ""@@ -228,7 +256,8 @@                     _ <- char '.' +++ char ','                     dd <- munch1 isDigit                     return $ '.' : dd-    return $ sign $ read $ digits ++ moredigits+    a <- readMaybeP $ digits ++ moredigits+    return $ sign a  zeroPad :: Maybe Int -> String -> Maybe String zeroPad Nothing s = Just s@@ -269,8 +298,8 @@                     PosNegSign -> '+' : s                     _ -> s -integerFormat :: (Show t, Read t, Num t) => SignOption -> Maybe Int -> Format t-integerFormat signOpt mdigitcount = MkFormat (showNumber signOpt mdigitcount) (readNumber signOpt mdigitcount False)+integerFormat :: (Show t, Integral t) => SignOption -> Maybe Int -> Format t+integerFormat signOpt mdigitcount = MkFormat (showNumber signOpt mdigitcount) (readIntegerNumber signOpt mdigitcount)  decimalFormat :: (Show t, Read t, Num t) => SignOption -> Maybe Int -> Format t decimalFormat signOpt mdigitcount = MkFormat (showNumber signOpt mdigitcount) (readNumber signOpt mdigitcount True)
lib/Data/Time/Calendar/Easter.hs view
@@ -37,7 +37,7 @@     century = (div year 100) + 1     shiftedEpact = mod (14 + 11 * (mod year 19) - (div (3 * century) 4) + (div (5 + 8 * century) 25)) 30     adjustedEpact =-        if shiftedEpact == 0 || ((shiftedEpact == 1) && (mod year 19 < 10))+        if shiftedEpact == 0 || ((shiftedEpact == 1) && (mod year 19 > 10))             then shiftedEpact + 1             else shiftedEpact 
lib/Data/Time/Calendar/Gregorian.hs view
@@ -137,7 +137,7 @@                 dayAllowed = addGregorianDurationRollOver (CalendarDiffDays mdiff 0) day1                 dd = diffDays day2 dayAllowed             in-                if dd <= 0 then CalendarDiffDays mdiff dd else findpos (succ mdiff)+                if dd <= 0 then CalendarDiffDays mdiff dd else findneg (succ mdiff)     in         if day2 >= day1             then findpos ymdiff
lib/Data/Time/Calendar/Julian.hs view
@@ -168,7 +168,7 @@                 dayAllowed = addJulianDurationRollOver (CalendarDiffDays mdiff 0) day1                 dd = diffDays day2 dayAllowed             in-                if dd <= 0 then CalendarDiffDays mdiff dd else findpos (succ mdiff)+                if dd <= 0 then CalendarDiffDays mdiff dd else findneg (succ mdiff)     in         if day2 >= day1             then findpos ymdiff
lib/Data/Time/Clock/POSIX.hs view
@@ -45,7 +45,12 @@     (fromInteger (diffDays d systemEpochDay) * posixDayLength) + min posixDayLength (realToFrac t)  systemToPOSIXTime :: SystemTime -> POSIXTime-systemToPOSIXTime (MkSystemTime s ns) = (fromIntegral s) + (fromIntegral ns) * 1E-9+systemToPOSIXTime (MkSystemTime s ns) =+    let+        (days, timeSeconds) = s `divMod` 86400+        time = fromIntegral timeSeconds + fromIntegral ns * 1E-9+    in+        fromIntegral days * posixDayLength + min posixDayLength time  -- | Get the current POSIX time from the system clock. getPOSIXTime :: IO POSIXTime
lib/Data/Time/Format/ISO8601.hs view
@@ -328,7 +328,7 @@ timeAndOffsetFormat :: Format t -> FormatExtension -> Format (t, TimeZone) timeAndOffsetFormat ft fe = ft <**> timeOffsetFormat fe -intDesignator :: (Eq t, Show t, Read t, Num t) => Char -> Format t+intDesignator :: (Show t, Integral t) => Char -> Format t intDesignator c = optionalFormat 0 $ integerFormat NegSign Nothing <** literalFormat [c]  decDesignator :: (Eq t, Show t, Read t, Num t) => Char -> Format t
lib/Data/Time/Format/Parse/Instances.hs view
@@ -122,15 +122,27 @@ readSpec_Z :: TimeLocale -> String -> Maybe TimeZone readSpec_Z _ str | Just offset <- readTzOffset str = Just $ TimeZone offset False "" readSpec_Z l str | Just zone <- getKnownTimeZone l str = Just zone-readSpec_Z _ "UTC" = Just utc+readSpec_Z _ str | eqCI str "UTC" = Just utc readSpec_Z _ [c] | Just zone <- getMilZone c = Just zone readSpec_Z _ _ = Nothing +eqCI :: String -> String -> Bool+eqCI x y = map toUpper x == map toUpper y++readIntegralMaybe :: Integral a => String -> Maybe a+readIntegralMaybe str = do+    i <- readMaybe str+    let+        a = fromInteger i+    if toInteger a == i+        then Just a+        else Nothing+ makeDayFact :: TimeLocale -> Char -> String -> Maybe [DayFact] makeDayFact l c x =     let-        ra :: Read a => Maybe a-        ra = readMaybe x+        ra :: Integral a => Maybe a+        ra = readIntegralMaybe x         zeroBasedListIndex :: [String] -> Maybe Int         zeroBasedListIndex ss = elemIndex (map toUpper x) $ fmap (map toUpper) ss         oneBasedListIndex :: [String] -> Maybe Int@@ -408,17 +420,16 @@ makeTimeFact :: TimeLocale -> Char -> String -> Maybe [TimeFact] makeTimeFact l c x =     let-        ra :: Read a => Maybe a-        ra = readMaybe x+        ra :: Integral a => Maybe a+        ra = readIntegralMaybe x         getAmPm =             let-                upx = map toUpper x                 (amStr, pmStr) = amPm l             in-                if upx == amStr+                if x `eqCI` amStr                     then Just [AMAPMTimeFact AM]                     else-                        if upx == pmStr+                        if x `eqCI` pmStr                             then Just [AMAPMTimeFact PM]                             else Nothing     in@@ -541,7 +552,7 @@             return $ TimeZone (hours * 60) False [yc]  getKnownTimeZone :: TimeLocale -> String -> Maybe TimeZone-getKnownTimeZone locale x = find (\tz -> map toUpper x == timeZoneName tz) (knownTimeZones locale)+getKnownTimeZone locale x = find (\tz -> x `eqCI` timeZoneName tz) (knownTimeZones locale)  instance ParseTime TimeZone where     substituteTimeSpecifier _ = timeSubstituteTimeSpecifier
lib/Data/Time/LocalTime/Internal/Foreign.hs view
@@ -22,24 +22,35 @@  #if defined(javascript_HOST_ARCH) -foreign import javascript "((dy,dm,dd,th,tm,ts) => { return new Date(dy,dm,dd,th,tm,ts).getTimezoneOffset(); })"-  js_get_timezone_minutes :: Int -> Int -> Int -> Int -> Int -> Int -> IO Int+foreign import javascript "((dy,dm,dd,th,tm,ts) => { const d = new Date(0); d.setUTCFullYear(dy,dm,dd); d.setUTCHours(th,tm,ts,0); return -d.getTimezoneOffset(); })"+    js_get_timezone_minutes :: Int -> Int -> Int -> Int -> Int -> Int -> IO Int -get_timezone_minutes :: UTCTime -> IO Int-get_timezone_minutes ut = let-    lt :: LocalTime-    lt = utcToLocalTime utc ut-    in case lt of-        LocalTime (YearMonthDay dy dm dd) (TimeOfDay th tm ts) ->-            js_get_timezone_minutes (fromInteger dy) (pred dm) dd th tm (floor ts)+foreign import javascript "((dy,dm,dd,th,tm,ts) => { const d = new Date(0); d.setUTCFullYear(dy,dm,dd); d.setUTCHours(th,tm,ts,0); const jan = new Date(0); jan.setFullYear(d.getFullYear(),0,1); jan.setHours(0,0,0,0); const jul = new Date(0); jul.setFullYear(d.getFullYear(),6,1); jul.setHours(0,0,0,0); return d.getTimezoneOffset() < Math.max(jan.getTimezoneOffset(),jul.getTimezoneOffset()) ? 1 : 0; })"+    js_get_timezone_summer :: Int -> Int -> Int -> Int -> Int -> Int -> IO Int +get_timezone :: UTCTime -> IO (Int, Bool)+get_timezone ut =+    let+        lt :: LocalTime+        lt = utcToLocalTime utc ut+    in+        case lt of+            LocalTime (YearMonthDay dy dm dd) (TimeOfDay th tm ts) -> do+                let+                    dy' = fromInteger dy+                    dm' = pred dm+                    ts' = floor ts+                mins <- js_get_timezone_minutes dy' dm' dd th tm ts'+                summer <- js_get_timezone_summer dy' dm' dd th tm ts'+                return (mins, summer /= 0)+ getTimeZoneCTime :: CTime -> IO TimeZone getTimeZoneCTime ct = do     let         ut :: UTCTime         ut = posixSecondsToUTCTime $ secondsToNominalDiffTime $ fromIntegral $ fromCTime ct-    mins <- get_timezone_minutes ut-    return $ TimeZone mins False ""+    (mins, summer) <- get_timezone ut+    return $ TimeZone mins summer ""  fromCTime :: CTime -> Int64 fromCTime (CTime tt) = fromIntegral tt
lib/cbits/HsTime.c view
@@ -36,14 +36,14 @@         return - (dst ? _timezone - 3600 : _timezone); #else # if HAVE_TZNAME || defined(__MHS__)-        *pname = *tzname;+        *pname = tzname[dst ? 1 : 0]; # else #  error "Don't know how to get timezone name on your OS" # endif # if HAVE_DECL_ALTZONE-        return dst ? altzone : timezone;+        return - (dst ? altzone : timezone); # else-        return dst ? timezone - 3600 : timezone;+        return - (dst ? timezone - 3600 : timezone); # endif #endif // HAVE_TM_ZONE     }
test/ForeignCalls.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE CPP #-}+ module Main (main) where  import Control.Exception@@ -10,12 +12,22 @@ import Data.Time.Clock.TAI import Data.Traversable import System.Exit+#if defined(javascript_HOST_ARCH)+import System.Environment+#endif import System.IO  data Test = MkTest String (IO ())  tests :: [Test] tests =+    foreignCallTests+#if defined(javascript_HOST_ARCH)+        ++ jsTimezoneTests+#endif++foreignCallTests :: [Test]+foreignCallTests =     [ MkTest "getCurrentTime" $ void $ getCurrentTime     , MkTest "getZonedTime" $ void $ getZonedTime     , MkTest "getCurrentTimeZone" $ void $ getCurrentTimeZone@@ -26,6 +38,40 @@     , MkTest "taiClock time" $ for_ taiClock $ \(_, getTime) -> void $ getTime     , MkTest "taiClock resolution" $ for_ taiClock $ \(res, _) -> void $ evaluate res     ]++#if defined(javascript_HOST_ARCH)+jsTimezoneTests :: [Test]+jsTimezoneTests =+    [ MkTest "getTimeZone JavaScript DST transition" $ do+        setEnv "TZ" "America/New_York"+        let+            transitionTime h m =+                UTCTime (fromGregorian 2024 3 10) $+                    secondsToDiffTime $+                        h * 3600 + m * 60+        zoneBefore <- getTimeZone $ transitionTime 6 30+        assertTimeZone "before DST transition" (-300) False zoneBefore+        zoneAfter <- getTimeZone $ transitionTime 7 30+        assertTimeZone "after DST transition" (-240) True zoneAfter+    ]++assertTimeZone :: String -> Int -> Bool -> TimeZone -> IO ()+assertTimeZone label expectedMinutes expectedSummer zone = do+    when (timeZoneMinutes zone /= expectedMinutes) $+        fail $+            label+                <> ": expected minutes "+                <> show expectedMinutes+                <> ", got "+                <> show (timeZoneMinutes zone)+    when (timeZoneSummerOnly zone /= expectedSummer) $+        fail $+            label+                <> ": expected summer flag "+                <> show expectedSummer+                <> ", got "+                <> show (timeZoneSummerOnly zone)+#endif  runTest :: Test -> IO Bool runTest (MkTest name action) = do
test/main/Test/Calendar/Duration.hs view
@@ -62,6 +62,20 @@         "positive-diff"         $ fmap testPositiveDiff addDiffs +testNegativeDiff :: CalendarAddDiff -> TestTree+testNegativeDiff (MkAddDiff{..}, _) = testProperty adName $ \day1 (MkSmallish i) ->+    let+        day2 = addDays (negate i) day1+        r = adDifference day2 day1+    in+        property $ cdMonths r <= 0 && cdDays r <= 0++testNegativeDiffs :: TestTree+testNegativeDiffs =+    testGroup+        "negative-diff"+        $ fmap testNegativeDiff addDiffs+ testSpecific :: CalendarAddDiff -> (Integer, Int, Int) -> (Integer, Int, Int) -> (Integer, Integer) -> TestTree testSpecific (MkAddDiff{..}, fromYMD) (y2, m2, d2) (y1, m1, d1) (em, ed) =     let@@ -89,6 +103,7 @@     testGroup         "specific"         [ testSpecificPair (2017, 04, 07) (2017, 04, 07) (0, 0) (0, 0)+        , testSpecificPair (1999, 12, 31) (2000, 01, 01) (0, -1) (0, -1)         , testSpecific gregorianClip (2017, 04, 07) (2017, 04, 01) (0, 6)         , testSpecific gregorianClip (2017, 04, 01) (2017, 04, 07) (0, -6)         , testSpecific gregorianClip (2017, 04, 07) (2017, 02, 01) (2, 6)@@ -103,4 +118,4 @@         ]  testDuration :: TestTree-testDuration = testGroup "CalendarDiffDays" [testAddDiffs, testPositiveDiffs, testSpecifics]+testDuration = testGroup "CalendarDiffDays" [testAddDiffs, testPositiveDiffs, testNegativeDiffs, testSpecifics]
test/main/Test/Calendar/Easter.hs view
@@ -2,38 +2,126 @@     testEaster, ) where +import Data.Foldable import Data.Time.Calendar import Data.Time.Calendar.Easter-import Data.Time.Format-import Test.Calendar.EasterRef import Test.Tasty import Test.Tasty.HUnit+import Text.Read ----days :: [Day]-days = [ModifiedJulianDay 53000 .. ModifiedJulianDay 53014]+easterDatesFile :: FilePath+easterDatesFile = "test/main/Test/Calendar/EasterData/easter500.txt" -showWithWDay :: Day -> String-showWithWDay = formatTime defaultTimeLocale "%F %A"+allEasterDatesFile :: FilePath+allEasterDatesFile = "test/main/Test/Calendar/EasterData/easter-reference-1900-2099.csv" +parseField :: Read a => String -> IO a+parseField field =+    case readMaybe field of+        Just value -> return value+        Nothing -> fail $ "invalid integer field: " ++ show field++parseEasterDates :: [String] -> IO [Day]+parseEasterDates [] = return []+parseEasterDates (monthText : dayText : yearText : rest) = do+    month <- parseField monthText+    day <- parseField dayText+    year <- parseField yearText+    easterDay <-+        maybe (fail $ "invalid date: " ++ unwords [yearText, monthText, dayText]) return $+            fromGregorianValid year month day+    (easterDay :) <$> parseEasterDates rest+parseEasterDates fields = fail $ "easter500.txt: expected month/day/year triples, leftover fields: " ++ show fields++getEasterDates :: IO [Day]+getEasterDates = do+    contents <- readFile easterDatesFile+    parseEasterDates $ words contents++splitCommas :: String -> [String]+splitCommas [] = [""]+splitCommas (',' : rest) = "" : splitCommas rest+splitCommas (char : rest) =+    case splitCommas rest of+        [] -> [[char]]+        field : fields -> (char : field) : fields++testGregorianEaster :: TestTree+testGregorianEaster =+    testCase "Gregorian Easter" $ do+        easterDates <- getEasterDates+        for_ easterDates $ \expectedDate@(YearMonthDay y _ _) -> do+            let+                foundDate = gregorianEaster y+            assertEqual "Gregorian Easter" expectedDate foundDate++getAllEasterDates :: IO [(Day, Day, Day, Day)]+getAllEasterDates = do+    contents <- readFile allEasterDatesFile+    parseAllEasterDates $ lines contents++parseAllEasterDates :: [String] -> IO [(Day, Day, Day, Day)]+parseAllEasterDates [] = fail $ allEasterDatesFile ++ ": empty file"+parseAllEasterDates (header : rows) = do+    let+        expectedHeader =+            [ "year"+            , "golden_number"+            , "gregorian_pfm"+            , "gregorian_easter"+            , "orthodox_pfm_gregorian"+            , "orthodox_easter_gregorian"+            ]+    if splitCommas header == expectedHeader+        then traverse parseAllEasterDateLine $ zip [2 :: Int ..] rows+        else fail $ allEasterDatesFile ++ ": unexpected header: " ++ show header++parseAllEasterDateLine :: (Int, String) -> IO (Day, Day, Day, Day)+parseAllEasterDateLine (lineNumber, line) =+    case splitCommas line of+        [yearText, _, gregorianMoonText, gregorianEasterText, orthodoxMoonText, orthodoxEasterText] -> do+            year <- parseField yearText+            gregorianMoon <- parseDayField lineNumber "gregorian_pfm" gregorianMoonText+            gregorianEasterDay <- parseDayField lineNumber "gregorian_easter" gregorianEasterText+            orthodoxMoon <- parseDayField lineNumber "orthodox_pfm_gregorian" orthodoxMoonText+            orthodoxEasterDay <- parseDayField lineNumber "orthodox_easter_gregorian" orthodoxEasterText+            let+                YearMonthDay gregorianMoonYear _ _ = gregorianMoon+            if gregorianMoonYear == year+                then return (gregorianMoon, gregorianEasterDay, orthodoxMoon, orthodoxEasterDay)+                else fail $ allEasterDatesFile ++ ":" ++ show lineNumber ++ ": row year does not match Gregorian Paschal moon"+        fields -> fail $ allEasterDatesFile ++ ":" ++ show lineNumber ++ ": expected 6 CSV fields, found " ++ show (length fields)++parseDayField :: Int -> String -> String -> IO Day+parseDayField lineNumber fieldName field =+    case splitDate field of+        [yearText, monthText, dayText] -> do+            year <- parseField yearText+            month <- parseField monthText+            day <- parseField dayText+            maybe+                (fail $ allEasterDatesFile ++ ":" ++ show lineNumber ++ ": invalid " ++ fieldName ++ ": " ++ show field)+                return+                $ fromGregorianValid year month day+        _ -> fail $ allEasterDatesFile ++ ":" ++ show lineNumber ++ ": invalid " ++ fieldName ++ ": " ++ show field++splitDate :: String -> [String]+splitDate [] = [""]+splitDate ('-' : rest) = "" : splitDate rest+splitDate (char : rest) =+    case splitDate rest of+        [] -> [[char]]+        field : fields -> (char : field) : fields++testAllEasters :: TestTree+testAllEasters =+    testCase "all Easters" $ do+        allEasterDates <- getAllEasterDates+        for_ allEasterDates $ \(expectedGM@(YearMonthDay y _ _), expectedGE, expectedOM, expectedOE) -> do+            assertEqual "Gregorian Paschal moon" expectedGM $ gregorianPaschalMoon y+            assertEqual "Gregorian Easter" expectedGE $ gregorianEaster y+            assertEqual "Orthodox Paschal moon" expectedOM $ orthodoxPaschalMoon y+            assertEqual "Orthodox Easter" expectedOE $ orthodoxEaster y+ testEaster :: TestTree-testEaster =-    testCase "testEaster" $-        let-            ds = unlines $ map (\day -> unwords [showWithWDay day, "->", showWithWDay (sundayAfter day)]) days-            f y =-                unwords-                    [ show y ++ ", Gregorian: moon,"-                    , show (gregorianPaschalMoon y) ++ ": Easter,"-                    , showWithWDay (gregorianEaster y)-                    ]-                    ++ "\n"-            g y =-                unwords-                    [ show y ++ ", Orthodox : moon,"-                    , show (orthodoxPaschalMoon y) ++ ": Easter,"-                    , showWithWDay (orthodoxEaster y)-                    ]-                    ++ "\n"-        in-            assertEqual "" testEasterRef $ ds ++ concatMap (\y -> f y ++ g y) [2000 .. 2020]+testEaster = testGroup "testEaster" [testGregorianEaster, testAllEasters]
+ test/main/Test/Calendar/EasterData/easter-reference-1900-2099.csv view
@@ -0,0 +1,201 @@+year,golden_number,gregorian_pfm,gregorian_easter,orthodox_pfm_gregorian,orthodox_easter_gregorian+1900,1,1900-04-14,1900-04-15,1900-04-18,1900-04-22+1901,2,1901-04-03,1901-04-07,1901-04-07,1901-04-14+1902,3,1902-03-23,1902-03-30,1902-04-26,1902-04-27+1903,4,1903-04-11,1903-04-12,1903-04-15,1903-04-19+1904,5,1904-03-31,1904-04-03,1904-04-04,1904-04-10+1905,6,1905-04-18,1905-04-23,1905-04-23,1905-04-30+1906,7,1906-04-08,1906-04-15,1906-04-12,1906-04-15+1907,8,1907-03-28,1907-03-31,1907-05-01,1907-05-05+1908,9,1908-04-16,1908-04-19,1908-04-20,1908-04-26+1909,10,1909-04-05,1909-04-11,1909-04-09,1909-04-11+1910,11,1910-03-25,1910-03-27,1910-04-28,1910-05-01+1911,12,1911-04-13,1911-04-16,1911-04-17,1911-04-23+1912,13,1912-04-02,1912-04-07,1912-04-06,1912-04-07+1913,14,1913-03-22,1913-03-23,1913-04-25,1913-04-27+1914,15,1914-04-10,1914-04-12,1914-04-14,1914-04-19+1915,16,1915-03-30,1915-04-04,1915-04-03,1915-04-04+1916,17,1916-04-17,1916-04-23,1916-04-22,1916-04-23+1917,18,1917-04-07,1917-04-08,1917-04-11,1917-04-15+1918,19,1918-03-27,1918-03-31,1918-04-30,1918-05-05+1919,1,1919-04-14,1919-04-20,1919-04-18,1919-04-20+1920,2,1920-04-03,1920-04-04,1920-04-07,1920-04-11+1921,3,1921-03-23,1921-03-27,1921-04-26,1921-05-01+1922,4,1922-04-11,1922-04-16,1922-04-15,1922-04-16+1923,5,1923-03-31,1923-04-01,1923-04-04,1923-04-08+1924,6,1924-04-18,1924-04-20,1924-04-23,1924-04-27+1925,7,1925-04-08,1925-04-12,1925-04-12,1925-04-19+1926,8,1926-03-28,1926-04-04,1926-05-01,1926-05-02+1927,9,1927-04-16,1927-04-17,1927-04-20,1927-04-24+1928,10,1928-04-05,1928-04-08,1928-04-09,1928-04-15+1929,11,1929-03-25,1929-03-31,1929-04-28,1929-05-05+1930,12,1930-04-13,1930-04-20,1930-04-17,1930-04-20+1931,13,1931-04-02,1931-04-05,1931-04-06,1931-04-12+1932,14,1932-03-22,1932-03-27,1932-04-25,1932-05-01+1933,15,1933-04-10,1933-04-16,1933-04-14,1933-04-16+1934,16,1934-03-30,1934-04-01,1934-04-03,1934-04-08+1935,17,1935-04-17,1935-04-21,1935-04-22,1935-04-28+1936,18,1936-04-07,1936-04-12,1936-04-11,1936-04-12+1937,19,1937-03-27,1937-03-28,1937-04-30,1937-05-02+1938,1,1938-04-14,1938-04-17,1938-04-18,1938-04-24+1939,2,1939-04-03,1939-04-09,1939-04-07,1939-04-09+1940,3,1940-03-23,1940-03-24,1940-04-26,1940-04-28+1941,4,1941-04-11,1941-04-13,1941-04-15,1941-04-20+1942,5,1942-03-31,1942-04-05,1942-04-04,1942-04-05+1943,6,1943-04-18,1943-04-25,1943-04-23,1943-04-25+1944,7,1944-04-08,1944-04-09,1944-04-12,1944-04-16+1945,8,1945-03-28,1945-04-01,1945-05-01,1945-05-06+1946,9,1946-04-16,1946-04-21,1946-04-20,1946-04-21+1947,10,1947-04-05,1947-04-06,1947-04-09,1947-04-13+1948,11,1948-03-25,1948-03-28,1948-04-28,1948-05-02+1949,12,1949-04-13,1949-04-17,1949-04-17,1949-04-24+1950,13,1950-04-02,1950-04-09,1950-04-06,1950-04-09+1951,14,1951-03-22,1951-03-25,1951-04-25,1951-04-29+1952,15,1952-04-10,1952-04-13,1952-04-14,1952-04-20+1953,16,1953-03-30,1953-04-05,1953-04-03,1953-04-05+1954,17,1954-04-17,1954-04-18,1954-04-22,1954-04-25+1955,18,1955-04-07,1955-04-10,1955-04-11,1955-04-17+1956,19,1956-03-27,1956-04-01,1956-04-30,1956-05-06+1957,1,1957-04-14,1957-04-21,1957-04-18,1957-04-21+1958,2,1958-04-03,1958-04-06,1958-04-07,1958-04-13+1959,3,1959-03-23,1959-03-29,1959-04-26,1959-05-03+1960,4,1960-04-11,1960-04-17,1960-04-15,1960-04-17+1961,5,1961-03-31,1961-04-02,1961-04-04,1961-04-09+1962,6,1962-04-18,1962-04-22,1962-04-23,1962-04-29+1963,7,1963-04-08,1963-04-14,1963-04-12,1963-04-14+1964,8,1964-03-28,1964-03-29,1964-05-01,1964-05-03+1965,9,1965-04-16,1965-04-18,1965-04-20,1965-04-25+1966,10,1966-04-05,1966-04-10,1966-04-09,1966-04-10+1967,11,1967-03-25,1967-03-26,1967-04-28,1967-04-30+1968,12,1968-04-13,1968-04-14,1968-04-17,1968-04-21+1969,13,1969-04-02,1969-04-06,1969-04-06,1969-04-13+1970,14,1970-03-22,1970-03-29,1970-04-25,1970-04-26+1971,15,1971-04-10,1971-04-11,1971-04-14,1971-04-18+1972,16,1972-03-30,1972-04-02,1972-04-03,1972-04-09+1973,17,1973-04-17,1973-04-22,1973-04-22,1973-04-29+1974,18,1974-04-07,1974-04-14,1974-04-11,1974-04-14+1975,19,1975-03-27,1975-03-30,1975-04-30,1975-05-04+1976,1,1976-04-14,1976-04-18,1976-04-18,1976-04-25+1977,2,1977-04-03,1977-04-10,1977-04-07,1977-04-10+1978,3,1978-03-23,1978-03-26,1978-04-26,1978-04-30+1979,4,1979-04-11,1979-04-15,1979-04-15,1979-04-22+1980,5,1980-03-31,1980-04-06,1980-04-04,1980-04-06+1981,6,1981-04-18,1981-04-19,1981-04-23,1981-04-26+1982,7,1982-04-08,1982-04-11,1982-04-12,1982-04-18+1983,8,1983-03-28,1983-04-03,1983-05-01,1983-05-08+1984,9,1984-04-16,1984-04-22,1984-04-20,1984-04-22+1985,10,1985-04-05,1985-04-07,1985-04-09,1985-04-14+1986,11,1986-03-25,1986-03-30,1986-04-28,1986-05-04+1987,12,1987-04-13,1987-04-19,1987-04-17,1987-04-19+1988,13,1988-04-02,1988-04-03,1988-04-06,1988-04-10+1989,14,1989-03-22,1989-03-26,1989-04-25,1989-04-30+1990,15,1990-04-10,1990-04-15,1990-04-14,1990-04-15+1991,16,1991-03-30,1991-03-31,1991-04-03,1991-04-07+1992,17,1992-04-17,1992-04-19,1992-04-22,1992-04-26+1993,18,1993-04-07,1993-04-11,1993-04-11,1993-04-18+1994,19,1994-03-27,1994-04-03,1994-04-30,1994-05-01+1995,1,1995-04-14,1995-04-16,1995-04-18,1995-04-23+1996,2,1996-04-03,1996-04-07,1996-04-07,1996-04-14+1997,3,1997-03-23,1997-03-30,1997-04-26,1997-04-27+1998,4,1998-04-11,1998-04-12,1998-04-15,1998-04-19+1999,5,1999-03-31,1999-04-04,1999-04-04,1999-04-11+2000,6,2000-04-18,2000-04-23,2000-04-23,2000-04-30+2001,7,2001-04-08,2001-04-15,2001-04-12,2001-04-15+2002,8,2002-03-28,2002-03-31,2002-05-01,2002-05-05+2003,9,2003-04-16,2003-04-20,2003-04-20,2003-04-27+2004,10,2004-04-05,2004-04-11,2004-04-09,2004-04-11+2005,11,2005-03-25,2005-03-27,2005-04-28,2005-05-01+2006,12,2006-04-13,2006-04-16,2006-04-17,2006-04-23+2007,13,2007-04-02,2007-04-08,2007-04-06,2007-04-08+2008,14,2008-03-22,2008-03-23,2008-04-25,2008-04-27+2009,15,2009-04-10,2009-04-12,2009-04-14,2009-04-19+2010,16,2010-03-30,2010-04-04,2010-04-03,2010-04-04+2011,17,2011-04-17,2011-04-24,2011-04-22,2011-04-24+2012,18,2012-04-07,2012-04-08,2012-04-11,2012-04-15+2013,19,2013-03-27,2013-03-31,2013-04-30,2013-05-05+2014,1,2014-04-14,2014-04-20,2014-04-18,2014-04-20+2015,2,2015-04-03,2015-04-05,2015-04-07,2015-04-12+2016,3,2016-03-23,2016-03-27,2016-04-26,2016-05-01+2017,4,2017-04-11,2017-04-16,2017-04-15,2017-04-16+2018,5,2018-03-31,2018-04-01,2018-04-04,2018-04-08+2019,6,2019-04-18,2019-04-21,2019-04-23,2019-04-28+2020,7,2020-04-08,2020-04-12,2020-04-12,2020-04-19+2021,8,2021-03-28,2021-04-04,2021-05-01,2021-05-02+2022,9,2022-04-16,2022-04-17,2022-04-20,2022-04-24+2023,10,2023-04-05,2023-04-09,2023-04-09,2023-04-16+2024,11,2024-03-25,2024-03-31,2024-04-28,2024-05-05+2025,12,2025-04-13,2025-04-20,2025-04-17,2025-04-20+2026,13,2026-04-02,2026-04-05,2026-04-06,2026-04-12+2027,14,2027-03-22,2027-03-28,2027-04-25,2027-05-02+2028,15,2028-04-10,2028-04-16,2028-04-14,2028-04-16+2029,16,2029-03-30,2029-04-01,2029-04-03,2029-04-08+2030,17,2030-04-17,2030-04-21,2030-04-22,2030-04-28+2031,18,2031-04-07,2031-04-13,2031-04-11,2031-04-13+2032,19,2032-03-27,2032-03-28,2032-04-30,2032-05-02+2033,1,2033-04-14,2033-04-17,2033-04-18,2033-04-24+2034,2,2034-04-03,2034-04-09,2034-04-07,2034-04-09+2035,3,2035-03-23,2035-03-25,2035-04-26,2035-04-29+2036,4,2036-04-11,2036-04-13,2036-04-15,2036-04-20+2037,5,2037-03-31,2037-04-05,2037-04-04,2037-04-05+2038,6,2038-04-18,2038-04-25,2038-04-23,2038-04-25+2039,7,2039-04-08,2039-04-10,2039-04-12,2039-04-17+2040,8,2040-03-28,2040-04-01,2040-05-01,2040-05-06+2041,9,2041-04-16,2041-04-21,2041-04-20,2041-04-21+2042,10,2042-04-05,2042-04-06,2042-04-09,2042-04-13+2043,11,2043-03-25,2043-03-29,2043-04-28,2043-05-03+2044,12,2044-04-13,2044-04-17,2044-04-17,2044-04-24+2045,13,2045-04-02,2045-04-09,2045-04-06,2045-04-09+2046,14,2046-03-22,2046-03-25,2046-04-25,2046-04-29+2047,15,2047-04-10,2047-04-14,2047-04-14,2047-04-21+2048,16,2048-03-30,2048-04-05,2048-04-03,2048-04-05+2049,17,2049-04-17,2049-04-18,2049-04-22,2049-04-25+2050,18,2050-04-07,2050-04-10,2050-04-11,2050-04-17+2051,19,2051-03-27,2051-04-02,2051-04-30,2051-05-07+2052,1,2052-04-14,2052-04-21,2052-04-18,2052-04-21+2053,2,2053-04-03,2053-04-06,2053-04-07,2053-04-13+2054,3,2054-03-23,2054-03-29,2054-04-26,2054-05-03+2055,4,2055-04-11,2055-04-18,2055-04-15,2055-04-18+2056,5,2056-03-31,2056-04-02,2056-04-04,2056-04-09+2057,6,2057-04-18,2057-04-22,2057-04-23,2057-04-29+2058,7,2058-04-08,2058-04-14,2058-04-12,2058-04-14+2059,8,2059-03-28,2059-03-30,2059-05-01,2059-05-04+2060,9,2060-04-16,2060-04-18,2060-04-20,2060-04-25+2061,10,2061-04-05,2061-04-10,2061-04-09,2061-04-10+2062,11,2062-03-25,2062-03-26,2062-04-28,2062-04-30+2063,12,2063-04-13,2063-04-15,2063-04-17,2063-04-22+2064,13,2064-04-02,2064-04-06,2064-04-06,2064-04-13+2065,14,2065-03-22,2065-03-29,2065-04-25,2065-04-26+2066,15,2066-04-10,2066-04-11,2066-04-14,2066-04-18+2067,16,2067-03-30,2067-04-03,2067-04-03,2067-04-10+2068,17,2068-04-17,2068-04-22,2068-04-22,2068-04-29+2069,18,2069-04-07,2069-04-14,2069-04-11,2069-04-14+2070,19,2070-03-27,2070-03-30,2070-04-30,2070-05-04+2071,1,2071-04-14,2071-04-19,2071-04-18,2071-04-19+2072,2,2072-04-03,2072-04-10,2072-04-07,2072-04-10+2073,3,2073-03-23,2073-03-26,2073-04-26,2073-04-30+2074,4,2074-04-11,2074-04-15,2074-04-15,2074-04-22+2075,5,2075-03-31,2075-04-07,2075-04-04,2075-04-07+2076,6,2076-04-18,2076-04-19,2076-04-23,2076-04-26+2077,7,2077-04-08,2077-04-11,2077-04-12,2077-04-18+2078,8,2078-03-28,2078-04-03,2078-05-01,2078-05-08+2079,9,2079-04-16,2079-04-23,2079-04-20,2079-04-23+2080,10,2080-04-05,2080-04-07,2080-04-09,2080-04-14+2081,11,2081-03-25,2081-03-30,2081-04-28,2081-05-04+2082,12,2082-04-13,2082-04-19,2082-04-17,2082-04-19+2083,13,2083-04-02,2083-04-04,2083-04-06,2083-04-11+2084,14,2084-03-22,2084-03-26,2084-04-25,2084-04-30+2085,15,2085-04-10,2085-04-15,2085-04-14,2085-04-15+2086,16,2086-03-30,2086-03-31,2086-04-03,2086-04-07+2087,17,2087-04-17,2087-04-20,2087-04-22,2087-04-27+2088,18,2088-04-07,2088-04-11,2088-04-11,2088-04-18+2089,19,2089-03-27,2089-04-03,2089-04-30,2089-05-01+2090,1,2090-04-14,2090-04-16,2090-04-18,2090-04-23+2091,2,2091-04-03,2091-04-08,2091-04-07,2091-04-08+2092,3,2092-03-23,2092-03-30,2092-04-26,2092-04-27+2093,4,2093-04-11,2093-04-12,2093-04-15,2093-04-19+2094,5,2094-03-31,2094-04-04,2094-04-04,2094-04-11+2095,6,2095-04-18,2095-04-24,2095-04-23,2095-04-24+2096,7,2096-04-08,2096-04-15,2096-04-12,2096-04-15+2097,8,2097-03-28,2097-03-31,2097-05-01,2097-05-05+2098,9,2098-04-16,2098-04-20,2098-04-20,2098-04-27+2099,10,2099-04-05,2099-04-12,2099-04-09,2099-04-12
+ test/main/Test/Calendar/EasterData/easter500.txt view
@@ -0,0 +1,500 @@+  4        2    1600
+  4       22    1601
+  4        7    1602
+  3       30    1603
+  4       18    1604
+  4       10    1605
+  3       26    1606
+  4       15    1607
+  4        6    1608
+  4       19    1609
+  4       11    1610
+  4        3    1611
+  4       22    1612
+  4        7    1613
+  3       30    1614
+  4       19    1615
+  4        3    1616
+  3       26    1617
+  4       15    1618
+  3       31    1619
+  4       19    1620
+  4       11    1621
+  3       27    1622
+  4       16    1623
+  4        7    1624
+  3       30    1625
+  4       12    1626
+  4        4    1627
+  4       23    1628
+  4       15    1629
+  3       31    1630
+  4       20    1631
+  4       11    1632
+  3       27    1633
+  4       16    1634
+  4        8    1635
+  3       23    1636
+  4       12    1637
+  4        4    1638
+  4       24    1639
+  4        8    1640
+  3       31    1641
+  4       20    1642
+  4        5    1643
+  3       27    1644
+  4       16    1645
+  4        1    1646
+  4       21    1647
+  4       12    1648
+  4        4    1649
+  4       17    1650
+  4        9    1651
+  3       31    1652
+  4       13    1653
+  4        5    1654
+  3       28    1655
+  4       16    1656
+  4        1    1657
+  4       21    1658
+  4       13    1659
+  3       28    1660
+  4       17    1661
+  4        9    1662
+  3       25    1663
+  4       13    1664
+  4        5    1665
+  4       25    1666
+  4       10    1667
+  4        1    1668
+  4       21    1669
+  4        6    1670
+  3       29    1671
+  4       17    1672
+  4        2    1673
+  3       25    1674
+  4       14    1675
+  4        5    1676
+  4       18    1677
+  4       10    1678
+  4        2    1679
+  4       21    1680
+  4        6    1681
+  3       29    1682
+  4       18    1683
+  4        2    1684
+  4       22    1685
+  4       14    1686
+  3       30    1687
+  4       18    1688
+  4       10    1689
+  3       26    1690
+  4       15    1691
+  4        6    1692
+  3       22    1693
+  4       11    1694
+  4        3    1695
+  4       22    1696
+  4        7    1697
+  3       30    1698
+  4       19    1699
+  4       11    1700
+  3       27    1701
+  4       16    1702
+  4        8    1703
+  3       23    1704
+  4       12    1705
+  4        4    1706
+  4       24    1707
+  4        8    1708
+  3       31    1709
+  4       20    1710
+  4        5    1711
+  3       27    1712
+  4       16    1713
+  4        1    1714
+  4       21    1715
+  4       12    1716
+  3       28    1717
+  4       17    1718
+  4        9    1719
+  3       31    1720
+  4       13    1721
+  4        5    1722
+  3       28    1723
+  4       16    1724
+  4        1    1725
+  4       21    1726
+  4       13    1727
+  3       28    1728
+  4       17    1729
+  4        9    1730
+  3       25    1731
+  4       13    1732
+  4        5    1733
+  4       25    1734
+  4       10    1735
+  4        1    1736
+  4       21    1737
+  4        6    1738
+  3       29    1739
+  4       17    1740
+  4        2    1741
+  3       25    1742
+  4       14    1743
+  4        5    1744
+  4       18    1745
+  4       10    1746
+  4        2    1747
+  4       14    1748
+  4        6    1749
+  3       29    1750
+  4       11    1751
+  4        2    1752
+  4       22    1753
+  4       14    1754
+  3       30    1755
+  4       18    1756
+  4       10    1757
+  3       26    1758
+  4       15    1759
+  4        6    1760
+  3       22    1761
+  4       11    1762
+  4        3    1763
+  4       22    1764
+  4        7    1765
+  3       30    1766
+  4       19    1767
+  4        3    1768
+  3       26    1769
+  4       15    1770
+  3       31    1771
+  4       19    1772
+  4       11    1773
+  4        3    1774
+  4       16    1775
+  4        7    1776
+  3       30    1777
+  4       19    1778
+  4        4    1779
+  3       26    1780
+  4       15    1781
+  3       31    1782
+  4       20    1783
+  4       11    1784
+  3       27    1785
+  4       16    1786
+  4        8    1787
+  3       23    1788
+  4       12    1789
+  4        4    1790
+  4       24    1791
+  4        8    1792
+  3       31    1793
+  4       20    1794
+  4        5    1795
+  3       27    1796
+  4       16    1797
+  4        8    1798
+  3       24    1799
+  4       13    1800
+  4        5    1801
+  4       18    1802
+  4       10    1803
+  4        1    1804
+  4       14    1805
+  4        6    1806
+  3       29    1807
+  4       17    1808
+  4        2    1809
+  4       22    1810
+  4       14    1811
+  3       29    1812
+  4       18    1813
+  4       10    1814
+  3       26    1815
+  4       14    1816
+  4        6    1817
+  3       22    1818
+  4       11    1819
+  4        2    1820
+  4       22    1821
+  4        7    1822
+  3       30    1823
+  4       18    1824
+  4        3    1825
+  3       26    1826
+  4       15    1827
+  4        6    1828
+  4       19    1829
+  4       11    1830
+  4        3    1831
+  4       22    1832
+  4        7    1833
+  3       30    1834
+  4       19    1835
+  4        3    1836
+  3       26    1837
+  4       15    1838
+  3       31    1839
+  4       19    1840
+  4       11    1841
+  3       27    1842
+  4       16    1843
+  4        7    1844
+  3       23    1845
+  4       12    1846
+  4        4    1847
+  4       23    1848
+  4        8    1849
+  3       31    1850
+  4       20    1851
+  4       11    1852
+  3       27    1853
+  4       16    1854
+  4        8    1855
+  3       23    1856
+  4       12    1857
+  4        4    1858
+  4       24    1859
+  4        8    1860
+  3       31    1861
+  4       20    1862
+  4        5    1863
+  3       27    1864
+  4       16    1865
+  4        1    1866
+  4       21    1867
+  4       12    1868
+  3       28    1869
+  4       17    1870
+  4        9    1871
+  3       31    1872
+  4       13    1873
+  4        5    1874
+  3       28    1875
+  4       16    1876
+  4        1    1877
+  4       21    1878
+  4       13    1879
+  3       28    1880
+  4       17    1881
+  4        9    1882
+  3       25    1883
+  4       13    1884
+  4        5    1885
+  4       25    1886
+  4       10    1887
+  4        1    1888
+  4       21    1889
+  4        6    1890
+  3       29    1891
+  4       17    1892
+  4        2    1893
+  3       25    1894
+  4       14    1895
+  4        5    1896
+  4       18    1897
+  4       10    1898
+  4        2    1899
+  4       15    1900
+  4        7    1901
+  3       30    1902
+  4       12    1903
+  4        3    1904
+  4       23    1905
+  4       15    1906
+  3       31    1907
+  4       19    1908
+  4       11    1909
+  3       27    1910
+  4       16    1911
+  4        7    1912
+  3       23    1913
+  4       12    1914
+  4        4    1915
+  4       23    1916
+  4        8    1917
+  3       31    1918
+  4       20    1919
+  4        4    1920
+  3       27    1921
+  4       16    1922
+  4        1    1923
+  4       20    1924
+  4       12    1925
+  4        4    1926
+  4       17    1927
+  4        8    1928
+  3       31    1929
+  4       20    1930
+  4        5    1931
+  3       27    1932
+  4       16    1933
+  4        1    1934
+  4       21    1935
+  4       12    1936
+  3       28    1937
+  4       17    1938
+  4        9    1939
+  3       24    1940
+  4       13    1941
+  4        5    1942
+  4       25    1943
+  4        9    1944
+  4        1    1945
+  4       21    1946
+  4        6    1947
+  3       28    1948
+  4       17    1949
+  4        9    1950
+  3       25    1951
+  4       13    1952
+  4        5    1953
+  4       18    1954
+  4       10    1955
+  4        1    1956
+  4       21    1957
+  4        6    1958
+  3       29    1959
+  4       17    1960
+  4        2    1961
+  4       22    1962
+  4       14    1963
+  3       29    1964
+  4       18    1965
+  4       10    1966
+  3       26    1967
+  4       14    1968
+  4        6    1969
+  3       29    1970
+  4       11    1971
+  4        2    1972
+  4       22    1973
+  4       14    1974
+  3       30    1975
+  4       18    1976
+  4       10    1977
+  3       26    1978
+  4       15    1979
+  4        6    1980
+  4       19    1981
+  4       11    1982
+  4        3    1983
+  4       22    1984
+  4        7    1985
+  3       30    1986
+  4       19    1987
+  4        3    1988
+  3       26    1989
+  4       15    1990
+  3       31    1991
+  4       19    1992
+  4       11    1993
+  4        3    1994
+  4       16    1995
+  4        7    1996
+  3       30    1997
+  4       12    1998
+  4        4    1999
+  4       23    2000
+  4       15    2001
+  3       31    2002
+  4       20    2003
+  4       11    2004
+  3       27    2005
+  4       16    2006
+  4        8    2007
+  3       23    2008
+  4       12    2009
+  4        4    2010
+  4       24    2011
+  4        8    2012
+  3       31    2013
+  4       20    2014
+  4        5    2015
+  3       27    2016
+  4       16    2017
+  4        1    2018
+  4       21    2019
+  4       12    2020
+  4        4    2021
+  4       17    2022
+  4        9    2023
+  3       31    2024
+  4       20    2025
+  4        5    2026
+  3       28    2027
+  4       16    2028
+  4        1    2029
+  4       21    2030
+  4       13    2031
+  3       28    2032
+  4       17    2033
+  4        9    2034
+  3       25    2035
+  4       13    2036
+  4        5    2037
+  4       25    2038
+  4       10    2039
+  4        1    2040
+  4       21    2041
+  4        6    2042
+  3       29    2043
+  4       17    2044
+  4        9    2045
+  3       25    2046
+  4       14    2047
+  4        5    2048
+  4       18    2049
+  4       10    2050
+  4        2    2051
+  4       21    2052
+  4        6    2053
+  3       29    2054
+  4       18    2055
+  4        2    2056
+  4       22    2057
+  4       14    2058
+  3       30    2059
+  4       18    2060
+  4       10    2061
+  3       26    2062
+  4       15    2063
+  4        6    2064
+  3       29    2065
+  4       11    2066
+  4        3    2067
+  4       22    2068
+  4       14    2069
+  3       30    2070
+  4       19    2071
+  4       10    2072
+  3       26    2073
+  4       15    2074
+  4        7    2075
+  4       19    2076
+  4       11    2077
+  4        3    2078
+  4       23    2079
+  4        7    2080
+  3       30    2081
+  4       19    2082
+  4        4    2083
+  3       26    2084
+  4       15    2085
+  3       31    2086
+  4       20    2087
+  4       11    2088
+  4        3    2089
+  4       16    2090
+  4        8    2091
+  3       30    2092
+  4       12    2093
+  4        4    2094
+  4       24    2095
+  4       15    2096
+  3       31    2097
+  4       20    2098
+  4       12    2099
− test/main/Test/Calendar/EasterRef.hs
@@ -1,63 +0,0 @@-module Test.Calendar.EasterRef where--testEasterRef :: String-testEasterRef =-    unlines-        [ "2003-12-27 Saturday -> 2003-12-28 Sunday"-        , "2003-12-28 Sunday -> 2004-01-04 Sunday"-        , "2003-12-29 Monday -> 2004-01-04 Sunday"-        , "2003-12-30 Tuesday -> 2004-01-04 Sunday"-        , "2003-12-31 Wednesday -> 2004-01-04 Sunday"-        , "2004-01-01 Thursday -> 2004-01-04 Sunday"-        , "2004-01-02 Friday -> 2004-01-04 Sunday"-        , "2004-01-03 Saturday -> 2004-01-04 Sunday"-        , "2004-01-04 Sunday -> 2004-01-11 Sunday"-        , "2004-01-05 Monday -> 2004-01-11 Sunday"-        , "2004-01-06 Tuesday -> 2004-01-11 Sunday"-        , "2004-01-07 Wednesday -> 2004-01-11 Sunday"-        , "2004-01-08 Thursday -> 2004-01-11 Sunday"-        , "2004-01-09 Friday -> 2004-01-11 Sunday"-        , "2004-01-10 Saturday -> 2004-01-11 Sunday"-        , "2000, Gregorian: moon, 2000-04-18: Easter, 2000-04-23 Sunday"-        , "2000, Orthodox : moon, 2000-04-23: Easter, 2000-04-30 Sunday"-        , "2001, Gregorian: moon, 2001-04-08: Easter, 2001-04-15 Sunday"-        , "2001, Orthodox : moon, 2001-04-12: Easter, 2001-04-15 Sunday"-        , "2002, Gregorian: moon, 2002-03-28: Easter, 2002-03-31 Sunday"-        , "2002, Orthodox : moon, 2002-05-01: Easter, 2002-05-05 Sunday"-        , "2003, Gregorian: moon, 2003-04-16: Easter, 2003-04-20 Sunday"-        , "2003, Orthodox : moon, 2003-04-20: Easter, 2003-04-27 Sunday"-        , "2004, Gregorian: moon, 2004-04-05: Easter, 2004-04-11 Sunday"-        , "2004, Orthodox : moon, 2004-04-09: Easter, 2004-04-11 Sunday"-        , "2005, Gregorian: moon, 2005-03-25: Easter, 2005-03-27 Sunday"-        , "2005, Orthodox : moon, 2005-04-28: Easter, 2005-05-01 Sunday"-        , "2006, Gregorian: moon, 2006-04-13: Easter, 2006-04-16 Sunday"-        , "2006, Orthodox : moon, 2006-04-17: Easter, 2006-04-23 Sunday"-        , "2007, Gregorian: moon, 2007-04-02: Easter, 2007-04-08 Sunday"-        , "2007, Orthodox : moon, 2007-04-06: Easter, 2007-04-08 Sunday"-        , "2008, Gregorian: moon, 2008-03-22: Easter, 2008-03-23 Sunday"-        , "2008, Orthodox : moon, 2008-04-25: Easter, 2008-04-27 Sunday"-        , "2009, Gregorian: moon, 2009-04-10: Easter, 2009-04-12 Sunday"-        , "2009, Orthodox : moon, 2009-04-14: Easter, 2009-04-19 Sunday"-        , "2010, Gregorian: moon, 2010-03-30: Easter, 2010-04-04 Sunday"-        , "2010, Orthodox : moon, 2010-04-03: Easter, 2010-04-04 Sunday"-        , "2011, Gregorian: moon, 2011-04-18: Easter, 2011-04-24 Sunday"-        , "2011, Orthodox : moon, 2011-04-22: Easter, 2011-04-24 Sunday"-        , "2012, Gregorian: moon, 2012-04-07: Easter, 2012-04-08 Sunday"-        , "2012, Orthodox : moon, 2012-04-11: Easter, 2012-04-15 Sunday"-        , "2013, Gregorian: moon, 2013-03-27: Easter, 2013-03-31 Sunday"-        , "2013, Orthodox : moon, 2013-04-30: Easter, 2013-05-05 Sunday"-        , "2014, Gregorian: moon, 2014-04-14: Easter, 2014-04-20 Sunday"-        , "2014, Orthodox : moon, 2014-04-18: Easter, 2014-04-20 Sunday"-        , "2015, Gregorian: moon, 2015-04-03: Easter, 2015-04-05 Sunday"-        , "2015, Orthodox : moon, 2015-04-07: Easter, 2015-04-12 Sunday"-        , "2016, Gregorian: moon, 2016-03-23: Easter, 2016-03-27 Sunday"-        , "2016, Orthodox : moon, 2016-04-26: Easter, 2016-05-01 Sunday"-        , "2017, Gregorian: moon, 2017-04-11: Easter, 2017-04-16 Sunday"-        , "2017, Orthodox : moon, 2017-04-15: Easter, 2017-04-16 Sunday"-        , "2018, Gregorian: moon, 2018-03-31: Easter, 2018-04-01 Sunday"-        , "2018, Orthodox : moon, 2018-04-04: Easter, 2018-04-08 Sunday"-        , "2019, Gregorian: moon, 2019-04-18: Easter, 2019-04-21 Sunday"-        , "2019, Orthodox : moon, 2019-04-23: Easter, 2019-04-28 Sunday"-        , "2020, Gregorian: moon, 2020-04-08: Easter, 2020-04-12 Sunday"-        , "2020, Orthodox : moon, 2020-04-12: Easter, 2020-04-19 Sunday"-        ]
test/main/Test/Clock/Conversion.hs view
@@ -3,6 +3,7 @@ ) where  import Data.Time.Clock+import Data.Time.Clock.POSIX import Data.Time.Clock.System import Test.Tasty import Test.Tasty.HUnit@@ -17,6 +18,19 @@                     [ testCase "systemToUTCTime" $ assertEqual (show ut) ut $ systemToUTCTime st                     , testCase "utcToSystemTime" $ assertEqual (show ut) st $ utcToSystemTime ut                     ]+            testPOSIXTime :: (SystemTime, POSIXTime) -> TestTree+            testPOSIXTime (st, pt) =+                testGroup+                    (show st)+                    [ testCase "expected" $+                        assertEqual (show st) pt $+                            systemToPOSIXTime st+                    , testCase "matches systemToUTCTime" $+                        assertEqual+                            (show st)+                            (utcTimeToPOSIXSeconds $ systemToUTCTime st)+                            (systemToPOSIXTime st)+                    ]         in             [ testPair (MkSystemTime 0 0, UTCTime systemEpochDay 0)             , testPair (MkSystemTime 86399 0, UTCTime systemEpochDay 86399)@@ -24,4 +38,13 @@             , testPair (MkSystemTime 86399 1000000000, UTCTime systemEpochDay 86400)             , testPair (MkSystemTime 86399 1999999999, UTCTime systemEpochDay 86400.999999999)             , testPair (MkSystemTime 86400 0, UTCTime (succ systemEpochDay) 0)+            , testGroup+                "systemToPOSIXTime"+                [ testPOSIXTime (MkSystemTime 0 0, 0)+                , testPOSIXTime (MkSystemTime 86399 999999999, 86399.999999999)+                , testPOSIXTime (MkSystemTime 86399 1000000000, 86400)+                , testPOSIXTime (MkSystemTime 86399 1500000000, 86400)+                , testPOSIXTime (MkSystemTime 86399 1999999999, 86400)+                , testPOSIXTime (MkSystemTime 86400 0, 86400)+                ]             ]
test/main/Test/Format/ISO8601.hs view
@@ -160,6 +160,9 @@ testReadFormat :: (Show t, Eq t) => String -> Format t -> String -> t -> TestTree testReadFormat name fmt str val = nameTest (name ++ ": " ++ str) $ assertEqual "" (Just val) $ formatParseM fmt str +testReadFormatFails :: (Show t, Eq t) => String -> Format t -> String -> TestTree+testReadFormatFails name fmt str = nameTest (name ++ ": " ++ str) $ assertEqual "" Nothing $ formatParseM fmt str+ testShowFormats :: TestTree testShowFormats =     nameTest@@ -240,6 +243,10 @@             (recurringIntervalFormat (calendarFormat ExtendedFormat) durationDaysFormat)             "R74/2015-06-13/P1Y2M7D"             (74, fromGregorian 2015 6 13, CalendarDiffDays 14 7)+        , testReadFormatFails+            "recurringIntervalFormat etc."+            (recurringIntervalFormat (calendarFormat ExtendedFormat) (calendarFormat ExtendedFormat))+            "R18446744073709551616/2024-01-01/2024-01-02"         , testShowReadFormat "timeOffsetFormat" iso8601Format "-06:30" (minutesToTimeZone (-390))         , testShowReadFormat "timeOffsetFormat" iso8601Format "-06:00" (minutesToTimeZone (-360))         , testReadFormat "timeOffsetFormat" iso8601Format "-06" (minutesToTimeZone (-360))
test/main/Test/Format/ParseTime.hs view
@@ -271,10 +271,34 @@         "particular"         [ parseTest @Day True Nothing "%-d%-m%0Y" "2122012" -- ISSUE #232         , parseTest @Day True Nothing "%-d%-m%0Y" "2132012" -- ISSUE #232+        , Test.Tasty.HUnit.testCase "#303 lower-case AM/PM locale parses its own %p output" $+            assertEqual+                ""+                (Just $ TimeOfDay 13 0 0)+                (parseTimeM False lowerAmPmLocale "%I %p" "01 pm")+        , Test.Tasty.HUnit.testCase "#303 UTC zone parsing is case-insensitive" $+            assertEqual+                ""+                (Just utc)+                (parseTimeM False defaultTimeLocale "%Z" "utc")+        , Test.Tasty.HUnit.testCase "#303 known time zone names are case-insensitive" $+            assertEqual+                ""+                (Just lowerKnownZone)+                (parseTimeM False lowerKnownZoneLocale "%Z" "foo")         ]+  where+    lowerAmPmLocale = defaultTimeLocale{amPm = ("am", "pm")}+    lowerKnownZone = TimeZone 90 False "foo"+    lowerKnownZoneLocale = defaultTimeLocale{knownTimeZones = [lowerKnownZone]}  badParseTests :: TestTree-badParseTests = testGroup "bad" [parseTest False (Nothing :: Maybe Day) "%Y" ""]+badParseTests =+    testGroup+        "bad"+        [ parseTest False (Nothing :: Maybe Day) "%Y" ""+        , parseTest False (Nothing :: Maybe TimeOfDay) "%-H" "18446744073709551616"+        ]  {- parseYMD :: Day -> TestTree
+ test/unix/Test/LocalTime/HsTime.h view
@@ -0,0 +1,14 @@+#ifndef TEST_UNIX_LOCALTIME_HSTIME_H+#define TEST_UNIX_LOCALTIME_HSTIME_H++#include <time.h>++#define HAVE_LOCALTIME_R 1+#define HAVE_TZSET 1+#define HAVE_TM_ZONE 0+#define HAVE_TZNAME 1+#define HAVE_DECL_ALTZONE 0++long int get_current_timezone_seconds(time_t, int *pdst, char const **pname);++#endif
test/unix/Test/LocalTime/TimeZone.hs view
@@ -1,19 +1,103 @@+{-# LANGUAGE ForeignFunctionInterface #-}+ module Test.LocalTime.TimeZone (     testTimeZone, ) where  import Data.Time+import Foreign+import Foreign.C import System.Environment (setEnv) import Test.Tasty import Test.Tasty.HUnit +type GetCurrentTimezoneSeconds =+    CTime -> Ptr CInt -> Ptr CString -> IO CLong++foreign import ccall unsafe "test_time_zone_fallback_set_state"+    test_time_zone_fallback_set_state :: CLong -> CLong -> CInt -> IO ()++foreign import ccall unsafe "test_get_current_timezone_seconds_no_altzone"+    test_get_current_timezone_seconds_no_altzone :: GetCurrentTimezoneSeconds++foreign import ccall unsafe "test_get_current_timezone_seconds_altzone"+    test_get_current_timezone_seconds_altzone :: GetCurrentTimezoneSeconds+ testTimeZone :: TestTree testTimeZone =-    testCase "getTimeZone respects TZ env var" $ do-        let-            epoch = UTCTime (ModifiedJulianDay 57000) 0-        setEnv "TZ" "UTC+0"-        zone1 <- getTimeZone epoch-        setEnv "TZ" "EST+5"-        zone2 <- getTimeZone epoch-        assertBool "zone not changed" $ zone1 /= zone2+    testGroup+        "TimeZone"+        [ testCase "getTimeZone respects TZ env var" $ do+            let+                epoch = UTCTime (ModifiedJulianDay 57000) 0+            setEnv "TZ" "UTC+0"+            zone1 <- getTimeZone epoch+            setEnv "TZ" "EST+5"+            zone2 <- getTimeZone epoch+            assertBool "zone not changed" $ zone1 /= zone2+        , dependentTestGroup+            "get_current_timezone_seconds fallback"+            AllFinish+            [ testFallback+                "without altzone, standard time"+                test_get_current_timezone_seconds_no_altzone+                18000+                14400+                0+                (-18000)+                "EST"+            , testFallback+                "without altzone, daylight time"+                test_get_current_timezone_seconds_no_altzone+                18000+                14400+                1+                (-14400)+                "EDT"+            , testFallback+                "with altzone, standard time"+                test_get_current_timezone_seconds_altzone+                18000+                14400+                0+                (-18000)+                "EST"+            , testFallback+                "with altzone, daylight time"+                test_get_current_timezone_seconds_altzone+                18000+                14400+                1+                (-14400)+                "EDT"+            ]+        ]++testFallback ::+    String ->+    GetCurrentTimezoneSeconds ->+    CLong ->+    CLong ->+    CInt ->+    CLong ->+    String ->+    TestTree+testFallback+    name+    getTimezoneSeconds+    timezoneSeconds+    altzoneSeconds+    isDst+    expectedSeconds+    expectedName =+        testCase name $+            with 0 $ \pdst ->+                with nullPtr $ \pcname -> do+                    test_time_zone_fallback_set_state timezoneSeconds altzoneSeconds isDst+                    seconds <- getTimezoneSeconds 0 pdst pcname+                    dst <- peek pdst+                    cname <- peek pcname+                    name' <- peekCString cname+                    assertEqual "seconds" expectedSeconds seconds+                    assertEqual "dst" isDst dst+                    assertEqual "name" expectedName name'
+ test/unix/Test/LocalTime/TimeZoneFallback.c view
@@ -0,0 +1,45 @@+#include <time.h>++static int test_time_zone_fallback_isdst = 0;+static long int test_time_zone_fallback_timezone = 0;+static long int test_time_zone_fallback_altzone = 0;+static char test_time_zone_fallback_std_name[] = "EST";+static char test_time_zone_fallback_dst_name[] = "EDT";+static char *test_time_zone_fallback_tzname[] = {+    test_time_zone_fallback_std_name,+    test_time_zone_fallback_dst_name+};++void test_time_zone_fallback_set_state(long int timezone_seconds, long int altzone_seconds, int isdst)+{+    test_time_zone_fallback_timezone = timezone_seconds;+    test_time_zone_fallback_altzone = altzone_seconds;+    test_time_zone_fallback_isdst = isdst;+}++void test_time_zone_fallback_tzset(void)+{+}++struct tm *test_time_zone_fallback_localtime_r(const time_t *timer, struct tm *result)+{+    (void) timer;+    result->tm_isdst = test_time_zone_fallback_isdst;+    return result;+}++#define tzset test_time_zone_fallback_tzset+#define localtime_r test_time_zone_fallback_localtime_r+#define timezone test_time_zone_fallback_timezone+#define altzone test_time_zone_fallback_altzone+#define tzname test_time_zone_fallback_tzname++#define get_current_timezone_seconds test_get_current_timezone_seconds_no_altzone+#include "../../../../lib/cbits/HsTime.c"+#undef get_current_timezone_seconds++#undef HAVE_DECL_ALTZONE+#define HAVE_DECL_ALTZONE 1+#define get_current_timezone_seconds test_get_current_timezone_seconds_altzone+#include "../../../../lib/cbits/HsTime.c"+#undef get_current_timezone_seconds
time.cabal view
@@ -1,6 +1,6 @@ cabal-version:  3.0 name:           time-version:        1.16+version:        1.16.0.1 stability:      stable license:        BSD-2-Clause license-file:   LICENSE@@ -25,8 +25,11 @@     configure     lib/include/HsTime.h     lib/include/HsTimeConfig.h.in+    test/main/Test/Calendar/EasterData/*.csv+    test/main/Test/Calendar/EasterData/*.txt     test/unix/Test/Format/*.c     test/unix/Test/Format/*.h+    test/unix/Test/LocalTime/*.h extra-tmp-files:     config.log     config.status@@ -201,7 +204,6 @@         Test.Calendar.ConvertBack         Test.Calendar.Duration         Test.Calendar.Easter-        Test.Calendar.EasterRef         Test.Calendar.DayPeriod         Test.Calendar.LongWeekYears         Test.Calendar.LongWeekYearsRef@@ -264,7 +266,10 @@     ghc-options: -Wall -fwarn-tabs     if !arch (wasm32)         ghc-options: -threaded -rtsopts -with-rtsopts=-N-    c-sources: test/unix/Test/Format/FormatStuff.c+    include-dirs: test/unix/Test/LocalTime+    c-sources:+        test/unix/Test/Format/FormatStuff.c+        test/unix/Test/LocalTime/TimeZoneFallback.c     build-depends:         base,         deepseq,