mirror of
https://github.com/simonmichael/hledger.git
synced 2024-11-08 07:09:28 +03:00
lib: Ensure parsed years have at least 4 digits.
This commit is contained in:
parent
7b9f9ae49c
commit
ffb5cf0773
@ -71,6 +71,7 @@ module Hledger.Data.Dates (
|
||||
fixSmartDateStr,
|
||||
fixSmartDateStrEither,
|
||||
fixSmartDateStrEither',
|
||||
yearp,
|
||||
daysInSpan,
|
||||
maybePeriod,
|
||||
mkdatespan,
|
||||
@ -84,6 +85,7 @@ import Control.Applicative (liftA2)
|
||||
import Control.Applicative.Permutations
|
||||
import Control.Monad (guard, unless)
|
||||
import "base-compat-batteries" Data.List.Compat
|
||||
import Data.Char (isDigit)
|
||||
import Data.Default
|
||||
import Data.Foldable (asum)
|
||||
import Data.Function (on)
|
||||
@ -763,12 +765,7 @@ Right (SmartYMD (Just 201813012) Nothing Nothing)
|
||||
smartdate :: TextParser m SmartDate
|
||||
smartdate = choice'
|
||||
-- XXX maybe obscures date errors ? see ledgerdate
|
||||
[ yyyymmdd
|
||||
, md
|
||||
, ymd
|
||||
, yd
|
||||
, month
|
||||
, mon
|
||||
[ yyyymmdd, md, ymd, smartYear, smartDay, month, mon
|
||||
, SmartRel This Day <$ string' "today"
|
||||
, SmartRel Last Day <$ string' "yesterday"
|
||||
, SmartRel Next Day <$ string' "tomorrow"
|
||||
@ -778,6 +775,11 @@ smartdate = choice'
|
||||
seqP = choice [This <$ string' "this", Last <$ string' "last", Next <$ string' "next"]
|
||||
intervalP = choice [Day <$ string' "day", Week <$ string' "week", Month <$ string' "month",
|
||||
Quarter <$ string' "quarter", Year <$ string' "year"]
|
||||
smartYear = (\y -> SmartYMD (Just y) Nothing Nothing) <$> yearp
|
||||
smartDay = do
|
||||
d <- SmartYMD Nothing Nothing . Just <$> decimal
|
||||
failIfInvalidDate d
|
||||
return d
|
||||
|
||||
-- | Like smartdate, but there must be nothing other than whitespace after the date.
|
||||
smartdateonly :: TextParser m SmartDate
|
||||
@ -812,7 +814,7 @@ yyyymmdd = do
|
||||
|
||||
ymd :: TextParser m SmartDate
|
||||
ymd = do
|
||||
y <- decimal
|
||||
y <- yearp
|
||||
sep <- datesepchar
|
||||
m <- decimal
|
||||
d <- optional $ char sep *> decimal
|
||||
@ -829,12 +831,13 @@ md = do
|
||||
failIfInvalidDate date
|
||||
return date
|
||||
|
||||
yd :: TextParser m SmartDate
|
||||
yd = do
|
||||
n <- decimal
|
||||
if n >= 1 && n <= 31
|
||||
then return $ SmartYMD Nothing Nothing (Just $ fromInteger n)
|
||||
else return $ SmartYMD (Just n) Nothing Nothing
|
||||
-- | Parse a year number from a Text, making sure that at least four digits are
|
||||
-- used.
|
||||
yearp :: TextParser m Integer
|
||||
yearp = do
|
||||
year <- takeWhile1P (Just "year") isDigit
|
||||
unless (T.length year >= 4) . Fail.fail $ "Year must contain at least 4 digits: " <> T.unpack year
|
||||
return $ readDecimal year
|
||||
|
||||
-- These are compared case insensitively, and should all be kept lower case.
|
||||
months = ["january","february","march","april","may","june",
|
||||
|
@ -98,7 +98,6 @@ import Data.Time.LocalTime
|
||||
import Safe
|
||||
import Text.Megaparsec hiding (parse)
|
||||
import Text.Megaparsec.Char
|
||||
import Text.Megaparsec.Char.Lexer (decimal)
|
||||
import Text.Megaparsec.Custom
|
||||
import Text.Printf
|
||||
import System.FilePath
|
||||
@ -553,8 +552,7 @@ defaultyeardirectivep :: JournalParser m ()
|
||||
defaultyeardirectivep = do
|
||||
char 'Y' <?> "default year"
|
||||
lift skipNonNewlineSpaces
|
||||
y <- decimal
|
||||
setYear y
|
||||
setYear =<< lift yearp
|
||||
|
||||
defaultcommoditydirectivep :: JournalParser m ()
|
||||
defaultcommoditydirectivep = do
|
||||
|
@ -50,12 +50,14 @@ module Hledger.Utils.Text
|
||||
-- fitStringMulti,
|
||||
textPadLeftWide,
|
||||
textPadRightWide,
|
||||
-- -- * Reading
|
||||
readDecimal,
|
||||
-- -- * tests
|
||||
tests_Text
|
||||
)
|
||||
where
|
||||
|
||||
-- import Data.Char
|
||||
import Data.Char (digitToInt)
|
||||
import Data.List
|
||||
#if !(MIN_VERSION_base(4,11,0))
|
||||
import Data.Monoid
|
||||
@ -400,6 +402,13 @@ textWidth s = maximum $ map (T.foldr (\a b -> charWidth a + b) 0) $ T.lines s
|
||||
-- | otherwise -> 1
|
||||
|
||||
|
||||
-- | Read a decimal number from a Text. Assumes the input consists only of digit
|
||||
-- characters.
|
||||
readDecimal :: Integral a => Text -> a
|
||||
readDecimal = foldl' step 0 . T.unpack
|
||||
where step a c = a * 10 + fromIntegral (digitToInt c)
|
||||
|
||||
|
||||
tests_Text = tests "Text" [
|
||||
test "quoteIfSpaced" $ do
|
||||
quoteIfSpaced "a'a" @?= "a'a"
|
||||
|
Loading…
Reference in New Issue
Block a user