imp: cli: report intervals can now start on arbitrary dates

Eg, where previously -p 'monthly from 1/15' or -M -b 1/15 would always
adjust the report start date to 1/1,
unless you used the special -p 'every 15th day of month from 1/15' form,
now the start date will not be adjusted. (It is still adjusted if
the report date is not specified explicitly, eg inferred from the journal).

This keeps behaviour consistent between report periods and periodic transactions.

'in' period expressions, like 'in 2023-01', are a grey area; they
do specify a start date (2023-01-01), although they look a bit implicit.
So previously, -p 'weekly in 2023-01' would adjust the start date to
the preceding monday (2022-12-26), but now it will start exactly on
2023-01-01 (a sunday, which also causes ugly verbose column headings).

To ensure monday based weeks and simple report headings here,
you would have to explicitly specific a start date that is a monday,
eg -p 'weekly from 2022-12-26 to 2023-02'.
This commit is contained in:
Simon Michael 2023-01-14 13:24:43 -10:00
parent 4260a350c8
commit 032ffd112b
5 changed files with 112 additions and 95 deletions

View File

@ -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)

View File

@ -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; <br>periods will be Mon, Tue, Wed, Thu, Fri-Sun |
| `-p "every weekendday"` | dates will be Sat, Sun; <br>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`),

View File

@ -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

View File

@ -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 ...').

View File

@ -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