diff options
-rw-r--r-- | src/derive.cc | 8 | ||||
-rw-r--r-- | src/global.cc | 7 | ||||
-rw-r--r-- | src/times.cc | 101 | ||||
-rw-r--r-- | src/times.h | 10 | ||||
-rw-r--r-- | test/unit/t_times.cc | 12 |
5 files changed, 111 insertions, 27 deletions
diff --git a/src/derive.cc b/src/derive.cc index 84fe4fba..98c50fe1 100644 --- a/src/derive.cc +++ b/src/derive.cc @@ -121,12 +121,12 @@ namespace { value_t::sequence_t::const_iterator end) { regex date_mask(_("([0-9]+(?:[-/.][0-9]+)?(?:[-/.][0-9]+))?")); - regex dow_mask(_("(sun|mon|tue|wed|thu|fri|sat)")); smatch what; xact_template_t tmpl; - bool check_for_date = true; + bool check_for_date = true; + optional<date_time::weekdays> weekday; xact_template_t::post_template_t * post = NULL; for (; begin != end; begin++) { @@ -136,8 +136,8 @@ namespace { check_for_date = false; } else if (check_for_date && - regex_match((*begin).to_string(), what, dow_mask)) { - short dow = static_cast<short>(string_to_day_of_week(what[0])); + bool(weekday = string_to_day_of_week(what[0]))) { + short dow = static_cast<short>(*weekday); date_t date = CURRENT_DATE() - date_duration(1); while (date.day_of_week() != dow) date -= date_duration(1); diff --git a/src/global.cc b/src/global.cc index 3b491c0e..a258d0bb 100644 --- a/src/global.cc +++ b/src/global.cc @@ -387,8 +387,11 @@ void global_scope_t::normalize_report_options(const string& verb) output_datetime_format = rep.HANDLER(date_format_).str() + " %H:%M:%S"; output_date_format = rep.HANDLER(date_format_).str(); } - if (rep.HANDLED(start_of_week_)) - start_of_week = string_to_day_of_week(rep.HANDLER(start_of_week_).str()); + if (rep.HANDLED(start_of_week_)) { + if (optional<date_time::weekdays> weekday = + string_to_day_of_week(rep.HANDLER(start_of_week_).str())) + start_of_week = *weekday; + } // jww (2008-08-14): This code really needs to be rationalized away for 3.0. // I might be able to do it with command objects, like register_t, which diff --git a/src/times.cc b/src/times.cc index 4bf5241b..5371b1da 100644 --- a/src/times.cc +++ b/src/times.cc @@ -35,7 +35,7 @@ namespace ledger { -int start_of_week = 0; +date_time::weekdays start_of_week = gregorian::Sunday; optional<std::string> input_date_format; std::string output_datetime_format = "%Y-%m-%d %H:%M:%S"; std::string output_date_format = "%Y-%m-%d"; @@ -54,11 +54,6 @@ namespace { "%Y-%m-%d", "%m-%d", "%Y-%m", - "%a", - "%A", - "%b", - "%B", - "%Y", NULL }; @@ -107,7 +102,7 @@ namespace { } } -date_time::weekdays string_to_day_of_week(const std::string& str) +optional<date_time::weekdays> string_to_day_of_week(const std::string& str) { if (str == _("sun") || str == _("sunday") || str == "0") return gregorian::Sunday; @@ -123,11 +118,41 @@ date_time::weekdays string_to_day_of_week(const std::string& str) return gregorian::Friday; else if (str == _("sat") || str == _("saturday") || str == "6") return gregorian::Saturday; - - assert(false); - return gregorian::Sunday; + else + return none; } +optional<date_time::months_of_year> +string_to_month_of_year(const std::string& str) +{ + if (str == _("jan") || str == _("january") || str == "0") + return gregorian::Jan; + else if (str == _("feb") || str == _("february") || str == "1") + return gregorian::Feb; + else if (str == _("mar") || str == _("march") || str == "2") + return gregorian::Mar; + else if (str == _("apr") || str == _("april") || str == "3") + return gregorian::Apr; + else if (str == _("may") || str == _("may") || str == "4") + return gregorian::May; + else if (str == _("jun") || str == _("june") || str == "5") + return gregorian::Jun; + else if (str == _("jul") || str == _("july") || str == "6") + return gregorian::Jul; + else if (str == _("aug") || str == _("august") || str == "7") + return gregorian::Aug; + else if (str == _("sep") || str == _("september") || str == "8") + return gregorian::Sep; + else if (str == _("oct") || str == _("october") || str == "9") + return gregorian::Oct; + else if (str == _("nov") || str == _("november") || str == "10") + return gregorian::Nov; + else if (str == _("dec") || str == _("december") || str == "11") + return gregorian::Dec; + else + return none; +} + datetime_t parse_datetime(const char * str, int) { std::tm when; @@ -335,11 +360,16 @@ bool date_interval_t::find_period(const date_t& date) return false; } - if (end_of_duration && date < *end_of_duration) { - DEBUG("times.interval", - "true: date [" << date << "] < end_of_duration [" - << *end_of_duration << "]"); - return true; + if (end_of_duration) { + if (date < *end_of_duration) { + DEBUG("times.interval", + "true: date [" << date << "] < end_of_duration [" + << *end_of_duration << "]"); + return true; + } + } else { + DEBUG("times.interval", "false: there is no end_of_duration"); + return false; } // If we've reached here, it means the date does not fall into the current @@ -524,6 +554,10 @@ void date_interval_t::parse(std::istream& in) { string word; + optional<date_time::months_of_year> mon; + optional<date_time::weekdays> wday; + optional<date_t::year_type> year; + while (! in.eof()) { read_lower_word(in, word); if (word == _("every")) { @@ -583,13 +617,50 @@ void date_interval_t::parse(std::istream& in) read_lower_word(in, word); parse_date_words(in, word, *this, false, true); } + else if (optional<date_time::months_of_year> + m = string_to_month_of_year(word)) { + mon = m; + } + else if (optional<date_time::weekdays> + d = string_to_day_of_week(word)) { + wday = d; + } + else if (all(word, is_digit())) { + year = lexical_cast<unsigned short>(word); + } else { + // otherwise, it should be an explicit date date_t b, e; parse_inclusion_specifier(word, &b, &e); start = b; end = e; } } + + if (year || mon || wday) { + if (! start) + start = CURRENT_DATE(); + + if (wday) { + while (start->day_of_week() != *wday) + *start -= gregorian::days(1); + + if (! end) + end = *start + gregorian::days(1); + } else { + if (year) { + start = date_t(*year, 1, 1); + if (! end) + end = *start + gregorian::years(1); + } + + if (mon) { + start = date_t(start->year(), *mon, 1); + if (! end) + end = *start + gregorian::months(1); + } + } + } } } // namespace ledger diff --git a/src/times.h b/src/times.h index 9750bbfb..141066a5 100644 --- a/src/times.h +++ b/src/times.h @@ -73,14 +73,18 @@ inline bool is_valid(const date_t& moment) { #endif #define CURRENT_DATE() boost::gregorian::day_clock::universal_day() -extern int start_of_week; +extern date_time::weekdays start_of_week; extern optional<std::string> input_date_format; -date_time::weekdays string_to_day_of_week(const std::string& str); +optional<date_time::weekdays> +string_to_day_of_week(const std::string& str); +optional<date_time::months_of_year> +string_to_month_of_year(const std::string& str); datetime_t parse_datetime(const char * str, int current_year = -1); -inline datetime_t parse_datetime(const std::string& str, int current_year = -1) { +inline datetime_t parse_datetime(const std::string& str, + int current_year = -1) { return parse_datetime(str.c_str(), current_year); } diff --git a/test/unit/t_times.cc b/test/unit/t_times.cc index b1dffac8..8485a2c9 100644 --- a/test/unit/t_times.cc +++ b/test/unit/t_times.cc @@ -28,12 +28,14 @@ void DateTimeTestCase::testConstructors() date_t d8; date_t d9; +#if 0 date_t d10; date_t d11; date_t d12; date_t d13; date_t d14; datetime_t d15; +#endif #endif // NOT_FOR_PYTHON d1 = parse_date("1990/01/01"); @@ -47,13 +49,15 @@ void DateTimeTestCase::testConstructors() d8 = parse_date("2006-12-25"); d9 = parse_date("12-25"); +#ifndef NOT_FOR_PYTHON +#if 0 d10 = parse_date("tue"); d11 = parse_date("tuesday"); d12 = parse_date("feb"); d13 = parse_date("february"); d14 = parse_date("2006"); -#ifndef NOT_FOR_PYTHON d15 = d3; +#endif #endif // NOT_FOR_PYTHON #ifndef NOT_FOR_PYTHON @@ -66,17 +70,19 @@ void DateTimeTestCase::testConstructors() assertTrue(CURRENT_DATE() > d4); #ifndef NOT_FOR_PYTHON +#if 0 assertEqual(d3, d15); +#endif #endif // NOT_FOR_PYTHON assertEqual(d4, d6); assertEqual(d4, d8); assertEqual(d5, d7); assertEqual(d5, d9); +#ifndef NOT_FOR_PYTHON +#if 0 assertEqual(d10, d11); assertEqual(d12, d13); -#if 0 -#ifndef NOT_FOR_PYTHON assertThrow(parse_date("2007/02/29"), boost::gregorian::bad_day_of_month); //assertThrow(parse_date("2007/13/01"), datetime_error); //assertThrow(parse_date("2007/00/01"), datetime_error); |