tighten up date parsing, make it io-friendly and parse Y, M/D, D

This commit is contained in:
Simon Michael 2008-11-25 23:52:42 +00:00
parent b3c0bba51e
commit 1c60514973
4 changed files with 59 additions and 22 deletions

View File

@ -500,10 +500,14 @@ smartdate = do
(y,m,d) <- ( (y,m,d) <- (
try ymd try ymd
<|> try ym <|> try ym
<|> try md
<|> try y <|> try y
-- <|> try md <|> try d
-- <|> try month -- <|> try month
-- <|> try mon -- <|> try mon
-- <|> try today
-- <|> try yesterday
-- <|> try tomorrow
-- <|> try thiswhatever -- <|> try thiswhatever
-- <|> try nextwhatever -- <|> try nextwhatever
-- <|> try lastwhatever -- <|> try lastwhatever
@ -517,27 +521,54 @@ ymd = do
y <- many digit y <- many digit
datesep datesep
m <- many digit m <- many digit
guard (read m <= 12)
datesep datesep
d <- many digit d <- many digit
guard (read d <= 31)
return (y,m,d) return (y,m,d)
ym :: Parser (String,String,String) ym :: Parser (String,String,String)
ym = do ym = do
y <- many digit y <- many digit
guard (read y > 12)
datesep datesep
m <- many digit m <- many digit
guard (read m <= 12)
return (y,m,"1") return (y,m,"1")
y :: Parser (String,String,String) y :: Parser (String,String,String)
y = do y = do
y <- many digit y <- many digit
guard (read y >= 1000)
return (y,"1","1") return (y,"1","1")
-- | Parse a flexible date string, with awareness of the current time, d :: Parser (String,String,String)
-- and return a Date or raise an error. d = do
smartparsedate :: String -> Date d <- many digit
smartparsedate s = parsedate $ printf "%04s/%02s/%02s" y m d guard (read d <= 31)
where (y,m,d) = fromparse $ parsewith smartdate s return ("","",d)
-- | Parse a M/D string as ("",M,D), year will be filled in later
md :: Parser (String,String,String)
md = do
m <- many digit
guard (read m <= 12)
datesep
d <- many digit
guard (read d <= 31)
return ("",m,d)
-- | Parse a flexible date string to a Date with awareness of the current
-- time, or raise an error.
smartparsedate :: String -> IO Date
smartparsedate s = do
let (y,m,d) = fromparse $ parsewith smartdate s
(thisy,thism,_) <- today >>= return . dateComponents
let (y',m',d') = case (y,m,d) of
("","",d) -> (show thisy,show thism,d)
("",m,d) -> (show thisy,m,d)
otherwise -> (y,m,d)
return $ parsedate $ printf "%04s/%02s/%02s" y' m' d'
type TransactionMatcher = Transaction -> Bool type TransactionMatcher = Transaction -> Bool

View File

@ -113,11 +113,11 @@ tildeExpand ('~':'/':xs) = getHomeDirectory >>= return . (++ ('/':xs))
tildeExpand xs = return xs tildeExpand xs = return xs
-- | Get the value of the begin date option, if any. -- | Get the value of the begin date option, if any.
beginDateFromOpts :: [Opt] -> Maybe Date beginDateFromOpts :: [Opt] -> IO (Maybe Date)
beginDateFromOpts opts = beginDateFromOpts opts =
case beginopts of case beginopts of
(x:_) -> Just $ smartparsedate $ last beginopts (x:_) -> smartparsedate (last beginopts) >>= return . Just
_ -> Nothing _ -> return Nothing
where where
beginopts = concatMap getbegindate opts beginopts = concatMap getbegindate opts
getbegindate (Begin s) = [s] getbegindate (Begin s) = [s]
@ -125,11 +125,11 @@ beginDateFromOpts opts =
defaultdate = "" defaultdate = ""
-- | Get the value of the end date option, if any. -- | Get the value of the end date option, if any.
endDateFromOpts :: [Opt] -> Maybe Date endDateFromOpts :: [Opt] -> IO (Maybe Date)
endDateFromOpts opts = endDateFromOpts opts = do
case endopts of case endopts of
(x:_) -> Just $ smartparsedate $ last endopts (x:_) -> smartparsedate (last endopts) >>= return . Just
_ -> Nothing _ -> return Nothing
where where
endopts = concatMap getenddate opts endopts = concatMap getenddate opts
getenddate (End s) = [s] getenddate (End s) = [s]

View File

@ -98,9 +98,15 @@ misc_tests = TestList [
assertparseequal timelog1 (parsewith timelog timelog1_str) assertparseequal timelog1 (parsewith timelog timelog1_str)
, ,
"smartparsedate" ~: do "smartparsedate" ~: do
assertequal (1999,12,13) (dateComponents $ smartparsedate "1999/12/13") (thisyear,thismonth,thisday) <- today >>= return . dateComponents
assertequal (2008,2,1) (dateComponents $ smartparsedate "2008-2") d <- smartparsedate "1999-12-02"; assertequal (1999,12,2) (dateComponents d)
assertequal (2008,1,1) (dateComponents $ smartparsedate "2008") d <- smartparsedate "1999.12.02"; assertequal (1999,12,2) (dateComponents d)
d <- smartparsedate "1999/3/2"; assertequal (1999,3,2) (dateComponents d)
d <- smartparsedate "2008/2"; assertequal (2008,2,1) (dateComponents d)
d <- smartparsedate "20/2"; assertequal (20,2,1) (dateComponents d)
d <- smartparsedate "4/2"; assertequal (thisyear,4,2) (dateComponents d)
d <- smartparsedate "1000"; assertequal (1000,1,1) (dateComponents d)
d <- smartparsedate "2"; assertequal (thisyear,thismonth,2) (dateComponents d)
] ]
balancereportacctnames_tests = TestList balancereportacctnames_tests = TestList

View File

@ -68,12 +68,12 @@ main = do
-- | parse the user's specified ledger file and do some action with it -- | parse the user's specified ledger file and do some action with it
-- (or report a parse error). This function makes the whole thing go. -- (or report a parse error). This function makes the whole thing go.
parseLedgerAndDo :: [Opt] -> [String] -> ([Opt] -> [String] -> Ledger -> IO ()) -> IO () parseLedgerAndDo :: [Opt] -> [String] -> ([Opt] -> [String] -> Ledger -> IO ()) -> IO ()
parseLedgerAndDo opts args cmd = parseLedgerAndDo opts args cmd = do
ledgerFilePathFromOpts opts >>= parseLedgerFile >>= either printParseError runcmd b <- beginDateFromOpts opts
e <- endDateFromOpts opts
let runcmd = cmd opts args . cacheLedger apats . filterRawLedger b e dpats c r . canonicaliseAmounts costbasis
ledgerFilePathFromOpts opts >>= parseLedgerFile >>= either printParseError runcmd
where where
runcmd = cmd opts args . cacheLedger apats . filterRawLedger b e dpats c r . canonicaliseAmounts costbasis
b = beginDateFromOpts opts
e = endDateFromOpts opts
(apats,dpats) = parseAccountDescriptionArgs opts args (apats,dpats) = parseAccountDescriptionArgs opts args
c = Cleared `elem` opts c = Cleared `elem` opts
r = Real `elem` opts r = Real `elem` opts