{-# LANGUAGE OverloadedStrings #-}

module Q.Time
        ( module Q.Time.Date
        , module Q.Time.DayCounter
        , parseDay
        , parseLocalTime
        ) where

import qualified Data.ByteString          as B
import           Data.ByteString.Char8    (unpack)
import           Data.Csv                 (FromField (..), ToField (..), record,
                                           toField, (.!), (.:))
import           Data.Maybe               (fromJust)
import           Data.Time
import           Data.Time.Format
import           Data.Time.Format.ISO8601
import           Data.Vector              (Vector, toList)
import           Q.Time.Date
import           Q.Time.DayCounter

-- | Converts a shortened ISO08601 date string, or datetime to a 'LocalTime'.
-- If the string doesn't contain time then 'midnight' is used.
parseLocalTime :: String -> Maybe LocalTime
parseLocalTime :: String -> Maybe LocalTime
parseLocalTime String
iso_datetime =
  if String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
iso_datetime Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
8 then do
    Day
day <- Format Day -> String -> Maybe Day
forall (m :: * -> *) t. MonadFail m => Format t -> String -> m t
formatParseM Format Day
dayFormat' String
iso_datetime
    LocalTime -> Maybe LocalTime
forall (m :: * -> *) a. Monad m => a -> m a
return (LocalTime -> Maybe LocalTime) -> LocalTime -> Maybe LocalTime
forall a b. (a -> b) -> a -> b
$ Day -> TimeOfDay -> LocalTime
LocalTime Day
day TimeOfDay
midnight
  else
    Format LocalTime -> String -> Maybe LocalTime
forall (m :: * -> *) t. MonadFail m => Format t -> String -> m t
formatParseM Format LocalTime
localTimeFormat' String
iso_datetime

-- | Converts a shortned ISO08601 date to a 'Day'
parseDay :: String -> Maybe Day
parseDay :: String -> Maybe Day
parseDay = Format Day -> String -> Maybe Day
forall (m :: * -> *) t. MonadFail m => Format t -> String -> m t
formatParseM Format Day
dayFormat'


-- | basic ISO08601 date/time format.
localTimeFormat' :: Format LocalTime
localTimeFormat' = Format Day -> Format TimeOfDay -> Format LocalTime
localTimeFormat Format Day
dayFormat' Format TimeOfDay
timeFormat'
-- | basic ISO08601 time format.
timeFormat' :: Format TimeOfDay
timeFormat' = FormatExtension -> Format TimeOfDay
timeOfDayFormat FormatExtension
BasicFormat
-- | basic ISO08601 day format.
dayFormat' :: Format Day
dayFormat' = FormatExtension -> Format Day
calendarFormat FormatExtension
BasicFormat

-- | Format a date as an basic ISO08601 format.
dateToString :: LocalTime -> String
dateToString :: LocalTime -> String
dateToString LocalTime
date = Format LocalTime -> LocalTime -> String
forall t. Format t -> t -> String
formatShow Format LocalTime
localTimeFormat' LocalTime
date


instance ToField Day where
   toField :: Day -> Field
toField Day
d = String -> Field
forall a. ToField a => a -> Field
toField (String -> Field) -> String -> Field
forall a b. (a -> b) -> a -> b
$ Format Day -> Day -> String
forall t. Format t -> t -> String
formatShow Format Day
dayFormat' Day
d
instance FromField Day where
  parseField :: Field -> Parser Day
parseField Field
s = Day -> Parser Day
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Day -> Parser Day) -> Day -> Parser Day
forall a b. (a -> b) -> a -> b
$ Maybe Day -> Day
forall a. HasCallStack => Maybe a -> a
fromJust (String -> Maybe Day
parseDay (Field -> String
unpack Field
s))