Merge branch 'next'
This commit is contained in:
commit
cc9110a43a
20 changed files with 1750 additions and 613 deletions
|
|
@ -55,9 +55,10 @@ typedef std::map<const string, account_t *> accounts_map;
|
|||
|
||||
class account_t : public supports_flags<>, public scope_t
|
||||
{
|
||||
#define ACCOUNT_NORMAL 0x00 // no flags at all, a basic account
|
||||
#define ACCOUNT_KNOWN 0x01
|
||||
#define ACCOUNT_TEMP 0x02 // account is a temporary object
|
||||
#define ACCOUNT_NORMAL 0x00 // no flags at all, a basic account
|
||||
#define ACCOUNT_KNOWN 0x01
|
||||
#define ACCOUNT_TEMP 0x02 // account is a temporary object
|
||||
#define ACCOUNT_GENERATED 0x04 // account never actually existed
|
||||
|
||||
public:
|
||||
account_t * parent;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
#include "xact.h"
|
||||
|
||||
#define LEDGER_MAGIC 0x4c454447
|
||||
#define ARCHIVE_VERSION 0x03000005
|
||||
#define ARCHIVE_VERSION 0x03000006
|
||||
|
||||
//BOOST_IS_ABSTRACT(ledger::scope_t)
|
||||
BOOST_CLASS_EXPORT(ledger::scope_t)
|
||||
|
|
|
|||
36
src/chain.cc
36
src/chain.cc
|
|
@ -41,7 +41,7 @@ namespace ledger {
|
|||
|
||||
post_handler_ptr chain_post_handlers(report_t& report,
|
||||
post_handler_ptr base_handler,
|
||||
bool only_preliminaries)
|
||||
bool for_accounts_report)
|
||||
{
|
||||
post_handler_ptr handler(base_handler);
|
||||
predicate_t display_predicate;
|
||||
|
|
@ -51,7 +51,7 @@ post_handler_ptr chain_post_handlers(report_t& report,
|
|||
expr_t& expr(report.HANDLER(amount_).expr);
|
||||
expr.set_context(&report);
|
||||
|
||||
if (! only_preliminaries) {
|
||||
if (! for_accounts_report) {
|
||||
// Make sure only forecast postings which match are allowed through
|
||||
if (report.HANDLED(forecast_while_)) {
|
||||
handler.reset(new filter_posts
|
||||
|
|
@ -77,25 +77,23 @@ post_handler_ptr chain_post_handlers(report_t& report,
|
|||
report.what_to_keep());
|
||||
handler.reset(new filter_posts(handler, display_predicate, report));
|
||||
}
|
||||
|
||||
// changed_value_posts adds virtual posts to the list to account for
|
||||
// changes in market value of commodities, which otherwise would affect
|
||||
// the running total unpredictably.
|
||||
if (report.HANDLED(revalued))
|
||||
handler.reset(new changed_value_posts
|
||||
(handler,
|
||||
report.HANDLER(display_amount_).expr,
|
||||
report.HANDLED(revalued_total_) ?
|
||||
report.HANDLER(revalued_total_).expr :
|
||||
report.HANDLER(display_total_).expr,
|
||||
report.HANDLER(display_total_).expr,
|
||||
report, report.HANDLED(revalued_only)));
|
||||
}
|
||||
|
||||
// changed_value_posts adds virtual posts to the list to account for changes
|
||||
// in market value of commodities, which otherwise would affect the running
|
||||
// total unpredictably.
|
||||
if (report.HANDLED(revalued) && (! for_accounts_report ||
|
||||
report.HANDLED(unrealized)))
|
||||
handler.reset(new changed_value_posts(handler, report,
|
||||
for_accounts_report,
|
||||
report.HANDLED(unrealized)));
|
||||
|
||||
// calc_posts computes the running total. When this appears will determine,
|
||||
// for example, whether filtered posts are included or excluded from the
|
||||
// running total.
|
||||
handler.reset(new calc_posts(handler, expr, only_preliminaries));
|
||||
handler.reset(new calc_posts(handler, expr, (! for_accounts_report ||
|
||||
(report.HANDLED(revalued) &&
|
||||
report.HANDLED(unrealized)))));
|
||||
|
||||
// filter_posts will only pass through posts matching the
|
||||
// `secondary_predicate'.
|
||||
|
|
@ -105,7 +103,7 @@ post_handler_ptr chain_post_handlers(report_t& report,
|
|||
handler.reset(new filter_posts(handler, only_predicate, report));
|
||||
}
|
||||
|
||||
if (! only_preliminaries) {
|
||||
if (! for_accounts_report) {
|
||||
// sort_posts will sort all the posts it sees, based on the `sort_order'
|
||||
// value expression.
|
||||
if (report.HANDLED(sort_)) {
|
||||
|
|
@ -139,10 +137,6 @@ post_handler_ptr chain_post_handlers(report_t& report,
|
|||
else if (report.HANDLED(subtotal))
|
||||
handler.reset(new subtotal_posts(handler, expr));
|
||||
}
|
||||
else if (! report.HANDLED(period_) &&
|
||||
! report.HANDLED(unsorted)) {
|
||||
handler.reset(new sort_posts(handler, "date"));
|
||||
}
|
||||
|
||||
if (report.HANDLED(dow))
|
||||
handler.reset(new dow_posts(handler, expr));
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class report_t;
|
|||
post_handler_ptr
|
||||
chain_post_handlers(report_t& report,
|
||||
post_handler_ptr base_handler,
|
||||
bool only_preliminaries = false);
|
||||
bool for_accounts_report = false);
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
|
|
|
|||
|
|
@ -637,7 +637,8 @@ bool compare_amount_commodities::operator()(const amount_t * left,
|
|||
return false;
|
||||
|
||||
if (aleftcomm.details.date && arightcomm.details.date) {
|
||||
date_duration_t diff = *aleftcomm.details.date - *arightcomm.details.date;
|
||||
gregorian::date_duration diff =
|
||||
*aleftcomm.details.date - *arightcomm.details.date;
|
||||
return diff.is_negative();
|
||||
}
|
||||
|
||||
|
|
|
|||
144
src/filters.cc
144
src/filters.cc
|
|
@ -217,7 +217,7 @@ void calc_posts::operator()(post_t& post)
|
|||
|
||||
if (last_post) {
|
||||
assert(last_post->has_xdata());
|
||||
if (! account_wise)
|
||||
if (calc_running_total)
|
||||
xdata.total = last_post->xdata().total;
|
||||
xdata.count = last_post->xdata().count + 1;
|
||||
} else {
|
||||
|
|
@ -230,7 +230,7 @@ void calc_posts::operator()(post_t& post)
|
|||
account_t * acct = post.reported_account();
|
||||
acct->xdata().add_flags(ACCOUNT_EXT_VISITED);
|
||||
|
||||
if (! account_wise)
|
||||
if (calc_running_total)
|
||||
add_or_set_value(xdata.total, xdata.visited_value);
|
||||
|
||||
item_handler<post_t>::operator()(post);
|
||||
|
|
@ -239,19 +239,21 @@ void calc_posts::operator()(post_t& post)
|
|||
}
|
||||
|
||||
namespace {
|
||||
typedef function<void (post_t *)> post_functor_t;
|
||||
typedef function<void (post_t&)> post_functor_t;
|
||||
|
||||
void handle_value(const value_t& value,
|
||||
account_t * account,
|
||||
account_t * account,
|
||||
xact_t * xact,
|
||||
temporaries_t& temps,
|
||||
item_handler<post_t>& handler,
|
||||
const date_t& date = date_t(),
|
||||
const value_t& total = value_t(),
|
||||
post_handler_ptr handler,
|
||||
const date_t& date = date_t(),
|
||||
const value_t& total = value_t(),
|
||||
const bool direct_amount = false,
|
||||
const bool mark_visited = false,
|
||||
const optional<post_functor_t>& functor = none)
|
||||
{
|
||||
post_t& post = temps.create_post(*xact, account);
|
||||
post.add_flags(ITEM_GENERATED);
|
||||
|
||||
// If the account for this post is all virtual, then report the post as
|
||||
// such. This allows subtotal reports to show "(Account)" for accounts
|
||||
|
|
@ -302,11 +304,16 @@ namespace {
|
|||
xdata.add_flags(POST_EXT_DIRECT_AMT);
|
||||
|
||||
if (functor)
|
||||
(*functor)(&post);
|
||||
(*functor)(post);
|
||||
|
||||
DEBUG("filter.changed_value.rounding", "post.amount = " << post.amount);
|
||||
|
||||
handler(post);
|
||||
(*handler)(post);
|
||||
|
||||
if (mark_visited) {
|
||||
post.xdata().add_flags(POST_EXT_VISITED);
|
||||
post.account->xdata().add_flags(ACCOUNT_EXT_VISITED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -344,7 +351,7 @@ void collapse_posts::report_subtotal()
|
|||
earliest_date : last_xact->_date);
|
||||
DEBUG("filter.collapse", "Pseudo-xact date = " << *xact._date);
|
||||
|
||||
handle_value(subtotal, &totals_account, &xact, temps, *handler);
|
||||
handle_value(subtotal, &totals_account, &xact, temps, handler);
|
||||
}
|
||||
|
||||
component_posts.clear();
|
||||
|
|
@ -404,30 +411,58 @@ void related_posts::flush()
|
|||
item_handler<post_t>::flush();
|
||||
}
|
||||
|
||||
changed_value_posts::changed_value_posts(post_handler_ptr handler,
|
||||
report_t& _report,
|
||||
bool _for_accounts_report,
|
||||
bool _show_unrealized)
|
||||
: item_handler<post_t>(handler), report(_report),
|
||||
for_accounts_report(_for_accounts_report),
|
||||
show_unrealized(_show_unrealized), last_post(NULL),
|
||||
revalued_account(temps.create_account(_("<Revalued>"))),
|
||||
rounding_account(temps.create_account(_("<Rounding>")))
|
||||
{
|
||||
TRACE_CTOR(changed_value_posts, "post_handler_ptr, report_t&, bool");
|
||||
|
||||
display_amount_expr = report.HANDLER(display_amount_).expr;
|
||||
total_expr = (report.HANDLED(revalued_total_) ?
|
||||
report.HANDLER(revalued_total_).expr :
|
||||
report.HANDLER(display_total_).expr);
|
||||
display_total_expr = report.HANDLER(display_total_).expr;
|
||||
changed_values_only = report.HANDLED(revalued_only);
|
||||
|
||||
gains_equity_account =
|
||||
report.session.journal->master->find_account(_("Equity:Unrealized Gains"));
|
||||
gains_equity_account->add_flags(ACCOUNT_GENERATED);
|
||||
|
||||
losses_equity_account =
|
||||
report.session.journal->master->find_account(_("Equity:Unrealized Losses"));
|
||||
losses_equity_account->add_flags(ACCOUNT_GENERATED);
|
||||
}
|
||||
|
||||
void changed_value_posts::flush()
|
||||
{
|
||||
if (last_post && last_post->date() <= report.terminus.date()) {
|
||||
output_revaluation(last_post, report.terminus.date());
|
||||
output_revaluation(*last_post, report.terminus.date());
|
||||
last_post = NULL;
|
||||
}
|
||||
item_handler<post_t>::flush();
|
||||
}
|
||||
|
||||
void changed_value_posts::output_revaluation(post_t * post, const date_t& date)
|
||||
void changed_value_posts::output_revaluation(post_t& post, const date_t& date)
|
||||
{
|
||||
if (is_valid(date))
|
||||
post->xdata().date = date;
|
||||
post.xdata().date = date;
|
||||
|
||||
value_t repriced_total;
|
||||
try {
|
||||
bind_scope_t bound_scope(report, *post);
|
||||
bind_scope_t bound_scope(report, post);
|
||||
repriced_total = total_expr.calc(bound_scope);
|
||||
}
|
||||
catch (...) {
|
||||
post->xdata().date = date_t();
|
||||
post.xdata().date = date_t();
|
||||
throw;
|
||||
}
|
||||
post->xdata().date = date_t();
|
||||
post.xdata().date = date_t();
|
||||
|
||||
DEBUG("filter.changed_value",
|
||||
"output_revaluation(last_balance) = " << last_total);
|
||||
|
|
@ -441,19 +476,44 @@ void changed_value_posts::output_revaluation(post_t * post, const date_t& date)
|
|||
|
||||
xact_t& xact = temps.create_xact();
|
||||
xact.payee = _("Commodities revalued");
|
||||
xact._date = is_valid(date) ? date : post->date();
|
||||
xact._date = is_valid(date) ? date : post.date();
|
||||
|
||||
handle_value(diff, &revalued_account, &xact, temps, *handler,
|
||||
*xact._date, repriced_total, false,
|
||||
optional<post_functor_t>
|
||||
(bind(&changed_value_posts::output_rounding, this, _1)));
|
||||
if (! for_accounts_report) {
|
||||
handle_value
|
||||
(/* value= */ diff,
|
||||
/* account= */ &revalued_account,
|
||||
/* xact= */ &xact,
|
||||
/* temps= */ temps,
|
||||
/* handler= */ handler,
|
||||
/* date= */ *xact._date,
|
||||
/* total= */ repriced_total,
|
||||
/* direct_amount= */ false,
|
||||
/* mark_visited= */ false,
|
||||
/* functor= */ (optional<post_functor_t>
|
||||
(bind(&changed_value_posts::output_rounding,
|
||||
this, _1))));
|
||||
}
|
||||
else if (show_unrealized) {
|
||||
handle_value
|
||||
(/* value= */ - diff,
|
||||
/* account= */ (diff < 0L ?
|
||||
losses_equity_account :
|
||||
gains_equity_account),
|
||||
/* xact= */ &xact,
|
||||
/* temps= */ temps,
|
||||
/* handler= */ handler,
|
||||
/* date= */ *xact._date,
|
||||
/* total= */ value_t(),
|
||||
/* direct_amount= */ false,
|
||||
/* mark_visited= */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void changed_value_posts::output_rounding(post_t * post)
|
||||
void changed_value_posts::output_rounding(post_t& post)
|
||||
{
|
||||
bind_scope_t bound_scope(report, *post);
|
||||
bind_scope_t bound_scope(report, post);
|
||||
value_t new_display_total(display_total_expr.calc(bound_scope));
|
||||
|
||||
DEBUG("filter.changed_value.rounding",
|
||||
|
|
@ -478,9 +538,9 @@ void changed_value_posts::output_rounding(post_t * post)
|
|||
|
||||
xact_t& xact = temps.create_xact();
|
||||
xact.payee = _("Commodity rounding");
|
||||
xact._date = post->date();
|
||||
xact._date = post.date();
|
||||
|
||||
handle_value(diff, &rounding_account, &xact, temps, *handler,
|
||||
handle_value(diff, &rounding_account, &xact, temps, handler,
|
||||
*xact._date, precise_display_total, true);
|
||||
}
|
||||
}
|
||||
|
|
@ -491,19 +551,19 @@ void changed_value_posts::output_rounding(post_t * post)
|
|||
void changed_value_posts::operator()(post_t& post)
|
||||
{
|
||||
if (last_post)
|
||||
output_revaluation(last_post, post.date());
|
||||
output_revaluation(*last_post, post.date());
|
||||
|
||||
if (changed_values_only)
|
||||
post.xdata().add_flags(POST_EXT_DISPLAYED);
|
||||
|
||||
output_rounding(&post);
|
||||
if (! for_accounts_report)
|
||||
output_rounding(post);
|
||||
|
||||
item_handler<post_t>::operator()(post);
|
||||
|
||||
bind_scope_t bound_scope(report, post);
|
||||
last_total = total_expr.calc(bound_scope);
|
||||
|
||||
last_post = &post;
|
||||
last_post = &post;
|
||||
}
|
||||
|
||||
void subtotal_posts::report_subtotal(const char * spec_fmt,
|
||||
|
|
@ -515,12 +575,14 @@ void subtotal_posts::report_subtotal(const char * spec_fmt,
|
|||
optional<date_t> range_start = interval ? interval->start : none;
|
||||
optional<date_t> range_finish = interval ? interval->inclusive_end() : none;
|
||||
|
||||
foreach (post_t * post, component_posts) {
|
||||
date_t date = post->date();
|
||||
if (! range_start || date < *range_start)
|
||||
range_start = date;
|
||||
if (! range_finish || date > *range_finish)
|
||||
range_finish = date;
|
||||
if (! range_start || ! range_finish) {
|
||||
foreach (post_t * post, component_posts) {
|
||||
date_t date = post->date();
|
||||
if (! range_start || date < *range_start)
|
||||
range_start = date;
|
||||
if (! range_finish || date > *range_finish)
|
||||
range_finish = date;
|
||||
}
|
||||
}
|
||||
component_posts.clear();
|
||||
|
||||
|
|
@ -542,7 +604,7 @@ void subtotal_posts::report_subtotal(const char * spec_fmt,
|
|||
|
||||
foreach (values_map::value_type& pair, values)
|
||||
handle_value(pair.second.value, pair.second.account, &xact, temps,
|
||||
*handler);
|
||||
handler);
|
||||
|
||||
values.clear();
|
||||
}
|
||||
|
|
@ -652,10 +714,10 @@ void posts_as_equity::report_subtotal()
|
|||
foreach (balance_t::amounts_map::value_type amount_pair,
|
||||
pair.second.value.as_balance().amounts)
|
||||
handle_value(amount_pair.second, pair.second.account, &xact, temps,
|
||||
*handler);
|
||||
handler);
|
||||
} else {
|
||||
handle_value(pair.second.value, pair.second.account, &xact, temps,
|
||||
*handler);
|
||||
handler);
|
||||
}
|
||||
total += pair.second.value;
|
||||
}
|
||||
|
|
@ -784,7 +846,7 @@ void budget_posts::report_budget_items(const date_t& date)
|
|||
assert(begin);
|
||||
|
||||
if (*begin <= date &&
|
||||
(! pair.first.end || *begin < *pair.first.end)) {
|
||||
(! pair.first.finish || *begin < *pair.first.finish)) {
|
||||
post_t& post = *pair.second;
|
||||
|
||||
DEBUG("budget.generate", "Reporting budget for "
|
||||
|
|
@ -905,8 +967,8 @@ void forecast_posts::flush()
|
|||
}
|
||||
|
||||
date_t& begin = *(*least).first.start;
|
||||
if ((*least).first.end)
|
||||
assert(begin < *(*least).first.end);
|
||||
if ((*least).first.finish)
|
||||
assert(begin < *(*least).first.finish);
|
||||
|
||||
// If the next date in the series for this periodic posting is more than 5
|
||||
// years beyond the last valid post we generated, drop it from further
|
||||
|
|
|
|||
|
|
@ -241,8 +241,7 @@ public:
|
|||
const predicate_t& predicate,
|
||||
scope_t& _context)
|
||||
: item_handler<post_t>(handler), pred(predicate), context(_context) {
|
||||
TRACE_CTOR(filter_posts,
|
||||
"post_handler_ptr, const predicate_t&, scope_t&");
|
||||
TRACE_CTOR(filter_posts, "post_handler_ptr, predicate_t, scope_t&");
|
||||
}
|
||||
virtual ~filter_posts() {
|
||||
TRACE_DTOR(filter_posts);
|
||||
|
|
@ -280,16 +279,16 @@ class calc_posts : public item_handler<post_t>
|
|||
{
|
||||
post_t * last_post;
|
||||
expr_t& amount_expr;
|
||||
bool account_wise;
|
||||
bool calc_running_total;
|
||||
|
||||
calc_posts();
|
||||
|
||||
public:
|
||||
calc_posts(post_handler_ptr handler,
|
||||
expr_t& _amount_expr,
|
||||
bool _account_wise = false)
|
||||
bool _calc_running_total = false)
|
||||
: item_handler<post_t>(handler), last_post(NULL),
|
||||
amount_expr(_amount_expr), account_wise(_account_wise) {
|
||||
amount_expr(_amount_expr), calc_running_total(_calc_running_total) {
|
||||
TRACE_CTOR(calc_posts, "post_handler_ptr, expr_t&, bool");
|
||||
}
|
||||
virtual ~calc_posts() {
|
||||
|
|
@ -379,39 +378,33 @@ class changed_value_posts : public item_handler<post_t>
|
|||
expr_t display_total_expr;
|
||||
report_t& report;
|
||||
bool changed_values_only;
|
||||
bool for_accounts_report;
|
||||
bool show_unrealized;
|
||||
post_t * last_post;
|
||||
value_t last_total;
|
||||
value_t last_display_total;
|
||||
temporaries_t temps;
|
||||
temporaries_t temps;
|
||||
account_t& revalued_account;
|
||||
account_t& rounding_account;
|
||||
account_t * gains_equity_account;
|
||||
account_t * losses_equity_account;
|
||||
|
||||
changed_value_posts();
|
||||
|
||||
public:
|
||||
changed_value_posts(post_handler_ptr handler,
|
||||
const expr_t& _display_amount_expr,
|
||||
const expr_t& _total_expr,
|
||||
const expr_t& _display_total_expr,
|
||||
report_t& _report,
|
||||
bool _changed_values_only)
|
||||
: item_handler<post_t>(handler),
|
||||
display_amount_expr(_display_amount_expr), total_expr(_total_expr),
|
||||
display_total_expr(_display_total_expr), report(_report),
|
||||
changed_values_only(_changed_values_only), last_post(NULL),
|
||||
revalued_account(temps.create_account(_("<Revalued>"))),
|
||||
rounding_account(temps.create_account(_("<Rounding>"))) {
|
||||
TRACE_CTOR(changed_value_posts,
|
||||
"post_handler_ptr, const expr_t&, const expr_t&, report_t&, bool");
|
||||
}
|
||||
report_t& _report,
|
||||
bool _for_accounts_report,
|
||||
bool _show_unrealized);
|
||||
|
||||
virtual ~changed_value_posts() {
|
||||
TRACE_DTOR(changed_value_posts);
|
||||
}
|
||||
|
||||
virtual void flush();
|
||||
|
||||
void output_revaluation(post_t * post, const date_t& current);
|
||||
void output_rounding(post_t * post);
|
||||
void output_revaluation(post_t& post, const date_t& current);
|
||||
void output_rounding(post_t& post);
|
||||
|
||||
virtual void operator()(post_t& post);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -165,57 +165,12 @@ value_t period_command(call_scope_t& args)
|
|||
report_t& report(find_scope<report_t>(args));
|
||||
std::ostream& out(report.output_stream);
|
||||
|
||||
show_period_tokens(out, arg);
|
||||
out << std::endl;
|
||||
|
||||
date_interval_t interval(arg);
|
||||
interval.dump(out, report.session.current_year);
|
||||
|
||||
out << _("global details => ") << std::endl << std::endl;
|
||||
|
||||
if (interval.start)
|
||||
out << _(" start: ") << format_date(*interval.start) << std::endl;
|
||||
else
|
||||
out << _(" start: TODAY: ") << format_date(CURRENT_DATE()) << std::endl;
|
||||
if (interval.end)
|
||||
out << _(" end: ") << format_date(*interval.end) << std::endl;
|
||||
|
||||
if (interval.skip_duration)
|
||||
out << _(" skip: ") << *interval.skip_duration << std::endl;
|
||||
if (interval.factor)
|
||||
out << _(" factor: ") << interval.factor << std::endl;
|
||||
if (interval.duration)
|
||||
out << _("duration: ") << *interval.duration << std::endl;
|
||||
|
||||
if (interval.find_period(interval.start ?
|
||||
*interval.start : CURRENT_DATE())) {
|
||||
out << std::endl
|
||||
<< _("after finding first period => ") << std::endl
|
||||
<< std::endl;
|
||||
|
||||
if (interval.start)
|
||||
out << _(" start: ") << format_date(*interval.start) << std::endl;
|
||||
if (interval.end)
|
||||
out << _(" end: ") << format_date(*interval.end) << std::endl;
|
||||
|
||||
if (interval.skip_duration)
|
||||
out << _(" skip: ") << *interval.skip_duration << std::endl;
|
||||
if (interval.factor)
|
||||
out << _(" factor: ") << interval.factor << std::endl;
|
||||
if (interval.duration)
|
||||
out << _("duration: ") << *interval.duration << std::endl;
|
||||
|
||||
out << std::endl;
|
||||
|
||||
for (int i = 0; i < 20 && interval; i++, ++interval) {
|
||||
out << std::right;
|
||||
out.width(2);
|
||||
|
||||
out << i << "): " << format_date(*interval.start);
|
||||
if (interval.end_of_duration)
|
||||
out << " -- " << format_date(*interval.inclusive_end());
|
||||
out << std::endl;
|
||||
|
||||
if (! interval.skip_duration)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NULL_VALUE;
|
||||
}
|
||||
|
||||
|
|
@ -229,14 +184,12 @@ value_t args_command(call_scope_t& args)
|
|||
out << std::endl << std::endl;
|
||||
|
||||
query_t query(args.value(), report.what_to_keep());
|
||||
if (! query)
|
||||
throw_(std::runtime_error,
|
||||
_("Invalid query predicate: %1") << join_args(args));
|
||||
if (query) {
|
||||
call_scope_t sub_args(static_cast<scope_t&>(args));
|
||||
sub_args.push_back(string_value(query.text()));
|
||||
|
||||
call_scope_t sub_args(static_cast<scope_t&>(args));
|
||||
sub_args.push_back(string_value(query.text()));
|
||||
|
||||
parse_command(sub_args);
|
||||
parse_command(sub_args);
|
||||
}
|
||||
|
||||
if (query.tokens_remaining()) {
|
||||
out << std::endl << _("====== Display predicate ======")
|
||||
|
|
@ -244,14 +197,12 @@ value_t args_command(call_scope_t& args)
|
|||
|
||||
query.parse_again();
|
||||
|
||||
if (! query)
|
||||
throw_(std::runtime_error,
|
||||
_("Invalid display predicate: %1") << join_args(args));
|
||||
if (query) {
|
||||
call_scope_t disp_sub_args(static_cast<scope_t&>(args));
|
||||
disp_sub_args.push_back(string_value(query.text()));
|
||||
|
||||
call_scope_t disp_sub_args(static_cast<scope_t&>(args));
|
||||
disp_sub_args.push_back(string_value(query.text()));
|
||||
|
||||
parse_command(disp_sub_args);
|
||||
parse_command(disp_sub_args);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL_VALUE;
|
||||
|
|
|
|||
|
|
@ -263,12 +263,12 @@ query_t::parser_t::parse_query_term(query_t::lexer_t::token_t::kind_t tok_contex
|
|||
node->set_right(arg1);
|
||||
}
|
||||
|
||||
if (interval.end) {
|
||||
if (interval.finish) {
|
||||
expr_t::ptr_op_t lt = new expr_t::op_t(expr_t::op_t::O_LT);
|
||||
lt->set_left(ident);
|
||||
|
||||
expr_t::ptr_op_t arg1 = new expr_t::op_t(expr_t::op_t::VALUE);
|
||||
arg1->set_value(*interval.end);
|
||||
arg1->set_value(*interval.finish);
|
||||
lt->set_right(arg1);
|
||||
|
||||
if (node) {
|
||||
|
|
|
|||
72
src/query.h
72
src/query.h
|
|
@ -96,14 +96,14 @@ public:
|
|||
explicit token_t(kind_t _kind = UNKNOWN,
|
||||
const optional<string>& _value = none)
|
||||
: kind(_kind), value(_value) {
|
||||
TRACE_CTOR(lexer_t::token_t, "");
|
||||
TRACE_CTOR(query_t::lexer_t::token_t, "");
|
||||
}
|
||||
token_t(const token_t& tok)
|
||||
: kind(tok.kind), value(tok.value) {
|
||||
TRACE_CTOR(lexer_t::token_t, "copy");
|
||||
TRACE_CTOR(query_t::lexer_t::token_t, "copy");
|
||||
}
|
||||
~token_t() throw() {
|
||||
TRACE_DTOR(lexer_t::token_t);
|
||||
TRACE_DTOR(query_t::lexer_t::token_t);
|
||||
}
|
||||
|
||||
token_t& operator=(const token_t& tok) {
|
||||
|
|
@ -120,40 +120,42 @@ public:
|
|||
|
||||
string to_string() const {
|
||||
switch (kind) {
|
||||
case UNKNOWN: return "UNKNOWN";
|
||||
case LPAREN: return "LPAREN";
|
||||
case RPAREN: return "RPAREN";
|
||||
case TOK_NOT: return "TOK_NOT";
|
||||
case TOK_AND: return "TOK_AND";
|
||||
case TOK_OR: return "TOK_OR";
|
||||
case TOK_EQ: return "TOK_EQ";
|
||||
case TOK_DATE: return "TOK_DATE";
|
||||
case TOK_CODE: return "TOK_CODE";
|
||||
case TOK_PAYEE: return "TOK_PAYEE";
|
||||
case TOK_NOTE: return "TOK_NOTE";
|
||||
case UNKNOWN: return "UNKNOWN";
|
||||
case LPAREN: return "LPAREN";
|
||||
case RPAREN: return "RPAREN";
|
||||
case TOK_NOT: return "TOK_NOT";
|
||||
case TOK_AND: return "TOK_AND";
|
||||
case TOK_OR: return "TOK_OR";
|
||||
case TOK_EQ: return "TOK_EQ";
|
||||
case TOK_DATE: return "TOK_DATE";
|
||||
case TOK_CODE: return "TOK_CODE";
|
||||
case TOK_PAYEE: return "TOK_PAYEE";
|
||||
case TOK_NOTE: return "TOK_NOTE";
|
||||
case TOK_ACCOUNT: return "TOK_ACCOUNT";
|
||||
case TOK_META: return "TOK_META";
|
||||
case TOK_EXPR: return "TOK_EXPR";
|
||||
case TERM: return string("TERM(") + *value + ")";
|
||||
case TOK_META: return "TOK_META";
|
||||
case TOK_EXPR: return "TOK_EXPR";
|
||||
case TERM: return string("TERM(") + *value + ")";
|
||||
case END_REACHED: return "END_REACHED";
|
||||
}
|
||||
assert(false);
|
||||
return empty_string;
|
||||
}
|
||||
|
||||
string symbol() const {
|
||||
switch (kind) {
|
||||
case LPAREN: return "(";
|
||||
case RPAREN: return ")";
|
||||
case TOK_NOT: return "not";
|
||||
case TOK_AND: return "and";
|
||||
case TOK_OR: return "or";
|
||||
case TOK_EQ: return "=";
|
||||
case TOK_DATE: return "date";
|
||||
case TOK_CODE: return "code";
|
||||
case TOK_PAYEE: return "payee";
|
||||
case TOK_NOTE: return "note";
|
||||
case LPAREN: return "(";
|
||||
case RPAREN: return ")";
|
||||
case TOK_NOT: return "not";
|
||||
case TOK_AND: return "and";
|
||||
case TOK_OR: return "or";
|
||||
case TOK_EQ: return "=";
|
||||
case TOK_DATE: return "date";
|
||||
case TOK_CODE: return "code";
|
||||
case TOK_PAYEE: return "payee";
|
||||
case TOK_NOTE: return "note";
|
||||
case TOK_ACCOUNT: return "account";
|
||||
case TOK_META: return "meta";
|
||||
case TOK_EXPR: return "expr";
|
||||
case TOK_META: return "meta";
|
||||
case TOK_EXPR: return "expr";
|
||||
|
||||
case END_REACHED: return "<EOF>";
|
||||
|
||||
|
|
@ -180,7 +182,7 @@ public:
|
|||
consume_whitespace(false),
|
||||
consume_next_arg(false)
|
||||
{
|
||||
TRACE_CTOR(lexer_t, "");
|
||||
TRACE_CTOR(query_t::lexer_t, "");
|
||||
assert(begin != end);
|
||||
arg_i = (*begin).as_string().begin();
|
||||
arg_end = (*begin).as_string().end();
|
||||
|
|
@ -192,10 +194,10 @@ public:
|
|||
consume_next_arg(lexer.consume_next_arg),
|
||||
token_cache(lexer.token_cache)
|
||||
{
|
||||
TRACE_CTOR(lexer_t, "copy");
|
||||
TRACE_CTOR(query_t::lexer_t, "copy");
|
||||
}
|
||||
~lexer_t() throw() {
|
||||
TRACE_DTOR(lexer_t);
|
||||
TRACE_DTOR(query_t::lexer_t);
|
||||
}
|
||||
|
||||
token_t next_token();
|
||||
|
|
@ -227,14 +229,14 @@ protected:
|
|||
public:
|
||||
parser_t(const value_t& _args)
|
||||
: args(_args), lexer(args.begin(), args.end()) {
|
||||
TRACE_CTOR(parser_t, "");
|
||||
TRACE_CTOR(query_t::parser_t, "");
|
||||
}
|
||||
parser_t(const parser_t& parser)
|
||||
: args(parser.args), lexer(parser.lexer) {
|
||||
TRACE_CTOR(parser_t, "copy");
|
||||
TRACE_CTOR(query_t::parser_t, "copy");
|
||||
}
|
||||
~parser_t() throw() {
|
||||
TRACE_DTOR(parser_t);
|
||||
TRACE_DTOR(query_t::parser_t);
|
||||
}
|
||||
|
||||
expr_t::ptr_op_t parse() {
|
||||
|
|
|
|||
|
|
@ -120,14 +120,15 @@ void report_t::normalize_options(const string& verb)
|
|||
|
||||
date_interval_t interval(HANDLER(period_).str());
|
||||
|
||||
if (! HANDLED(begin_) && interval.start) {
|
||||
string predicate =
|
||||
"date>=[" + to_iso_extended_string(*interval.start) + "]";
|
||||
optional<date_t> begin = interval.begin(session.current_year);
|
||||
optional<date_t> end = interval.end(session.current_year);
|
||||
|
||||
if (! HANDLED(begin_) && begin) {
|
||||
string predicate = "date>=[" + to_iso_extended_string(*begin) + "]";
|
||||
HANDLER(limit_).on(string("?normalize"), predicate);
|
||||
}
|
||||
if (! HANDLED(end_) && interval.end) {
|
||||
string predicate =
|
||||
"date<[" + to_iso_extended_string(*interval.end) + "]";
|
||||
if (! HANDLED(end_) && end) {
|
||||
string predicate = "date<[" + to_iso_extended_string(*end) + "]";
|
||||
HANDLER(limit_).on(string("?normalize"), predicate);
|
||||
}
|
||||
|
||||
|
|
@ -221,25 +222,21 @@ void report_t::normalize_options(const string& verb)
|
|||
void report_t::parse_query_args(const value_t& args, const string& whence)
|
||||
{
|
||||
query_t query(args, what_to_keep());
|
||||
if (! query)
|
||||
throw_(std::runtime_error,
|
||||
_("Invalid query predicate: %1") << query.text());
|
||||
if (query) {
|
||||
HANDLER(limit_).on(whence, query.text());
|
||||
|
||||
HANDLER(limit_).on(whence, query.text());
|
||||
|
||||
DEBUG("report.predicate",
|
||||
"Predicate = " << HANDLER(limit_).str());
|
||||
DEBUG("report.predicate",
|
||||
"Predicate = " << HANDLER(limit_).str());
|
||||
}
|
||||
|
||||
if (query.tokens_remaining()) {
|
||||
query.parse_again();
|
||||
if (! query)
|
||||
throw_(std::runtime_error,
|
||||
_("Invalid display predicate: %1") << query.text());
|
||||
if (query) {
|
||||
HANDLER(display_).on(whence, query.text());
|
||||
|
||||
HANDLER(display_).on(whence, query.text());
|
||||
|
||||
DEBUG("report.predicate",
|
||||
"Display predicate = " << HANDLER(display_).str());
|
||||
DEBUG("report.predicate",
|
||||
"Display predicate = " << HANDLER(display_).str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -281,6 +278,12 @@ void report_t::accounts_report(acct_handler_ptr handler)
|
|||
chain_post_handlers(*this, post_handler_ptr(new ignore_posts), true);
|
||||
pass_down_posts(chain, walker);
|
||||
|
||||
HANDLER(amount_).expr.mark_uncompiled();
|
||||
HANDLER(total_).expr.mark_uncompiled();
|
||||
HANDLER(display_amount_).expr.mark_uncompiled();
|
||||
HANDLER(display_total_).expr.mark_uncompiled();
|
||||
HANDLER(revalued_total_).expr.mark_uncompiled();
|
||||
|
||||
scoped_ptr<accounts_iterator> iter;
|
||||
if (! HANDLED(sort_)) {
|
||||
iter.reset(new basic_accounts_iterator(*session.journal->master));
|
||||
|
|
@ -884,6 +887,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
|
|||
case 'u':
|
||||
OPT(unbudgeted);
|
||||
else OPT(uncleared);
|
||||
else OPT(unrealized);
|
||||
else OPT(unround);
|
||||
else OPT(unsorted);
|
||||
break;
|
||||
|
|
|
|||
34
src/report.h
34
src/report.h
|
|
@ -50,6 +50,7 @@
|
|||
#include "option.h"
|
||||
#include "commodity.h"
|
||||
#include "annotate.h"
|
||||
#include "session.h"
|
||||
#include "format.h"
|
||||
|
||||
namespace ledger {
|
||||
|
|
@ -300,6 +301,7 @@ public:
|
|||
HANDLER(truncate_).report(out);
|
||||
HANDLER(unbudgeted).report(out);
|
||||
HANDLER(uncleared).report(out);
|
||||
HANDLER(unrealized).report(out);
|
||||
HANDLER(unround).report(out);
|
||||
HANDLER(unsorted).report(out);
|
||||
HANDLER(weekly).report(out);
|
||||
|
|
@ -352,7 +354,7 @@ public:
|
|||
set_expr(args[0].to_string(), args[1].to_string());
|
||||
});
|
||||
|
||||
OPTION(report_t, amount_data);
|
||||
OPTION(report_t, amount_data); // -j
|
||||
OPTION(report_t, anon);
|
||||
|
||||
OPTION_(report_t, average, DO() { // -A
|
||||
|
|
@ -377,14 +379,14 @@ public:
|
|||
});
|
||||
|
||||
OPTION_(report_t, begin_, DO_(args) { // -b
|
||||
date_interval_t interval(args[1].to_string());
|
||||
if (! interval.start)
|
||||
date_interval_t interval(args[1].to_string());
|
||||
optional<date_t> begin = interval.begin(parent->session.current_year);
|
||||
if (! begin)
|
||||
throw_(std::invalid_argument,
|
||||
_("Could not determine beginning of period '%1'")
|
||||
<< args[1].to_string());
|
||||
|
||||
string predicate =
|
||||
"date>=[" + to_iso_extended_string(*interval.start) + "]";
|
||||
string predicate = "date>=[" + to_iso_extended_string(*begin) + "]";
|
||||
parent->HANDLER(limit_).on(string("--begin"), predicate);
|
||||
});
|
||||
|
||||
|
|
@ -524,17 +526,19 @@ public:
|
|||
OPTION(report_t, empty); // -E
|
||||
|
||||
OPTION_(report_t, end_, DO_(args) { // -e
|
||||
date_interval_t interval(args[1].to_string());
|
||||
if (! interval.start)
|
||||
date_interval_t interval(args[1].to_string());
|
||||
// Use begin() here so that if the user says --end=2008, we end on
|
||||
// 2008/01/01 instead of 2009/01/01 (which is what end() would return).
|
||||
optional<date_t> end = interval.begin(parent->session.current_year);
|
||||
if (! end)
|
||||
throw_(std::invalid_argument,
|
||||
_("Could not determine end of period '%1'")
|
||||
<< args[1].to_string());
|
||||
|
||||
string predicate =
|
||||
"date<[" + to_iso_extended_string(*interval.start) + "]";
|
||||
string predicate = "date<[" + to_iso_extended_string(*end) + "]";
|
||||
parent->HANDLER(limit_).on(string("--end"), predicate);
|
||||
|
||||
parent->terminus = datetime_t(*interval.start);
|
||||
parent->terminus = datetime_t(*end);
|
||||
});
|
||||
|
||||
OPTION(report_t, equity);
|
||||
|
|
@ -622,11 +626,13 @@ public:
|
|||
|
||||
OPTION_(report_t, now_, DO_(args) {
|
||||
date_interval_t interval(args[1].to_string());
|
||||
if (! interval.start)
|
||||
optional<date_t> begin = interval.begin(parent->session.current_year);
|
||||
if (! begin)
|
||||
throw_(std::invalid_argument,
|
||||
_("Could not determine beginning of period '%1'")
|
||||
<< args[1].to_string());
|
||||
ledger::epoch = datetime_t(*interval.start);
|
||||
ledger::epoch = parent->terminus = datetime_t(*begin);
|
||||
parent->session.current_year = ledger::epoch->date().year();
|
||||
});
|
||||
|
||||
OPTION__
|
||||
|
|
@ -844,7 +850,7 @@ public:
|
|||
set_expr(args[0].to_string(), args[1].to_string());
|
||||
});
|
||||
|
||||
OPTION(report_t, total_data);
|
||||
OPTION(report_t, total_data); // -J
|
||||
|
||||
OPTION_(report_t, truncate_, DO_(args) {
|
||||
string style(args[1].to_string());
|
||||
|
|
@ -868,6 +874,8 @@ public:
|
|||
parent->HANDLER(limit_).on(string("--uncleared"), "uncleared|pending");
|
||||
});
|
||||
|
||||
OPTION(report_t, unrealized);
|
||||
|
||||
OPTION_(report_t, unround, DO() {
|
||||
parent->HANDLER(display_amount_)
|
||||
.set_expr(string("--unround"), "unrounded(amount_expr)");
|
||||
|
|
|
|||
1213
src/times.cc
1213
src/times.cc
File diff suppressed because it is too large
Load diff
529
src/times.h
529
src/times.h
|
|
@ -59,7 +59,6 @@ inline bool is_valid(const datetime_t& moment) {
|
|||
}
|
||||
|
||||
typedef boost::gregorian::date date_t;
|
||||
typedef boost::gregorian::date_duration date_duration_t;
|
||||
typedef boost::gregorian::date_iterator date_iterator_t;
|
||||
|
||||
inline bool is_valid(const date_t& moment) {
|
||||
|
|
@ -85,19 +84,19 @@ string_to_day_of_week(const std::string& str);
|
|||
optional<date_time::months_of_year>
|
||||
string_to_month_of_year(const std::string& str);
|
||||
|
||||
datetime_t parse_datetime(const char * str,
|
||||
optional<date_t::year_type> current_year = none);
|
||||
typedef optional<date_t::year_type> optional_year;
|
||||
|
||||
datetime_t parse_datetime(const char * str, optional_year current_year = none);
|
||||
|
||||
inline datetime_t parse_datetime(const std::string& str,
|
||||
optional<date_t::year_type> current_year = none) {
|
||||
optional_year current_year = none) {
|
||||
return parse_datetime(str.c_str(), current_year);
|
||||
}
|
||||
|
||||
date_t parse_date(const char * str,
|
||||
optional<date_t::year_type> current_year = none);
|
||||
date_t parse_date(const char * str, optional_year current_year = none);
|
||||
|
||||
inline date_t parse_date(const std::string& str,
|
||||
optional<date_t::year_type> current_year = none) {
|
||||
optional_year current_year = none) {
|
||||
return parse_date(str.c_str(), current_year);
|
||||
}
|
||||
|
||||
|
|
@ -138,105 +137,423 @@ inline void to_xml(std::ostream& out, const date_t& when,
|
|||
}
|
||||
}
|
||||
|
||||
struct date_traits_t
|
||||
{
|
||||
bool has_year;
|
||||
bool has_month;
|
||||
bool has_day;
|
||||
|
||||
date_traits_t(bool _has_year = false,
|
||||
bool _has_month = false,
|
||||
bool _has_day = false)
|
||||
: has_year(_has_year), has_month(_has_month), has_day(_has_day) {
|
||||
TRACE_CTOR(date_traits_t, "bool, bool, bool");
|
||||
}
|
||||
date_traits_t(const date_traits_t& traits)
|
||||
: has_year(traits.has_year),
|
||||
has_month(traits.has_month),
|
||||
has_day(traits.has_day) {
|
||||
TRACE_CTOR(date_traits_t, "copy");
|
||||
}
|
||||
~date_traits_t() throw() {
|
||||
TRACE_DTOR(date_traits_t);
|
||||
}
|
||||
|
||||
date_traits_t& operator=(const date_traits_t& traits) {
|
||||
has_year = traits.has_year;
|
||||
has_month = traits.has_month;
|
||||
has_day = traits.has_day;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const date_traits_t& traits) const {
|
||||
return (has_year == traits.has_year &&
|
||||
has_month == traits.has_month &&
|
||||
has_day == traits.has_day);
|
||||
}
|
||||
|
||||
#if defined(HAVE_BOOST_SERIALIZATION)
|
||||
private:
|
||||
/** Serialization. */
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive& ar, const unsigned int /* version */) {
|
||||
ar & has_year;
|
||||
ar & has_month;
|
||||
ar & has_day;
|
||||
}
|
||||
#endif // HAVE_BOOST_SERIALIZATION
|
||||
};
|
||||
|
||||
struct date_duration_t
|
||||
{
|
||||
enum skip_quantum_t {
|
||||
DAYS, WEEKS, MONTHS, QUARTERS, YEARS
|
||||
} quantum;
|
||||
int length;
|
||||
|
||||
date_duration_t() : quantum(DAYS), length(0) {
|
||||
TRACE_CTOR(date_duration_t, "");
|
||||
}
|
||||
date_duration_t(skip_quantum_t _quantum, int _length)
|
||||
: quantum(_quantum), length(_length) {
|
||||
TRACE_CTOR(date_duration_t, "skip_quantum_t, int");
|
||||
}
|
||||
date_duration_t(const date_duration_t& dur)
|
||||
: quantum(dur.quantum), length(dur.length) {
|
||||
TRACE_CTOR(date_duration_t, "copy");
|
||||
}
|
||||
~date_duration_t() throw() {
|
||||
TRACE_DTOR(date_duration_t);
|
||||
}
|
||||
|
||||
date_t add(const date_t& date) const {
|
||||
switch (quantum) {
|
||||
case DAYS:
|
||||
return date + gregorian::days(length);
|
||||
case WEEKS:
|
||||
return date + gregorian::weeks(length);
|
||||
case MONTHS:
|
||||
return date + gregorian::months(length);
|
||||
case QUARTERS:
|
||||
return date + gregorian::months(length * 3);
|
||||
case YEARS:
|
||||
return date + gregorian::years(length);
|
||||
default:
|
||||
assert(false); return date_t();
|
||||
}
|
||||
}
|
||||
|
||||
date_t subtract(const date_t& date) const {
|
||||
switch (quantum) {
|
||||
case DAYS:
|
||||
return date - gregorian::days(length);
|
||||
case WEEKS:
|
||||
return date - gregorian::weeks(length);
|
||||
case MONTHS:
|
||||
return date - gregorian::months(length);
|
||||
case QUARTERS:
|
||||
return date - gregorian::months(length * 3);
|
||||
case YEARS:
|
||||
return date - gregorian::years(length);
|
||||
default:
|
||||
assert(false); return date_t();
|
||||
}
|
||||
}
|
||||
|
||||
string to_string() const {
|
||||
std::ostringstream out;
|
||||
|
||||
out << length << ' ';
|
||||
|
||||
switch (quantum) {
|
||||
case DAYS: out << "day"; break;
|
||||
case WEEKS: out << "week"; break;
|
||||
case MONTHS: out << "month"; break;
|
||||
case QUARTERS: out << "quarter"; break;
|
||||
case YEARS: out << "year"; break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (length > 1)
|
||||
out << 's';
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
static date_t find_nearest(const date_t& date, skip_quantum_t skip);
|
||||
|
||||
#if defined(HAVE_BOOST_SERIALIZATION)
|
||||
private:
|
||||
/** Serialization. */
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive& ar, const unsigned int /* version */) {
|
||||
ar & quantum;
|
||||
ar & length;
|
||||
}
|
||||
#endif // HAVE_BOOST_SERIALIZATION
|
||||
};
|
||||
|
||||
class date_specifier_t
|
||||
{
|
||||
friend class date_parser_t;
|
||||
|
||||
#if 0
|
||||
typedef date_t::year_type year_type;
|
||||
#else
|
||||
typedef unsigned short year_type;
|
||||
#endif
|
||||
typedef date_t::month_type month_type;
|
||||
typedef date_t::day_type day_type;
|
||||
typedef date_t::day_of_week_type day_of_week_type;
|
||||
|
||||
optional<year_type> year;
|
||||
optional<month_type> month;
|
||||
optional<day_type> day;
|
||||
optional<day_of_week_type> wday;
|
||||
|
||||
public:
|
||||
date_specifier_t(const optional<year_type>& _year = none,
|
||||
const optional<month_type>& _month = none,
|
||||
const optional<day_type>& _day = none,
|
||||
const optional<day_of_week_type>& _wday = none)
|
||||
: year(_year), month(_month), day(_day), wday(_wday) {
|
||||
TRACE_CTOR(date_specifier_t,
|
||||
"year_type, month_type, day_type, day_of_week_type");
|
||||
}
|
||||
date_specifier_t(const date_t& date,
|
||||
const optional<date_traits_t>& traits = none) {
|
||||
TRACE_CTOR(date_specifier_t, "date_t, date_traits_t");
|
||||
if (! traits || traits->has_year)
|
||||
year = date.year();
|
||||
if (! traits || traits->has_month)
|
||||
month = date.month();
|
||||
if (! traits || traits->has_day)
|
||||
day = date.day();
|
||||
}
|
||||
date_specifier_t(const date_specifier_t& other)
|
||||
: year(other.year), month(other.month),
|
||||
day(other.day), wday(other.wday) {
|
||||
TRACE_CTOR(date_specifier_t, "copy");
|
||||
}
|
||||
~date_specifier_t() throw() {
|
||||
TRACE_DTOR(date_specifier_t);
|
||||
}
|
||||
|
||||
date_t begin(const optional_year& current_year = none) const;
|
||||
date_t end(const optional_year& current_year = none) const;
|
||||
|
||||
bool is_within(const date_t& date,
|
||||
const optional_year& current_year = none) const {
|
||||
return date >= begin(current_year) && date < end(current_year);
|
||||
}
|
||||
|
||||
optional<date_duration_t> implied_duration() const {
|
||||
if (day || wday)
|
||||
return date_duration_t(date_duration_t::DAYS, 1);
|
||||
else if (month)
|
||||
return date_duration_t(date_duration_t::MONTHS, 1);
|
||||
else if (year)
|
||||
return date_duration_t(date_duration_t::YEARS, 1);
|
||||
else
|
||||
return none;
|
||||
}
|
||||
|
||||
string to_string() const {
|
||||
std::ostringstream out;
|
||||
|
||||
if (year)
|
||||
out << " year " << *year;
|
||||
if (month)
|
||||
out << " month " << *month;
|
||||
if (day)
|
||||
out << " day " << *day;
|
||||
if (wday)
|
||||
out << " wday " << *wday;
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
#if defined(HAVE_BOOST_SERIALIZATION)
|
||||
private:
|
||||
/** Serialization. */
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive& ar, const unsigned int /* version */) {
|
||||
ar & year;
|
||||
ar & month;
|
||||
ar & day;
|
||||
ar & wday;
|
||||
}
|
||||
#endif // HAVE_BOOST_SERIALIZATION
|
||||
};
|
||||
|
||||
class date_range_t
|
||||
{
|
||||
friend class date_parser_t;
|
||||
|
||||
optional<date_specifier_t> range_begin;
|
||||
optional<date_specifier_t> range_end;
|
||||
|
||||
bool end_inclusive;
|
||||
|
||||
public:
|
||||
date_range_t(const optional<date_specifier_t>& _range_begin = none,
|
||||
const optional<date_specifier_t>& _range_end = none)
|
||||
: range_begin(_range_begin), range_end(_range_end),
|
||||
end_inclusive(false) {
|
||||
TRACE_CTOR(date_range_t, "date_specifier_t, date_specifier_t");
|
||||
}
|
||||
date_range_t(const date_range_t& other)
|
||||
: range_begin(other.range_begin), range_end(other.range_end),
|
||||
end_inclusive(other.end_inclusive) {
|
||||
TRACE_CTOR(date_range_t, "date_range_t");
|
||||
}
|
||||
~date_range_t() throw() {
|
||||
TRACE_DTOR(date_range_t);
|
||||
}
|
||||
|
||||
optional<date_t> begin(const optional_year& current_year = none) const {
|
||||
if (range_begin)
|
||||
return range_begin->begin(current_year);
|
||||
else
|
||||
return none;
|
||||
}
|
||||
optional<date_t> end(const optional_year& current_year = none) const {
|
||||
if (range_end) {
|
||||
if (end_inclusive)
|
||||
return range_end->end(current_year);
|
||||
else
|
||||
return range_end->begin(current_year);
|
||||
} else {
|
||||
return none;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_within(const date_t& date,
|
||||
const optional_year& current_year = none) const {
|
||||
optional<date_t> b = begin(current_year);
|
||||
optional<date_t> e = end(current_year);
|
||||
bool after_begin = b ? date >= *b : true;
|
||||
bool before_end = e ? date < *e : true;
|
||||
return after_begin && before_end;
|
||||
}
|
||||
|
||||
string to_string() const {
|
||||
std::ostringstream out;
|
||||
|
||||
if (range_begin)
|
||||
out << "from" << range_begin->to_string();
|
||||
if (range_end)
|
||||
out << " to" << range_end->to_string();
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
#if defined(HAVE_BOOST_SERIALIZATION)
|
||||
private:
|
||||
/** Serialization. */
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive& ar, const unsigned int /* version */) {
|
||||
ar & range_begin;
|
||||
ar & range_end;
|
||||
ar & end_inclusive;
|
||||
}
|
||||
#endif // HAVE_BOOST_SERIALIZATION
|
||||
};
|
||||
|
||||
class date_specifier_or_range_t
|
||||
{
|
||||
typedef variant<int, date_specifier_t, date_range_t> value_type;
|
||||
|
||||
value_type specifier_or_range;
|
||||
|
||||
public:
|
||||
date_specifier_or_range_t() {
|
||||
TRACE_CTOR(date_specifier_or_range_t, "");
|
||||
}
|
||||
date_specifier_or_range_t(const date_specifier_or_range_t& other)
|
||||
: specifier_or_range(other.specifier_or_range) {
|
||||
TRACE_CTOR(date_specifier_or_range_t, "copy");
|
||||
}
|
||||
date_specifier_or_range_t(const date_specifier_t& specifier)
|
||||
: specifier_or_range(specifier) {
|
||||
TRACE_CTOR(date_specifier_or_range_t, "date_specifier_t");
|
||||
}
|
||||
date_specifier_or_range_t(const date_range_t& range)
|
||||
: specifier_or_range(range) {
|
||||
TRACE_CTOR(date_specifier_or_range_t, "date_range_t");
|
||||
}
|
||||
~date_specifier_or_range_t() throw() {
|
||||
TRACE_DTOR(date_specifier_or_range_t);
|
||||
}
|
||||
|
||||
optional<date_t> begin(const optional_year& current_year = none) const {
|
||||
if (specifier_or_range.type() == typeid(date_specifier_t))
|
||||
return boost::get<date_specifier_t>(specifier_or_range).begin(current_year);
|
||||
else if (specifier_or_range.type() == typeid(date_range_t))
|
||||
return boost::get<date_range_t>(specifier_or_range).begin(current_year);
|
||||
else
|
||||
return none;
|
||||
}
|
||||
optional<date_t> end(const optional_year& current_year = none) const {
|
||||
if (specifier_or_range.type() == typeid(date_specifier_t))
|
||||
return boost::get<date_specifier_t>(specifier_or_range).end(current_year);
|
||||
else if (specifier_or_range.type() == typeid(date_range_t))
|
||||
return boost::get<date_range_t>(specifier_or_range).end(current_year);
|
||||
else
|
||||
return none;
|
||||
}
|
||||
|
||||
|
||||
string to_string() const {
|
||||
std::ostringstream out;
|
||||
|
||||
if (specifier_or_range.type() == typeid(date_specifier_t))
|
||||
out << "in" << boost::get<date_specifier_t>(specifier_or_range).to_string();
|
||||
else if (specifier_or_range.type() == typeid(date_range_t))
|
||||
out << boost::get<date_range_t>(specifier_or_range).to_string();
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
#if defined(HAVE_BOOST_SERIALIZATION)
|
||||
private:
|
||||
/** Serialization. */
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive& ar, const unsigned int /* version */) {
|
||||
ar & specifier_or_range;
|
||||
}
|
||||
#endif // HAVE_BOOST_SERIALIZATION
|
||||
};
|
||||
|
||||
class date_interval_t : public equality_comparable<date_interval_t>
|
||||
{
|
||||
public:
|
||||
struct duration_t
|
||||
{
|
||||
enum skip_quantum_t {
|
||||
DAYS, WEEKS, MONTHS, YEARS
|
||||
} quantum;
|
||||
int length;
|
||||
static date_t add_duration(const date_t& date,
|
||||
const date_duration_t& duration);
|
||||
static date_t subtract_duration(const date_t& date,
|
||||
const date_duration_t& duration);
|
||||
|
||||
duration_t() : quantum(DAYS), length(0) {
|
||||
TRACE_CTOR(date_interval_t::duration_t, "");
|
||||
}
|
||||
duration_t(skip_quantum_t _quantum, int _length)
|
||||
: quantum(_quantum), length(_length) {
|
||||
TRACE_CTOR(date_interval_t::duration_t, "skip_quantum_t, int");
|
||||
}
|
||||
duration_t(const duration_t& dur)
|
||||
: quantum(dur.quantum), length(dur.length) {
|
||||
TRACE_CTOR(date_interval_t::duration_t, "copy");
|
||||
}
|
||||
~duration_t() throw() {
|
||||
TRACE_DTOR(date_interval_t::duration_t);
|
||||
}
|
||||
optional<date_specifier_or_range_t> range;
|
||||
|
||||
date_t add(const date_t& date) const {
|
||||
switch (quantum) {
|
||||
case DAYS:
|
||||
return date + gregorian::days(length);
|
||||
case WEEKS:
|
||||
return date + gregorian::weeks(length);
|
||||
case MONTHS:
|
||||
return date + gregorian::months(length);
|
||||
case YEARS:
|
||||
return date + gregorian::years(length);
|
||||
default:
|
||||
assert(false); return date_t();
|
||||
}
|
||||
}
|
||||
optional<date_t> start; // the real start, after adjustment
|
||||
optional<date_t> finish; // the real end, likewise
|
||||
bool aligned;
|
||||
optional<date_t> next;
|
||||
optional<date_duration_t> duration;
|
||||
optional<date_t> end_of_duration;
|
||||
|
||||
date_t subtract(const date_t& date) const {
|
||||
switch (quantum) {
|
||||
case DAYS:
|
||||
return date - gregorian::days(length);
|
||||
case WEEKS:
|
||||
return date - gregorian::weeks(length);
|
||||
case MONTHS:
|
||||
return date - gregorian::months(length);
|
||||
case YEARS:
|
||||
return date - gregorian::years(length);
|
||||
default:
|
||||
assert(false); return date_t();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_BOOST_SERIALIZATION)
|
||||
private:
|
||||
/** Serialization. */
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive& ar, const unsigned int /* version */) {
|
||||
ar & quantum;
|
||||
ar & length;
|
||||
}
|
||||
#endif // HAVE_BOOST_SERIALIZATION
|
||||
};
|
||||
|
||||
static date_t add_duration(const date_t& date,
|
||||
const duration_t& duration);
|
||||
static date_t subtract_duration(const date_t& date,
|
||||
const duration_t& duration);
|
||||
|
||||
optional<date_t> start;
|
||||
bool aligned;
|
||||
optional<duration_t> skip_duration;
|
||||
std::size_t factor;
|
||||
optional<date_t> next;
|
||||
optional<duration_t> duration;
|
||||
optional<date_t> end_of_duration;
|
||||
optional<date_t> end;
|
||||
|
||||
explicit date_interval_t() : aligned(false), factor(1) {
|
||||
explicit date_interval_t() : aligned(false) {
|
||||
TRACE_CTOR(date_interval_t, "");
|
||||
}
|
||||
date_interval_t(const string& str) : aligned(false), factor(1) {
|
||||
date_interval_t(const string& str) : aligned(false) {
|
||||
TRACE_CTOR(date_interval_t, "const string&");
|
||||
parse(str);
|
||||
}
|
||||
date_interval_t(const date_interval_t& other)
|
||||
: start(other.start),
|
||||
: range(other.range),
|
||||
start(other.start),
|
||||
finish(other.finish),
|
||||
aligned(other.aligned),
|
||||
skip_duration(other.skip_duration),
|
||||
factor(other.factor),
|
||||
next(other.next),
|
||||
duration(other.duration),
|
||||
end_of_duration(other.end_of_duration),
|
||||
end(other.end) {
|
||||
end_of_duration(other.end_of_duration) {
|
||||
TRACE_CTOR(date_interval_t, "copy");
|
||||
}
|
||||
~date_interval_t() throw() {
|
||||
|
|
@ -252,17 +569,19 @@ public:
|
|||
return is_valid();
|
||||
}
|
||||
|
||||
void parse(std::istream& in);
|
||||
|
||||
void parse(const string& str) {
|
||||
std::istringstream in(str);
|
||||
parse(in);
|
||||
optional<date_t> begin(const optional_year& current_year = none) const {
|
||||
return start ? start : (range ? range->begin(current_year) : none);
|
||||
}
|
||||
optional<date_t> end(const optional_year& current_year = none) const {
|
||||
return finish ? finish : (range ? range->end(current_year) : none);
|
||||
}
|
||||
|
||||
void resolve_end();
|
||||
void stabilize(const optional<date_t>& date = none);
|
||||
void parse(const string& str);
|
||||
|
||||
bool is_valid() const {
|
||||
void resolve_end();
|
||||
void stabilize(const optional<date_t>& date = none);
|
||||
|
||||
bool is_valid() const {
|
||||
return start;
|
||||
}
|
||||
|
||||
|
|
@ -280,6 +599,8 @@ public:
|
|||
|
||||
date_interval_t& operator++();
|
||||
|
||||
void dump(std::ostream& out, optional_year current_year = none);
|
||||
|
||||
#if defined(HAVE_BOOST_SERIALIZATION)
|
||||
private:
|
||||
/** Serialization. */
|
||||
|
|
@ -288,14 +609,13 @@ private:
|
|||
|
||||
template<class Archive>
|
||||
void serialize(Archive& ar, const unsigned int /* version */) {
|
||||
ar & range;
|
||||
ar & start;
|
||||
ar & finish;
|
||||
ar & aligned;
|
||||
ar & skip_duration;
|
||||
ar & factor;
|
||||
ar & next;
|
||||
ar & duration;
|
||||
ar & end_of_duration;
|
||||
ar & end;
|
||||
}
|
||||
#endif // HAVE_BOOST_SERIALIZATION
|
||||
};
|
||||
|
|
@ -303,8 +623,9 @@ private:
|
|||
void times_initialize();
|
||||
void times_shutdown();
|
||||
|
||||
std::ostream& operator<<(std::ostream& out,
|
||||
const date_interval_t::duration_t& duration);
|
||||
void show_period_tokens(std::ostream& out, const string& arg);
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const date_duration_t& duration);
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
|
|
|
|||
|
|
@ -206,11 +206,12 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags)
|
|||
length++;
|
||||
|
||||
date_interval_t timespan(buf);
|
||||
if (! timespan)
|
||||
optional<date_t> begin = timespan.begin();
|
||||
if (! begin)
|
||||
throw_(parse_error,
|
||||
_("Date specifier does not refer to a starting date"));
|
||||
kind = VALUE;
|
||||
value = *timespan.start;
|
||||
value = *begin;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -194,6 +194,11 @@ public:
|
|||
string(const string& str);
|
||||
string(const std::string& str);
|
||||
string(size_type len, char x);
|
||||
template<class _InputIterator>
|
||||
string(_InputIterator __beg, _InputIterator __end)
|
||||
: std::string(__beg, __end) {
|
||||
TRACE_CTOR(string, "InputIterator, InputIterator");
|
||||
}
|
||||
string(const char * str);
|
||||
string(const char * str, const char * end);
|
||||
string(const string& str, size_type x);
|
||||
|
|
|
|||
36
src/value.cc
36
src/value.cc
|
|
@ -338,10 +338,13 @@ value_t& value_t::operator+=(const value_t& val)
|
|||
case DATETIME:
|
||||
switch (val.type()) {
|
||||
case INTEGER:
|
||||
as_datetime_lval() += date_duration(val.as_long());
|
||||
as_datetime_lval() +=
|
||||
time_duration_t(0, 0, static_cast<time_duration_t::sec_type>(val.as_long()));
|
||||
return *this;
|
||||
case AMOUNT:
|
||||
as_datetime_lval() += date_duration(val.as_amount().to_long());
|
||||
as_datetime_lval() +=
|
||||
time_duration_t(0, 0, static_cast<time_duration_t::sec_type>
|
||||
(val.as_amount().to_long()));
|
||||
return *this;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -351,10 +354,10 @@ value_t& value_t::operator+=(const value_t& val)
|
|||
case DATE:
|
||||
switch (val.type()) {
|
||||
case INTEGER:
|
||||
as_date_lval() += date_duration_t(val.as_long());
|
||||
as_date_lval() += gregorian::date_duration(val.as_long());
|
||||
return *this;
|
||||
case AMOUNT:
|
||||
as_date_lval() += date_duration_t(val.as_amount().to_long());
|
||||
as_date_lval() += gregorian::date_duration(val.as_amount().to_long());
|
||||
return *this;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -466,10 +469,13 @@ value_t& value_t::operator-=(const value_t& val)
|
|||
case DATETIME:
|
||||
switch (val.type()) {
|
||||
case INTEGER:
|
||||
as_datetime_lval() -= date_duration(val.as_long());
|
||||
as_datetime_lval() -=
|
||||
time_duration_t(0, 0, static_cast<time_duration_t::sec_type>(val.as_long()));
|
||||
return *this;
|
||||
case AMOUNT:
|
||||
as_datetime_lval() -= date_duration(val.as_amount().to_long());
|
||||
as_datetime_lval() -=
|
||||
time_duration_t(0, 0, static_cast<time_duration_t::sec_type>
|
||||
(val.as_amount().to_long()));
|
||||
return *this;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -479,10 +485,10 @@ value_t& value_t::operator-=(const value_t& val)
|
|||
case DATE:
|
||||
switch (val.type()) {
|
||||
case INTEGER:
|
||||
as_date_lval() -= date_duration_t(val.as_long());
|
||||
as_date_lval() -= gregorian::date_duration(val.as_long());
|
||||
return *this;
|
||||
case AMOUNT:
|
||||
as_date_lval() -= date_duration_t(val.as_amount().to_long());
|
||||
as_date_lval() -= gregorian::date_duration(val.as_amount().to_long());
|
||||
return *this;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -1187,6 +1193,13 @@ void value_t::in_place_negate()
|
|||
case BALANCE:
|
||||
as_balance_lval().in_place_negate();
|
||||
return;
|
||||
case SEQUENCE: {
|
||||
value_t temp;
|
||||
foreach (const value_t& value, as_sequence())
|
||||
temp.push_back(- value);
|
||||
*this = temp;
|
||||
return;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1216,6 +1229,13 @@ void value_t::in_place_not()
|
|||
case STRING:
|
||||
set_boolean(as_string().empty());
|
||||
return;
|
||||
case SEQUENCE: {
|
||||
value_t temp;
|
||||
foreach (const value_t& value, as_sequence())
|
||||
temp.push_back(! value);
|
||||
*this = temp;
|
||||
return;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
20
test/baseline/opt-unrealized.test
Normal file
20
test/baseline/opt-unrealized.test
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
bal -V --unrealized
|
||||
<<<
|
||||
2008/10/01 Sample
|
||||
Assets:Brokerage 10 AAPL
|
||||
Assets:Checking $-200.00
|
||||
|
||||
P 2008/10/20 12:00:00 AAPL $30.00
|
||||
|
||||
; 2008/10/20 <Generated Transaction>
|
||||
; Assets:Brokerage $100
|
||||
; Equity:Unrealized Gains
|
||||
>>>1
|
||||
$100.00 Assets
|
||||
$300.00 Brokerage
|
||||
$-200.00 Checking
|
||||
$-100.00 Equity:Unrealized Gains
|
||||
--------------------
|
||||
0
|
||||
>>>2
|
||||
=== 0
|
||||
|
|
@ -1,50 +1,95 @@
|
|||
period --now=2010/11/01 12/01
|
||||
<<<
|
||||
>>>1
|
||||
global details =>
|
||||
--- Period expression tokens ---
|
||||
TOK_DATE: month Dec day 1
|
||||
END_REACHED: <EOF>
|
||||
|
||||
start: 09-Dec-01
|
||||
end: 09-Dec-02
|
||||
factor: 1
|
||||
--- Before stabilization ---
|
||||
range: in month Dec day 1
|
||||
|
||||
--- After stabilization ---
|
||||
range: in month Dec day 1
|
||||
start: 10-Dec-01
|
||||
finish: 10-Dec-02
|
||||
|
||||
--- Sample dates in range (max. 20) ---
|
||||
1: 10-Dec-01
|
||||
>>>2
|
||||
=== 0
|
||||
period --now=2010/11/01 10/01
|
||||
<<<
|
||||
>>>1
|
||||
global details =>
|
||||
--- Period expression tokens ---
|
||||
TOK_DATE: month Oct day 1
|
||||
END_REACHED: <EOF>
|
||||
|
||||
--- Before stabilization ---
|
||||
range: in month Oct day 1
|
||||
|
||||
--- After stabilization ---
|
||||
range: in month Oct day 1
|
||||
start: 10-Oct-01
|
||||
end: 10-Oct-02
|
||||
factor: 1
|
||||
finish: 10-Oct-02
|
||||
|
||||
--- Sample dates in range (max. 20) ---
|
||||
1: 10-Oct-01
|
||||
>>>2
|
||||
=== 0
|
||||
period --now=2010/11/01 2009/10
|
||||
<<<
|
||||
>>>1
|
||||
global details =>
|
||||
--- Period expression tokens ---
|
||||
TOK_DATE: year 2009 month Oct
|
||||
END_REACHED: <EOF>
|
||||
|
||||
--- Before stabilization ---
|
||||
range: in year 2009 month Oct
|
||||
|
||||
--- After stabilization ---
|
||||
range: in year 2009 month Oct
|
||||
start: 09-Oct-01
|
||||
end: 09-Nov-01
|
||||
factor: 1
|
||||
finish: 09-Nov-01
|
||||
|
||||
--- Sample dates in range (max. 20) ---
|
||||
1: 09-Oct-01
|
||||
>>>2
|
||||
=== 0
|
||||
period --now=2010/11/01 2009/10/01
|
||||
<<<
|
||||
>>>1
|
||||
global details =>
|
||||
--- Period expression tokens ---
|
||||
TOK_DATE: year 2009 month Oct day 1
|
||||
END_REACHED: <EOF>
|
||||
|
||||
--- Before stabilization ---
|
||||
range: in year 2009 month Oct day 1
|
||||
|
||||
--- After stabilization ---
|
||||
range: in year 2009 month Oct day 1
|
||||
start: 09-Oct-01
|
||||
end: 09-Oct-02
|
||||
factor: 1
|
||||
finish: 09-Oct-02
|
||||
|
||||
--- Sample dates in range (max. 20) ---
|
||||
1: 09-Oct-01
|
||||
>>>2
|
||||
=== 0
|
||||
period --now=2010/11/01 2009
|
||||
<<<
|
||||
>>>1
|
||||
global details =>
|
||||
--- Period expression tokens ---
|
||||
TOK_A_YEAR: 2009
|
||||
END_REACHED: <EOF>
|
||||
|
||||
--- Before stabilization ---
|
||||
range: in year 2009
|
||||
|
||||
--- After stabilization ---
|
||||
range: in year 2009
|
||||
start: 09-Jan-01
|
||||
end: 10-Jan-01
|
||||
factor: 1
|
||||
finish: 10-Jan-01
|
||||
|
||||
--- Sample dates in range (max. 20) ---
|
||||
1: 09-Jan-01
|
||||
>>>2
|
||||
=== 0
|
||||
|
|
|
|||
|
|
@ -1,10 +1,20 @@
|
|||
period june 2008
|
||||
<<<
|
||||
>>>1
|
||||
global details =>
|
||||
--- Period expression tokens ---
|
||||
TOK_A_MONTH: Jun
|
||||
TOK_A_YEAR: 2008
|
||||
END_REACHED: <EOF>
|
||||
|
||||
--- Before stabilization ---
|
||||
range: in year 2008 month Jun
|
||||
|
||||
--- After stabilization ---
|
||||
range: in year 2008 month Jun
|
||||
start: 08-Jun-01
|
||||
end: 08-Jul-01
|
||||
factor: 1
|
||||
finish: 08-Jul-01
|
||||
|
||||
--- Sample dates in range (max. 20) ---
|
||||
1: 08-Jun-01
|
||||
>>>2
|
||||
=== 0
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue