diff options
author | John Wiegley <johnw@newartisans.com> | 2008-08-02 00:37:36 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2008-08-02 00:37:36 -0400 |
commit | 5bf3f536b37e77b5dd663fffbd32e71b403d2c7a (patch) | |
tree | bb7a434cd8d04b5e67d278e44b2618b4a10efacc | |
parent | 858978de8931ce5c98882472b10051f4e57dd029 (diff) | |
download | fork-ledger-5bf3f536b37e77b5dd663fffbd32e71b403d2c7a.tar.gz fork-ledger-5bf3f536b37e77b5dd663fffbd32e71b403d2c7a.tar.bz2 fork-ledger-5bf3f536b37e77b5dd663fffbd32e71b403d2c7a.zip |
Restored the interval_t time and added a new "period" debugging command.
You can use 'ledger period "daily in june"' to find out how Ledger will parse
that date string, plus up to the first 20 dates it encounters in the range.
Note that the 'end' displayed is currently exclusive.
-rw-r--r-- | main.cc | 25 | ||||
-rw-r--r-- | times.cc | 198 | ||||
-rw-r--r-- | times.h | 136 | ||||
-rw-r--r-- | walk.cc | 11 | ||||
-rw-r--r-- | walk.h | 4 |
5 files changed, 154 insertions, 220 deletions
@@ -222,6 +222,31 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[], fmt.dump(*out); return 0; } + else if (verb == "period") { + interval_t interval(*arg); + + if (! is_valid(interval.begin)) { + *out << "Time period has no beginning." << std::endl; + } else { + *out << "begin: " << format_date(interval.begin) << std::endl; + *out << " end: " << format_date(interval.end) << std::endl; + *out << std::endl; + + date_t date = interval.first(); + + for (int i = 0; i < 20; i++) { + *out << std::right; + out->width(2); + + *out << i << ": " << format_date(date) << std::endl; + + date = interval.increment(date); + if (is_valid(interval.end) && date >= interval.end) + break; + } + } + return 0; + } // Parse the initialization file, which can only be textual; then // parse the journal data. @@ -29,7 +29,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "utils.h" +#include "utils.h" // this brings in times.h namespace ledger { @@ -66,82 +66,92 @@ namespace { }; } -string output_time_format = "%Y/%m/%d"; - -#if 0 -datetime_t datetime_t::now(std::time(NULL)); +optional<string> input_date_format; +string output_date_format = "%Y/%m/%d"; namespace { - static std::time_t base = -1; - static int base_year = -1; + bool parse_date_mask(const char * date_str, std::tm& result) + { + if (input_date_format) { + std::memset(&result, -1, sizeof(std::tm)); + if (strptime(date_str, input_date_format->c_str(), &result)) + return true; + } + for (const char ** f = formats; *f; f++) { + std::memset(&result, -1, sizeof(std::tm)); + if (strptime(date_str, *f, &result)) + return true; + } + return false; + } - static const int month_days[12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; + bool parse_date(const char * date_str, std::tm& result, const int year) + { + if (! parse_date_mask(date_str, result)) + return false; + + result.tm_hour = 0; + result.tm_min = 0; + result.tm_sec = 0; + + if (result.tm_year == -1) + result.tm_year = ((year == -1) ? current_year : year) - 1900; + + if (result.tm_mon == -1) + result.tm_mon = 0; + + if (result.tm_mday == -1) + result.tm_mday = 1; + + return true; + } - bool parse_date_mask(const char * date_str, struct std::tm * result); - bool parse_date(const char * date_str, std::time_t * result, - const int year = -1); - bool quick_parse_date(const char * date_str, std::time_t * result); + bool quick_parse_date(const char * date_str, std::tm& result) + { + return parse_date(date_str, result, current_year); + } } -#endif datetime_t parse_datetime(const char * str) { -#if 0 - return parse_abs_datetime(in); -#else - int year = ((str[0] - '0') * 1000 + - (str[1] - '0') * 100 + - (str[2] - '0') * 10 + - (str[3] - '0')); - - int mon = ((str[5] - '0') * 10 + - (str[6] - '0')); - - int day = ((str[8] - '0') * 10 + - (str[9] - '0')); + std::tm when; + // jww (2008-08-01): This needs to look for HH:MM:SS as well. + quick_parse_date(str, when); + return posix_time::ptime_from_tm(when); +} - return datetime_t(boost::gregorian::date(year, mon, day)); -#endif +date_t parse_date(const char * str) +{ + std::tm when; + quick_parse_date(str, when); + return gregorian::date_from_tm(when); } -date_t interval_t::first(const date_t& moment) const +date_t interval_t::first(const optional<date_t>& moment) const { + if (! is_valid(begin)) + throw_(date_error, + "Use of interval_t::first() with specifying a range start"); + date_t quant(begin); if (! advanced) advanced = true; -#if 0 - if (is_valid(moment) && moment > quant) { + if (moment && *moment > quant) { // Find an efficient starting point for the upcoming while loop. // We want a date early enough that the range will be correct, but // late enough that we don't spend hundreds of thousands of loops // skipping through time. - struct std::tm * desc = std::localtime(&moment.when); - - if (years) - desc->tm_mon = 0; - desc->tm_mday = 1; - - desc->tm_hour = 0; - desc->tm_min = 0; - desc->tm_sec = 0; - desc->tm_isdst = -1; - - quant = std::mktime(desc); - + date_t quant(moment->year(), gregorian::Jan, 1); date_t temp; - while (moment >= (temp = increment(quant))) { + while (*moment >= (temp = increment(quant))) { if (quant == temp) break; quant = temp; } } -#endif - return quant; } @@ -150,8 +160,8 @@ date_t interval_t::increment(const date_t& moment) const date_t future(moment); if (years) future += gregorian::years(years); - if (months) future += gregorian::years(months); - if (days) future += gregorian::years(days); + if (months) future += gregorian::months(months); + if (days) future += gregorian::days(days); return future; } @@ -160,11 +170,9 @@ namespace { void parse_inclusion_specifier(const string& word, 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)) + if (! parse_date_mask(word.c_str(), when)) throw_(date_error, "Could not parse date mask: " << word); when.tm_hour = 0; @@ -177,7 +185,7 @@ namespace { bool saw_day = true; if (when.tm_year == -1) { - when.tm_year = date_t::current_year - 1900; + when.tm_year = current_year - 1900; saw_year = false; } if (when.tm_mon == -1) { @@ -195,19 +203,14 @@ namespace { } if (begin) { - *begin = std::mktime(&when); - assert(int(*begin) != -1); - if (end) { + *begin = gregorian::date_from_tm(when); + if (end) *end = interval_t(saw_day ? 1 : 0, saw_mon ? 1 : 0, saw_year ? 1 : 0).increment(*begin); - assert(int(*end) != -1); - } } else if (end) { - *end = std::mktime(&when); - assert(int(*end) != -1); + *end = gregorian::date_from_tm(when); } -#endif } inline void read_lower_word(std::istream& in, string& word) { @@ -235,18 +238,13 @@ namespace { } if (word == "month") { -#if 0 - // jww (2008-05-08): - std::strftime(buf, 31, "%B", date_t::now.localtime()); -#endif + time_t now = to_time_t(current_time); + std::strftime(buf, 31, "%B", localtime(&now)); word = buf; mon_spec = true; } else if (word == "year") { -#if 0 - // jww (2008-05-08): - std::strftime(buf, 31, "%Y", date_t::now.localtime()); -#endif + std::sprintf(buf, "%04d", current_year); word = buf; } @@ -349,62 +347,4 @@ void interval_t::parse(std::istream& in) } } -namespace { - bool parse_date_mask(const char * date_str, struct std::tm * result) - { -#if 0 - // jww (2008-05-08): - if (! date_t::input_format.empty()) { - std::memset(result, -1, sizeof(struct std::tm)); - if (strptime(date_str, date_t::input_format.c_str(), result)) - return true; - } - for (const char ** f = formats; *f; f++) { - std::memset(result, INT_MAX, sizeof(struct std::tm)); - if (strptime(date_str, *f, result)) - return true; - } -#endif - return false; - } - - bool parse_date(const char * date_str, std::time_t * result, const int year) - { -#if 0 - // jww (2008-05-08): - struct std::tm when; - - if (! parse_date_mask(date_str, &when)) - return false; - - when.tm_hour = 0; - when.tm_min = 0; - when.tm_sec = 0; - - if (when.tm_year == -1) - when.tm_year = ((year == -1) ? date_t::current_year : year) - 1900; - - if (when.tm_mon == -1) - when.tm_mon = 0; - - if (when.tm_mday == -1) - when.tm_mday = 1; - - *result = std::mktime(&when); -#endif - - return true; - } - - bool quick_parse_date(const char * date_str, std::time_t * result) - { -#if 0 - // jww (2008-05-08): - return parse_date(date_str, result, date_t::current_year); -#else - return false; -#endif - } -} - } // namespace ledger @@ -54,41 +54,79 @@ inline bool is_valid(const date_t& moment) { 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; +extern optional<string> input_date_format; +extern string output_date_format; + +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 parse_date(str.c_str()); +} +date_t parse_date(const char * str); + +inline std::time_t to_time_t(const ptime& t) +{ + if( t == posix_time::neg_infin ) + return 0; + else if( t == posix_time::pos_infin ) + return LONG_MAX; + ptime start(date(1970,1,1)); + return (t-start).total_seconds(); +} + +inline string format_datetime(const datetime_t& when) +{ + char buf[256]; + time_t moment = to_time_t(when); + std::strftime(buf, 255, (output_date_format + " %H:%M:%S").c_str(), + std::localtime(&moment)); + return buf; +} + +inline string format_date(const date_t& when, + const optional<string>& format = none) +{ + if (format) { + char buf[256]; + std::tm moment = gregorian::to_tm(when); + std::strftime(buf, 255, format->c_str(), &moment); + return buf; + } else { + return to_iso_extended_string(when); + } +} struct interval_t { - unsigned short years; - unsigned short months; - unsigned short days; - date_t begin; - date_t end; - mutable bool advanced; + int years; + int months; + int days; + date_t begin; + date_t end; + + mutable bool advanced; interval_t(int _days = 0, int _months = 0, int _years = 0, const date_t& _begin = date_t(), const date_t& _end = date_t()) : years(_years), months(_months), days(_days), begin(_begin), end(_end), advanced(false) { - TRACE_CTOR(interval_t, - "int, int, int, const date_t&, const date_t&"); + TRACE_CTOR(interval_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), - begin(other.begin), end(other.end), - advanced(other.advanced) { TRACE_CTOR(interval_t, "copy"); } - interval_t(const string& desc) - : years(0), months(0), days(0), - begin(), end(), advanced(false) { + : years(0), months(0), days(0), begin(), end(), advanced(false) { TRACE_CTOR(interval_t, "const string&"); std::istringstream stream(desc); parse(stream); @@ -99,82 +137,18 @@ struct interval_t } operator bool() const { - return years > 0 || months > 0 || days > 0; + return years != 0 || months != 0 || days != 0; } void start(const date_t& moment) { begin = first(moment); } - date_t first(const date_t& moment = date_t()) const; + date_t first(const optional<date_t>& moment = none) const; date_t increment(const date_t&) const; void parse(std::istream& in); }; -#if 0 -inline datetime_t ptime_local_to_utc(const datetime_t& when) { - struct std::tm tm_gmt = to_tm(when); - return boost::posix_time::from_time_t(std::mktime(&tm_gmt)); -} - -// jww (2007-04-18): I need to make a general parsing function -// instead, and then make these into private methods. -inline datetime_t ptime_from_local_date_string(const string& date_string) { - return ptime_local_to_utc(datetime_t(boost::gregorian::from_string(date_string), - time_duration())); -} - -inline datetime_t ptime_from_local_time_string(const string& time_string) { - return ptime_local_to_utc(boost::posix_time::time_from_string(time_string)); -} -#endif - -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) -{ - if( t == posix_time::neg_infin ) - return 0; - else if( t == posix_time::pos_infin ) - return LONG_MAX; - ptime start(date(1970,1,1)); - return (t-start).total_seconds(); -} - -inline string format_datetime(const datetime_t& when) { - char buf[64]; - time_t moment = to_time_t(when); - // jww (2008-07-29): Need to make the output format configurable - std::strftime(buf, 63, "%Y/%m/%d", std::localtime(&moment)); - return buf; -} - -inline string format_date(const date_t& when) { - return to_iso_extended_string(when); -} - -#if 0 -struct intorchar -{ - int ival; - string sval; - - intorchar() : ival(-1) {} - intorchar(int val) : ival(val) {} - intorchar(const string& val) : ival(-1), sval(val) {} - intorchar(const intorchar& o) : ival(o.ival), sval(o.sval) {} -}; - -ledger::datetime_t parse_abs_datetime(std::istream& input); -#endif - } // namespace ledger #endif // _TIMES_H @@ -438,15 +438,10 @@ void subtotal_xacts::report_subtotal(const char * spec_fmt) std::ostringstream out_date; if (! spec_fmt) { string fmt = "- "; - fmt += output_time_format; // jww (2008-04-24): output_date_format? - // jww (2008-04-24): There is no date output function? -#if 0 - finish.write(out_date, fmt); -#endif + fmt += output_date_format; + out_date << format_date(finish, string(fmt)); } else { -#if 0 - finish.write(out_date, spec_fmt); -#endif + out_date << format_date(finish, string(spec_fmt)); } entry_temps.push_back(entry_t()); @@ -657,8 +657,8 @@ protected: values_map values; bool remember_components; - std::list<entry_t> entry_temps; - std::list<xact_t> xact_temps; + std::list<entry_t> entry_temps; + std::list<xact_t> xact_temps; public: date_t start; |