Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #2218 and three more report interval start dates #2221

Merged
merged 5 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 7 additions & 11 deletions doc/relnotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -1653,10 +1653,9 @@ Features

- Periodic transactions and multi-period reports can now start on any date.
To enable this while still maintaining pretty good backward compatibility,
hledger now treats inferred dates, and dates where the day is unspecified,
as "flexible" (which can be automatically adjusted to interval boundaries),
and dates specified to the day as "exact" (which can not).
Eg:
hledger now keeps explicitly specified start dates as they are,
but still automatically adjusts inferred start dates to interval boundaries.
This means, eg:

- A periodic rule like `~ monthly from 2023-01-15` now works as
you'd expect instead of raising an error. This also improves
Expand All @@ -1665,13 +1664,10 @@ Features
- Period options like `-p 'monthly from 2023/1/15'` or `-M -b 2023/1/15`
now start the report on exactly 1/15 instead of being adjusted to 1/1.

Note: periods using `in` may look partial but are considered to specify exact dates.
So weekly reports such as `-p 'weekly in 2023-01'`, which previously
were adjusted to start on a monday, will now start exactly on 2023-01-01.
This can also cause more verbose column headings.
To guarantee simple week headings, you must now start such reports
exactly on a monday, eg `-p 'weekly from 2022-12-26 to 2023-02'`.
([#1982])
- `-p 'weekly in 2023-01'`, which previously was adjusted to start on a monday,
now starts exactly on 2023-01-01. This can cause more verbose report headings.
To ensure simple week headings, now weekly reports must start on a monday,
eg `-p 'weekly from 2022-12-26 to 2023-02'`. ([#1982])

- You can now freely combine @/@@ notation and conversion postings
in a single transaction. This can help readability, and also allows
Expand Down
284 changes: 153 additions & 131 deletions hledger-lib/Hledger/Data/Dates.hs

Large diffs are not rendered by default.

16 changes: 0 additions & 16 deletions hledger-lib/Hledger/Data/PeriodicTransaction.hs
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,6 @@ instance Show PeriodicTransaction where
-- <BLANKLINE>
--
-- >>> _ptgen "every 2nd day of month from 2017/02 to 2017/04"
-- 2017-01-02
-- ; generated-transaction: ~ every 2nd day of month from 2017/02 to 2017/04
-- a $1.00
-- <BLANKLINE>
-- 2017-02-02
-- ; generated-transaction: ~ every 2nd day of month from 2017/02 to 2017/04
-- a $1.00
Expand All @@ -128,10 +124,6 @@ instance Show PeriodicTransaction where
-- <BLANKLINE>
--
-- >>> _ptgen "every 30th day of month from 2017/1 to 2017/5"
-- 2016-12-30
-- ; generated-transaction: ~ every 30th day of month from 2017/1 to 2017/5
-- a $1.00
-- <BLANKLINE>
-- 2017-01-30
-- ; generated-transaction: ~ every 30th day of month from 2017/1 to 2017/5
-- a $1.00
Expand All @@ -150,10 +142,6 @@ instance Show PeriodicTransaction where
-- <BLANKLINE>
--
-- >>> _ptgen "every 2nd Thursday of month from 2017/1 to 2017/4"
-- 2016-12-08
-- ; generated-transaction: ~ every 2nd Thursday of month from 2017/1 to 2017/4
-- a $1.00
-- <BLANKLINE>
-- 2017-01-12
-- ; generated-transaction: ~ every 2nd Thursday of month from 2017/1 to 2017/4
-- a $1.00
Expand All @@ -168,10 +156,6 @@ instance Show PeriodicTransaction where
-- <BLANKLINE>
--
-- >>> _ptgen "every nov 29th from 2017 to 2019"
-- 2016-11-29
-- ; generated-transaction: ~ every nov 29th from 2017 to 2019
-- a $1.00
-- <BLANKLINE>
-- 2017-11-29
-- ; generated-transaction: ~ every nov 29th from 2017 to 2019
-- a $1.00
Expand Down
25 changes: 7 additions & 18 deletions hledger-lib/Hledger/Data/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ data DateSpan = DateSpan (Maybe EFDay) (Maybe EFDay) deriving (Eq,Ord,Generic)

instance Default DateSpan where def = DateSpan Nothing Nothing

-- Typical report periods (spans of time), both finite and open-ended.
-- Some common report subperiods, both finite and open-ended.
-- A higher-level abstraction than DateSpan.
data Period =
DayPeriod Day
Expand All @@ -132,30 +132,19 @@ data Period =

instance Default Period where def = PeriodAll

---- Typical report period/subperiod durations, from a day to a year.
--data Duration =
-- DayLong
-- WeekLong
-- MonthLong
-- QuarterLong
-- YearLong
-- deriving (Eq,Ord,Show,Generic)

-- Ways in which a period can be divided into subperiods.
-- All the kinds of report interval allowed in a period expression
-- (to generate periodic reports or periodic transactions).
data Interval =
NoInterval
| Days Int
| Weeks Int
| Months Int
| Quarters Int
| Years Int
| DayOfMonth Int
| WeekdayOfMonth Int Int
| DaysOfWeek [Int]
| DayOfYear Int Int -- Month, Day
-- WeekOfYear Int
-- MonthOfYear Int
-- QuarterOfYear Int
| NthWeekdayOfMonth Int Int -- n, weekday 1-7
| MonthDay Int -- 1-31
| MonthAndDay Int Int -- month 1-12, monthday 1-31
| DaysOfWeek [Int] -- [weekday 1-7]
deriving (Eq,Show,Ord,Generic)

instance Default Interval where def = NoInterval
Expand Down
56 changes: 41 additions & 15 deletions hledger/hledger.m4.md
Original file line number Diff line number Diff line change
Expand Up @@ -4692,22 +4692,48 @@ More complex intervals can be specified using `-p/--period`, described below.

## Date adjustments

A report interval other than daily may cause the report's start and end date
to be adjusted, as follows:
### Start date adjustment

A "soft" start date -
ie one which was not specified explicitly, but inferred, perhaps from the journal -
will be adjusted earlier if needed to start on a natural subperiod boundary.
If you let hledger infer a report's start date, it will adjust the date to the previous natural boundary of the report interval,
for convenient periodic reports. (If you don't want that, specify a start date.)

A "hard" start date - one specified explicitly, eg by `-b` - will not be adjusted (since hledger 1.29).
This makes it possible to start the subperiods on any date.
If you specify a start date, it's ideal to set it to a subperiod boundary
(eg a monday for weekly reports, a first day of month for monthly reports..),
as this will generate simple subperiod headings; otherwise they will be more verbose.
For example, if the journal's first transaction is on january 10th,

The end date - even if specified explicitly, eg by `-e` -
will be adjusted later as needed to enclose a whole number of report intervals.
Eg in a `--yearly` report, all subperiods will be one year long.
- `hledger register` (no report interval) will start the report on january 10th.
- `hledger register --monthly` will start the report on the previous month boundary, january 1st.
- `hledger register --monthly --begin 1/5` will start the report on january 5th [1].

Also if you are generating transactions or budget goals with [periodic transaction rules](#periodic-transactions),
their start date may be adjusted in a similar way (in certain situations). <!-- TBD -->

### End date adjustment

A report's end date is always adjusted to include a whole number of intervals,
so that the last subperiod has the same length as the others.

For example, if the journal's last transaction is on february 20th,

- `hledger register` will end the report on february 20th.
- `hledger register --monthly` will end the report at the end of february.
- `hledger register --monthly --end 2/14` also will end the report at the end of february.
- `hledger register --monthly --begin 1/5 --end 2/14` will end the report on march 4th [1].

[1] Since hledger 1.29.

## Period headings

With non-standard subperiods, hledger will show "STARTDATE..ENDDATE" headings.
With standard subperiods (ie, starting on a natural interval boundary), you'll see more compact headings, which are usually preferable.
(Though month names will be in english, currently.)

So if you are specifying a start date and you want compact headings:
choose a start of year for yearly reports,
a start of quarter for quarterly reports,
a start of month for monthly reports, etc.
(Remember, you can write eg `-b 2024` or `1/1` as a shortcut for a start of year,
or `2024-04` or `202404` or `Apr` for a start of month or quarter.)
For weekly reports, choose a date that's a Monday.
(You can try different dates until you see the short headings, or write eg `-b '3 weeks ago'`.)

## Period expressions

Expand Down Expand Up @@ -4796,7 +4822,7 @@ Monthly on a custom day:
- `every Nth day [of month]` (`31st day` will be adjusted to each month's last day)
- `every Nth WEEKDAYNAME [of month]`

Yearly on a custom day:
Yearly on a custom month and 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)
Expand Down Expand Up @@ -5184,7 +5210,7 @@ $ hledger print --forecast --today=2023/4/21
expenses:rent $1000
```

Here there are no ordinary transactions, so the forecasted transactions begin on the first occurence after today's date.
Here there are no ordinary transactions, so the forecasted transactions begin on the first occurrence after today's date.
(You won't normally use `--today`; it's just to make these examples reproducible.)

## Forecast reports
Expand Down
8 changes: 8 additions & 0 deletions hledger/test/cli/date-options.test
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,11 @@ $ hledger -f- reg date:2019-01-01-2019-02-01
# ** 0. Dashed range syntax, partial dates
$ hledger -f- reg date:2019-01-2019-02
2019-01-01 (a) 2 2

# ** 0. A "every Nth day (of month)" periodic rule will generate occurrences only after the start date. (#2218)
<
~ every 31st day from 2024-07 to 2024-09
(a) 1
$ hledger -f- reg --forecast=2024
2024-07-31 (a) 1 1
2024-08-31 (a) 1 2
111 changes: 111 additions & 0 deletions hledger/test/register/intervals.test
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,114 @@ $ hledger -f- register --monthly
$ hledger -f- register -p monthly
2019-01 a 2 2
2019-02 a 1 3

# ** Date adjustment/clipping, with various intervals, of periodic reports and periodic transactions.
# With periodic reports generally:
# Start dates should be within the specified report period.
# If start date is unspecifed, it should be the inferred start date adjusted to a natural boundary.
# The end date should be adjusted so that the last period has equal length.
# With periodic transactions generally:
# All occurrences should be within the specified report period.
# If start date is unspecifed, it should be the inferred start date adjusted to a natural boundary.
# The end date should be adjusted so that the gap before last occurrence has equal length. (?)

# ** 13. every Nth day of month from DATE.
<
2024-01-02
(monthly1/02) 1

2024-01-10
(monthly1/10) 1

2024-02-20
(monthly2/20) 1

2024-02-24
(monthly2/24) 1

$ hledger -f- reg monthly -p 'every 5th day of month from 2024/1/5 to 2024/2/14'
2024-01-05..2024-02-04 monthly1/10 1 1
2024-02-05..2024-03-04 monthly2/20 1 2
monthly2/24 1 3

# ** 14. every Nth day of month from DATE, periodic transactions. #2218, fixed in 1.40.
<
~ every 31st day from 2024-07 to 2024-09
(a) 1

$ hledger -f- reg --forecast=2024
2024-07-31 (a) 1 1
2024-08-31 (a) 1 2

# ** 15. every M/D from DATE. Fixed in 1.40.
<
2023-01-10
(yearly2023/1/10) 1

2024-01-10
(yearly2024/1/10) 1

2025-01-10
(yearly2025/1/10) 1

2026-01-10
(yearly2026/1/10) 1

$ hledger -f- reg yearly -p 'every 1/20 from 2024 to 2026'
2024-01-20..2025-01-19 yearly2025/1/10 1 1
2025-01-20..2026-01-19 yearly2026/1/10 1 2

# ** 16. every M/D from DATE, periodic transactions. Fixed in 1.40.
<
~ every 14th February from 2024 to 2026
(yearly) 1

$ hledger -f- reg yearly --forecast=2022-2027
2024-02-14 (yearly) 1 1
2025-02-14 (yearly) 1 2


# ** 17. every Nth WEEKDAY, inferred start date.
# The start date is adjusted to 2023/12/11, encompassing the 2024/1/1 posting.
<
2024-01-01
(mondays2024/01/01) 1

2024-01-08
(mondays2024/01/08) 1

2024-01-15
(mondays2024/01/15) 1

2024-02-05
(mondays2024/02/05) 1

2024-02-12
(mondays2024/02/12) 1

2024-02-19
(mondays2024/02/19) 1

$ hledger -f- reg mondays -p 'every 2nd monday'
2023-12-11..2024-01-07 mondays2024/01/01 1 1
2024-01-08..2024-02-11 mondays2024/01/08 1 2
mondays2024/01/15 1 3
mondays2024/02/05 1 4
2024-02-12..2024-03-10 mondays2024/02/12 1 5
mondays2024/02/19 1 6

# ** 18. every Nth WEEKDAY from DATE. Fixed in 1.40.
$ hledger -f- reg mondays -p 'every 2nd monday from 2024/1/5 to 2024/2'
2024-01-08..2024-02-11 mondays2024/01/08 1 1
mondays2024/01/15 1 2
mondays2024/02/05 1 3

# ** 19. every Nth WEEKDAY from DATE, periodic transactions.
<
~ every 2nd monday from 2024/1/5 to 2024/3
(mondays) 1

$ hledger -f- reg mondays --forecast=2024
2024-01-08 (mondays) 1 1
2024-02-12 (mondays) 1 2