more time interval support: last month, last feb, next year, etc.
This commit is contained in:
parent
9d1bdd0989
commit
8af33274fb
8 changed files with 101 additions and 54 deletions
62
datetime.cc
62
datetime.cc
|
|
@ -5,8 +5,8 @@
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
std::time_t now = std::time(NULL);
|
std::time_t now = std::time(NULL);
|
||||||
struct std::tm * now_tm = std::localtime(&now);
|
int now_year = std::localtime(&now)->tm_year;
|
||||||
|
|
||||||
static std::time_t base = -1;
|
static std::time_t base = -1;
|
||||||
static int base_year = -1;
|
static int base_year = -1;
|
||||||
|
|
@ -35,9 +35,11 @@ std::time_t interval_t::increment(const std::time_t moment)
|
||||||
std::time_t then = moment;
|
std::time_t then = moment;
|
||||||
|
|
||||||
if (years || months) {
|
if (years || months) {
|
||||||
struct std::tm * desc = std::gmtime(&then);
|
struct std::tm * desc = std::localtime(&then);
|
||||||
|
|
||||||
if (years)
|
if (years)
|
||||||
desc->tm_year += years;
|
desc->tm_year += years;
|
||||||
|
|
||||||
if (months) {
|
if (months) {
|
||||||
desc->tm_mon += months;
|
desc->tm_mon += months;
|
||||||
|
|
||||||
|
|
@ -45,7 +47,12 @@ std::time_t interval_t::increment(const std::time_t moment)
|
||||||
desc->tm_year++;
|
desc->tm_year++;
|
||||||
desc->tm_mon -= 12;
|
desc->tm_mon -= 12;
|
||||||
}
|
}
|
||||||
|
else if (desc->tm_mon < 0) {
|
||||||
|
desc->tm_year--;
|
||||||
|
desc->tm_mon += 12;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
then = std::mktime(desc);
|
then = std::mktime(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,7 +76,7 @@ static void parse_inclusion_specifier(const std::string& word,
|
||||||
bool saw_mon = true;
|
bool saw_mon = true;
|
||||||
|
|
||||||
if (when.tm_year == -1) {
|
if (when.tm_year == -1) {
|
||||||
when.tm_year = now_tm->tm_year;
|
when.tm_year = now_year;
|
||||||
saw_year = false;
|
saw_year = false;
|
||||||
}
|
}
|
||||||
if (when.tm_mon == -1) {
|
if (when.tm_mon == -1) {
|
||||||
|
|
@ -135,6 +142,47 @@ interval_t * interval_t::parse(std::istream& in,
|
||||||
months = 3;
|
months = 3;
|
||||||
else if (word == "yearly")
|
else if (word == "yearly")
|
||||||
years = 1;
|
years = 1;
|
||||||
|
else if (word == "this" || word == "last" || word == "next") {
|
||||||
|
std::string type = word;
|
||||||
|
bool mon_spec = false;
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
if (! in.eof())
|
||||||
|
in >> word;
|
||||||
|
else
|
||||||
|
word = "month";
|
||||||
|
|
||||||
|
if (word == "month") {
|
||||||
|
std::strftime(buf, 31, "%B", std::localtime(&now));
|
||||||
|
word = buf;
|
||||||
|
mon_spec = true;
|
||||||
|
}
|
||||||
|
else if (word == "year") {
|
||||||
|
std::strftime(buf, 31, "%Y", std::localtime(&now));
|
||||||
|
word = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_inclusion_specifier(word, begin, end);
|
||||||
|
|
||||||
|
if (type == "last") {
|
||||||
|
if (mon_spec) {
|
||||||
|
*begin = interval_t(0, -1, 0).increment(*begin);
|
||||||
|
*end = interval_t(0, -1, 0).increment(*end);
|
||||||
|
} else {
|
||||||
|
*begin = interval_t(0, 0, -1).increment(*begin);
|
||||||
|
*end = interval_t(0, 0, -1).increment(*end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == "next") {
|
||||||
|
if (mon_spec) {
|
||||||
|
*begin = interval_t(0, 1, 0).increment(*begin);
|
||||||
|
*end = interval_t(0, 1, 0).increment(*end);
|
||||||
|
} else {
|
||||||
|
*begin = interval_t(0, 0, 1).increment(*begin);
|
||||||
|
*end = interval_t(0, 0, 1).increment(*end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (word == "in") {
|
else if (word == "in") {
|
||||||
in >> word;
|
in >> word;
|
||||||
parse_inclusion_specifier(word, begin, end);
|
parse_inclusion_specifier(word, begin, end);
|
||||||
|
|
@ -180,7 +228,7 @@ bool parse_date(const char * date_str, std::time_t * result, const int year)
|
||||||
when.tm_sec = 0;
|
when.tm_sec = 0;
|
||||||
|
|
||||||
if (when.tm_year == -1)
|
if (when.tm_year == -1)
|
||||||
when.tm_year = ((year == -1) ? now_tm->tm_year : (year - 1900));
|
when.tm_year = ((year == -1) ? now_year : (year - 1900));
|
||||||
|
|
||||||
if (when.tm_mon == -1)
|
if (when.tm_mon == -1)
|
||||||
when.tm_mon = 0;
|
when.tm_mon = 0;
|
||||||
|
|
@ -225,8 +273,8 @@ bool quick_parse_date(char * date_str, std::time_t * result)
|
||||||
struct std::tm when;
|
struct std::tm when;
|
||||||
std::memset(&when, 0, sizeof(when));
|
std::memset(&when, 0, sizeof(when));
|
||||||
|
|
||||||
base_year = year == -1 ? now_tm->tm_year + 1900 : year;
|
base_year = year == -1 ? now_year + 1900 : year;
|
||||||
when.tm_year = year == -1 ? now_tm->tm_year : year - 1900;
|
when.tm_year = year == -1 ? now_year : year - 1900;
|
||||||
when.tm_mday = 1;
|
when.tm_mday = 1;
|
||||||
|
|
||||||
base = std::mktime(&when);
|
base = std::mktime(&when);
|
||||||
|
|
|
||||||
13
datetime.h
13
datetime.h
|
|
@ -9,12 +9,11 @@ namespace ledger {
|
||||||
|
|
||||||
struct interval_t
|
struct interval_t
|
||||||
{
|
{
|
||||||
unsigned long years;
|
int years;
|
||||||
unsigned long months;
|
int months;
|
||||||
unsigned long seconds;
|
int seconds;
|
||||||
|
|
||||||
interval_t(unsigned long _seconds, unsigned long _months = 0,
|
interval_t(int _seconds, int _months = 0, int _years = 0)
|
||||||
unsigned long _years = 0)
|
|
||||||
: years(_years), months(_months), seconds(_seconds) {}
|
: years(_years), months(_months), seconds(_seconds) {}
|
||||||
|
|
||||||
std::time_t increment(const std::time_t);
|
std::time_t increment(const std::time_t);
|
||||||
|
|
@ -23,8 +22,8 @@ struct interval_t
|
||||||
std::time_t * end);
|
std::time_t * end);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::time_t now;
|
extern std::time_t now;
|
||||||
extern struct std::tm * now_tm;
|
extern int now_year;
|
||||||
|
|
||||||
bool parse_date_mask(const char * date_str, struct std::tm * result);
|
bool parse_date_mask(const char * date_str, struct std::tm * result);
|
||||||
|
|
||||||
|
|
|
||||||
8
debug.h
8
debug.h
|
|
@ -92,10 +92,10 @@ inline bool _debug_active(const char * const cls) {
|
||||||
}
|
}
|
||||||
#define DEBUG_PRINT_(x) DEBUG_PRINT(_debug_cls, x)
|
#define DEBUG_PRINT_(x) DEBUG_PRINT(_debug_cls, x)
|
||||||
|
|
||||||
#define DEBUG_PRINT_TIME(cls, x) { \
|
#define DEBUG_PRINT_TIME(cls, x) { \
|
||||||
char buf[256]; \
|
char buf[256]; \
|
||||||
std::strftime(buf, 255, "%Y/%m/%d", std::gmtime(&x)); \
|
std::strftime(buf, 255, "%Y/%m/%d", std::localtime(&x)); \
|
||||||
DEBUG_PRINT(cls, #x << " is " << buf); \
|
DEBUG_PRINT(cls, #x << " is " << buf); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DEBUG_PRINT_TIME_(x) DEBUG_PRINT_TIME(_debug_cls, x)
|
#define DEBUG_PRINT_TIME_(x) DEBUG_PRINT_TIME(_debug_cls, x)
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,7 @@ void format_t::format_elements(std::ostream& out,
|
||||||
if (details.entry && details.entry->date != -1) {
|
if (details.entry && details.entry->date != -1) {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
std::strftime(buf, 255, elem->chars.c_str(),
|
std::strftime(buf, 255, elem->chars.c_str(),
|
||||||
std::gmtime(&details.entry->date));
|
std::localtime(&details.entry->date));
|
||||||
out << (elem->max_width == 0 ? buf : truncated(buf, elem->max_width));
|
out << (elem->max_width == 0 ? buf : truncated(buf, elem->max_width));
|
||||||
} else {
|
} else {
|
||||||
out << " ";
|
out << " ";
|
||||||
|
|
|
||||||
58
main.cc
58
main.cc
|
|
@ -365,35 +365,6 @@ int main(int argc, char * argv[], char * envp[])
|
||||||
show_all_related = true;
|
show_all_related = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile the format strings
|
|
||||||
|
|
||||||
const char * f;
|
|
||||||
if (! config->format_string.empty())
|
|
||||||
f = config->format_string.c_str();
|
|
||||||
else if (command == "b")
|
|
||||||
f = bal_fmt.c_str();
|
|
||||||
else if (command == "r")
|
|
||||||
f = reg_fmt.c_str();
|
|
||||||
else if (command == "E")
|
|
||||||
f = equity_fmt.c_str();
|
|
||||||
else
|
|
||||||
f = print_fmt.c_str();
|
|
||||||
|
|
||||||
std::string first_line_format;
|
|
||||||
std::string next_lines_format;
|
|
||||||
|
|
||||||
if (const char * p = std::strstr(f, "%/")) {
|
|
||||||
first_line_format = std::string(f, 0, p - f);
|
|
||||||
next_lines_format = std::string(p + 2);
|
|
||||||
} else {
|
|
||||||
first_line_format = next_lines_format = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
format_t format(first_line_format);
|
|
||||||
format_t nformat(next_lines_format);
|
|
||||||
|
|
||||||
TIMER_STOP(handle_options);
|
|
||||||
|
|
||||||
// Setup a few local and global variables, depending on the config
|
// Setup a few local and global variables, depending on the config
|
||||||
// settings.
|
// settings.
|
||||||
|
|
||||||
|
|
@ -453,6 +424,35 @@ int main(int argc, char * argv[], char * envp[])
|
||||||
"disp-pred: " << config->display_predicate);
|
"disp-pred: " << config->display_predicate);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Compile the format strings
|
||||||
|
|
||||||
|
const char * f;
|
||||||
|
if (! config->format_string.empty())
|
||||||
|
f = config->format_string.c_str();
|
||||||
|
else if (command == "b")
|
||||||
|
f = bal_fmt.c_str();
|
||||||
|
else if (command == "r")
|
||||||
|
f = reg_fmt.c_str();
|
||||||
|
else if (command == "E")
|
||||||
|
f = equity_fmt.c_str();
|
||||||
|
else
|
||||||
|
f = print_fmt.c_str();
|
||||||
|
|
||||||
|
std::string first_line_format;
|
||||||
|
std::string next_lines_format;
|
||||||
|
|
||||||
|
if (const char * p = std::strstr(f, "%/")) {
|
||||||
|
first_line_format = std::string(f, 0, p - f);
|
||||||
|
next_lines_format = std::string(p + 2);
|
||||||
|
} else {
|
||||||
|
first_line_format = next_lines_format = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
format_t format(first_line_format);
|
||||||
|
format_t nformat(next_lines_format);
|
||||||
|
|
||||||
|
TIMER_STOP(handle_options);
|
||||||
|
|
||||||
// Walk the entries based on the report type and the options
|
// Walk the entries based on the report type and the options
|
||||||
|
|
||||||
TIMER_START(report_gen);
|
TIMER_START(report_gen);
|
||||||
|
|
|
||||||
|
|
@ -476,8 +476,8 @@ unsigned int parse_textual_journal(std::istream& in, journal_t * journal,
|
||||||
|
|
||||||
case 'Y': // set the current year
|
case 'Y': // set the current year
|
||||||
in >> c;
|
in >> c;
|
||||||
in >> now_tm->tm_year;
|
in >> now_year;
|
||||||
now_tm->tm_year -= 1900;
|
now_year -= 1900;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef TIMELOG_SUPPORT
|
#ifdef TIMELOG_SUPPORT
|
||||||
|
|
|
||||||
6
walk.cc
6
walk.cc
|
|
@ -132,9 +132,9 @@ void subtotal_transactions::flush(const char * spec_fmt)
|
||||||
if (start != finish)
|
if (start != finish)
|
||||||
finish -= 86400;
|
finish -= 86400;
|
||||||
|
|
||||||
std::strftime(buf, 255, fmt.c_str(), std::gmtime(&finish));
|
std::strftime(buf, 255, fmt.c_str(), std::localtime(&finish));
|
||||||
} else {
|
} else {
|
||||||
std::strftime(buf, 255, spec_fmt, std::gmtime(&finish));
|
std::strftime(buf, 255, spec_fmt, std::localtime(&finish));
|
||||||
}
|
}
|
||||||
|
|
||||||
entry_t * entry = new entry_t;
|
entry_t * entry = new entry_t;
|
||||||
|
|
@ -199,7 +199,7 @@ void interval_transactions::operator()(transaction_t * xact)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! interval.seconds) {
|
if (! interval.seconds) {
|
||||||
struct std::tm * desc = std::gmtime(&xact->entry->date);
|
struct std::tm * desc = std::localtime(&xact->entry->date);
|
||||||
if (interval.years)
|
if (interval.years)
|
||||||
desc->tm_mon = 0;
|
desc->tm_mon = 0;
|
||||||
desc->tm_mday = 1;
|
desc->tm_mday = 1;
|
||||||
|
|
|
||||||
2
walk.h
2
walk.h
|
|
@ -327,7 +327,7 @@ class dow_transactions : public subtotal_transactions
|
||||||
|
|
||||||
virtual void flush();
|
virtual void flush();
|
||||||
virtual void operator()(transaction_t * xact) {
|
virtual void operator()(transaction_t * xact) {
|
||||||
struct std::tm * desc = std::gmtime(&xact->entry->date);
|
struct std::tm * desc = std::localtime(&xact->entry->date);
|
||||||
days_of_the_week[desc->tm_wday].push_back(xact);
|
days_of_the_week[desc->tm_wday].push_back(xact);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue