diff options
-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; |