Rewrote the date interval parser/stepper
The new implementation uses boost::gregorian::date_duration objects, rather than manually stepping.
This commit is contained in:
parent
aba7a39e87
commit
dda7c3a58a
5 changed files with 111 additions and 27 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
101
src/times.cc
101
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
|
||||
|
|
|
|||
10
src/times.h
10
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue