cli: clarify smart dates with more examples; add support for YYYYMM

This commit is contained in:
Simon Michael 2018-04-04 17:45:23 +01:00
parent 0e5aa349c8
commit 0b5ddcebee
6 changed files with 609 additions and 490 deletions

View File

@ -650,25 +650,58 @@ parsedate s = fromMaybe (error' $ "could not parse date \"" ++ s ++ "\"")
-- #endif
{-|
Parse a date in any of the formats allowed in ledger's period expressions,
and maybe some others:
> 2004
> 2004/10
> 2004/10/1
> 10/1
> 21
> october, oct
> yesterday, today, tomorrow
> this/next/last week/day/month/quarter/year
Returns a SmartDate, to be converted to a full date later (see fixSmartDate).
Parse a date in any of the formats allowed in Ledger's period expressions, and some others.
Assumes any text in the parse stream has been lowercased.
Returns a SmartDate, to be converted to a full date later (see fixSmartDate).
Examples:
> 2004 (start of year, which must have 4+ digits)
> 2004/10 (start of month, which must be 1-12)
> 2004/10/1 (exact date, day must be 1-31)
> 10/1 (month and day in current year)
> 21 (day in current month)
> october, oct (start of month in current year)
> yesterday, today, tomorrow (-1, 0, 1 days from today)
> last/this/next day/week/month/quarter/year (-1, 0, 1 periods from the current period)
> 20181201 (8 digit YYYYMMDD with valid year month and day)
> 201812 (6 digit YYYYMM with valid year and month)
Note malformed digit sequences might give surprising results:
> 201813 (6 digits with an invalid month is parsed as start of 6-digit year)
> 20181301 (8 digits with an invalid month is parsed as start of 8-digit year)
> 20181232 (8 digits with an invalid day gives an error)
> 201801012 (9+ digits beginning with a valid YYYYMMDD gives an error)
Eg:
YYYYMMDD is parsed as year-month-date if those parts are valid
(>=4 digits, 1-12, and 1-31 respectively):
>>> parsewith (smartdate <* eof) "20181201"
Right ("2018","12","01")
YYYYMM is parsed as year-month-01 if year and month are valid:
>>> parsewith (smartdate <* eof) "201804"
Right ("2018","04","01")
With an invalid month, it's parsed as a year:
>>> parsewith (smartdate <* eof) "201813"
Right ("201813","","")
A 9+ digit number beginning with valid YYYYMMDD gives an error:
>>> parsewith (smartdate <* eof) "201801012"
Left (TrivialError (SourcePos {sourceName = "", sourceLine = Pos 1, sourceColumn = Pos 9} :| []) (Just (Tokens ('2' :| ""))) (fromList [EndOfInput]))
Big numbers not beginning with a valid YYYYMMDD are parsed as a year:
>>> parsewith (smartdate <* eof) "201813012"
Right ("201813012","","")
-}
smartdate :: SimpleTextParser SmartDate
smartdate = do
-- XXX maybe obscures date errors ? see ledgerdate
(y,m,d) <- choice' [yyyymmdd, ymd, ym, md, y, d, month, mon, today, yesterday, tomorrow, lastthisnextthing]
(y,m,d) <- choice' [yyyymmdd, yyyymm, ymd, ym, md, y, d, month, mon, today, yesterday, tomorrow, lastthisnextthing]
return (y,m,d)
-- | Like smartdate, but there must be nothing other than whitespace after the date.
@ -703,6 +736,13 @@ yyyymmdd = do
failIfInvalidDay d
return (y,m,d)
yyyymm :: SimpleTextParser SmartDate
yyyymm = do
y <- count 4 digitChar
m <- count 2 digitChar
failIfInvalidMonth m
return (y,m,"01")
ymd :: SimpleTextParser SmartDate
ymd = do
y <- some digitChar
@ -946,6 +986,9 @@ periodexprdatespan rdate = choice $ map try [
justdatespan rdate
]
-- |
-- -- >>> parsewith (doubledatespan (parsedate "2018/01/01") <* eof) "20180101-201804"
-- Right DateSpan 2018/01/01-2018/04/01
doubledatespan :: Day -> SimpleTextParser DateSpan
doubledatespan rdate = do
optional (string "from" >> skipMany spacenonewline)

View File

@ -306,6 +306,7 @@ tests_parseQueryTerm = [
"real:1" `gives` (Left $ Real True)
"date:2008" `gives` (Left $ Date $ DateSpan (Just $ parsedate "2008/01/01") (Just $ parsedate "2009/01/01"))
"date:from 2012/5/17" `gives` (Left $ Date $ DateSpan (Just $ parsedate "2012/05/17") Nothing)
"date:20180101-201804" `gives` (Left $ Date $ DateSpan (Just $ parsedate "2018/01/01") (Just $ parsedate "2018/04/01"))
"inacct:a" `gives` (Right $ QueryOptInAcct "a")
"tag:a" `gives` (Left $ Tag "a" Nothing)
"tag:a=some value" `gives` (Left $ Tag "a" (Just "some value"))

View File

@ -493,49 +493,83 @@ Examples:
tab(@);
l l.
T{
\f[C]2009/1/1\f[], \f[C]2009/01/01\f[], \f[C]2009\-1\-1\f[],
\f[C]2009.1.1\f[]
\f[C]2004/10/1\f[], \f[C]2004\-01\-01\f[], \f[C]2004.9.1\f[]
T}@T{
simple dates, several separators allowed
exact date, several separators allowed.
Year is 4+ digits, month is 1\-12, day is 1\-31
T}
T{
\f[C]2009/1\f[], \f[C]2009\f[]
\f[C]2004\f[]
T}@T{
same as above \- a missing day or month defaults to 1
start of year
T}
T{
\f[C]1/1\f[], \f[C]january\f[], \f[C]jan\f[], \f[C]this\ year\f[]
\f[C]2004/10\f[]
T}@T{
relative dates, meaning january 1 of the current year
start of month
T}
T{
\f[C]next\ year\f[]
\f[C]10/1\f[]
T}@T{
january 1 of next year
month and day in current year
T}
T{
\f[C]this\ month\f[]
\f[C]21\f[]
T}@T{
the 1st of the current month
day in current month
T}
T{
\f[C]this\ week\f[]
\f[C]october,\ oct\f[]
T}@T{
the most recent monday
start of month in current year
T}
T{
\f[C]last\ week\f[]
\f[C]yesterday,\ today,\ tomorrow\f[]
T}@T{
the monday of the week before this one
\-1, 0, 1 days from today
T}
T{
\f[C]lastweek\f[]
\f[C]last/this/next\ day/week/month/quarter/year\f[]
T}@T{
spaces are optional
\-1, 0, 1 periods from the current period
T}
T{
\f[C]today\f[], \f[C]yesterday\f[], \f[C]tomorrow\f[]
\f[C]20181201\f[]
T}@T{
8 digit YYYYMMDD with valid year month and day
T}
T{
\f[C]201812\f[]
T}@T{
6 digit YYYYMM with valid year and month
T}
.TE
.PP
Counterexamples \- malformed digit sequences might give surprising
results:
.PP
.TS
tab(@);
l l.
T{
\f[C]201813\f[]
T}@T{
6 digits with an invalid month is parsed as start of 6\-digit year
T}
T{
\f[C]20181301\f[]
T}@T{
8 digits with an invalid month is parsed as start of 8\-digit year
T}
T{
\f[C]20181232\f[]
T}@T{
8 digits with an invalid day gives an error
T}
T{
\f[C]201801012\f[]
T}@T{
9+ digits beginning with a valid YYYYMMDD gives an error
T}
.TE
.SS Report start & end date

View File

@ -390,15 +390,25 @@ omitted (defaulting to 1).
Examples:
'2009/1/1', '2009/01/01', '2009-1-1', '2009.1.1' simple dates, several separators allowed
'2009/1', '2009' same as above - a missing day or month defaults to 1
'1/1', 'january', 'jan', 'this year' relative dates, meaning january 1 of the current year
'next year' january 1 of next year
'this month' the 1st of the current month
'this week' the most recent monday
'last week' the monday of the week before this one
'lastweek' spaces are optional
'today', 'yesterday', 'tomorrow'
'2004/10/1', '2004-01-01', '2004.9.1' exact date, several separators allowed. Year is 4+ digits, month is 1-12, day is 1-31
'2004' start of year
'2004/10' start of month
'10/1' month and day in current year
'21' day in current month
'october, oct' start of month in current year
'yesterday, today, tomorrow' -1, 0, 1 days from today
'last/this/next -1, 0, 1 periods from the current period
day/week/month/quarter/year'
'20181201' 8 digit YYYYMMDD with valid year month and day
'201812' 6 digit YYYYMM with valid year and month
Counterexamples - malformed digit sequences might give surprising
results:
'201813' 6 digits with an invalid month is parsed as start of 6-digit year
'20181301' 8 digits with an invalid month is parsed as start of 8-digit year
'20181232' 8 digits with an invalid day gives an error
'201801012' 9+ digits beginning with a valid YYYYMMDD gives an error

File: hledger.info, Node: Report start & end date, Next: Report intervals, Prev: Smart dates, Up: OPTIONS
@ -2411,117 +2421,117 @@ Node: Input files9632
Ref: #input-files9768
Node: Smart dates11738
Ref: #smart-dates11879
Node: Report start & end date12858
Ref: #report-start-end-date13028
Node: Report intervals14093
Ref: #report-intervals14256
Node: Period expressions14657
Ref: #period-expressions14817
Node: Depth limiting18774
Ref: #depth-limiting18918
Node: Pivoting19260
Ref: #pivoting19378
Node: Cost21054
Ref: #cost21162
Node: Market value21280
Ref: #market-value21415
Node: Combining -B and -V22598
Ref: #combining--b-and--v22761
Node: Output destination22908
Ref: #output-destination23070
Node: Output format23353
Ref: #output-format23505
Node: Regular expressions23890
Ref: #regular-expressions24027
Node: QUERIES25388
Ref: #queries25490
Node: COMMANDS29457
Ref: #commands29569
Node: accounts30551
Ref: #accounts30649
Node: activity31895
Ref: #activity32005
Node: add32365
Ref: #add32464
Node: balance35125
Ref: #balance35236
Node: Flat mode38740
Ref: #flat-mode38865
Node: Depth limited balance reports39285
Ref: #depth-limited-balance-reports39486
Node: Multicolumn balance reports39906
Ref: #multicolumn-balance-reports40101
Node: Budgets44790
Ref: #budgets44937
Node: Custom balance output48906
Ref: #custom-balance-output49068
Node: Colour support51234
Ref: #colour-support51366
Node: balancesheet51539
Ref: #balancesheet51675
Node: balancesheetequity53986
Ref: #balancesheetequity54135
Node: cashflow54672
Ref: #cashflow54800
Node: check-dates56923
Ref: #check-dates57050
Node: check-dupes57167
Ref: #check-dupes57291
Node: close57428
Ref: #close57535
Node: help57865
Ref: #help57965
Node: import59039
Ref: #import59153
Node: incomestatement59883
Ref: #incomestatement60017
Node: prices62421
Ref: #prices62536
Node: print62579
Ref: #print62689
Node: print-unique67583
Ref: #print-unique67709
Node: register67777
Ref: #register67904
Node: Custom register output72405
Ref: #custom-register-output72534
Node: register-match73764
Ref: #register-match73898
Node: rewrite74081
Ref: #rewrite74198
Node: stats74267
Ref: #stats74370
Node: tags75240
Ref: #tags75338
Node: test75574
Ref: #test75658
Node: ADD-ON COMMANDS76026
Ref: #add-on-commands76136
Node: Official add-ons77423
Ref: #official-add-ons77563
Node: api77650
Ref: #api77739
Node: ui77791
Ref: #ui77890
Node: web77948
Ref: #web78037
Node: Third party add-ons78083
Ref: #third-party-add-ons78258
Node: diff78393
Ref: #diff78490
Node: iadd78589
Ref: #iadd78703
Node: interest78786
Ref: #interest78907
Node: irr79002
Ref: #irr79100
Node: Experimental add-ons79178
Ref: #experimental-add-ons79330
Node: autosync79610
Ref: #autosync79721
Node: chart79960
Ref: #chart80079
Node: check80150
Ref: #check80252
Node: Report start & end date13285
Ref: #report-start-end-date13455
Node: Report intervals14520
Ref: #report-intervals14683
Node: Period expressions15084
Ref: #period-expressions15244
Node: Depth limiting19201
Ref: #depth-limiting19345
Node: Pivoting19687
Ref: #pivoting19805
Node: Cost21481
Ref: #cost21589
Node: Market value21707
Ref: #market-value21842
Node: Combining -B and -V23025
Ref: #combining--b-and--v23188
Node: Output destination23335
Ref: #output-destination23497
Node: Output format23780
Ref: #output-format23932
Node: Regular expressions24317
Ref: #regular-expressions24454
Node: QUERIES25815
Ref: #queries25917
Node: COMMANDS29884
Ref: #commands29996
Node: accounts30978
Ref: #accounts31076
Node: activity32322
Ref: #activity32432
Node: add32792
Ref: #add32891
Node: balance35552
Ref: #balance35663
Node: Flat mode39167
Ref: #flat-mode39292
Node: Depth limited balance reports39712
Ref: #depth-limited-balance-reports39913
Node: Multicolumn balance reports40333
Ref: #multicolumn-balance-reports40528
Node: Budgets45217
Ref: #budgets45364
Node: Custom balance output49333
Ref: #custom-balance-output49495
Node: Colour support51661
Ref: #colour-support51793
Node: balancesheet51966
Ref: #balancesheet52102
Node: balancesheetequity54413
Ref: #balancesheetequity54562
Node: cashflow55099
Ref: #cashflow55227
Node: check-dates57350
Ref: #check-dates57477
Node: check-dupes57594
Ref: #check-dupes57718
Node: close57855
Ref: #close57962
Node: help58292
Ref: #help58392
Node: import59466
Ref: #import59580
Node: incomestatement60310
Ref: #incomestatement60444
Node: prices62848
Ref: #prices62963
Node: print63006
Ref: #print63116
Node: print-unique68010
Ref: #print-unique68136
Node: register68204
Ref: #register68331
Node: Custom register output72832
Ref: #custom-register-output72961
Node: register-match74191
Ref: #register-match74325
Node: rewrite74508
Ref: #rewrite74625
Node: stats74694
Ref: #stats74797
Node: tags75667
Ref: #tags75765
Node: test76001
Ref: #test76085
Node: ADD-ON COMMANDS76453
Ref: #add-on-commands76563
Node: Official add-ons77850
Ref: #official-add-ons77990
Node: api78077
Ref: #api78166
Node: ui78218
Ref: #ui78317
Node: web78375
Ref: #web78464
Node: Third party add-ons78510
Ref: #third-party-add-ons78685
Node: diff78820
Ref: #diff78917
Node: iadd79016
Ref: #iadd79130
Node: interest79213
Ref: #interest79334
Node: irr79429
Ref: #irr79527
Node: Experimental add-ons79605
Ref: #experimental-add-ons79757
Node: autosync80037
Ref: #autosync80148
Node: chart80387
Ref: #chart80506
Node: check80577
Ref: #check80679

End Tag Table

File diff suppressed because it is too large Load Diff

View File

@ -128,17 +128,27 @@ and can have less-significant date parts omitted (defaulting to 1).
Examples:
------------------------------------------------- -----------------------------------------------------------------------------
`2009/1/1`, `2009/01/01`, `2009-1-1`, `2009.1.1` simple dates, several separators allowed
`2009/1`, `2009` same as above - a missing day or month defaults to 1
`1/1`, `january`, `jan`, `this year` relative dates, meaning january 1 of the current year
`next year` january 1 of next year
`this month` the 1st of the current month
`this week` the most recent monday
`last week` the monday of the week before this one
`lastweek` spaces are optional
`today`, `yesterday`, `tomorrow`
---
--------------------------------------------- -----------------------------------------------------------------------------
`2004/10/1`, `2004-01-01`, `2004.9.1` exact date, several separators allowed. Year is 4+ digits, month is 1-12, day is 1-31
`2004` start of year
`2004/10` start of month
`10/1` month and day in current year
`21` day in current month
`october, oct` start of month in current year
`yesterday, today, tomorrow` -1, 0, 1 days from today
`last/this/next day/week/month/quarter/year` -1, 0, 1 periods from the current period
`20181201` 8 digit YYYYMMDD with valid year month and day
`201812` 6 digit YYYYMM with valid year and month
--------------------------------------------- -----------------------------------------------------------------------------
Counterexamples - malformed digit sequences might give surprising results:
--------------------------------------------- -----------------------------------------------------------------------------
`201813` 6 digits with an invalid month is parsed as start of 6-digit year
`20181301` 8 digits with an invalid month is parsed as start of 8-digit year
`20181232` 8 digits with an invalid day gives an error
`201801012` 9+ digits beginning with a valid YYYYMMDD gives an error
--------------------------------------------- -----------------------------------------------------------------------------
## Report start & end date