summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
7 files changed, 38 insertions, 17 deletions
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 {