summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2005-10-19 22:42:24 +0000
committerJohn Wiegley <johnw@newartisans.com>2008-04-13 02:41:19 -0400
commiteb0525e3157b579d45aab568e3ee06432fbaa338 (patch)
tree308ada59d939b363afd3791ef5f26406cedcebe1
parenta53f44ecdaf9051c9e7f64993787c88d98b5348a (diff)
downloadfork-ledger-eb0525e3157b579d45aab568e3ee06432fbaa338.tar.gz
fork-ledger-eb0525e3157b579d45aab568e3ee06432fbaa338.tar.bz2
fork-ledger-eb0525e3157b579d45aab568e3ee06432fbaa338.zip
See ChangeLog
-rw-r--r--NEWS81
-rw-r--r--binary.cc16
-rw-r--r--config.cc8
-rw-r--r--derive.cc2
-rw-r--r--emacs.cc4
-rw-r--r--format.cc63
-rw-r--r--format.h10
-rw-r--r--gnucash.cc2
-rw-r--r--journal.cc27
-rw-r--r--journal.h40
-rw-r--r--ledger.texi38
-rw-r--r--qif.cc2
-rw-r--r--reconcile.cc2
-rw-r--r--textual.cc32
-rw-r--r--valexpr.cc9
-rw-r--r--walk.cc38
-rw-r--r--walk.h3
-rw-r--r--xml.cc24
18 files changed, 331 insertions, 70 deletions
diff --git a/NEWS b/NEWS
index 350a6c42..76d52503 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,86 @@
Ledger NEWS
+* 2.5
+
+- Effective dates may now be specified for entries:
+
+ 2004/10/03=2004/09/30 Credit card company
+ Liabilities:MasterCard $100.00
+ Assets:Checking
+
+ This entry says that although the actual transactions occurred on
+ October 3rd, their effective date was September 30th. This is
+ especially useful for budgeting, in case you want the transactions
+ to show up in September instead of October.
+
+ To report using effective dates, use the --effective option.
+
+- Actual and effective dates may now be specified for individual
+ transactions:
+
+ 2004/10/03=2004/09/30 Credit card company
+ Liabilities:MasterCard $100.00
+ Assets:Checking ; [2004/10/10=2004/09/15]
+
+ This states that although the actual date of the entry is
+ 2004/10/03, and the effective date of the entry is 2004/09/30, the
+ actual date of the Checking transaction itself is 2004/10/10, and
+ its effective date is 2004/09/15. The effective date is optional
+ (just specifying the actual date would have read "[2004/10/10]").
+
+ If no effective date is given for a transaction, the effective date
+ of the entry is assumed. If no actual date is given, the actual
+ date of the entry is assumed. The syntax of the latter is simply
+ [=2004/09/15].
+
+- To support the above, there is a new formatting option: "%d". This
+ outputs only the date (like "%D") if there is no effective date, but
+ outputs "ADATE=EDATE" if there is one. The "print" report now uses
+ this.
+
+- To support the above, the register report may now split up entries
+ whose component transactions have different dates. For example,
+ given the following entry:
+
+ 2005/10/15=2005/09/01 iTunes
+ Expenses:Music $1.08 ; [2005/10/20=2005/08/01]
+ Liabilities:MasterCard
+
+ The command "ledger register" on this data file reports:
+
+ 2005/10/20 iTunes Expenses:Music $1.08 $1.08
+ 2005/10/15 iTunes Liabilities:MasterCard $-1.08 0
+
+ The command "ledger --effective register" reports:
+
+ 2005/08/01 iTunes Expenses:Music $1.08 $1.08
+ 2005/09/01 iTunes Liabilities:MasterCard $-1.08 0
+
+ Although it appears as though two entries are being reported, both
+ transactions belong to the same entry.
+
+- Individual transactions may now be cleared separately. The old
+ syntax, which is still supported, clears all transactions in an
+ entry:
+
+ 2004/05/27 * Book Store
+ Expenses:Dining $20.00
+ Liabilities:MasterCard
+
+ The new (and optional) syntax allows clearing just the MasterCard
+ transaction:
+
+ 2004/05/27 Book Store
+ Expenses:Dining $20.00
+ * Liabilities:MasterCard
+
+ NOTE: This changes the output format of the "emacs" and "xml"
+ reports. ledger.el will use the new syntax unless the Lisp variable
+ `ledger-clear-whole-entries' is set to t.
+
+- Added a new value expression regexp command:
+ C// compare against transaction amount's commodity symbol
+
* 2.4
- Both "-$100.00" and "$-100.00" are now equivalent amounts.
diff --git a/binary.cc b/binary.cc
index 2a573f8f..119b1ec5 100644
--- a/binary.cc
+++ b/binary.cc
@@ -11,7 +11,7 @@
namespace ledger {
static unsigned long binary_magic_number = 0xFFEED765;
-static unsigned long format_version = 0x00020042;
+static unsigned long format_version = 0x00020044;
static account_t ** accounts;
static account_t ** accounts_next;
@@ -178,8 +178,9 @@ inline void read_binary_amount(char *& data, amount_t& amt)
inline void read_binary_transaction(char *& data, transaction_t * xact)
{
+ read_binary_number(data, xact->_date);
+ read_binary_number(data, xact->_date_eff);
xact->account = accounts[read_binary_number<account_t::ident_t>(data) - 1];
-
read_binary_amount(data, xact->amount);
if (*data++ == 1) {
@@ -188,6 +189,7 @@ inline void read_binary_transaction(char *& data, transaction_t * xact)
} else {
xact->cost = NULL;
}
+
read_binary_number(data, xact->state);
read_binary_number(data, xact->flags);
xact->flags |= TRANSACTION_BULK_ALLOC;
@@ -218,7 +220,8 @@ inline void read_binary_entry(char *& data, entry_t * entry,
transaction_t *& xact_pool)
{
read_binary_entry_base(data, entry, xact_pool);
- read_binary_number(data, entry->date);
+ read_binary_number(data, entry->_date);
+ read_binary_number(data, entry->_date_eff);
read_binary_string(data, &entry->code);
read_binary_string(data, &entry->payee);
}
@@ -540,14 +543,18 @@ void write_binary_amount(std::ostream& out, const amount_t& amt)
void write_binary_transaction(std::ostream& out, transaction_t * xact)
{
+ write_binary_number(out, xact->_date);
+ write_binary_number(out, xact->_date_eff);
write_binary_number(out, xact->account->ident);
write_binary_amount(out, xact->amount);
+
if (xact->cost) {
write_binary_number<char>(out, 1);
write_binary_amount(out, *xact->cost);
} else {
write_binary_number<char>(out, 0);
}
+
write_binary_number(out, xact->state);
write_binary_number(out, xact->flags);
write_binary_string(out, xact->note);
@@ -571,7 +578,8 @@ void write_binary_entry_base(std::ostream& out, entry_base_t * entry)
void write_binary_entry(std::ostream& out, entry_t * entry)
{
write_binary_entry_base(out, entry);
- write_binary_number(out, entry->date);
+ write_binary_number(out, entry->_date);
+ write_binary_number(out, entry->_date_eff);
write_binary_string(out, entry->code);
write_binary_string(out, entry->payee);
}
diff --git a/config.cc b/config.cc
index 9bebfa7c..7dfcc2fc 100644
--- a/config.cc
+++ b/config.cc
@@ -36,8 +36,8 @@ config_t::config_t()
"%48|%-.38A %22.108t %22.132T\n");
plot_amount_format = "%D %(St)\n";
plot_total_format = "%D %(ST)\n";
- print_format = "\n%D %Y%C%P\n %-34W %12o%n\n%/ %-34W %12o%n\n";
- write_hdr_format = "%D %Y%C%P\n";
+ print_format = "\n%d %Y%C%P\n %-34W %12o%n\n%/ %-34W %12o%n\n";
+ write_hdr_format = "%d %Y%C%P\n";
write_xact_format = " %-34W %12o%n\n";
equity_format = "\n%D %Y%C%P\n%/ %-34W %12t\n";
#ifndef USE_BOOST_PYTHON
@@ -714,6 +714,10 @@ OPT_BEGIN(plot_amount_format, ":") {
OPT_BEGIN(plot_total_format, ":") {
config.plot_total_format = optarg;
+
+OPT_BEGIN(effective, "") {
+ transaction_t::use_effective_date = true;
+} OPT_END(effective);
} OPT_END(plot_total_format);
OPT_BEGIN(print_format, ":") {
diff --git a/derive.cc b/derive.cc
index 5141c18e..402eef8a 100644
--- a/derive.cc
+++ b/derive.cc
@@ -15,7 +15,7 @@ entry_t * derive_new_entry(journal_t& journal,
entry_t * matching = NULL;
- if (! parse_date((*i).c_str(), &added->date))
+ if (! parse_date((*i).c_str(), &added->_date))
throw error("Bad date passed to 'entry'");
if (++i == end)
diff --git a/emacs.cc b/emacs.cc
index d4e9c1f5..1a6b02a0 100644
--- a/emacs.cc
+++ b/emacs.cc
@@ -15,8 +15,8 @@ void format_emacs_transactions::write_entry(entry_t& entry)
out << (((unsigned long)entry.beg_pos) + 1) << " ";
- out << "(" << (entry.date / 65536) << " "
- << (entry.date % 65536) << " 0) ";
+ std::time_t date = entry.date();
+ out << "(" << (date / 65536) << " " << (date % 65536) << " 0) ";
if (entry.code.empty())
out << "nil ";
diff --git a/format.cc b/format.cc
index f31289e4..050d3322 100644
--- a/format.cc
+++ b/format.cc
@@ -206,6 +206,10 @@ element_t * format_t::parse_elements(const std::string& fmt)
break;
}
+ case 'd':
+ current->type = element_t::COMPLETE_DATE_STRING;
+ current->chars = format_t::date_format;
+ break;
case 'D':
current->type = element_t::DATE_STRING;
current->chars = format_t::date_format;
@@ -420,16 +424,51 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
out << details.entry->end_line;
break;
- case element_t::DATE_STRING:
- if (details.entry && details.entry->date) {
- char buf[256];
- std::strftime(buf, 255, elem->chars.c_str(),
- std::localtime(&details.entry->date));
+ case element_t::DATE_STRING: {
+ std::time_t date = 0;
+ if (details.xact)
+ date = details.xact->date();
+ else if (details.entry)
+ date = details.entry->date();
+
+ char buf[256];
+ std::strftime(buf, 255, elem->chars.c_str(), std::localtime(&date));
+ out << (elem->max_width == 0 ? buf : truncated(buf, elem->max_width));
+ break;
+ }
+
+ case element_t::COMPLETE_DATE_STRING: {
+ std::time_t actual_date = 0;
+ std::time_t effective_date = 0;
+ if (details.xact) {
+ actual_date = details.xact->actual_date();
+ effective_date = details.xact->effective_date();
+ }
+ else if (details.entry) {
+ actual_date = details.entry->actual_date();
+ effective_date = details.entry->effective_date();
+ }
+
+ char abuf[256];
+ std::strftime(abuf, 255, elem->chars.c_str(),
+ std::localtime(&actual_date));
+
+ if (effective_date) {
+ char buf[512];
+ char ebuf[256];
+ std::strftime(ebuf, 255, elem->chars.c_str(),
+ std::localtime(&effective_date));
+
+ std::strcpy(buf, abuf);
+ std::strcat(buf, "=");
+ std::strcat(buf, ebuf);
+
out << (elem->max_width == 0 ? buf : truncated(buf, elem->max_width));
} else {
- out << " ";
+ out << (elem->max_width == 0 ? abuf : truncated(abuf, elem->max_width));
}
break;
+ }
case element_t::CLEARED:
if (details.xact) {
@@ -575,7 +614,7 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
format_transactions::format_transactions(std::ostream& _output_stream,
const std::string& format)
- : output_stream(_output_stream), last_entry(NULL)
+ : output_stream(_output_stream), last_entry(NULL), last_xact(NULL)
{
const char * f = format.c_str();
if (const char * p = std::strstr(f, "%/")) {
@@ -594,10 +633,16 @@ void format_transactions::operator()(transaction_t& xact)
if (last_entry != xact.entry) {
first_line_format.format(output_stream, details_t(xact));
last_entry = xact.entry;
- } else {
+ }
+ else if (last_xact->date() != xact.date()) {
+ first_line_format.format(output_stream, details_t(xact));
+ }
+ else {
next_lines_format.format(output_stream, details_t(xact));
}
+
transaction_xdata(xact).dflags |= TRANSACTION_DISPLAYED;
+ last_xact = &xact;
}
}
@@ -729,7 +774,7 @@ format_equity::format_equity(std::ostream& _output_stream,
entry_t header_entry;
header_entry.payee = "Opening Balances";
- header_entry.date = now;
+ header_entry._date = now;
first_line_format.format(output_stream, details_t(header_entry));
}
diff --git a/format.h b/format.h
index d2975141..3d2439bf 100644
--- a/format.h
+++ b/format.h
@@ -24,6 +24,7 @@ struct element_t
END_POS,
END_LINE,
DATE_STRING,
+ COMPLETE_DATE_STRING,
CLEARED,
ENTRY_CLEARED,
CODE,
@@ -97,10 +98,11 @@ struct format_t
class format_transactions : public item_handler<transaction_t>
{
protected:
- std::ostream& output_stream;
- format_t first_line_format;
- format_t next_lines_format;
- entry_t * last_entry;
+ std::ostream& output_stream;
+ format_t first_line_format;
+ format_t next_lines_format;
+ entry_t * last_entry;
+ transaction_t * last_xact;
public:
format_transactions(std::ostream& _output_stream,
diff --git a/gnucash.cc b/gnucash.cc
index 45c0e0dc..665f555f 100644
--- a/gnucash.cc
+++ b/gnucash.cc
@@ -236,7 +236,7 @@ static void dataHandler(void *userData, const char *s, int len)
case ENTRY_DATE: {
struct tm when;
strptime(std::string(s, len).c_str(), "%Y-%m-%d %H:%M:%S %z", &when);
- curr_entry->date = std::mktime(&when);
+ curr_entry->_date = std::mktime(&when);
break;
}
diff --git a/journal.cc b/journal.cc
index 8310b431..67cd7f57 100644
--- a/journal.cc
+++ b/journal.cc
@@ -14,6 +14,26 @@ namespace ledger {
const std::string version = PACKAGE_VERSION;
+bool transaction_t::use_effective_date = false;
+
+std::time_t transaction_t::actual_date() const
+{
+ if (_date == 0) {
+ assert(entry);
+ return entry->actual_date();
+ }
+ return _date;
+}
+
+std::time_t transaction_t::effective_date() const
+{
+ if (_date_eff == 0) {
+ assert(entry);
+ return entry->effective_date();
+ }
+ return _date_eff;
+}
+
bool transaction_t::valid() const
{
if (! entry)
@@ -201,7 +221,8 @@ bool entry_base_t::finalize()
}
entry_t::entry_t(const entry_t& e)
- : entry_base_t(e), date(e.date), code(e.code), payee(e.payee)
+ : entry_base_t(e), _date(e._date), _date_eff(e._date_eff),
+ code(e.code), payee(e.payee)
{
DEBUG_PRINT("ledger.memory.ctors", "ctor entry_t");
@@ -219,7 +240,7 @@ void entry_t::add_transaction(transaction_t * xact)
bool entry_t::valid() const
{
- if (! date || ! journal)
+ if (! _date || ! journal)
return false;
for (transactions_list::const_iterator i = transactions.begin();
@@ -459,7 +480,7 @@ bool journal_t::add_entry(entry_t * entry)
i != entry->transactions.end();
i++)
if ((*i)->cost && (*i)->amount)
- (*i)->amount.commodity().add_price(entry->date,
+ (*i)->amount.commodity().add_price(entry->date(),
*(*i)->cost / (*i)->amount);
return true;
diff --git a/journal.h b/journal.h
index b34accc3..a0416079 100644
--- a/journal.h
+++ b/journal.h
@@ -32,6 +32,8 @@ class transaction_t
enum state_t { UNCLEARED, CLEARED, PENDING };
entry_t * entry;
+ std::time_t _date;
+ std::time_t _date_eff;
account_t * account;
amount_t amount;
amount_t * cost;
@@ -40,8 +42,10 @@ class transaction_t
std::string note;
mutable void * data;
+ static bool use_effective_date;
+
transaction_t(account_t * _account = NULL)
- : entry(NULL), account(_account), cost(NULL),
+ : entry(NULL), _date(0), account(_account), cost(NULL),
state(UNCLEARED), flags(TRANSACTION_NORMAL), data(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
}
@@ -50,14 +54,15 @@ class transaction_t
const amount_t& _amount,
unsigned int _flags = TRANSACTION_NORMAL,
const std::string& _note = "")
- : entry(NULL), account(_account), amount(_amount),
+ : entry(NULL), _date(0), account(_account), amount(_amount),
cost(NULL), state(UNCLEARED), flags(_flags),
note(_note), data(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
}
transaction_t(const transaction_t& xact)
- : entry(xact.entry), account(xact.account), amount(xact.amount),
+ : entry(xact.entry), _date(0), account(xact.account),
+ amount(xact.amount),
cost(xact.cost ? new amount_t(*xact.cost) : NULL),
state(xact.state), flags(xact.flags), note(xact.note),
data(NULL) {
@@ -70,6 +75,15 @@ class transaction_t
delete cost;
}
+ std::time_t actual_date() const;
+ std::time_t effective_date() const;
+ std::time_t date() const {
+ if (use_effective_date)
+ return effective_date();
+ else
+ return actual_date();
+ }
+
bool operator==(const transaction_t& xact) {
return this == &xact;
}
@@ -133,11 +147,12 @@ class entry_base_t
class entry_t : public entry_base_t
{
public:
- std::time_t date;
+ std::time_t _date;
+ std::time_t _date_eff;
std::string code;
std::string payee;
- entry_t() : date(0) {
+ entry_t() : _date(0), _date_eff(0) {
DEBUG_PRINT("ledger.memory.ctors", "ctor entry_t");
}
entry_t(const entry_t& e);
@@ -148,6 +163,21 @@ class entry_t : public entry_base_t
}
#endif
+ std::time_t actual_date() const {
+ return _date;
+ }
+ std::time_t effective_date() const {
+ if (_date_eff == 0)
+ return _date;
+ return _date_eff;
+ }
+ std::time_t date() const {
+ if (transaction_t::use_effective_date)
+ return effective_date();
+ else
+ return actual_date();
+ }
+
virtual void add_transaction(transaction_t * xact);
virtual bool valid() const;
diff --git a/ledger.texi b/ledger.texi
index bf756c1a..b8da037a 100644
--- a/ledger.texi
+++ b/ledger.texi
@@ -1983,6 +1983,11 @@ used can be changed at any time with the @option{-y} flag, however.
Using @samp{%D} gives the user more control over the way dates are
output.
+@item d
+This is the same as the @samp{%D} option, unless the entry has an
+effective date, in which case it prints
+@samp{[ACTUAL_DATE=EFFECtIVE_DATE]}.
+
@item X
If a transaction has been cleared, this inserts @samp{*} followed by a
space; otherwise nothing is inserted.
@@ -2369,17 +2374,32 @@ by any number of lines, each beginning with whitespace, to denote the
entry's account transactions. The format of the first line is:
@example
-DATE [*|!] [(CODE)] DESC
+DATE[=EDATE] [*|!] [(CODE)] DESC
+@end example
+
+If @samp{*} appears after the date (with optional effective date), it
+indicates the entry is ``cleared'', which can mean whatever the user
+wants it t omean. If @samp{!} appears after the date, it indicates d
+the entry is ``pending''; i.e., tentatively cleared from the user's
+point of view, but not yet actually cleared. If a @samp{CODE} appears
+in parentheses, it may be used to indicate a check number, or the type
+of the transaction. Following these is the payee, or a description of
+the transaction.
+
+The format of each following transaction is:
+
+@example
+ ACCOUNT AMOUNT [; NOTE]
@end example
-If @samp{*} appears after the date, it indicates that entry is
-``cleared'', meaning it has been seen a bank statement, or otherwise
-verified. If @samp{!} appears after the date, it indicates that the
-entry is ``pending''; i.e., tentatively cleared from the user's point
-of view, but not yet cleared with your financial institution. If a
-@samp{CODE} appears in parentheses, it may be used to indicate a check
-number, or the type of the transaction. Following these is the payee,
-or a description of the transaction.
+The @samp{ACCOUNT} may be surrounded by parentheses if it is a virtual
+transactions, or square brackets if it is a virtual transactions that
+must balance. The @samp{AMOUNT} can be followed by a per-unit
+transaction cost, by specifying @samp{@ AMOUNT}, or a complete
+transaction cost with @samp{@@ AMOUNT}. Lastly, the @samp{NOTE} may
+specify an actual and/or effective date for the transaction by using
+the syntax @samp{[ACTUAL_DATE]} or @samp{[=EFFECTIVE_DATE]} or
+@samp{[ACTUAL_DATE=EFFECtIVE_DATE]}.
@item =
An automated entry. A value expression must appear after the equal
diff --git a/qif.cc b/qif.cc
index cb72de9a..051996f5 100644
--- a/qif.cc
+++ b/qif.cc
@@ -103,7 +103,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
case 'D':
SET_BEG_POS_AND_LINE();
get_line(in);
- if (! parse_date(line, &entry->date))
+ if (! parse_date(line, &entry->_date))
throw parse_error(path, linenum, "Failed to parse date");
break;
diff --git a/reconcile.cc b/reconcile.cc
index 07e2125d..b28718ee 100644
--- a/reconcile.cc
+++ b/reconcile.cc
@@ -44,7 +44,7 @@ void reconcile_transactions::flush()
for (transactions_list::iterator x = xacts.begin();
x != xacts.end();
x++) {
- if (! cutoff || std::difftime((*x)->entry->date, cutoff) < 0) {
+ if (! cutoff || std::difftime((*x)->date(), cutoff) < 0) {
switch ((*x)->state) {
case transaction_t::CLEARED:
cleared_balance += (*x)->amount;
diff --git a/textual.cc b/textual.cc
index 9ff39435..f144bcb3 100644
--- a/textual.cc
+++ b/textual.cc
@@ -205,7 +205,27 @@ transaction_t * parse_transaction(char * line, account_t * account)
if (char * note_str = std::strchr(amount, ';')) {
if (amount == note_str)
amount = NULL;
+
*note_str++ = '\0';
+ note_str = skip_ws(note_str);
+
+ if (char * b = std::strchr(note_str, '['))
+ if (char * e = std::strchr(note_str, ']')) {
+ char buf[256];
+ std::strncpy(buf, b + 1, e - b);
+ buf[e - b] = '\0';
+
+ if (char * p = std::strchr(buf, '=')) {
+ *p++ = '\0';
+ if (! quick_parse_date(p, &xact->_date_eff))
+ throw parse_error(path, linenum,
+ "Failed to parse effective date");
+ }
+
+ if (buf[0] && ! quick_parse_date(buf, &xact->_date))
+ throw parse_error(path, linenum, "Failed to parse date");
+ }
+
xact->note = skip_ws(note_str);
}
@@ -313,7 +333,13 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master,
char * next = next_element(line);
- if (! quick_parse_date(line, &curr->date))
+ if (char * p = std::strchr(line, '=')) {
+ *p++ = '\0';
+ if (! quick_parse_date(p, &curr->_date_eff))
+ throw parse_error(path, linenum, "Failed to parse effective date");
+ }
+
+ if (! quick_parse_date(line, &curr->_date))
throw parse_error(path, linenum, "Failed to parse date");
TIMER_STOP(entry_date);
@@ -439,11 +465,11 @@ static void clock_out_from_timelog(const std::time_t when,
journal_t * journal)
{
std::auto_ptr<entry_t> curr(new entry_t);
- curr->date = when;
+ curr->_date = when;
curr->code = "";
curr->payee = last_desc;
- double diff = std::difftime(curr->date, time_in);
+ double diff = std::difftime(curr->_date, time_in);
char buf[32];
std::sprintf(buf, "%lds", long(diff));
amount_t amt;
diff --git a/valexpr.cc b/valexpr.cc
index f2b369ae..e65ecb26 100644
--- a/valexpr.cc
+++ b/valexpr.cc
@@ -107,12 +107,13 @@ void value_expr_t::compute(value_t& result, const details_t& details) const
if (details.xact && transaction_has_xdata(*details.xact) &&
transaction_xdata_(*details.xact).date)
result = long(transaction_xdata_(*details.xact).date);
+ else if (details.xact)
+ result = long(details.xact->date());
else if (details.entry)
- result = long(details.entry->date);
+ result = long(details.entry->date());
else
result = long(now);
break;
-
case CLEARED:
if (details.xact)
result = details.xact->state == transaction_t::CLEARED;
@@ -292,8 +293,10 @@ void value_expr_t::compute(value_t& result, const details_t& details) const
if (details.xact && transaction_has_xdata(*details.xact) &&
transaction_xdata_(*details.xact).date)
moment = transaction_xdata_(*details.xact).date;
+ else if (details.xact)
+ moment = details.xact->date();
else if (details.entry)
- moment = details.entry->date;
+ moment = details.entry->date();
break;
case CONSTANT_T:
moment = right->constant_t;
diff --git a/walk.cc b/walk.cc
index fe7d6076..679b2f8e 100644
--- a/walk.cc
+++ b/walk.cc
@@ -232,7 +232,7 @@ void collapse_transactions::report_subtotal()
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = last_entry->payee;
- entry.date = last_entry->date;
+ entry._date = last_entry->_date;
handle_value(subtotal, &totals_account, last_entry, 0, xact_temps,
*handler);
@@ -308,7 +308,7 @@ void changed_value_transactions::output_diff(const std::time_t current)
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = "Commodities revalued";
- entry.date = current;
+ entry._date = current;
handle_value(diff, NULL, &entry, TRANSACTION_NO_TOTAL, xact_temps,
*handler);
@@ -321,8 +321,8 @@ void changed_value_transactions::operator()(transaction_t& xact)
std::time_t moment = 0;
if (transaction_has_xdata(*last_xact))
moment = transaction_xdata_(*last_xact).date;
- if (! moment)
- moment = xact.entry->date;
+ else
+ moment = xact.date();
output_diff(moment);
}
@@ -352,7 +352,7 @@ void subtotal_transactions::report_subtotal(const char * spec_fmt)
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = buf;
- entry.date = start;
+ entry._date = start;
for (values_map::iterator i = values.begin();
i != values.end();
@@ -365,10 +365,10 @@ void subtotal_transactions::report_subtotal(const char * spec_fmt)
void subtotal_transactions::operator()(transaction_t& xact)
{
- if (! start || std::difftime(xact.entry->date, start) < 0)
- start = xact.entry->date;
- if (! finish || std::difftime(xact.entry->date, finish) > 0)
- finish = xact.entry->date;
+ if (! start || std::difftime(xact.date(), start) < 0)
+ start = xact.date();
+ if (! finish || std::difftime(xact.date(), finish) > 0)
+ finish = xact.date();
account_t * acct = xact.account;
assert(acct);
@@ -400,7 +400,7 @@ void interval_transactions::report_subtotal(const std::time_t moment)
if (moment)
finish = moment - 86400;
else
- finish = last_xact->entry->date;
+ finish = last_xact->date();
subtotal_transactions::report_subtotal();
@@ -412,7 +412,7 @@ void interval_transactions::report_subtotal(const std::time_t moment)
void interval_transactions::operator()(transaction_t& xact)
{
- const std::time_t date = xact.entry->date;
+ const std::time_t date = xact.date();
if ((interval.begin && std::difftime(date, interval.begin) < 0) ||
(interval.end && std::difftime(date, interval.end) >= 0))
@@ -483,8 +483,8 @@ void by_payee_transactions::operator()(transaction_t& xact)
i = result.first;
}
- if (std::difftime(xact.entry->date, (*i).second->start) > 0)
- (*i).second->start = xact.entry->date;
+ if (std::difftime(xact.date(), (*i).second->start) > 0)
+ (*i).second->start = xact.date();
(*(*i).second)(xact);
}
@@ -493,7 +493,7 @@ void set_comm_as_payee::operator()(transaction_t& xact)
{
entry_temps.push_back(*xact.entry);
entry_t& entry = entry_temps.back();
- entry.date = xact.entry->date;
+ entry._date = xact.date();
entry.code = xact.entry->code;
entry.payee = xact.amount.commodity().symbol;
@@ -569,7 +569,7 @@ void budget_transactions::report_budget_items(const std::time_t moment)
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = "Budget entry";
- entry.date = begin;
+ entry._date = begin;
xact_temps.push_back(xact);
transaction_t& temp = xact_temps.back();
@@ -611,7 +611,7 @@ void budget_transactions::operator()(transaction_t& xact)
handle:
if (xact_in_budget && flags & BUDGET_BUDGETED) {
- report_budget_items(xact.entry->date);
+ report_budget_items(xact.date());
item_handler<transaction_t>::operator()(xact);
}
else if (! xact_in_budget && flags & BUDGET_UNBUDGETED) {
@@ -661,7 +661,7 @@ void forecast_transactions::flush()
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = "Forecast entry";
- entry.date = begin;
+ entry._date = begin;
xact_temps.push_back(xact);
transaction_t& temp = xact_temps.back();
@@ -682,7 +682,7 @@ void forecast_transactions::flush()
transaction_xdata_(temp).dflags & TRANSACTION_MATCHES) {
if (! pred(temp))
break;
- last = temp.entry->date;
+ last = temp.date();
passed.clear();
} else {
bool found = false;
@@ -856,7 +856,7 @@ void walk_commodities(commodities_map& commodities,
for (history_map::iterator j = (*i).second->history->prices.begin();
j != (*i).second->history->prices.end();
j++) {
- entry_temps.back().date = (*j).first;
+ entry_temps.back()._date = (*j).first;
xact_temps.push_back(transaction_t(&acct_temps.back()));
transaction_t& temp = xact_temps.back();
diff --git a/walk.h b/walk.h
index b59195b3..9a37d456 100644
--- a/walk.h
+++ b/walk.h
@@ -500,7 +500,8 @@ class dow_transactions : public subtotal_transactions
virtual void flush();
virtual void operator()(transaction_t& xact) {
- struct std::tm * desc = std::localtime(&xact.entry->date);
+ std::time_t when = xact.date();
+ struct std::tm * desc = std::localtime(&when);
days_of_the_week[desc->tm_wday].push_back(&xact);
}
};
diff --git a/xml.cc b/xml.cc
index 6dea19cf..edfefe83 100644
--- a/xml.cc
+++ b/xml.cc
@@ -83,7 +83,10 @@ static void endElement(void *userData, const char *name)
curr_entry = NULL;
}
else if (std::strcmp(name, "en:date") == 0) {
- quick_parse_date(data.c_str(), &curr_entry->date);
+ quick_parse_date(data.c_str(), &curr_entry->_date);
+ }
+ else if (std::strcmp(name, "en:date_eff") == 0) {
+ quick_parse_date(data.c_str(), &curr_entry->_date_eff);
}
else if (std::strcmp(name, "en:code") == 0) {
curr_entry->code = data;
@@ -331,11 +334,17 @@ void format_xml_entries::format_last_entry()
{
char buf[256];
std::strftime(buf, 255, format_t::date_format.c_str(),
- std::localtime(&last_entry->date));
+ std::localtime(&last_entry->_date));
output_stream << " <entry>\n"
<< " <en:date>" << buf << "</en:date>\n";
+ if (last_entry->_date_eff) {
+ std::strftime(buf, 255, format_t::date_format.c_str(),
+ std::localtime(&last_entry->_date_eff));
+ output_stream << " <en:date_eff>" << buf << "</en:date_eff>\n";
+ }
+
if (! last_entry->code.empty()) {
output_stream << " <en:code>";
output_xml_string(output_stream, last_entry->code);
@@ -361,6 +370,17 @@ void format_xml_entries::format_last_entry()
output_stream << " <transaction>\n";
+ if ((*i)->_date) {
+ std::strftime(buf, 255, format_t::date_format.c_str(),
+ std::localtime(&(*i)->_date));
+ output_stream << " <tr:date>" << buf << "</tr:date>\n";
+ }
+ if ((*i)->_date_eff) {
+ std::strftime(buf, 255, format_t::date_format.c_str(),
+ std::localtime(&(*i)->_date_eff));
+ output_stream << " <tr:date_eff>" << buf << "</tr:date_eff>\n";
+ }
+
if ((*i)->state == transaction_t::CLEARED)
output_stream << " <tr:cleared/>\n";
else if ((*i)->state == transaction_t::PENDING)