summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan2020 <Ian2020@users.noreply.github.com>2023-11-29 13:12:24 +0000
committerJohn Wiegley <johnw@newartisans.com>2024-08-06 11:08:15 -1000
commit762353945a744ae4b89970b9e08c2c22a52ddbff (patch)
tree1e3cc5fcbe4f89c5134f0fcb7a5f7ba3a8fb372d
parentb7be0a1fedfeec26e4b7d35357157d5a9209f3ee (diff)
downloadfork-ledger-762353945a744ae4b89970b9e08c2c22a52ddbff.tar.gz
fork-ledger-762353945a744ae4b89970b9e08c2c22a52ddbff.tar.bz2
fork-ledger-762353945a744ae4b89970b9e08c2c22a52ddbff.zip
Add new --align-intervals option.
-rw-r--r--contrib/ledger-completion.bash2
-rw-r--r--doc/ledger3.texi16
-rw-r--r--src/chain.cc3
-rw-r--r--src/filters.cc6
-rw-r--r--src/filters.h7
-rw-r--r--src/report.cc1
-rw-r--r--src/report.h3
-rw-r--r--src/times.cc22
-rw-r--r--src/times.h13
-rw-r--r--test/baseline/opt-align-intervals.test293
10 files changed, 347 insertions, 19 deletions
diff --git a/contrib/ledger-completion.bash b/contrib/ledger-completion.bash
index 0ef969ae..87b96f89 100644
--- a/contrib/ledger-completion.bash
+++ b/contrib/ledger-completion.bash
@@ -43,7 +43,7 @@ _ledger()
# report.cc::lookup_option
# session.cc::lookup_option
#
- options="--abbrev-len= --account-width= --account= --actual --actual-dates --add-budget --amount-data --amount-width= --amount= --anon --ansi --args-only --auto-match --aux-date --average --balance-format= --base --basis --begin= --bold-if= --budget --budget-format= --by-payee --cache= --change --check-payees --cleared --cleared-format= --collapse --collapse-if-zero --color --columns= --cost --count --csv-format= --current --daily --date-format= --date-width= --date= --datetime-format= --day-break --days-of-week --dc --debug= --decimal-comma --depth= --detail --deviation --display-amount= --display-total= --display= --dow --download --effective --empty --end= --equity --exact --exchange= --explicit --file= --first= --flat --force-color --force-pager --forecast-while= --forecast-years= --forecast= --format= --full-help --gain --generated --group-by= --group-title-format= --head= --help --help-calc --help-comm --help-disp --historical --immediate --init-file= --inject= --input-date-format= --invert --last= --leeway= --limit= --lot-dates --lot-notes --lot-prices --lot-tags --lots --lots-actual --market --master-account= --meta-width= --meta= --monthly --no-aliases --no-color --no-pager --no-rounding --no-titles --no-total --now= --only= --options --output= --pager= --payee-width= --payee= --pedantic --pending --percent --period-sort= --period= --permissive --pivot= --plot-amount-format= --plot-total-format= --prepend-format= --prepend-width= --price --price-db= --price-exp= --pricedb-format= --prices-format= --primary-date --quantity --quarterly --raw --real --recursive-aliases --register-format= --related --related-all --revalued --revalued-only --revalued-total= --rich-data --script= --seed= --sort-all= --sort-xacts= --sort= --start-of-week= --strict --subtotal --tail= --time-colon --time-report --total-data --total-width= --total= --trace= --truncate= --unbudgeted --uncleared --unrealized --unrealized-gains= --unrealized-losses= --unround --value --value-expr= --values --verbose --verify --verify-memory --version --weekly --wide --yearly"
+ options="--abbrev-len= --account-width= --account= --actual --actual-dates --add-budget --align-intervals --amount-data --amount-width= --amount= --anon --ansi --args-only --auto-match --aux-date --average --balance-format= --base --basis --begin= --bold-if= --budget --budget-format= --by-payee --cache= --change --check-payees --cleared --cleared-format= --collapse --collapse-if-zero --color --columns= --cost --count --csv-format= --current --daily --date-format= --date-width= --date= --datetime-format= --day-break --days-of-week --dc --debug= --decimal-comma --depth= --detail --deviation --display-amount= --display-total= --display= --dow --download --effective --empty --end= --equity --exact --exchange= --explicit --file= --first= --flat --force-color --force-pager --forecast-while= --forecast-years= --forecast= --format= --full-help --gain --generated --group-by= --group-title-format= --head= --help --help-calc --help-comm --help-disp --historical --immediate --init-file= --inject= --input-date-format= --invert --last= --leeway= --limit= --lot-dates --lot-notes --lot-prices --lot-tags --lots --lots-actual --market --master-account= --meta-width= --meta= --monthly --no-aliases --no-color --no-pager --no-rounding --no-titles --no-total --now= --only= --options --output= --pager= --payee-width= --payee= --pedantic --pending --percent --period-sort= --period= --permissive --pivot= --plot-amount-format= --plot-total-format= --prepend-format= --prepend-width= --price --price-db= --price-exp= --pricedb-format= --prices-format= --primary-date --quantity --quarterly --raw --real --recursive-aliases --register-format= --related --related-all --revalued --revalued-only --revalued-total= --rich-data --script= --seed= --sort-all= --sort-xacts= --sort= --start-of-week= --strict --subtotal --tail= --time-colon --time-report --total-data --total-width= --total= --trace= --truncate= --unbudgeted --uncleared --unrealized --unrealized-gains= --unrealized-losses= --unround --value --value-expr= --values --verbose --verify --verify-memory --version --weekly --wide --yearly"
# Bash FAQ E13 http://tiswww.case.edu/php/chet/bash/FAQ
#
diff --git a/doc/ledger3.texi b/doc/ledger3.texi
index f6cc6230..8c3ab3e8 100644
--- a/doc/ledger3.texi
+++ b/doc/ledger3.texi
@@ -6343,6 +6343,13 @@ transactions.
@item --add-budget
Show only unbudgeted postings.
+@item --align-intervals
+@findex --start-of-week @var{INT}
+Use the begin time of a period expression as the start of its intervals, if
+specified (@pxref{Period Expressions}). For example with a period expression of
+"weekly from 2009/01/10" then the begin time of "2009/01/10 will be used as the
+start of the weekly intervals. Overrides @samp{--start-of-week @var{INT}}.
+
@item --amount @var{EXPR}
@itemx -t @var{EXPR}
Apply the given value expression to the posting amount (@pxref{Value
@@ -7052,9 +7059,10 @@ to sort.
Sort the postings within transactions using the given value expression.
@item --start-of-week @var{INT}
+@findex --align-intervals
Tell ledger to use a particular day of the week to start its ``weekly''
summary. @samp{--start-of-week=1} specifies Monday as the start of the
-week.
+week. Can be overriden by @samp{--align-intervals}.
@item --subtotal
@itemx -s
@@ -7953,6 +7961,11 @@ October. The possible forms are:
in <SPEC>
@end smallexample
+@findex --align-intervals
+Intervals begin at the start of the week, first day of the month,
+quarter or year. This can be overridden by specifying @option{--align-intervals}
+which will instead use the begin time if specified.
+
Here are a few examples of period expressions:
@smallexample
@@ -7963,6 +7976,7 @@ weekly from last month
from sep to oct
from 10/1 to 10/5
monthly until 2005
+monthly from 2005/04/06
from apr
until nov
last oct
diff --git a/src/chain.cc b/src/chain.cc
index 8c4f8599..a103f7f8 100644
--- a/src/chain.cc
+++ b/src/chain.cc
@@ -229,7 +229,8 @@ post_handler_ptr chain_post_handlers(post_handler_ptr base_handler,
handler.reset(new interval_posts(handler, expr,
report.HANDLER(period_).str(),
report.HANDLED(exact),
- report.HANDLED(empty)));
+ report.HANDLED(empty),
+ report.HANDLED(align_intervals)));
if (report.HANDLED(date_))
handler.reset(new transfer_details(handler, transfer_details::SET_DATE,
diff --git a/src/filters.cc b/src/filters.cc
index 3acb5624..b5b7fb19 100644
--- a/src/filters.cc
+++ b/src/filters.cc
@@ -974,7 +974,7 @@ void interval_posts::operator()(post_t& post)
if (interval.duration) {
all_posts.push_back(&post);
}
- else if (interval.find_period(post.date())) {
+ else if (interval.find_period(post.date(), align_intervals)) {
item_handler<post_t>::operator()(post);
}
}
@@ -991,10 +991,10 @@ void interval_posts::flush()
sort_posts_by_date());
// only if the interval has no start use the earliest post
- if (!(interval.begin() && interval.find_period(*interval.begin())))
+ if (!(interval.begin() && interval.find_period(*interval.begin(), align_intervals)))
// Determine the beginning interval by using the earliest post
if (all_posts.size() > 0 && all_posts.front()
- && !interval.find_period(all_posts.front()->date()))
+ && !interval.find_period(all_posts.front()->date(), align_intervals))
throw_(std::logic_error, _("Failed to find period for interval report"));
// Walk the interval forward reporting all posts within each one
diff --git a/src/filters.h b/src/filters.h
index 18bf912d..a4cec5b6 100644
--- a/src/filters.h
+++ b/src/filters.h
@@ -731,6 +731,7 @@ class interval_posts : public subtotal_posts
account_t * empty_account;
bool exact_periods;
bool generate_empty_posts;
+ bool align_intervals;
std::deque<post_t *> all_posts;
@@ -742,10 +743,12 @@ public:
expr_t& amount_expr,
const date_interval_t& _interval,
bool _exact_periods = false,
- bool _generate_empty_posts = false)
+ bool _generate_empty_posts = false,
+ bool _align_intervals = false)
: subtotal_posts(_handler, amount_expr), start_interval(_interval),
interval(start_interval), exact_periods(_exact_periods),
- generate_empty_posts(_generate_empty_posts) {
+ generate_empty_posts(_generate_empty_posts),
+ align_intervals(_align_intervals) {
create_accounts();
TRACE_CTOR(interval_posts,
"post_handler_ptr, expr_t&, date_interval_t, bool, bool");
diff --git a/src/report.cc b/src/report.cc
index 6c957767..d632a0d2 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -1150,6 +1150,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
else OPT(amount_);
else OPT(amount_data);
else OPT_ALT(primary_date, actual_dates);
+ else OPT(align_intervals);
else OPT(anon);
else OPT_ALT(color, ansi);
else OPT(auto_match);
diff --git a/src/report.h b/src/report.h
index daa9c7c0..318a4ad6 100644
--- a/src/report.h
+++ b/src/report.h
@@ -246,6 +246,7 @@ public:
HANDLER(account_).report(out);
HANDLER(actual).report(out);
HANDLER(add_budget).report(out);
+ HANDLER(align_intervals).report(out);
HANDLER(amount_).report(out);
HANDLER(amount_data).report(out);
HANDLER(anon).report(out);
@@ -396,6 +397,8 @@ public:
parent->budget_flags |= BUDGET_BUDGETED | BUDGET_UNBUDGETED;
});
+ OPTION(report_t, align_intervals);
+
OPTION__
(report_t, amount_, // -t
DECL1(report_t, amount_, merged_expr_t, expr, ("amount_expr", "amount")) {}
diff --git a/src/times.cc b/src/times.cc
index 2c45cfcf..b66a6e30 100644
--- a/src/times.cc
+++ b/src/times.cc
@@ -1112,6 +1112,7 @@ date_interval_t date_parser_t::parse()
range.end_inclusive = end_inclusive;
period.range = date_specifier_or_range_t(range);
+ period.since_specified = static_cast<bool>(since_specifier);
}
else if (inclusion_specifier) {
period.range = date_specifier_or_range_t(*inclusion_specifier);
@@ -1180,7 +1181,7 @@ date_t date_duration_t::find_nearest(const date_t& date, skip_quantum_t skip)
return result;
}
-void date_interval_t::stabilize(const optional<date_t>& date)
+void date_interval_t::stabilize(const optional<date_t>& date, bool align_intervals)
{
#if DEBUG_ON
if (date)
@@ -1220,7 +1221,11 @@ void date_interval_t::stabilize(const optional<date_t>& date)
// These start on most recent period start quantum before when
DEBUG("times.interval",
"stabilize: monthly, quarterly or yearly duration");
- start = date_duration_t::find_nearest(when, duration->quantum);
+ if (align_intervals && since_specified) {
+ start = when;
+ } else {
+ start = date_duration_t::find_nearest(when, duration->quantum);
+ }
break;
case date_duration_t::WEEKS:
// Weeks start on the beginning of week prior to 400 remainder period length
@@ -1228,9 +1233,13 @@ void date_interval_t::stabilize(const optional<date_t>& date)
// implies period is never less than 400 days not too unreasonable
DEBUG("times.interval", "stabilize: weekly duration");
{
- int period = duration->length * 7;
- start = date_duration_t::find_nearest(
- when - gregorian::days(period + 400 % period), duration->quantum);
+ if (align_intervals && since_specified) {
+ start = when;
+ } else {
+ int period = duration->length * 7;
+ start = date_duration_t::find_nearest(
+ when - gregorian::days(period + 400 % period), duration->quantum);
+ }
}
break;
default:
@@ -1298,9 +1307,10 @@ void date_interval_t::stabilize(const optional<date_t>& date)
}
bool date_interval_t::find_period(const date_t& date,
+ const bool align_intervals,
const bool allow_shift)
{
- stabilize(date);
+ stabilize(date, align_intervals);
if (finish && date > *finish) {
DEBUG("times.interval",
diff --git a/src/times.h b/src/times.h
index b9d48521..b0aa6e9f 100644
--- a/src/times.h
+++ b/src/times.h
@@ -451,6 +451,7 @@ public:
optional<date_t> next;
optional<date_duration_t> duration;
optional<date_t> end_of_duration;
+ bool since_specified = false;
explicit date_interval_t() : aligned(false) {
TRACE_CTOR(date_interval_t, "");
@@ -466,7 +467,8 @@ public:
aligned(other.aligned),
next(other.next),
duration(other.duration),
- end_of_duration(other.end_of_duration) {
+ end_of_duration(other.end_of_duration),
+ since_specified(other.since_specified) {
TRACE_CTOR(date_interval_t, "copy");
}
~date_interval_t() throw() {
@@ -496,7 +498,7 @@ public:
void parse(const string& str);
void resolve_end();
- void stabilize(const optional<date_t>& date = none);
+ void stabilize(const optional<date_t>& date = none, bool align_intervals = false);
bool is_valid() const {
return static_cast<bool>(start);
@@ -505,10 +507,11 @@ public:
/** Find the current or next period containing date. Returns false if
no such period can be found. If allow_shift is true, the default,
then the interval may be shifted in time to find the period. */
- bool find_period(const date_t& date = CURRENT_DATE(),
- const bool allow_shift = true);
+ bool find_period(const date_t& date = CURRENT_DATE(),
+ const bool align_intervals = false,
+ const bool allow_shift = true);
bool within_period(const date_t& date = CURRENT_DATE()) {
- return find_period(date, false);
+ return find_period(date, false, false);
}
optional<date_t> inclusive_end() const {
diff --git a/test/baseline/opt-align-intervals.test b/test/baseline/opt-align-intervals.test
new file mode 100644
index 00000000..7a11c8e6
--- /dev/null
+++ b/test/baseline/opt-align-intervals.test
@@ -0,0 +1,293 @@
+2008/01/01 January
+ Expenses:Books $10.00
+ Liabilities:Cards $10.00
+ Assets:Cash
+
+2008/01/31 End of January
+ Expenses:Books $10.00
+ Liabilities:Cards $10.00
+ Assets:Cash
+
+2008/02/01 February
+ Expenses:Books $20.00
+ Liabilities:Cards $20.00
+ Assets:Cash
+
+2008/02/28 End of February
+ Expenses:Books $20.00
+ Liabilities:Cards $20.00
+ Assets:Cash
+
+2008/03/01 March
+ Expenses:Books $30.00
+ Liabilities:Cards $30.00
+ Assets:Cash
+
+2008/03/31 End of March
+ Expenses:Books $30.00
+ Liabilities:Cards $30.00
+ Assets:Cash
+
+2008/04/01 April
+ Expenses:Books $40.00
+ Liabilities:Cards $40.00
+ Assets:Cash
+
+2008/04/30 End of April
+ Expenses:Books $40.00
+ Liabilities:Cards $40.00
+ Assets:Cash
+
+2008/05/01 May
+ Expenses:Books $50.00
+ Liabilities:Cards $50.00
+ Assets:Cash
+
+2008/05/31 End of May
+ Expenses:Books $50.00
+ Liabilities:Cards $50.00
+ Assets:Cash
+
+2008/06/01 June
+ Expenses:Books $60.00
+ Liabilities:Cards $60.00
+ Assets:Cash
+
+2008/06/30 End of June
+ Expenses:Books $60.00
+ Liabilities:Cards $60.00
+ Assets:Cash
+
+2008/07/01 July
+ Expenses:Books $70.00
+ Liabilities:Cards $70.00
+ Assets:Cash
+
+2008/07/31 End of July
+ Expenses:Books $70.00
+ Liabilities:Cards $70.00
+ Assets:Cash
+
+2008/08/01 August
+ Expenses:Books $80.00
+ Liabilities:Cards $80.00
+ Assets:Cash
+
+2008/08/31 End of August
+ Expenses:Books $80.00
+ Liabilities:Cards $80.00
+ Assets:Cash
+
+2008/09/01 September
+ Expenses:Books $90.00
+ Liabilities:Cards $90.00
+ Assets:Cash
+
+2008/09/30 End of September
+ Expenses:Books $90.00
+ Liabilities:Cards $90.00
+ Assets:Cash
+
+2008/10/01 October
+ Expenses:Books $100.00
+ Liabilities:Cards $100.00
+ Assets:Cash
+
+2008/10/31 End of October
+ Expenses:Books $100.00
+ Liabilities:Cards $100.00
+ Assets:Cash
+
+2008/11/01 November
+ Expenses:Books $110.00
+ Liabilities:Cards $110.00
+ Assets:Cash
+
+2008/11/30 End of November
+ Expenses:Books $110.00
+ Liabilities:Cards $110.00
+ Assets:Cash
+
+2008/12/01 December
+ Expenses:Books $120.00
+ Liabilities:Cards $120.00
+ Assets:Cash
+
+2008/12/31 End of December
+ Expenses:Books $120.00
+ Liabilities:Cards $120.00
+ Assets:Cash
+
+2009/01/01 January
+ Expenses:Books $10.00
+ Liabilities:Cards $10.00
+ Assets:Cash
+
+2009/01/31 End of January
+ Expenses:Books $10.00
+ Liabilities:Cards $10.00
+ Assets:Cash
+
+2009/02/01 February
+ Expenses:Books $20.00
+ Liabilities:Cards $20.00
+ Assets:Cash
+
+2009/02/28 End of February
+ Expenses:Books $20.00
+ Liabilities:Cards $20.00
+ Assets:Cash
+
+2009/03/01 March
+ Expenses:Books $30.00
+ Liabilities:Cards $30.00
+ Assets:Cash
+
+2009/03/31 End of March
+ Expenses:Books $30.00
+ Liabilities:Cards $30.00
+ Assets:Cash
+
+2009/04/01 April
+ Expenses:Books $40.00
+ Liabilities:Cards $40.00
+ Assets:Cash
+
+2009/04/30 End of April
+ Expenses:Books $40.00
+ Liabilities:Cards $40.00
+ Assets:Cash
+
+2009/05/01 May
+ Expenses:Books $50.00
+ Liabilities:Cards $50.00
+ Assets:Cash
+
+2009/05/31 End of May
+ Expenses:Books $50.00
+ Liabilities:Cards $50.00
+ Assets:Cash
+
+2009/06/01 June
+ Expenses:Books $60.00
+ Liabilities:Cards $60.00
+ Assets:Cash
+
+2009/06/30 End of June
+ Expenses:Books $60.00
+ Liabilities:Cards $60.00
+ Assets:Cash
+
+2009/07/01 July
+ Expenses:Books $70.00
+ Liabilities:Cards $70.00
+ Assets:Cash
+
+2009/07/31 End of July
+ Expenses:Books $70.00
+ Liabilities:Cards $70.00
+ Assets:Cash
+
+2009/08/01 August
+ Expenses:Books $80.00
+ Liabilities:Cards $80.00
+ Assets:Cash
+
+2009/08/31 End of August
+ Expenses:Books $80.00
+ Liabilities:Cards $80.00
+ Assets:Cash
+
+2009/09/01 September
+ Expenses:Books $90.00
+ Liabilities:Cards $90.00
+ Assets:Cash
+
+2009/09/30 End of September
+ Expenses:Books $90.00
+ Liabilities:Cards $90.00
+ Assets:Cash
+
+2009/10/01 October
+ Expenses:Books $100.00
+ Liabilities:Cards $100.00
+ Assets:Cash
+
+2009/10/31 End of October
+ Expenses:Books $100.00
+ Liabilities:Cards $100.00
+ Assets:Cash
+
+2009/11/01 November
+ Expenses:Books $110.00
+ Liabilities:Cards $110.00
+ Assets:Cash
+
+2009/11/30 End of November
+ Expenses:Books $110.00
+ Liabilities:Cards $110.00
+ Assets:Cash
+
+2009/12/01 December
+ Expenses:Books $120.00
+ Liabilities:Cards $120.00
+ Assets:Cash
+
+2009/12/31 End of December
+ Expenses:Books $120.00
+ Liabilities:Cards $120.00
+ Assets:Cash
+
+test reg -p "weekly from 2009/11/26" --align-intervals
+09-Nov-26 - 09-Dec-02 Assets:Cash $-460.00 $-460.00
+ Expenses:Books $230.00 $-230.00
+ Liabilities:Cards $230.00 0
+09-Dec-31 - 10-Jan-06 Assets:Cash $-240.00 $-240.00
+ Expenses:Books $120.00 $-120.00
+ Liabilities:Cards $120.00 0
+end test
+
+test reg -p "monthly from 2009/11/15" --align-intervals
+09-Nov-15 - 09-Dec-14 Assets:Cash $-460.00 $-460.00
+ Expenses:Books $230.00 $-230.00
+ Liabilities:Cards $230.00 0
+09-Dec-15 - 10-Jan-14 Assets:Cash $-240.00 $-240.00
+ Expenses:Books $120.00 $-120.00
+ Liabilities:Cards $120.00 0
+end test
+
+test reg -p "quarterly from 2008/01/15" --align-intervals
+08-Jan-15 - 08-Apr-14 Assets:Cash $-300.00 $-300.00
+ Expenses:Books $150.00 $-150.00
+ Liabilities:Cards $150.00 0
+08-Apr-15 - 08-Jul-14 Assets:Cash $-660.00 $-660.00
+ Expenses:Books $330.00 $-330.00
+ Liabilities:Cards $330.00 0
+08-Jul-15 - 08-Oct-14 Assets:Cash $-1020.00 $-1020.00
+ Expenses:Books $510.00 $-510.00
+ Liabilities:Cards $510.00 0
+08-Oct-15 - 09-Jan-14 Assets:Cash $-1140.00 $-1140.00
+ Expenses:Books $570.00 $-570.00
+ Liabilities:Cards $570.00 0
+09-Jan-15 - 09-Apr-14 Assets:Cash $-300.00 $-300.00
+ Expenses:Books $150.00 $-150.00
+ Liabilities:Cards $150.00 0
+09-Apr-15 - 09-Jul-14 Assets:Cash $-660.00 $-660.00
+ Expenses:Books $330.00 $-330.00
+ Liabilities:Cards $330.00 0
+09-Jul-15 - 09-Oct-14 Assets:Cash $-1020.00 $-1020.00
+ Expenses:Books $510.00 $-510.00
+ Liabilities:Cards $510.00 0
+09-Oct-15 - 10-Jan-14 Assets:Cash $-1120.00 $-1120.00
+ Expenses:Books $560.00 $-560.00
+ Liabilities:Cards $560.00 0
+end test
+
+test reg -p "yearly from 2008/02/28" --align-intervals
+08-Feb-28 - 09-Feb-27 Assets:Cash $-3120.00 $-3120.00
+ Expenses:Books $1560.00 $-1560.00
+ Liabilities:Cards $1560.00 0
+09-Feb-28 - 10-Feb-27 Assets:Cash $-3040.00 $-3040.00
+ Expenses:Books $1520.00 $-1520.00
+ Liabilities:Cards $1520.00 0
+end test