diff --git a/changelog.md b/changelog.md index b3ea3a70..5dae202e 100644 --- a/changelog.md +++ b/changelog.md @@ -8,6 +8,7 @@ - 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 diff --git a/lib/Data/Time/Clock/POSIX.hs b/lib/Data/Time/Clock/POSIX.hs index 8e499d64..135aa322 100644 --- a/lib/Data/Time/Clock/POSIX.hs +++ b/lib/Data/Time/Clock/POSIX.hs @@ -45,7 +45,12 @@ utcTimeToPOSIXSeconds (UTCTime d t) = (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 diff --git a/test/main/Test/Clock/Conversion.hs b/test/main/Test/Clock/Conversion.hs index 020ee0d9..b5c04a22 100644 --- a/test/main/Test/Clock/Conversion.hs +++ b/test/main/Test/Clock/Conversion.hs @@ -3,6 +3,7 @@ module Test.Clock.Conversion ( ) 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,18 @@ testClockConversion = [ 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 +37,13 @@ testClockConversion = , 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) + ] ]