diff --git a/hledger-lib/Hledger/Reports/ReportOptions.hs b/hledger-lib/Hledger/Reports/ReportOptions.hs index 01378170d..57e0b6226 100644 --- a/hledger-lib/Hledger/Reports/ReportOptions.hs +++ b/hledger-lib/Hledger/Reports/ReportOptions.hs @@ -71,7 +71,7 @@ import Data.Either (fromRight) import Data.Either.Extra (eitherToMaybe) import Data.Functor.Identity (Identity(..)) import Data.List.Extra (find, isPrefixOf, nubSort) -import Data.Maybe (fromMaybe, isJust) +import Data.Maybe (fromMaybe, isJust, isNothing) import qualified Data.Text as T import Data.Time.Calendar (Day, addDays) import Data.Default (Default(..)) @@ -687,8 +687,9 @@ reportSpanHelper bothdates j ReportSpec{_rsQuery=query, _rsReportOpts=ropts} = -- and all txns are in the future. intervalspans = dbg3 "intervalspans" $ splitSpan adjust (interval_ ropts) requestedspan' where - -- When calculating report periods, we will always adjust the start date back to the nearest interval boundary. - adjust = True -- isNothing $ spanStart requestedspan + -- When calculating report periods, we will adjust the start date back to the nearest interval boundary + -- unless a start date was specified explicitly. + adjust = isNothing $ spanStart requestedspan -- The requested span enlarged to enclose a whole number of intervals. -- This can be the null span if there were no intervals. reportspan = dbg3 "reportspan" $ DateSpan (spanStart =<< headMay intervalspans) diff --git a/hledger/hledger.m4.md b/hledger/hledger.m4.md index 81ef77b52..b8f0e47d5 100644 --- a/hledger/hledger.m4.md +++ b/hledger/hledger.m4.md @@ -4383,8 +4383,8 @@ Some notes: start/end dates from options and that from `date:` queries. That is, `date:2019-01 date:2019 -p'2000 to 2030'` yields January 2019, the smallest common time span. -- With a [report interval](#report-intervals) (see below), the report start date - will be adjusted back to the nearest subperiod boundary, if needed. +- In some cases a [report interval](#report-intervals) will adjust start/end dates + to fall on interval boundaries (see below). Examples: @@ -4440,11 +4440,8 @@ transaction rules; those are not affected by `--today`.) A report interval can be specified so that commands like [register](#register), [balance](#balance) and [activity](#activity) -become multi-period, showing each subperiod as a separate row or -column. - -The following "standard" report intervals can be enabled by using -their corresponding flag: +become multi-period, showing each subperiod as a separate row or column. +These "standard" report intervals can be enabled by using the corresponding flag: - `-D/--daily` - `-W/--weekly` @@ -4452,24 +4449,25 @@ their corresponding flag: - `-Q/--quarterly` - `-Y/--yearly` -Intervals specified by these flags will always start on their natural -boundaries: eg `--weekly` starts on mondays, `--monthly` starts on -first days of months, `--yearly` starts on January 1st, etc. +More complex intervals can be specified using `-p/--period` (see below). -Intervals starting on other dates, and more complex intervals, can be -specified with the `-p/--period` option. These are described in -[period expressions](#period-expressions), below. +Specifying a report interval other than daily can cause a report's +start date and end date to be adjusted in some cases: -When you use a report interval (other than `--daily`), the overall -report period will be expanded to fill a whole number of subperiods, -(possibly overriding your requested report start or end dates). -This ensures first and last subperiods are comparable to the others. +- If the report start date is specified explicitly, periods will start exactly on that date. + Eg with `-M -b 2023/1/15', + periods will begin on the 15th day of each month, starting from 2023-01-15. + (Since hledger 1.29). -To summarise: +- If the report start date is inferred, eg from the journal, + it will be adjusted earlier if necessary to start on a natural interval boundary. + Eg with `-M` by itself, and if the journal's earliest transaction is on 2023-02-04, + periods will begin on the 1st of each month, starting from 2023-02-01. -- Reports with the standard `--weekly`/`--monthly`/`--quarterly`/`--yearly` intervals will start on the first day of a week/month/quarter/year. -- `--period` (below) can specify more complex intervals, starting on any date. -- In multiperiod reports, all subperiods will be the same length. +- The report end date will be adjusted later if necessary + so that the last period is a whole interval, the same length as the others. + Eg in the example above if the journal's latest transaction is on 2023-03-15, + the report end date will be adjusted to 2023-04-01. ## Period expressions @@ -4534,8 +4532,6 @@ Or you can specify a single quarter like so: `-p/--period`'s argument can also begin with, or entirely consist of, a [report interval](#report-intervals). This should be separated from the start/end dates (if any) by a space, or the word `in`. -The basic intervals (which can also be written as command line flags) -are `daily`, `weekly`, `monthly`, `quarterly`, and `yearly`. Some examples: | | @@ -4544,24 +4540,12 @@ Some examples: | `-p "monthly in 2008"` | | `-p "quarterly"` | -When specifying report periods at the command line, -the simple `weekly`, `monthly`, `quarterly` and `yearly` intervals -will force the report to start on the first day of a week, month, quarter or year -(moving the start date backward if needed). -For example: - -| | | -|------------------------------------------------|------------------------------------------------------------------------------------| -| `-p "weekly from 2009/1/1 to 2009/4/1"` | starts on 2008/12/29, closest preceding Monday | -| `-p "monthly in 2008/11/25"` | starts on 2018/11/01 | -| `-p "quarterly from 2009-05-05 to 2009-06-01"` | starts on 2009/04/01, ends on 2009/06/30, which are first and last days of Q2 2009 | -| `-p "yearly from 2009-12-29"` | starts on 2009/01/01, first day of 2009 | - -All periods in a multi-period report will have similar length. +Note a report interval can cause the report start/end dates to be adjusted in some cases, +as described above in [Report intervals](#report-intervals). ### More complex report intervals -These other kinds of interval are also supported in period expressions: +Period expressions allow some more complex kinds of interval to be specified, including: - `biweekly` - `fortnightly` @@ -4569,30 +4553,25 @@ These other kinds of interval are also supported in period expressions: - `every day|week|month|quarter|year` - `every N days|weeks|months|quarters|years` -These too will force report start date to be adjusted to an interval boundary, if needed. +Examples: +| | +|------------------------------------| +| `-p "bimonthly from 2008"` | +| `-p "every 2 weeks"` | +| `-p "every 5 months from 2009/03"` | -| | | -|------------------------------------|-------------------------------------------------------------| -| `-p "bimonthly from 2008"` | periods will have boundaries on 2008/01/01, 2008/03/01, ... | -| `-p "every 2 weeks"` | starts on closest preceding Monday | -| `-p "every 5 months from 2009/03"` | periods will have boundaries on 2009/03/01, 2009/08/01, ... | - -### Intervals with arbitrary start date - -You can start report periods on any date by using one of these forms: - -Each certain day of the week: +Weekly on custom day: - `every Nth day of week` (`th`, `nd`, `rd`, or `st` are all accepted after the number) - `every WEEKDAYNAME` (full or three-letter english weekday name, case insensitive) -Each certain day of the month: +Monthly on custom day: - `every Nth day [of month]` - `every Nth WEEKDAYNAME [of month]` -Each certain day of the year: +Yearly on custom day: - `every MM/DD [of year]` (month number and day of month number) - `every MONTHNAME DDth [of year]` (full or three-letter english month name, case insensitive, and day of month number) @@ -4622,10 +4601,18 @@ Group postings from the start of wednesday to end of the following tuesday (N is $ hledger register checking -p "every 3rd day of week" ``` -### Starting on multiple weekdays +### Multiple weekday intervals -- `every WEEKDAYNAME,WEEKDAYNAME,...` allows multiple days of week to be specified. - `weekday` and `weekendday` are accepted as shorthand for `mon,tue,wed,thu,fri` and `sat,sun`. +This special form is also supported: + +- `every WEEKDAYNAME,WEEKDAYNAME,...` (full or three-letter english weekday names, case insensitive) + +Also, `weekday` and `weekendday` are shorthand for `mon,tue,wed,thu,fri` and `sat,sun`. + +This is mainly intended for use with `--forecast`, to generate +[periodic transactions](#periodic-transactions) on arbitrary days of the week. +It may be less useful with `-p`, since it divides each week into subperiods of unequal length, which is unusual. +(Related: [#1632](https://github.com/simonmichael/hledger/pull/1632)) Examples: @@ -4635,13 +4622,6 @@ Examples: | `-p "every weekday"` | dates will be Mon, Tue, Wed, Thu, Fri;
periods will be Mon, Tue, Wed, Thu, Fri-Sun | | `-p "every weekendday"` | dates will be Sat, Sun;
periods will be Sat, Sun-Fri | -This form is mainly intended for use with `--forecast`, to generate -[periodic transactions](#periodic-transactions) on arbitrary days of the week. -It may be less useful with `-p`, since it divides each week into subperiods of unequal length. -Related: [#1632](https://github.com/simonmichael/hledger/pull/1632) - - - # Depth With the `--depth NUM` option (short form: `-NUM`), diff --git a/hledger/test/balance/intervals.test b/hledger/test/balance/intervals.test index fa5920792..e0b3f8b22 100644 --- a/hledger/test/balance/intervals.test +++ b/hledger/test/balance/intervals.test @@ -207,24 +207,28 @@ Balance changes in 2014-01: ---++----- || 2 -# 18. All matched postings in the displayed intervals should be reported on. +# 18. Here, the report interval is monthly (interval size is one month) +# but the explicitly-specified start date causes report periods to start there. +# And the end date is expanded to make a whole last period. < 2014/1/5 - (before) 1 + (before report period) 1ew 2014/2/1 - (within) 1 + (explicit report period) 10 2014/2/25 - (after) 1 + (expanded report period) 100 + +2014/3/10 + (after report period) 1000 $ hledger -f- balance -p 'monthly 2014/1/10-2014/2/20' -Balance changes in 2014-01-01..2014-02-28: +Balance changes in 2014-01-10..2014-03-09: - || Jan Feb -========++========== - after || 0 1 - before || 1 0 - within || 0 1 ---------++---------- - || 1 2 + || 2014-01-10..2014-02-09 2014-02-10..2014-03-09 +========================++================================================ + expanded report period || 0 100 + explicit report period || 10 0 +------------------------++------------------------------------------------ + || 10 100 diff --git a/hledger/test/cli/report-interval.test b/hledger/test/cli/report-interval.test index 93d147cb0..7f519180b 100644 --- a/hledger/test/cli/report-interval.test +++ b/hledger/test/cli/report-interval.test @@ -20,19 +20,18 @@ $ hledger -f- register --monthly --weekly 2018-12-31W01 a 2 2 2019-01-28W05 a 1 3 -# 3. The last report interval option takes precedence. -# The --period expression is no exception. +# 3. The last report interval option (--weekly) takes precedence, +# including over a -p option. +# The -p option's "in 2019" sets an explicit start date here. $ hledger -f- register -p 'monthly in 2019' --weekly -2018-12-31W01 a 2 2 -2019-01-28W05 a 1 3 +2019-01-01..2019-01-07 a 2 2 +2019-01-29..2019-02-04 a 1 3 # 4. $ hledger -f- register --weekly -p 'monthly in 2019' 2019-01 a 2 2 2019-02 a 1 3 - - # The next three tests test the bugfix for issue #1008: # The report interval from an --period expression only counts if it is # explicitly specified (e.g. -p 'monthly in ...'). diff --git a/hledger/test/register/intervals.test b/hledger/test/register/intervals.test index 2068eb196..c97cbf48a 100644 --- a/hledger/test/register/intervals.test +++ b/hledger/test/register/intervals.test @@ -53,26 +53,59 @@ $ hledger -f- register --monthly --date2 2014-01 a 1 1 b 1 2 -# 6. All matched postings in the displayed intervals should be reported on. +# < 2014/1/5 - (before) 1 + (before report period) 1 2014/2/1 - (within) 1 + (explicit report period) 10 2014/2/25 - (after) 1 + (expanded report period) 100 +2014/3/12 + (after report period) 1000 + +# 6. Here, the report interval is monthly (interval size is one month) +# but the explicitly-specified start date causes report periods to start there. +# And the end date is expanded to make a whole month-long last period. $ hledger -f- register -p 'monthly 2014/1/10-2014/2/20' -2014-01 before 1 1 -2014-02 after 1 2 - within 1 3 +2014-01-10..2014-02-09 explicit report period 10 10 +2014-02-10..2014-03-09 expanded report period 100 110 +# 7. Here no definite start date has been specifed so it is inferred from the journal +# (2014/1/5), but it is specified to be a tuesday, so that is adjusted to +# the nearest previous tuesday (2013/12/31). +# No end date has been specified so it is inferred from the journal (2014/3/11), +# but that is adjusted to make a whole week-long last period (2014/3/18). +# -E is required here to see the empty weeks. +$ hledger -f- register -p 'every tue' -E +2013-12-31..2014-01-06 before report period 1 1 +2014-01-07..2014-01-13 0 1 +2014-01-14..2014-01-20 0 1 +2014-01-21..2014-01-27 0 1 +2014-01-28..2014-02-03 explicit report period 10 11 +2014-02-04..2014-02-10 0 11 +2014-02-11..2014-02-17 0 11 +2014-02-18..2014-02-24 0 11 +2014-02-25..2014-03-03 expanded report period 100 111 +2014-03-04..2014-03-10 0 111 +2014-03-11..2014-03-17 after report period 1000 1111 -# 7. Custom ranges should display fully. -$ hledger -f- register -p 'every tue' -2013-12-31..2014-01-06 before 1 1 -2014-01-28..2014-02-03 within 1 2 -2014-02-25..2014-03-03 after 1 3 +# 8. "in 2014-02" is considered to explicitly specify a start date of 2014/2/1 +# (a saturday), forcing the periods to start there. +$ hledger -f- register -p 'weekly in 2014-02' -E +2014-02-01..2014-02-07 explicit report period 10 10 +2014-02-08..2014-02-14 0 10 +2014-02-15..2014-02-21 0 10 +2014-02-22..2014-02-28 expanded report period 100 110 +# 9. So to see simple monday-based week periods here, you must specify a start date +# that is a monday. +$ hledger -f- register -p 'weekly from 2014-01-27 to 2014-03' -E +2014-01-27W05 explicit report period 10 10 +2014-02-03W06 0 10 +2014-02-10W07 0 10 +2014-02-17W08 0 10 +2014-02-24W09 expanded report period 100 110