summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/item.cc4
-rw-r--r--src/item.h6
-rw-r--r--src/session.h2
-rw-r--r--src/system.hh.in4
-rw-r--r--src/textual.cc5
-rw-r--r--src/times.cc174
-rw-r--r--src/times.h45
-rw-r--r--test/regress/461980A1.test2
-rw-r--r--test/regress/55831A79.test2
9 files changed, 120 insertions, 124 deletions
diff --git a/src/item.cc b/src/item.cc
index 9e297052..54f36e11 100644
--- a/src/item.cc
+++ b/src/item.cc
@@ -114,7 +114,7 @@ void item_t::set_tag(const string& tag,
assert(result.second);
}
-void item_t::parse_tags(const char * p, int current_year)
+void item_t::parse_tags(const char * p, optional<date_t::year_type> current_year)
{
if (const char * b = std::strchr(p, '[')) {
if (const char * e = std::strchr(p, ']')) {
@@ -160,7 +160,7 @@ void item_t::parse_tags(const char * p, int current_year)
}
}
-void item_t::append_note(const char * p, int current_year)
+void item_t::append_note(const char * p, optional<date_t::year_type> current_year)
{
if (note) {
*note += '\n';
diff --git a/src/item.h b/src/item.h
index 1d9a63c7..7855d6b7 100644
--- a/src/item.h
+++ b/src/item.h
@@ -129,8 +129,10 @@ public:
virtual void set_tag(const string& tag,
const optional<string>& value = none);
- virtual void parse_tags(const char * p, int current_year = -1);
- virtual void append_note(const char * p, int current_year = -1);
+ virtual void parse_tags(const char * p,
+ optional<date_t::year_type> current_year = none);
+ virtual void append_note(const char * p,
+ optional<date_t::year_type> current_year = none);
static bool use_effective_date;
diff --git a/src/session.h b/src/session.h
index 5d6a12b9..894c59fa 100644
--- a/src/session.h
+++ b/src/session.h
@@ -67,7 +67,7 @@ class session_t : public symbol_scope_t
public:
bool flush_on_next_data_file;
- int current_year;
+ date_t::year_type current_year;
shared_ptr<commodity_pool_t> commodity_pool;
scoped_ptr<account_t> master;
diff --git a/src/system.hh.in b/src/system.hh.in
index 2358ddcd..1f4a7d63 100644
--- a/src/system.hh.in
+++ b/src/system.hh.in
@@ -53,6 +53,7 @@
#include <algorithm>
#include <exception>
#include <typeinfo>
+#include <locale>
#include <stdexcept>
#include <iostream>
#include <streambuf>
@@ -98,7 +99,6 @@ typedef std::ostream::pos_type ostream_pos_type;
#include <cstdio>
#include <cstdlib>
#include <cstring>
-#include <ctime>
#include <csignal>
#if defined __FreeBSD__ && __FreeBSD__ <= 4
@@ -144,6 +144,8 @@ typedef std::ostream::pos_type ostream_pos_type;
#include <boost/cast.hpp>
#include <boost/current_function.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/date_time/posix_time/posix_time_io.hpp>
+#include <boost/date_time/gregorian/gregorian_io.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/filesystem/exception.hpp>
#include <boost/filesystem/fstream.hpp>
diff --git a/src/textual.cc b/src/textual.cc
index 35fa0028..967e2f1b 100644
--- a/src/textual.cc
+++ b/src/textual.cc
@@ -65,7 +65,6 @@ namespace {
account_t * master;
const path * original_file;
accounts_map account_aliases;
- int current_year;
bool strict;
path pathname;
@@ -76,6 +75,8 @@ namespace {
std::size_t count;
std::size_t errors;
+ optional<date_t::year_type> current_year;
+
scoped_ptr<auto_xact_finalizer_t> auto_xact_finalizer;
instance_t(std::list<account_t *>& _account_stack,
@@ -476,7 +477,7 @@ void instance_t::nomarket_directive(char * line)
void instance_t::year_directive(char * line)
{
- current_year = lexical_cast<int>(skip_ws(line + 1));
+ current_year = lexical_cast<unsigned short>(skip_ws(line + 1));
}
void instance_t::option_directive(char * line)
diff --git a/src/times.cc b/src/times.cc
index deb51058..45f7ed10 100644
--- a/src/times.cc
+++ b/src/times.cc
@@ -41,64 +41,83 @@ std::string output_datetime_format = "%Y-%m-%d %H:%M:%S";
std::string output_date_format = "%Y-%m-%d";
namespace {
- const char * formats[] = {
- "%y/%m/%d",
- "%Y/%m/%d",
- "%m/%d",
- "%Y/%m",
- "%y.%m.%d",
- "%Y.%m.%d",
- "%m.%d",
- "%Y.%m",
- "%y-%m-%d",
- "%Y-%m-%d",
- "%m-%d",
- "%Y-%m",
- NULL
+ struct date_format_t {
+ const char * format;
+ bool has_year;
+ date_format_t(const char * _format, bool _has_year)
+ : format(_format), has_year(_has_year) {}
};
- 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;
- }
+ const date_format_t formats[] = {
+ date_format_t("%m/%d", false),
+ date_format_t("%Y/%m/%d", true),
+ date_format_t("%Y/%m", true),
+ date_format_t("%y/%m/%d", true),
+ date_format_t("%m.%d", false),
+ date_format_t("%Y.%m.%d", true),
+ date_format_t("%Y.%m", true),
+ date_format_t("%y.%m.%d", true),
+ date_format_t("%m-%d", false),
+ date_format_t("%Y-%m-%d", true),
+ date_format_t("%Y-%m", true),
+ date_format_t("%y-%m-%d", true)
+ };
- bool quick_parse_date(const char * date_str, std::tm& result, const int year)
+ date_t parse_date_mask_routine(const char * date_str, const date_format_t& df,
+ optional<date_t::year_type> year, bool& saw_year)
{
- if (! parse_date_mask(date_str, result))
- return false;
+ std::string str(date_str);
- result.tm_hour = 0;
- result.tm_min = 0;
- result.tm_sec = 0;
+ gregorian::date_input_facet * facet(new gregorian::date_input_facet(df.format));
+ std::istringstream sstr(str);
+ sstr.imbue(std::locale(sstr.getloc(), facet));
- if (result.tm_mday == -1)
- result.tm_mday = 1;
+ date_t when;
+ sstr >> when;
- if (result.tm_mon == -1) {
- result.tm_mon = 0;
+ if (! when.is_not_a_date()) {
+ if (sstr.good() && ! sstr.eof() && sstr.peek() != EOF)
+ return date_t();
- if (result.tm_mday > (CURRENT_DATE().day() - 1))
- result.tm_mon = 11;
+ DEBUG("times.parse", "Parsed date string: " << date_str);
+ DEBUG("times.parse", "Parsed result is: " << when);
+ DEBUG("times.parse", "Format used was: " << df.format);
+
+ if (! df.has_year) {
+ saw_year = false;
+
+ when = date_t(year ? *year : CURRENT_DATE().year(),
+ when.month(), when.day());
+
+ if (when.month() > CURRENT_DATE().month())
+ when -= gregorian::years(1);
+ } else {
+ saw_year = true;
+ }
}
+ return when;
+ }
- if (result.tm_year == -1) {
- result.tm_year = (year == -1 ? int(CURRENT_DATE().year()) : year) - 1900;
+ date_t parse_date_mask(const char * date_str, optional<date_t::year_type> year,
+ bool& saw_year)
+ {
+ if (input_date_format) {
+ date_format_t df(input_date_format->c_str(), true);
+ if (! icontains(*input_date_format, "%y"))
+ df.has_year = false;
+ date_t when = parse_date_mask_routine(date_str, df, year, saw_year);
+ if (! when.is_not_a_date())
+ return when;
+ }
- if (year == -1 && result.tm_mon > (CURRENT_DATE().month() - 1))
- result.tm_year--;
+ for (uint8_t i = 0; i < (sizeof(formats) / sizeof(date_format_t)); i++) {
+ date_t when = parse_date_mask_routine(date_str, formats[i], year,
+ saw_year);
+ if (! when.is_not_a_date())
+ return when;
}
- return true;
+ return date_t();
}
}
@@ -153,21 +172,24 @@ string_to_month_of_year(const std::string& str)
return none;
}
-datetime_t parse_datetime(const char * str, int)
+datetime_t parse_datetime(const char * str, optional<date_t::year_type>)
{
- std::tm when;
- std::memset(&when, -1, sizeof(std::tm));
- if (strptime(str, "%Y/%m/%d %H:%M:%S", &when))
- return posix_time::ptime_from_tm(when);
- else
- return datetime_t();
+ posix_time::time_input_facet * facet
+ (new posix_time::time_input_facet("%Y/%m/%d %H:%M:%S"));
+
+ std::string temp(str);
+ std::istringstream sstr(temp);
+ sstr.imbue(std::locale(sstr.getloc(), facet));
+
+ datetime_t when;
+ sstr >> when;
+ return when;
}
-date_t parse_date(const char * str, int current_year)
+date_t parse_date(const char * str, optional<date_t::year_type> current_year)
{
- std::tm when;
- quick_parse_date(str, when, current_year);
- return gregorian::date_from_tm(when);
+ bool saw_year;
+ return parse_date_mask(str, current_year, saw_year);
}
date_t date_interval_t::add_duration(const date_t& date,
@@ -436,52 +458,24 @@ namespace {
date_t * begin,
date_t * end)
{
- struct std::tm when;
+ bool saw_year = true;
+ date_t when = parse_date_mask(word.c_str(), none, saw_year);
- if (! parse_date_mask(word.c_str(), when))
+ if (when.is_not_a_date())
throw_(date_error, _("Could not parse date mask: %1") << word);
- when.tm_hour = 0;
- when.tm_min = 0;
- when.tm_sec = 0;
- when.tm_isdst = -1;
-
- bool saw_year = true;
- bool saw_mon = true;
- bool saw_day = true;
-
- if (when.tm_year == -1) {
- when.tm_year = CURRENT_DATE().year() - 1900;
- saw_year = false;
- }
- if (when.tm_mon == -1) {
- when.tm_mon = 0;
- saw_mon = false;
- } else {
- saw_year = false; // don't increment by year if month used
- }
- if (when.tm_mday == -1) {
- when.tm_mday = 1;
- saw_day = false;
- } else {
- saw_mon = false; // don't increment by month if day used
- saw_year = false; // don't increment by year if day used
- }
-
if (begin) {
- *begin = gregorian::date_from_tm(when);
+ *begin = when;
if (end) {
if (saw_year)
*end = *begin + gregorian::years(1);
- else if (saw_mon)
+ else
*end = *begin + gregorian::months(1);
- else if (saw_day)
- *end = *begin + gregorian::days(1);
}
}
else if (end) {
- *end = gregorian::date_from_tm(when);
+ *end = when;
}
}
diff --git a/src/times.h b/src/times.h
index 1ff98325..247c9393 100644
--- a/src/times.h
+++ b/src/times.h
@@ -81,39 +81,34 @@ 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);
+datetime_t parse_datetime(const char * str,
+ optional<date_t::year_type> current_year = none);
inline datetime_t parse_datetime(const std::string& str,
- int current_year = -1) {
+ optional<date_t::year_type> current_year = none) {
return parse_datetime(str.c_str(), current_year);
}
-date_t parse_date(const char * str, int current_year = -1);
+date_t parse_date(const char * str,
+ optional<date_t::year_type> current_year = none);
-inline date_t parse_date(const std::string& str, int current_year = -1) {
+inline date_t parse_date(const std::string& str,
+ optional<date_t::year_type> current_year = none) {
return parse_date(str.c_str(), current_year);
}
-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();
-}
-
extern std::string output_datetime_format;
inline std::string format_datetime(const datetime_t& when,
const optional<std::string>& format = none)
{
- char buf[256];
- std::time_t moment = to_time_t(when);
- std::strftime(buf, 255, format ? format->c_str() :
- output_datetime_format.c_str(), std::localtime(&moment));
- return buf;
+ posix_time::time_facet * facet
+ (new posix_time::time_facet(format ? format->c_str() :
+ output_datetime_format.c_str()));
+ std::ostringstream buf;
+ buf.imbue(std::locale(std::locale::classic(), facet));
+ buf << when;
+ return buf.str();
}
extern std::string output_date_format;
@@ -121,11 +116,13 @@ extern std::string output_date_format;
inline std::string format_date(const date_t& when,
const optional<std::string>& format = none)
{
- char buf[256];
- std::tm moment = gregorian::to_tm(when);
- std::strftime(buf, 255, format ? format->c_str() :
- output_date_format.c_str(), &moment);
- return buf;
+ gregorian::date_facet * facet
+ (new gregorian::date_facet(format ? format->c_str() :
+ output_date_format.c_str()));
+ std::ostringstream buf;
+ buf.imbue(std::locale(std::locale::classic(), facet));
+ buf << when;
+ return buf.str();
}
class date_interval_t : public equality_comparable<date_interval_t>
diff --git a/test/regress/461980A1.test b/test/regress/461980A1.test
index d78b5fb7..bbf2ee4e 100644
--- a/test/regress/461980A1.test
+++ b/test/regress/461980A1.test
@@ -1,6 +1,6 @@
bal
<<<
-2008/1/1 one
+2008/01/01 one
test:a 1
test:b
>>>1
diff --git a/test/regress/55831A79.test b/test/regress/55831A79.test
index 3f4a6348..d553bdfa 100644
--- a/test/regress/55831A79.test
+++ b/test/regress/55831A79.test
@@ -13,7 +13,7 @@ bal discover
liabilities:credit cards:discover 4462:interest $-28.17
assets:bank:wells fargo:checking
-2008/3/1 * discover card payment
+2008/03/01 * discover card payment
liabilities:credit cards:discover 4462 $1198.14
assets:bank:wells fargo:checking
>>>1