Add comment about difference between Postgres and Haskell dates

This commit is contained in:
2023-10-04 13:30:51 +02:00
parent 9c93d3a42b
commit 4f39966da2
2 changed files with 28 additions and 26 deletions
+13 -11
View File
@@ -19,13 +19,12 @@ import Data.Proxy (Proxy (..))
import Data.Time
( Day (..)
, DiffTime
, LocalTime (..)
, TimeOfDay
, UTCTime (..)
, addDays
, fromGregorian
, picosecondsToDiffTime
, timeToTimeOfDay
, toGregorian
)
import Data.Text (Text)
import Data.Word (Word32, Word64)
@@ -131,15 +130,13 @@ postgresEpoch :: Day
postgresEpoch = fromGregorian 2000 1 1
fromPostgresJulian :: Integer -> Day
fromPostgresJulian x
| year <= 0 = fromGregorian (year - 1) month dayOfMonth
| otherwise = day
where
day = addDays (fromIntegral x) postgresEpoch
(year, month, dayOfMonth) = toGregorian day
fromPostgresJulian x = addDays x postgresEpoch
-- | See https://www.postgresql.org/docs/current/datatype-datetime.html.
-- Relevant as well: https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/adt/datetime.c;h=267dfd37b2e8b9bc63797c69b9ca2e45e6bfde61;hb=HEAD#l267.
-- Note that Postgres uses the proleptic Gregorian calendar, whereas @Show Day@ and @fromGregorian@ use an astronomical calendar.
-- In short, Postgres treats 1 BC as a leap year and doesn't have a year zero.
-- This means that working with negative dates will be different in Postgres and your application code.
instance FromField Day where
validOid Proxy = Oid.date
parseField = fromPostgresJulian . fromIntegral <$> intParser @Int32
@@ -161,18 +158,23 @@ instance FromField TimeOfDay where
validOid Proxy = Oid.time
parseField = timeToTimeOfDay <$> parseField @DiffTime
instance FromField UTCTime where
-- | See https://www.postgresql.org/docs/current/datatype-datetime.html.
-- | Accepts @timestamp@.
-- Note that Postgres uses the proleptic Gregorian calendar, whereas @Show Day@ and @fromGregorian@ use an astronomical calendar.
-- In short, Postgres treats 1 BC as a leap year and doesn't have a year zero.
-- This means that working with negative dates will be different in Postgres and your application code.
instance FromField LocalTime where
validOid Proxy = Oid.timestamp
parseField = fromPostgresTimestamp <$> intParser @Int
where
fromPostgresTimestamp :: Int -> UTCTime
fromPostgresTimestamp :: Int -> LocalTime
fromPostgresTimestamp ts =
let
(days, microseconds) = ts `divMod` (86400 * 1000000)
day = fromPostgresJulian $ fromIntegral days
time = picosecondsToDiffTime $ fromIntegral microseconds * 1000000
in
UTCTime day time
LocalTime day (timeToTimeOfDay time)
newtype RawField a = RawField a
deriving (Eq, Show)