diff options
-rw-r--r-- | commodity.cc | 6 | ||||
-rw-r--r-- | commodity.h | 19 | ||||
-rw-r--r-- | derive.cc | 4 | ||||
-rw-r--r-- | emacs.cc | 2 | ||||
-rw-r--r-- | entry.cc | 5 | ||||
-rw-r--r-- | entry.h | 14 | ||||
-rw-r--r-- | format.cc | 6 | ||||
-rw-r--r-- | gnucash.cc | 2 | ||||
-rw-r--r-- | journal.cc | 3 | ||||
-rw-r--r-- | op.cc | 8 | ||||
-rw-r--r-- | qif.cc | 3 | ||||
-rw-r--r-- | reconcile.h | 11 | ||||
-rw-r--r-- | report.cc | 6 | ||||
-rw-r--r-- | session.h | 1 | ||||
-rw-r--r-- | test/numerics/t_commodity.cc | 14 | ||||
-rw-r--r-- | textual.cc | 18 | ||||
-rw-r--r-- | times.cc | 123 | ||||
-rw-r--r-- | times.h | 73 | ||||
-rw-r--r-- | utils.cc | 2 | ||||
-rw-r--r-- | value.cc | 92 | ||||
-rw-r--r-- | value.h | 30 | ||||
-rw-r--r-- | walk.cc | 58 | ||||
-rw-r--r-- | walk.h | 16 | ||||
-rw-r--r-- | xact.cc | 4 | ||||
-rw-r--r-- | xact.h | 34 | ||||
-rw-r--r-- | xml.cc | 4 |
26 files changed, 308 insertions, 250 deletions
diff --git a/commodity.cc b/commodity.cc index 81259c8b..a1c1e2c9 100644 --- a/commodity.cc +++ b/commodity.cc @@ -182,7 +182,7 @@ amount_t commodity_t::exchange(const amount_t& amount, basis_cost = final_cost; amount_t ann_amount(amount); - ann_amount.annotate(annotation_t(per_unit_cost, moment, tag)); + ann_amount.annotate(annotation_t(per_unit_cost, moment->date(), tag)); return ann_amount; } @@ -324,7 +324,7 @@ void annotation_t::parse(std::istream& in) else throw_(amount_error, "Commodity date lacks closing bracket"); - date = parse_datetime(buf); + date = parse_date(buf); } else if (c == '(') { if (tag) @@ -458,7 +458,7 @@ bool compare_amount_commodities::operator()(const amount_t * left, return false; if (aleftcomm.details.date && arightcomm.details.date) { - duration_t diff = *aleftcomm.details.date - *arightcomm.details.date; + date_duration_t diff = *aleftcomm.details.date - *arightcomm.details.date; return diff.is_negative(); } diff --git a/commodity.h b/commodity.h index 94aa6b08..2f5ce258 100644 --- a/commodity.h +++ b/commodity.h @@ -225,16 +225,15 @@ inline std::ostream& operator<<(std::ostream& out, const commodity_t& comm) { struct annotation_t : public equality_comparable<annotation_t> { - optional<amount_t> price; - optional<datetime_t> date; - optional<string> tag; - - explicit annotation_t - (const optional<amount_t>& _price = none, - const optional<datetime_t>& _date = none, - const optional<string>& _tag = none) + optional<amount_t> price; + optional<date_t> date; + optional<string> tag; + + explicit annotation_t(const optional<amount_t>& _price = none, + const optional<date_t>& _date = none, + const optional<string>& _tag = none) : price(_price), date(_date), tag(_tag) { - TRACE_CTOR(annotation_t, "const optional<amount_t>& + datetime_t + string"); + TRACE_CTOR(annotation_t, "const optional<amount_t>& + date_t + string"); } annotation_t(const annotation_t& other) : price(other.price), date(other.date), tag(other.tag) { @@ -258,7 +257,7 @@ struct annotation_t : public equality_comparable<annotation_t> void parse(std::istream& in); void print(std::ostream& out) const { out << "price " << (price ? price->to_string() : "NONE") << " " - << "date " << (date ? *date : datetime_t()) << " " + << "date " << (date ? *date : date_t()) << " " << "tag " << (tag ? *tag : "NONE"); } @@ -14,9 +14,7 @@ entry_t * derive_new_entry(report_t& report, entry_t * matching = NULL; - // jww (2008-04-20): Need to parse the string here - //added->_date = *i++; - added->_date = boost::posix_time::time_from_string(*i++); + added->_date = parse_date(*i++); if (i == end) throw std::runtime_error("Too few arguments to 'entry'"); @@ -13,7 +13,7 @@ void format_emacs_xacts::write_entry(entry_t& entry) out << (static_cast<unsigned long>(entry.beg_line) + 1) << " "; - tm when = boost::posix_time::to_tm(entry.date()); + tm when = gregorian::to_tm(entry.date()); std::time_t date = std::mktime(&when); // jww (2008-04-20): Is this GMT or local? out << "(" << (date / 65536) << " " << (date % 65536) << " 0) "; @@ -275,8 +275,9 @@ bool entry_base_t::finalize() amount_t final_cost; amount_t basis_cost; amount_t ann_amount = - commodity_t::exchange(x_amt, final_cost, basis_cost, - xact->cost, none, xact->actual_date(), + commodity_t::exchange(x_amt, final_cost, basis_cost, xact->cost, none, + datetime_t(xact->actual_date(), + time_duration_t(0, 0, 0)), entry ? entry->code : optional<string>()); if (xact->amount.annotated()) { @@ -81,10 +81,10 @@ public: class entry_t : public entry_base_t, public scope_t { public: - datetime_t _date; - optional<datetime_t> _date_eff; - optional<string> code; - string payee; + date_t _date; + optional<date_t> _date_eff; + optional<string> code; + string payee; entry_t() { TRACE_CTOR(entry_t, ""); @@ -95,15 +95,15 @@ public: TRACE_DTOR(entry_t); } - datetime_t actual_date() const { + date_t actual_date() const { return _date; } - datetime_t effective_date() const { + date_t effective_date() const { if (! _date_eff) return _date; return *_date_eff; } - datetime_t date() const { + date_t date() const { if (xact_t::use_effective_date) return effective_date(); else @@ -476,12 +476,12 @@ void format_t::format(std::ostream& out_str, scope_t& scope) const break; case element_t::DATE_STRING: - out << format_datetime(scope.resolve("date").as_datetime()); + out << format_date(scope.resolve("date").as_date()); break; case element_t::COMPLETE_DATE_STRING: { - datetime_t actual_date; - datetime_t effective_date; + date_t actual_date; + date_t effective_date; if (details.xact) { actual_date = details.xact->actual_date(); effective_date = details.xact->effective_date(); @@ -274,7 +274,7 @@ static void dataHandler(void *userData, const char *s, int len) break; case ENTRY_DATE: - curr_entry->_date = parse_datetime(string(s, len)); + curr_entry->_date = parse_date(string(s, len)); break; case ENTRY_DESC: @@ -105,7 +105,8 @@ bool journal_t::add_entry(entry_t * entry) foreach (const xact_t * xact, entry->xacts) if (xact->cost) { assert(xact->amount); - xact->amount.commodity().add_price(entry->date(), + xact->amount.commodity().add_price(datetime_t(entry->date(), + time_duration_t(0, 0, 0)), *xact->cost / xact->amount.number()); } @@ -298,16 +298,16 @@ void expr_t::op_t::compute(value_t& result, throw compute_error("Invalid date passed to year|month|day(date)"); } - const datetime_t& moment(result.as_datetime()); + const date_t& moment(result.as_date()); switch (kind) { case F_YEAR: - result = (long)moment.date().year(); + result = (long)moment.year(); break; case F_MONTH: - result = (long)moment.date().month(); + result = (long)moment.month(); break; case F_DAY: - result = (long)moment.date().day(); + result = (long)moment.day(); break; default: break; @@ -98,7 +98,8 @@ unsigned int qif_parser_t::parse(std::istream& in, case 'D': SET_BEG_POS_AND_LINE(); get_line(in); - entry->_date = parse_datetime(line); + // jww (2008-08-01): Is this just a date? + entry->_date = parse_date(line); break; case 'T': diff --git a/reconcile.h b/reconcile.h index c6affb81..ab15c15c 100644 --- a/reconcile.h +++ b/reconcile.h @@ -9,20 +9,19 @@ namespace ledger { class reconcile_xacts : public item_handler<xact_t> { value_t balance; - datetime_t cutoff; - + date_t cutoff; xacts_list xacts; reconcile_xacts(); public: - reconcile_xacts(xact_handler_ptr handler, - const value_t& _balance, - const datetime_t& _cutoff) + reconcile_xacts(xact_handler_ptr handler, + const value_t& _balance, + const date_t& _cutoff) : item_handler<xact_t>(handler), balance(_balance), cutoff(_cutoff) { TRACE_CTOR(reconcile_xacts, - "xact_handler_ptr, const value_t&, const datetime_t&"); + "xact_handler_ptr, const value_t&, const date_t&"); } virtual ~reconcile_xacts() throw() { TRACE_DTOR(reconcile_xacts); @@ -87,9 +87,9 @@ report_t::chain_xact_handlers(xact_handler_ptr base_handler, // xacts which can be reconciled to a given balance // (calculated against the xacts which it receives). if (! reconcile_balance.empty()) { - datetime_t cutoff = current_moment; + date_t cutoff = current_date; if (! reconcile_date.empty()) - cutoff = parse_datetime(reconcile_date); + cutoff = parse_date(reconcile_date); handler.reset(new reconcile_xacts (handler, value_t(reconcile_balance), cutoff)); } @@ -309,7 +309,7 @@ value_t report_t::ftime(call_scope_t& args) if (args.size() < 1) throw_(std::logic_error, "usage: ftime(DATE [, DATE_FORMAT])"); - datetime_t date = args[0].as_datetime(); + date_t date = args[0].as_date(); string date_format; if (args.size() == 2) @@ -73,6 +73,7 @@ public: bool cache_dirty; datetime_t now; + date_t today; #if 0 elision_style_t elision_style; diff --git a/test/numerics/t_commodity.cc b/test/numerics/t_commodity.cc index 03acafc1..a96bed72 100644 --- a/test/numerics/t_commodity.cc +++ b/test/numerics/t_commodity.cc @@ -11,12 +11,12 @@ void CommodityTestCase::tearDown() { void CommodityTestCase::testPriceHistory() { - ptime jan17_07 = parse_datetime("2007/01/17 00:00:00"); - ptime feb27_07 = parse_datetime("2007/02/27 18:00:00"); - ptime feb28_07 = parse_datetime("2007/02/28 06:00:00"); - ptime feb28_07sbm = parse_datetime("2007/02/28 11:59:59"); - ptime mar01_07 = parse_datetime("2007/03/01 00:00:00"); - ptime apr15_07 = parse_datetime("2007/04/15 13:00:00"); + datetime_t jan17_07 = parse_datetime("2007/01/17 00:00:00"); + datetime_t feb27_07 = parse_datetime("2007/02/27 18:00:00"); + datetime_t feb28_07 = parse_datetime("2007/02/28 06:00:00"); + datetime_t feb28_07sbm = parse_datetime("2007/02/28 11:59:59"); + datetime_t mar01_07 = parse_datetime("2007/03/01 00:00:00"); + datetime_t apr15_07 = parse_datetime("2007/04/15 13:00:00"); // jww (2007-04-17): tbd amount_t x0; @@ -40,7 +40,7 @@ void CommodityTestCase::testPriceHistory() assertTrue(amt1); assertEqual(amount_t("$1831.83"), *amt1); - optional<amount_t> amt2 = x1.value(current_moment); + optional<amount_t> amt2 = x1.value(current_time); assertTrue(amt2); assertEqual(amount_t("$2124.12"), *amt2); @@ -384,10 +384,10 @@ xact_t * parse_xact(char * line, account_t * account, if (char * p = std::strchr(buf, '=')) { *p++ = '\0'; - xact->_date_eff = parse_datetime(p); + xact->_date_eff = parse_date(p); } if (buf[0]) - xact->_date = parse_datetime(buf); + xact->_date = parse_date(buf); } } } @@ -455,9 +455,9 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master, if (char * p = std::strchr(line, '=')) { *p++ = '\0'; - curr->_date_eff = parse_datetime(p); + curr->_date_eff = parse_date(p); } - curr->_date = parse_datetime(line); + curr->_date = parse_date(line); // Parse the optional cleared flag: * @@ -624,16 +624,16 @@ static void clock_out_from_timelog(std::list<time_entry_t>& time_entries, } std::auto_ptr<entry_t> curr(new entry_t); - curr->_date = when; + curr->_date = when.date(); curr->code = desc ? desc : ""; curr->payee = event.desc; - if (curr->_date < event.checkin) + if (when < event.checkin) throw parse_error ("Timelog check-out date less than corresponding check-in"); char buf[32]; - std::sprintf(buf, "%lds", long((curr->_date - event.checkin).seconds())); + std::sprintf(buf, "%lds", long((when - event.checkin).seconds())); amount_t amt; amt.parse(buf); assert(amt.valid()); @@ -993,8 +993,8 @@ unsigned int textual_parser_t::parse(std::istream& in, accounts.push_back(time_entry.account); foreach (account_t * account, accounts) - clock_out_from_timelog(time_entries, current_moment, account, - NULL, journal); + clock_out_from_timelog(time_entries, current_time, account, NULL, + journal); assert(time_entries.empty()); } @@ -33,48 +33,42 @@ namespace ledger { +namespace { #ifdef BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK -const ptime time_now = boost::posix_time::microsec_clock::universal_time(); + const ptime time_now = boost::posix_time::microsec_clock::universal_time(); #else -const ptime time_now = boost::posix_time::second_clock::universal_time(); + const ptime time_now = boost::posix_time::second_clock::universal_time(); #endif -const date date_now = boost::gregorian::day_clock::universal_day(); + const date date_now = boost::gregorian::day_clock::universal_day(); +} -#ifdef SUPPORT_DATE_AND_TIME -const datetime_t& current_moment(time_now); -#else -const datetime_t& current_moment(date_now); -#endif +const datetime_t& current_time(time_now); +const date_t& current_date(date_now); + int current_year(current_date.year()); -int current_year(current_moment.date().year()); +namespace { + const char * formats[] = { + "%y/%m/%d", + "%Y/%m/%d", + "%m/%d", + "%y.%m.%d", + "%Y.%m.%d", + "%m.%d", + "%y-%m-%d", + "%Y-%m-%d", + "%m-%d", + "%a", + "%A", + "%b", + "%B", + "%Y", + NULL + }; +} -string input_time_format; string output_time_format = "%Y/%m/%d"; #if 0 -static const char * formats[] = { - "%y/%m/%d", - "%Y/%m/%d", - "%m/%d", - "%y.%m.%d", - "%Y.%m.%d", - "%m.%d", - "%y-%m-%d", - "%Y-%m-%d", - "%m-%d", - "%a", - "%A", - "%b", - "%B", - "%Y", - NULL -}; -#endif - -bool day_before_month = false; -static bool day_before_month_initialized = false; - -#if 0 datetime_t datetime_t::now(std::time(NULL)); namespace { @@ -94,14 +88,6 @@ namespace { datetime_t parse_datetime(const char * str) { - if (! day_before_month_initialized) { -#ifdef HAVE_NL_LANGINFO - const char * d_fmt = nl_langinfo(D_FMT); - if (d_fmt && std::strlen(d_fmt) > 1 && d_fmt[1] == 'd') - day_before_month = true; - day_before_month_initialized = true; -#endif - } #if 0 return parse_abs_datetime(in); #else @@ -120,9 +106,9 @@ datetime_t parse_datetime(const char * str) #endif } -datetime_t interval_t::first(const datetime_t& moment) const +date_t interval_t::first(const date_t& moment) const { - datetime_t quant(begin); + date_t quant(begin); if (! advanced) advanced = true; @@ -147,7 +133,7 @@ datetime_t interval_t::first(const datetime_t& moment) const quant = std::mktime(desc); - datetime_t temp; + date_t temp; while (moment >= (temp = increment(quant))) { if (quant == temp) break; @@ -159,40 +145,27 @@ datetime_t interval_t::first(const datetime_t& moment) const return quant; } -datetime_t interval_t::increment(const datetime_t& moment) const +date_t interval_t::increment(const date_t& moment) const { -#if 0 - struct std::tm * desc = std::localtime(&moment.when); + date_t future(moment); - if (years) - desc->tm_year += years; - if (months) - desc->tm_mon += months; - if (days) - desc->tm_mday += days; + if (years) future += gregorian::years(years); + if (months) future += gregorian::years(months); + if (days) future += gregorian::years(days); - desc->tm_hour += hours; - desc->tm_min += minutes; - desc->tm_sec += seconds; - - desc->tm_isdst = -1; - - return std::mktime(desc); -#else - return datetime_t(); -#endif + return future; } namespace { void parse_inclusion_specifier(const string& word, - datetime_t * begin, datetime_t * end) + date_t * begin, date_t * end) { #if 0 // jww (2008-05-08): Implement! struct std::tm when; if (! parse_date_mask(word.c_str(), &when)) - throw_(datetime_error, "Could not parse date mask: " << word); + throw_(date_error, "Could not parse date mask: " << word); when.tm_hour = 0; when.tm_min = 0; @@ -244,7 +217,7 @@ namespace { } void parse_date_words(std::istream& in, string& word, - datetime_t * begin, datetime_t * end) + date_t * begin, date_t * end) { string type; @@ -264,7 +237,7 @@ namespace { if (word == "month") { #if 0 // jww (2008-05-08): - std::strftime(buf, 31, "%B", datetime_t::now.localtime()); + std::strftime(buf, 31, "%B", date_t::now.localtime()); #endif word = buf; mon_spec = true; @@ -272,7 +245,7 @@ namespace { else if (word == "year") { #if 0 // jww (2008-05-08): - std::strftime(buf, 31, "%Y", datetime_t::now.localtime()); + std::strftime(buf, 31, "%Y", date_t::now.localtime()); #endif word = buf; } @@ -329,12 +302,6 @@ void interval_t::parse(std::istream& in) months = 3 * quantity; else if (word == "years") years = quantity; - else if (word == "hours") - hours = quantity; - else if (word == "minutes") - minutes = quantity; - else if (word == "seconds") - seconds = quantity; } else if (word == "day") days = 1; @@ -346,12 +313,6 @@ void interval_t::parse(std::istream& in) months = 3; else if (word == "year") years = 1; - else if (word == "hour") - hours = 1; - else if (word == "minute") - minutes = 1; - else if (word == "second") - seconds = 1; } else if (word == "daily") days = 1; @@ -367,8 +328,6 @@ void interval_t::parse(std::istream& in) months = 3; else if (word == "yearly") years = 1; - else if (word == "hourly") - hours = 1; else if (word == "this" || word == "last" || word == "next") { parse_date_words(in, word, &begin, &end); } @@ -34,65 +34,50 @@ namespace ledger { -#define SUPPORT_DATE_AND_TIME 1 -#ifdef SUPPORT_DATE_AND_TIME +DECLARE_EXCEPTION(datetime_error, std::runtime_error); +DECLARE_EXCEPTION(date_error, std::runtime_error); typedef boost::posix_time::ptime datetime_t; -typedef datetime_t::time_duration_type duration_t; +typedef datetime_t::time_duration_type time_duration_t; inline bool is_valid(const datetime_t& moment) { return ! moment.is_not_a_date_time(); } -#else // SUPPORT_DATE_AND_TIME - -typedef boost::gregorian::date datetime_t; -typedef boost::gregorian::date_duration duration_t; +typedef boost::gregorian::date date_t; +typedef boost::gregorian::date_duration date_duration_t; -inline bool is_valid(const datetime_t& moment) { +inline bool is_valid(const date_t& moment) { return ! moment.is_not_a_date(); } -#endif // SUPPORT_DATE_AND_TIME - -extern const datetime_t& current_moment; - -extern int current_year; -extern string input_time_format; -extern string output_time_format; - -DECLARE_EXCEPTION(datetime_error, std::runtime_error); +extern const datetime_t& current_time; +extern const date_t& current_date; +extern int current_year; +extern string input_time_format; +extern string output_time_format; struct interval_t { unsigned short years; unsigned short months; unsigned short days; - unsigned short hours; - unsigned short minutes; - unsigned short seconds; - - datetime_t begin; - datetime_t end; - + date_t begin; + date_t end; mutable bool advanced; interval_t(int _days = 0, int _months = 0, int _years = 0, - const datetime_t& _begin = datetime_t(), - const datetime_t& _end = datetime_t()) + const date_t& _begin = date_t(), + const date_t& _end = date_t()) : years(_years), months(_months), days(_days), - hours(0), minutes(0), seconds(0), begin(_begin), end(_end), advanced(false) { TRACE_CTOR(interval_t, - "int, int, int, const datetime_t&, const datetime_t&"); + "int, int, int, const date_t&, const date_t&"); } interval_t(const interval_t& other) : years(other.years), months(other.months), days(other.days), - hours(other.hours), - minutes(other.minutes), - seconds(other.seconds), begin(other.begin), end(other.end), @@ -103,7 +88,6 @@ struct interval_t interval_t(const string& desc) : years(0), months(0), days(0), - hours(0), minutes(0), seconds(0), begin(), end(), advanced(false) { TRACE_CTOR(interval_t, "const string&"); std::istringstream stream(desc); @@ -115,18 +99,16 @@ struct interval_t } operator bool() const { - return (years > 0 || months > 0 || days > 0 || - hours > 0 || minutes > 0 || seconds > 0); + return years > 0 || months > 0 || days > 0; } - void start(const datetime_t& moment) { + void start(const date_t& moment) { begin = first(moment); } - datetime_t first(const datetime_t& moment = datetime_t()) const; - - datetime_t increment(const datetime_t&) const; + date_t first(const date_t& moment = date_t()) const; + date_t increment(const date_t&) const; - void parse(std::istream& in); + void parse(std::istream& in); }; #if 0 @@ -147,11 +129,14 @@ inline datetime_t ptime_from_local_time_string(const string& time_string) { } #endif -datetime_t parse_datetime(const char * str); - inline datetime_t parse_datetime(const string& str) { return parse_datetime(str.c_str()); } +datetime_t parse_datetime(const char * str); + +inline date_t parse_date(const string& str) { + return gregorian::from_string(str); +} inline std::time_t to_time_t(const ptime& t) { @@ -171,9 +156,9 @@ inline string format_datetime(const datetime_t& when) { return buf; } -extern const ptime time_now; -extern const date date_now; -extern bool day_before_month; +inline string format_date(const date_t& when) { + return to_iso_extended_string(when); +} #if 0 struct intorchar @@ -467,7 +467,7 @@ bool logger_func(log_level_t level) IF_VERIFY() *_log_stream << " TIME OBJSZ MEMSZ" << std::endl; - appender = (logger_start - current_moment).total_milliseconds(); + appender = (logger_start - current_time).total_milliseconds(); } *_log_stream << std::right << std::setw(5) @@ -48,6 +48,11 @@ value_t::storage_t& value_t::storage_t::operator=(const value_t::storage_t& rhs) (const_cast<char *>(rhs.data))); break; + case DATE: + new(reinterpret_cast<date_t *>(data)) + date_t(*reinterpret_cast<date_t *>(const_cast<char *>(rhs.data))); + break; + case AMOUNT: new(reinterpret_cast<amount_t *>(data)) amount_t(*reinterpret_cast<amount_t *> @@ -130,6 +135,7 @@ void value_t::initialize() #if 0 BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(bool)); BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(datetime_t)); + BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(date_t)); BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(long)); BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(amount_t)); BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(balance_t *)); @@ -143,6 +149,8 @@ void value_t::initialize() << " sizeof(bool)"); DEBUG_(std::setw(3) << std::right << sizeof(datetime_t) << " sizeof(datetime_t)"); + DEBUG_(std::setw(3) << std::right << sizeof(date_t) + << " sizeof(date_t)"); DEBUG_(std::setw(3) << std::right << sizeof(long) << " sizeof(long)"); DEBUG_(std::setw(3) << std::right << sizeof(amount_t) @@ -179,6 +187,8 @@ value_t::operator bool() const return as_boolean(); case DATETIME: return is_valid(as_datetime()); + case DATE: + return is_valid(as_date()); case INTEGER: return as_long(); case AMOUNT: @@ -223,6 +233,17 @@ datetime_t value_t::to_datetime() const } } +date_t value_t::to_date() const +{ + if (is_date()) { + return as_date(); + } else { + value_t temp(*this); + temp.in_place_cast(DATE); + return temp.as_date(); + } +} + long value_t::to_long() const { if (is_long()) { @@ -356,6 +377,19 @@ value_t& value_t::operator+=(const value_t& val) } break; + case DATE: + switch (val.type()) { + case INTEGER: + as_date_lval() += date_duration_t(val.as_long()); + return *this; + case AMOUNT: + as_date_lval() += date_duration_t(val.as_amount().to_long()); + return *this; + default: + break; + } + break; + case INTEGER: switch (val.type()) { case INTEGER: @@ -494,6 +528,19 @@ value_t& value_t::operator-=(const value_t& val) } break; + case DATE: + switch (val.type()) { + case INTEGER: + as_date_lval() -= date_duration_t(val.as_long()); + return *this; + case AMOUNT: + as_date_lval() -= date_duration_t(val.as_amount().to_long()); + return *this; + default: + break; + } + break; + case INTEGER: switch (val.type()) { case INTEGER: @@ -798,6 +845,11 @@ bool value_t::operator==(const value_t& val) const return as_datetime() == val.as_datetime(); break; + case DATE: + if (val.is_date()) + return as_date() == val.as_date(); + break; + case INTEGER: switch (val.type()) { case INTEGER: @@ -885,6 +937,11 @@ bool value_t::operator<(const value_t& val) const return as_datetime() < val.as_datetime(); break; + case DATE: + if (val.is_date()) + return as_date() < val.as_date(); + break; + case INTEGER: switch (val.type()) { case INTEGER: @@ -930,6 +987,11 @@ bool value_t::operator>(const value_t& val) const return as_datetime() > val.as_datetime(); break; + case DATE: + if (val.is_date()) + return as_date() > val.as_date(); + break; + case INTEGER: switch (val.type()) { case INTEGER: @@ -1142,6 +1204,9 @@ void value_t::in_place_negate() case DATETIME: set_long(- as_long()); return; + case DATE: + set_long(- as_long()); + return; case AMOUNT: as_amount_lval().in_place_negate(); return; @@ -1167,6 +1232,8 @@ bool value_t::is_realzero() const return as_long() == 0; case DATETIME: return ! is_valid(as_datetime()); + case DATE: + return ! is_valid(as_date()); case AMOUNT: return as_amount().is_realzero(); case BALANCE: @@ -1198,6 +1265,8 @@ bool value_t::is_zero() const return as_long() == 0; case DATETIME: return ! is_valid(as_datetime()); + case DATE: + return ! is_valid(as_date()); case AMOUNT: return as_amount().is_zero(); case BALANCE: @@ -1353,6 +1422,8 @@ value_t value_t::annotated_date() const switch (type()) { case DATETIME: return *this; + case DATE: + return *this; case AMOUNT: { optional<datetime_t> temp = as_amount().annotation_details().date; @@ -1400,6 +1471,7 @@ value_t value_t::strip_annotations(const bool keep_price, case BOOLEAN: case INTEGER: case DATETIME: + case DATE: case STRING: case POINTER: return *this; @@ -1505,6 +1577,10 @@ void value_t::dump(std::ostream& out, const int first_width, out << as_datetime(); break; + case DATE: + out << as_date(); + break; + case INTEGER: out << as_long(); break; @@ -1580,7 +1656,10 @@ void value_t::print(std::ostream& out, const bool relaxed) const break; case DATETIME: - out << '[' << format_datetime(as_datetime()) << ']'; + assert(false); + break; + case DATE: + out << '[' << format_date(as_date()) << ']'; break; case STRING: @@ -1623,6 +1702,12 @@ void value_t::read(const char *& data) set_datetime(read_long<unsigned long>(data)); #endif break; + case DATE: +#if 0 + // jww (2008-04-22): I need to record and read a date_t directly + set_date(read_long<unsigned long>(data)); +#endif + break; case AMOUNT: { amount_t temp; temp.read(data); @@ -1652,6 +1737,11 @@ void value_t::write(std::ostream& out) const binary::write_number(out, as_datetime()); #endif break; + case DATE: +#if 0 + binary::write_number(out, as_date()); +#endif + break; case AMOUNT: as_amount().write(out); break; @@ -102,6 +102,7 @@ public: VOID, // a null value (i.e., uninitialized) BOOLEAN, // a boolean DATETIME, // a date and time (Boost posix_time) + DATE, // a date (Boost gregorian::date) INTEGER, // a signed integer value AMOUNT, // a ledger::amount_t BALANCE, // a ledger::balance_t @@ -267,10 +268,14 @@ public: set_boolean(val); } - value_t(const datetime_t val) { - TRACE_CTOR(value_t, "const datetime_t"); + value_t(const datetime_t& val) { + TRACE_CTOR(value_t, "const datetime_t&"); set_datetime(val); } + value_t(const date_t& val) { + TRACE_CTOR(value_t, "const date_t&"); + set_date(val); + } value_t(const long val) { TRACE_CTOR(value_t, "const long"); @@ -459,6 +464,7 @@ public: * is_boolean() * is_long() * is_datetime() + * is_date() * is_amount() * is_balance() * is_balance_pair() @@ -514,6 +520,23 @@ public: new(reinterpret_cast<datetime_t *>(storage->data)) datetime_t(val); } + bool is_date() const { + return is_type(DATE); + } + date_t& as_date_lval() { + assert(is_date()); + _dup(); + return *reinterpret_cast<date_t *>(storage->data); + } + const date_t& as_date() const { + assert(is_date()); + return *reinterpret_cast<date_t *>(storage->data); + } + void set_date(const date_t& val) { + set_type(DATE); + new(reinterpret_cast<date_t *>(storage->data)) date_t(val); + } + bool is_long() const { return is_type(INTEGER); } @@ -695,6 +718,7 @@ public: bool to_boolean() const; long to_long() const; datetime_t to_datetime() const; + date_t to_date() const; amount_t to_amount() const; balance_t to_balance() const; balance_pair_t to_balance_pair() const; @@ -828,6 +852,8 @@ public: return "a boolean"; case DATETIME: return "a date/time"; + case DATE: + return "a date"; case INTEGER: return "an integer"; case AMOUNT: @@ -242,7 +242,7 @@ void handle_value(const value_t& value, unsigned int flags, std::list<xact_t>& temps, item_handler<xact_t>& handler, - const datetime_t& date = datetime_t(), + const date_t& date = date_t(), xacts_list * component_xacts = NULL) { temps.push_back(xact_t(account)); @@ -278,6 +278,7 @@ void handle_value(const value_t& value, switch (value.type()) { case value_t::BOOLEAN: case value_t::DATETIME: + case value_t::DATE: case value_t::INTEGER: temp.cast(value_t::AMOUNT); // fall through... @@ -372,11 +373,11 @@ void related_xacts::flush() item_handler<xact_t>::flush(); } -void changed_value_xacts::output_diff(const datetime_t& current) +void changed_value_xacts::output_diff(const date_t& date) { value_t cur_bal; - xact_xdata(*last_xact).date = current; + xact_xdata(*last_xact).date = date; #if 0 compute_total(cur_bal, details_t(*last_xact)); #endif @@ -390,7 +391,7 @@ void changed_value_xacts::output_diff(const datetime_t& current) entry_temps.push_back(entry_t()); entry_t& entry = entry_temps.back(); entry.payee = "Commodities revalued"; - entry._date = current; + entry._date = date; handle_value(diff, NULL, &entry, XACT_NO_TOTAL, xact_temps, *handler); @@ -400,12 +401,12 @@ void changed_value_xacts::output_diff(const datetime_t& current) void changed_value_xacts::operator()(xact_t& xact) { if (last_xact) { - datetime_t moment; + date_t date; if (xact_has_xdata(*last_xact)) - moment = xact_xdata_(*last_xact).date; + date = xact_xdata_(*last_xact).date; else - moment = xact.date(); - output_diff(moment); + date = xact.date(); + output_diff(date); } if (changed_values_only) @@ -497,18 +498,13 @@ void subtotal_xacts::operator()(xact_t& xact) account_xdata(*xact_account(xact)).dflags |= ACCOUNT_HAS_UNB_VIRTUALS; } -void interval_xacts::report_subtotal(const datetime_t& moment) +void interval_xacts::report_subtotal(const date_t& date) { assert(last_xact); start = interval.begin; - if (is_valid(moment)) - // jww (2008-04-24): How to change this back into a datetime? -#if 0 - finish = moment - 86400L; -#else - ; -#endif + if (is_valid(date)) + finish = date - gregorian::days(1); else finish = last_xact->date(); @@ -519,7 +515,7 @@ void interval_xacts::report_subtotal(const datetime_t& moment) void interval_xacts::operator()(xact_t& xact) { - const datetime_t date = xact.date(); + const date_t& date(xact.date()); if ((is_valid(interval.begin) && date < interval.begin) || (is_valid(interval.end) && date >= interval.end)) @@ -533,12 +529,12 @@ void interval_xacts::operator()(xact_t& xact) started = true; } - datetime_t quant = interval.increment(interval.begin); + date_t quant = interval.increment(interval.begin); if (date >= quant) { if (last_xact) report_subtotal(quant); - datetime_t temp; + date_t temp; while (date >= (temp = interval.increment(quant))) { if (quant == temp) break; @@ -670,7 +666,7 @@ void generate_xacts::add_xact(const interval_t& period, pending_xacts.push_back(pending_xacts_pair(period, &xact)); } -void budget_xacts::report_budget_items(const datetime_t& moment) +void budget_xacts::report_budget_items(const date_t& date) { if (pending_xacts.size() == 0) return; @@ -679,13 +675,13 @@ void budget_xacts::report_budget_items(const datetime_t& moment) do { reported = false; foreach (pending_xacts_list::value_type& pair, pending_xacts) { - datetime_t& begin = pair.first.begin; + date_t& begin = pair.first.begin; if (! is_valid(begin)) { - pair.first.start(moment); + pair.first.start(date); begin = pair.first.begin; } - if (begin < moment && + if (begin < date && (! is_valid(pair.first.end) || begin < pair.first.end)) { xact_t& xact = *pair.second; @@ -694,7 +690,7 @@ void budget_xacts::report_budget_items(const datetime_t& moment) #if 0 // jww (2008-04-24): Need a new debug macro here DEBUG_TIME("ledger.walk.budget", begin); - DEBUG_TIME("ledger.walk.budget", moment); + DEBUG_TIME("ledger.walk.budget", date); #endif entry_temps.push_back(entry_t()); @@ -753,10 +749,10 @@ void forecast_xacts::add_xact(const interval_t& period, xact_t& xact) interval_t& i = pending_xacts.back().first; if (! is_valid(i.begin)) { - i.start(current_moment); + i.start(current_date); i.begin = i.increment(i.begin); } else { - while (i.begin < current_moment) + while (i.begin < current_date) i.begin = i.increment(i.begin); } } @@ -764,7 +760,7 @@ void forecast_xacts::add_xact(const interval_t& period, xact_t& xact) void forecast_xacts::flush() { xacts_list passed; - datetime_t last; + date_t last; while (pending_xacts.size() > 0) { pending_xacts_list::iterator least = pending_xacts.begin(); @@ -774,7 +770,7 @@ void forecast_xacts::flush() if ((*i).first.begin < (*least).first.begin) least = i; - datetime_t& begin = (*least).first.begin; + date_t& begin = (*least).first.begin; if (is_valid((*least).first.end) && begin >= (*least).first.end) { pending_xacts.erase(least); @@ -795,11 +791,13 @@ void forecast_xacts::flush() temp.add_flags(XACT_AUTO | XACT_TEMP); entry.add_xact(&temp); - datetime_t next = (*least).first.increment(begin); + date_t next = (*least).first.increment(begin); +#if 0 // jww (2008-04-24): Does seconds() here give the total seconds? if (next < begin || // wraparound (is_valid(last) && (next - last).seconds() > 365 * 5 * 24 * 3600)) break; +#endif begin = next; item_handler<xact_t>::operator()(temp); @@ -957,7 +955,7 @@ void walk_commodities(commodity_pool_t::commodities_by_ident& commodities, if ((*i)->history()) foreach (const commodity_t::history_map::value_type& pair, (*i)->history()->prices) { - entry_temps.back()._date = pair.first; + entry_temps.back()._date = pair.first.date(); xact_temps.push_back(xact_t(&acct_temps.back())); xact_t& temp = xact_temps.back(); @@ -98,7 +98,7 @@ struct xact_xdata_t : public noncopyable value_t value; unsigned int index; unsigned short dflags; - datetime_t date; + date_t date; account_t * account; void * ptr; xacts_list * component_xacts; @@ -609,13 +609,13 @@ public: virtual void flush() { if (last_xact) { - output_diff(current_moment); + output_diff(current_date); last_xact = NULL; } item_handler<xact_t>::flush(); } - void output_diff(const datetime_t& current); + void output_diff(const date_t& current); virtual void operator()(xact_t& xact); }; @@ -661,8 +661,8 @@ protected: std::list<xact_t> xact_temps; public: - datetime_t start; - datetime_t finish; + date_t start; + date_t finish; subtotal_xacts(xact_handler_ptr handler, bool _remember_components = false) @@ -715,7 +715,7 @@ public: TRACE_DTOR(interval_xacts); } - void report_subtotal(const datetime_t& moment = datetime_t()); + void report_subtotal(const date_t& moment = date_t()); virtual void flush() { if (last_xact) @@ -807,7 +807,7 @@ public: virtual void flush(); virtual void operator()(xact_t& xact) { - days_of_the_week[xact.date().date().day_of_week()].push_back(&xact); + days_of_the_week[xact.date().day_of_week()].push_back(&xact); } }; @@ -860,7 +860,7 @@ public: TRACE_DTOR(budget_xacts); } - void report_budget_items(const datetime_t& moment); + void report_budget_items(const date_t& date); virtual void operator()(xact_t& xact); }; @@ -42,14 +42,14 @@ xact_t::~xact_t() TRACE_DTOR(xact_t); } -datetime_t xact_t::actual_date() const +date_t xact_t::actual_date() const { if (! _date && entry) return entry->actual_date(); return *_date; } -datetime_t xact_t::effective_date() const +date_t xact_t::effective_date() const { if (! _date_eff && entry) return entry->effective_date(); @@ -55,20 +55,20 @@ class xact_t : public supports_flags<>, public scope_t public: enum state_t { UNCLEARED, CLEARED, PENDING }; - entry_t * entry; - state_t state; - account_t * account; - optional<datetime_t> _date; - optional<datetime_t> _date_eff; - amount_t amount; - optional<expr_t> amount_expr; - optional<amount_t> cost; - optional<expr_t> cost_expr; - optional<string> note; - istream_pos_type beg_pos; - unsigned long beg_line; - istream_pos_type end_pos; - unsigned long end_line; + entry_t * entry; + state_t state; + account_t * account; + optional<date_t> _date; + optional<date_t> _date_eff; + amount_t amount; + optional<expr_t> amount_expr; + optional<amount_t> cost; + optional<expr_t> cost_expr; + optional<string> note; + istream_pos_type beg_pos; + unsigned long beg_line; + istream_pos_type end_pos; + unsigned long end_line; mutable void * data; static bool use_effective_date; @@ -113,9 +113,9 @@ class xact_t : public supports_flags<>, public scope_t } ~xact_t(); - datetime_t actual_date() const; - datetime_t effective_date() const; - datetime_t date() const { + date_t actual_date() const; + date_t effective_date() const; + date_t date() const { if (use_effective_date) return effective_date(); else @@ -70,10 +70,10 @@ static void endElement(void *userData, const char *name) curr_entry = NULL; } else if (std::strcmp(name, "en:date") == 0) { - curr_entry->_date = parse_datetime(data); + curr_entry->_date = parse_date(data); } else if (std::strcmp(name, "en:date_eff") == 0) { - curr_entry->_date_eff = parse_datetime(data); + curr_entry->_date_eff = parse_date(data); } else if (std::strcmp(name, "en:code") == 0) { curr_entry->code = data; |