summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/derive.cc8
-rw-r--r--src/global.cc7
-rw-r--r--src/times.cc101
-rw-r--r--src/times.h10
-rw-r--r--test/unit/t_times.cc12
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);