packages feed

hpgsql-simple-compat-0.1.0.0: src/Database/PostgreSQL/Simple/Time/Implementation.hs

------------------------------------------------------------------------------
------------------------------------------------------------------------------
------------------------------------------------------------------------------
------------------------------------------------------------------------------

-- |
-- Module:      Database.PostgreSQL.Simple.Time.Implementation
-- Copyright:   (c) 2012-2015 Leon P Smith
-- License:     BSD3
-- Maintainer:  Leon P Smith <leon@melding-monads.com>
-- Stability:   experimental
module Database.PostgreSQL.Simple.Time.Implementation where

import Control.Applicative
import qualified Data.Attoparsec.ByteString.Char8 as A
import qualified Data.ByteString as B
import Data.ByteString.Builder (Builder, byteString)
import Data.ByteString.Builder.Prim (primBounded)
import Data.Maybe (fromMaybe)
import Data.Time.Compat (Day, LocalTime, NominalDiffTime, TimeOfDay, TimeZone, UTCTime, ZonedTime, utc)
import Data.Time.LocalTime.Compat (CalendarDiffTime)
import qualified Database.PostgreSQL.Simple.Time.Internal.Parser as TP
import qualified Database.PostgreSQL.Simple.Time.Internal.Printer as TPP
import Hpgsql.Time (Unbounded (..))
import Prelude hiding (take)

type LocalTimestamp = Unbounded LocalTime

type UTCTimestamp = Unbounded UTCTime

type ZonedTimestamp = Unbounded ZonedTime

type Date = Unbounded Day

parseUTCTime :: B.ByteString -> Either String UTCTime
parseUTCTime = A.parseOnly (getUTCTime <* A.endOfInput)

parseZonedTime :: B.ByteString -> Either String ZonedTime
parseZonedTime = A.parseOnly (getZonedTime <* A.endOfInput)

parseLocalTime :: B.ByteString -> Either String LocalTime
parseLocalTime = A.parseOnly (getLocalTime <* A.endOfInput)

parseDay :: B.ByteString -> Either String Day
parseDay = A.parseOnly (getDay <* A.endOfInput)

parseTimeOfDay :: B.ByteString -> Either String TimeOfDay
parseTimeOfDay = A.parseOnly (getTimeOfDay <* A.endOfInput)

parseUTCTimestamp :: B.ByteString -> Either String UTCTimestamp
parseUTCTimestamp = A.parseOnly (getUTCTimestamp <* A.endOfInput)

parseZonedTimestamp :: B.ByteString -> Either String ZonedTimestamp
parseZonedTimestamp = A.parseOnly (getZonedTimestamp <* A.endOfInput)

parseLocalTimestamp :: B.ByteString -> Either String LocalTimestamp
parseLocalTimestamp = A.parseOnly (getLocalTimestamp <* A.endOfInput)

parseDate :: B.ByteString -> Either String Date
parseDate = A.parseOnly (getDate <* A.endOfInput)

parseCalendarDiffTime :: B.ByteString -> Either String CalendarDiffTime
parseCalendarDiffTime = A.parseOnly (getCalendarDiffTime <* A.endOfInput)

getUnbounded :: A.Parser a -> A.Parser (Unbounded a)
getUnbounded getFinite =
  (pure NegInfinity <* A.string "-infinity")
    <|> (pure PosInfinity <* A.string "infinity")
    <|> (Finite <$> getFinite)

getDay :: A.Parser Day
getDay = TP.day

getDate :: A.Parser Date
getDate = getUnbounded getDay

getTimeOfDay :: A.Parser TimeOfDay
getTimeOfDay = TP.timeOfDay

getLocalTime :: A.Parser LocalTime
getLocalTime = TP.localTime

getLocalTimestamp :: A.Parser LocalTimestamp
getLocalTimestamp = getUnbounded getLocalTime

getTimeZone :: A.Parser TimeZone
getTimeZone = fromMaybe utc <$> TP.timeZone

type TimeZoneHMS = (Int, Int, Int)

getTimeZoneHMS :: A.Parser TimeZoneHMS
getTimeZoneHMS = munge <$> TP.timeZoneHMS
  where
    munge Nothing = (0, 0, 0)
    munge (Just (TP.UTCOffsetHMS h m s)) = (h, m, s)

localToUTCTimeOfDayHMS :: TimeZoneHMS -> TimeOfDay -> (Integer, TimeOfDay)
localToUTCTimeOfDayHMS (dh, dm, ds) tod =
  TP.localToUTCTimeOfDayHMS (TP.UTCOffsetHMS dh dm ds) tod

getZonedTime :: A.Parser ZonedTime
getZonedTime = TP.zonedTime

getZonedTimestamp :: A.Parser ZonedTimestamp
getZonedTimestamp = getUnbounded getZonedTime

getUTCTime :: A.Parser UTCTime
getUTCTime = TP.utcTime

getUTCTimestamp :: A.Parser UTCTimestamp
getUTCTimestamp = getUnbounded getUTCTime

getCalendarDiffTime :: A.Parser CalendarDiffTime
getCalendarDiffTime = TP.calendarDiffTime

dayToBuilder :: Day -> Builder
dayToBuilder = primBounded TPP.day

timeOfDayToBuilder :: TimeOfDay -> Builder
timeOfDayToBuilder = primBounded TPP.timeOfDay

timeZoneToBuilder :: TimeZone -> Builder
timeZoneToBuilder = primBounded TPP.timeZone

utcTimeToBuilder :: UTCTime -> Builder
utcTimeToBuilder = primBounded TPP.utcTime

zonedTimeToBuilder :: ZonedTime -> Builder
zonedTimeToBuilder = primBounded TPP.zonedTime

localTimeToBuilder :: LocalTime -> Builder
localTimeToBuilder = primBounded TPP.localTime

unboundedToBuilder :: (a -> Builder) -> (Unbounded a -> Builder)
unboundedToBuilder finiteToBuilder unbounded =
  case unbounded of
    NegInfinity -> byteString "-infinity"
    Finite a -> finiteToBuilder a
    PosInfinity -> byteString "infinity"

utcTimestampToBuilder :: UTCTimestamp -> Builder
utcTimestampToBuilder = unboundedToBuilder utcTimeToBuilder

zonedTimestampToBuilder :: ZonedTimestamp -> Builder
zonedTimestampToBuilder = unboundedToBuilder zonedTimeToBuilder

localTimestampToBuilder :: LocalTimestamp -> Builder
localTimestampToBuilder = unboundedToBuilder localTimeToBuilder

dateToBuilder :: Date -> Builder
dateToBuilder = unboundedToBuilder dayToBuilder

nominalDiffTimeToBuilder :: NominalDiffTime -> Builder
nominalDiffTimeToBuilder = TPP.nominalDiffTime

calendarDiffTimeToBuilder :: CalendarDiffTime -> Builder
calendarDiffTimeToBuilder = TPP.calendarDiffTime