module Taskell.Data.Date.RelativeParser ( parseRelative ) where import ClassyPrelude import Data.Attoparsec.Text import Data.Time.Clock (addUTCTime) import Taskell.Data.Date.Types (Due (DueDate, DueTime)) import Taskell.Utility.Parser (lexeme, only) -- utility functions addP :: (Integral a) => Parser a -> UTCTime -> Parser UTCTime addP p now = ($ now) . addUTCTime . fromIntegral . sum <$> many1 p -- relative time parsing minute :: Int minute = 60 hour :: Int hour = minute * 60 day :: Int day = hour * 24 week :: Int week = day * 7 timePeriodP :: Char -> Parser Int timePeriodP c = lexeme decimal <* char c wP :: Parser Int wP = (* week) <$> timePeriodP 'w' dP :: Parser Int dP = (* day) <$> timePeriodP 'd' hP :: Parser Int hP = (* hour) <$> timePeriodP 'h' mP :: Parser Int mP = (* minute) <$> timePeriodP 'm' sP :: Parser Int sP = timePeriodP 's' timeP :: UTCTime -> Parser (Maybe Due) timeP now = only . lexeme $ Just . DueTime <$> addP (sP <|> mP <|> hP <|> dP <|> wP) now -- relative date parsing dateP :: UTCTime -> Parser (Maybe Due) dateP now = only . lexeme $ Just . DueDate . utctDay <$> addP (dP <|> wP) now -- relative parser relativeP :: UTCTime -> Parser (Maybe Due) relativeP now = dateP now <|> timeP now parseRelative :: UTCTime -> Text -> Either Text Due parseRelative now text = case parseOnly (relativeP now) text of Right (Just due) -> Right due _ -> Left "Could not parse date."