interval_t objects now play nicely with python. see the bottom of main.py
This commit is contained in:
parent
e414123ecb
commit
e1d6c4bff2
10 changed files with 140 additions and 63 deletions
14
config.cc
14
config.cc
|
|
@ -42,7 +42,6 @@ config_t::config_t()
|
||||||
download_quotes = false;
|
download_quotes = false;
|
||||||
use_cache = false;
|
use_cache = false;
|
||||||
cache_dirty = false;
|
cache_dirty = false;
|
||||||
interval_begin = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -226,25 +225,22 @@ void config_t::process_options(const std::string& command,
|
||||||
if (! report_interval && ! interval_text.empty()) {
|
if (! report_interval && ! interval_text.empty()) {
|
||||||
try {
|
try {
|
||||||
std::istringstream stream(interval_text);
|
std::istringstream stream(interval_text);
|
||||||
std::time_t begin = -1, end = -1;
|
|
||||||
|
|
||||||
report_interval = interval_t::parse(stream, &begin, &end);
|
report_interval.parse(stream);
|
||||||
|
|
||||||
if (begin != -1) {
|
|
||||||
interval_begin = begin;
|
|
||||||
|
|
||||||
|
if (report_interval.begin) {
|
||||||
if (! predicate.empty())
|
if (! predicate.empty())
|
||||||
predicate += "&";
|
predicate += "&";
|
||||||
char buf[32];
|
char buf[32];
|
||||||
std::sprintf(buf, "d>=%lu", begin);
|
std::sprintf(buf, "d>=%lu", report_interval.begin);
|
||||||
predicate += buf;
|
predicate += buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end != -1) {
|
if (report_interval.end) {
|
||||||
if (! predicate.empty())
|
if (! predicate.empty())
|
||||||
predicate += "&";
|
predicate += "&";
|
||||||
char buf[32];
|
char buf[32];
|
||||||
std::sprintf(buf, "d<%lu", end);
|
std::sprintf(buf, "d<%lu", report_interval.end);
|
||||||
predicate += buf;
|
predicate += buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
config.h
1
config.h
|
|
@ -55,7 +55,6 @@ struct config_t
|
||||||
bool use_cache;
|
bool use_cache;
|
||||||
bool cache_dirty;
|
bool cache_dirty;
|
||||||
interval_t report_interval;
|
interval_t report_interval;
|
||||||
std::time_t interval_begin;
|
|
||||||
format_t format;
|
format_t format;
|
||||||
format_t nformat;
|
format_t nformat;
|
||||||
|
|
||||||
|
|
|
||||||
129
datetime.cc
129
datetime.cc
|
|
@ -30,6 +30,30 @@ static const char * formats[] = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::time_t interval_t::first(const std::time_t moment)
|
||||||
|
{
|
||||||
|
std::time_t quant = begin;
|
||||||
|
|
||||||
|
if (moment && std::difftime(moment, quant) > 0) {
|
||||||
|
if (! seconds) {
|
||||||
|
struct std::tm * desc = std::localtime(&moment);
|
||||||
|
if (years)
|
||||||
|
desc->tm_mon = 0;
|
||||||
|
desc->tm_mday = 1;
|
||||||
|
desc->tm_hour = 0;
|
||||||
|
desc->tm_min = 0;
|
||||||
|
desc->tm_sec = 0;
|
||||||
|
quant = std::mktime(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::time_t temp;
|
||||||
|
while (std::difftime(moment, temp = increment(quant)) > 0)
|
||||||
|
quant = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return quant;
|
||||||
|
}
|
||||||
|
|
||||||
std::time_t interval_t::increment(const std::time_t moment)
|
std::time_t interval_t::increment(const std::time_t moment)
|
||||||
{
|
{
|
||||||
std::time_t then = moment;
|
std::time_t then = moment;
|
||||||
|
|
@ -93,15 +117,10 @@ static void parse_inclusion_specifier(const std::string& word,
|
||||||
saw_year ? 1 : 0).increment(*begin);
|
saw_year ? 1 : 0).increment(*begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
interval_t interval_t::parse(std::istream& in,
|
void interval_t::parse(std::istream& in)
|
||||||
std::time_t * begin,
|
|
||||||
std::time_t * end)
|
|
||||||
{
|
{
|
||||||
unsigned long years = 0;
|
|
||||||
unsigned long months = 0;
|
|
||||||
unsigned long seconds = 0;
|
|
||||||
|
|
||||||
std::string word;
|
std::string word;
|
||||||
|
|
||||||
while (! in.eof()) {
|
while (! in.eof()) {
|
||||||
in >> word;
|
in >> word;
|
||||||
if (word == "every") {
|
if (word == "every") {
|
||||||
|
|
@ -165,57 +184,47 @@ interval_t interval_t::parse(std::istream& in,
|
||||||
word = buf;
|
word = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_inclusion_specifier(word, begin, end);
|
parse_inclusion_specifier(word, &begin, &end);
|
||||||
|
|
||||||
if (type == "last") {
|
if (type == "last") {
|
||||||
if (mon_spec) {
|
if (mon_spec) {
|
||||||
if (begin)
|
begin = interval_t(0, -1, 0).increment(begin);
|
||||||
*begin = interval_t(0, -1, 0).increment(*begin);
|
end = interval_t(0, -1, 0).increment(end);
|
||||||
if (end)
|
|
||||||
*end = interval_t(0, -1, 0).increment(*end);
|
|
||||||
} else {
|
} else {
|
||||||
if (begin)
|
begin = interval_t(0, 0, -1).increment(begin);
|
||||||
*begin = interval_t(0, 0, -1).increment(*begin);
|
end = interval_t(0, 0, -1).increment(end);
|
||||||
if (end)
|
|
||||||
*end = interval_t(0, 0, -1).increment(*end);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (type == "next") {
|
else if (type == "next") {
|
||||||
if (mon_spec) {
|
if (mon_spec) {
|
||||||
if (begin)
|
begin = interval_t(0, 1, 0).increment(begin);
|
||||||
*begin = interval_t(0, 1, 0).increment(*begin);
|
end = interval_t(0, 1, 0).increment(end);
|
||||||
if (end)
|
|
||||||
*end = interval_t(0, 1, 0).increment(*end);
|
|
||||||
} else {
|
} else {
|
||||||
if (begin)
|
begin = interval_t(0, 0, 1).increment(begin);
|
||||||
*begin = interval_t(0, 0, 1).increment(*begin);
|
end = interval_t(0, 0, 1).increment(end);
|
||||||
if (end)
|
|
||||||
*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);
|
||||||
}
|
}
|
||||||
else if (word == "from") {
|
else if (word == "from") {
|
||||||
in >> word;
|
in >> word;
|
||||||
if (! parse_date(word.c_str(), begin))
|
if (! parse_date(word.c_str(), &begin))
|
||||||
throw interval_expr_error("Could not parse 'from' date");
|
throw interval_expr_error("Could not parse 'from' date");
|
||||||
if (! in.eof())
|
if (! in.eof())
|
||||||
in >> word;
|
in >> word;
|
||||||
}
|
}
|
||||||
else if (word == "to") {
|
else if (word == "to") {
|
||||||
in >> word;
|
in >> word;
|
||||||
if (! parse_date(word.c_str(), end))
|
if (! parse_date(word.c_str(), &end))
|
||||||
throw interval_expr_error("Could not parse 'to' date");
|
throw interval_expr_error("Could not parse 'to' date");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
parse_inclusion_specifier(word, begin, end);
|
parse_inclusion_specifier(word, &begin, &end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return interval_t(seconds, months, years);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_date_mask(const char * date_str, struct std::tm * result)
|
bool parse_date_mask(const char * date_str, struct std::tm * result)
|
||||||
|
|
@ -308,3 +317,63 @@ bool quick_parse_date(char * date_str, std::time_t * result)
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
||||||
|
#ifdef USE_BOOST_PYTHON
|
||||||
|
|
||||||
|
#include <boost/python.hpp>
|
||||||
|
|
||||||
|
using namespace boost::python;
|
||||||
|
using namespace ledger;
|
||||||
|
|
||||||
|
unsigned int interval_len(interval_t& interval)
|
||||||
|
{
|
||||||
|
int periods = 1;
|
||||||
|
std::time_t when = interval.first();
|
||||||
|
while (interval.end && when < interval.end) {
|
||||||
|
when = interval.increment(when);
|
||||||
|
if (when < interval.end)
|
||||||
|
periods++;
|
||||||
|
}
|
||||||
|
return periods;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::time_t interval_getitem(interval_t& interval, int i)
|
||||||
|
{
|
||||||
|
static std::time_t last_index = 0;
|
||||||
|
static std::time_t last_moment = 0;
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
last_index = 0;
|
||||||
|
last_moment = interval.first();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
last_moment = interval.increment(last_moment);
|
||||||
|
if (interval.end && last_moment >= interval.end) {
|
||||||
|
PyErr_SetString(PyExc_IndexError, "Index out of range");
|
||||||
|
throw_error_already_set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return last_moment;
|
||||||
|
}
|
||||||
|
|
||||||
|
void export_datetime()
|
||||||
|
{
|
||||||
|
class_< interval_t >
|
||||||
|
("Interval", init<optional<int, int, int, std::time_t, std::time_t> >())
|
||||||
|
.def(init<std::string>())
|
||||||
|
.def(! self)
|
||||||
|
|
||||||
|
.def_readwrite("years", &interval_t::years)
|
||||||
|
.def_readwrite("months", &interval_t::months)
|
||||||
|
.def_readwrite("seconds", &interval_t::seconds)
|
||||||
|
.def_readwrite("begin", &interval_t::begin)
|
||||||
|
.def_readwrite("end", &interval_t::end)
|
||||||
|
|
||||||
|
.def("__len__", interval_len)
|
||||||
|
.def("__getitem__", interval_getitem)
|
||||||
|
|
||||||
|
.def("increment", &interval_t::increment)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USE_BOOST_PYTHON
|
||||||
|
|
|
||||||
26
datetime.h
26
datetime.h
|
|
@ -4,19 +4,30 @@
|
||||||
#include "ledger.h"
|
#include "ledger.h"
|
||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
struct interval_t
|
struct interval_t
|
||||||
{
|
{
|
||||||
int years;
|
unsigned int years;
|
||||||
int months;
|
unsigned int months;
|
||||||
int seconds;
|
unsigned int seconds;
|
||||||
|
std::time_t begin;
|
||||||
|
std::time_t end;
|
||||||
|
|
||||||
interval_t(int _seconds = 0, int _months = 0, int _years = 0)
|
interval_t(int _seconds = 0, int _months = 0, int _years = 0,
|
||||||
: years(_years), months(_months), seconds(_seconds) {
|
std::time_t _begin = 0, std::time_t _end = 0)
|
||||||
|
: years(_years), months(_months), seconds(_seconds),
|
||||||
|
begin(_begin), end(_end) {
|
||||||
DEBUG_PRINT("ledger.memory.ctors", "ctor interval_t");
|
DEBUG_PRINT("ledger.memory.ctors", "ctor interval_t");
|
||||||
}
|
}
|
||||||
|
interval_t(const std::string& desc)
|
||||||
|
: years(0), months(0), seconds(0), begin(0), end(0){
|
||||||
|
DEBUG_PRINT("ledger.memory.ctors", "ctor interval_t");
|
||||||
|
std::istringstream stream(desc);
|
||||||
|
parse(stream);
|
||||||
|
}
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
~interval_t() {
|
~interval_t() {
|
||||||
DEBUG_PRINT("ledger.memory.dtors", "dtor interval_t");
|
DEBUG_PRINT("ledger.memory.dtors", "dtor interval_t");
|
||||||
|
|
@ -27,11 +38,10 @@ struct interval_t
|
||||||
return seconds > 0 || months > 0 || years > 0;
|
return seconds > 0 || months > 0 || years > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::time_t first(const std::time_t moment = 0);
|
||||||
std::time_t increment(const std::time_t);
|
std::time_t increment(const std::time_t);
|
||||||
|
|
||||||
static interval_t parse(std::istream& in,
|
void parse(std::istream& in);
|
||||||
std::time_t * begin,
|
|
||||||
std::time_t * end);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::time_t now;
|
extern std::time_t now;
|
||||||
|
|
|
||||||
3
main.cc
3
main.cc
|
|
@ -202,8 +202,7 @@ chain_formatters(const std::string& command,
|
||||||
else if (config.report_interval)
|
else if (config.report_interval)
|
||||||
ptrs.push_back(formatter =
|
ptrs.push_back(formatter =
|
||||||
new interval_transactions(formatter,
|
new interval_transactions(formatter,
|
||||||
config.report_interval,
|
config.report_interval));
|
||||||
config.interval_begin));
|
|
||||||
else if (config.days_of_the_week)
|
else if (config.days_of_the_week)
|
||||||
ptrs.push_back(formatter = new dow_transactions(formatter));
|
ptrs.push_back(formatter = new dow_transactions(formatter));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
main.py
5
main.py
|
|
@ -1,5 +1,6 @@
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
from ledger import *
|
from ledger import *
|
||||||
|
|
||||||
|
|
@ -29,3 +30,7 @@ handler = FilterTransactions (handler, "/Checking/")
|
||||||
for entry in journal:
|
for entry in journal:
|
||||||
for xact in entry:
|
for xact in entry:
|
||||||
handler (xact)
|
handler (xact)
|
||||||
|
|
||||||
|
span = Interval ("monthly last year")
|
||||||
|
for date in span:
|
||||||
|
print time.strftime ("%c", time.localtime (date))
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ void export_gnucash();
|
||||||
void export_option();
|
void export_option();
|
||||||
void export_walk();
|
void export_walk();
|
||||||
void export_format();
|
void export_format();
|
||||||
|
void export_datetime();
|
||||||
|
|
||||||
BOOST_PYTHON_MODULE(ledger) {
|
BOOST_PYTHON_MODULE(ledger) {
|
||||||
export_amount();
|
export_amount();
|
||||||
|
|
@ -35,4 +36,5 @@ BOOST_PYTHON_MODULE(ledger) {
|
||||||
export_option();
|
export_option();
|
||||||
export_walk();
|
export_walk();
|
||||||
export_format();
|
export_format();
|
||||||
|
export_datetime();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -512,9 +512,8 @@ value_expr_t * parse_value_term(std::istream& in)
|
||||||
|
|
||||||
node.reset(new value_expr_t(value_expr_t::CONSTANT_T));
|
node.reset(new value_expr_t(value_expr_t::CONSTANT_T));
|
||||||
|
|
||||||
std::string datespec = buf;
|
interval_t timespan(buf);
|
||||||
std::istringstream stream(datespec);
|
node->constant_t = timespan.first();
|
||||||
interval_t::parse(stream, &node->constant_t, NULL);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
6
walk.cc
6
walk.cc
|
|
@ -256,10 +256,10 @@ void subtotal_transactions::operator()(transaction_t& xact)
|
||||||
|
|
||||||
void interval_transactions::operator()(transaction_t& xact)
|
void interval_transactions::operator()(transaction_t& xact)
|
||||||
{
|
{
|
||||||
std::time_t quant = interval.increment(begin);
|
std::time_t quant = interval.increment(interval.begin);
|
||||||
if (std::difftime(xact.entry->date, quant) > 0) {
|
if (std::difftime(xact.entry->date, quant) > 0) {
|
||||||
if (last_xact) {
|
if (last_xact) {
|
||||||
start = begin;
|
start = interval.begin;
|
||||||
finish = quant;
|
finish = quant;
|
||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
|
|
@ -279,7 +279,7 @@ void interval_transactions::operator()(transaction_t& xact)
|
||||||
while (std::difftime(xact.entry->date,
|
while (std::difftime(xact.entry->date,
|
||||||
temp = interval.increment(quant)) > 0)
|
temp = interval.increment(quant)) > 0)
|
||||||
quant = temp;
|
quant = temp;
|
||||||
begin = quant;
|
interval.begin = quant;
|
||||||
}
|
}
|
||||||
|
|
||||||
subtotal_transactions::operator()(xact);
|
subtotal_transactions::operator()(xact);
|
||||||
|
|
|
||||||
12
walk.h
12
walk.h
|
|
@ -379,20 +379,18 @@ class subtotal_transactions : public item_handler<transaction_t>
|
||||||
|
|
||||||
class interval_transactions : public subtotal_transactions
|
class interval_transactions : public subtotal_transactions
|
||||||
{
|
{
|
||||||
std::time_t begin;
|
|
||||||
interval_t interval;
|
interval_t interval;
|
||||||
transaction_t * last_xact;
|
transaction_t * last_xact;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
interval_transactions(item_handler<transaction_t> * handler,
|
interval_transactions(item_handler<transaction_t> * handler,
|
||||||
const interval_t& _interval,
|
const interval_t& _interval)
|
||||||
const std::time_t _begin = 0)
|
: subtotal_transactions(handler), interval(_interval),
|
||||||
: subtotal_transactions(handler), begin(_begin),
|
last_xact(NULL) {}
|
||||||
interval(_interval), last_xact(NULL) {}
|
|
||||||
|
|
||||||
virtual ~interval_transactions() {
|
virtual ~interval_transactions() {
|
||||||
start = begin;
|
start = interval.begin;
|
||||||
finish = interval.increment(begin);
|
finish = interval.increment(interval.begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void operator()(transaction_t& xact);
|
virtual void operator()(transaction_t& xact);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue