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