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;
|
||||
use_cache = false;
|
||||
cache_dirty = false;
|
||||
interval_begin = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -226,25 +225,22 @@ void config_t::process_options(const std::string& command,
|
|||
if (! report_interval && ! interval_text.empty()) {
|
||||
try {
|
||||
std::istringstream stream(interval_text);
|
||||
std::time_t begin = -1, end = -1;
|
||||
|
||||
report_interval = interval_t::parse(stream, &begin, &end);
|
||||
|
||||
if (begin != -1) {
|
||||
interval_begin = begin;
|
||||
report_interval.parse(stream);
|
||||
|
||||
if (report_interval.begin) {
|
||||
if (! predicate.empty())
|
||||
predicate += "&";
|
||||
char buf[32];
|
||||
std::sprintf(buf, "d>=%lu", begin);
|
||||
std::sprintf(buf, "d>=%lu", report_interval.begin);
|
||||
predicate += buf;
|
||||
}
|
||||
|
||||
if (end != -1) {
|
||||
if (report_interval.end) {
|
||||
if (! predicate.empty())
|
||||
predicate += "&";
|
||||
char buf[32];
|
||||
std::sprintf(buf, "d<%lu", end);
|
||||
std::sprintf(buf, "d<%lu", report_interval.end);
|
||||
predicate += buf;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1
config.h
1
config.h
|
|
@ -55,7 +55,6 @@ struct config_t
|
|||
bool use_cache;
|
||||
bool cache_dirty;
|
||||
interval_t report_interval;
|
||||
std::time_t interval_begin;
|
||||
format_t format;
|
||||
format_t nformat;
|
||||
|
||||
|
|
|
|||
129
datetime.cc
129
datetime.cc
|
|
@ -30,6 +30,30 @@ static const char * formats[] = {
|
|||
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 then = moment;
|
||||
|
|
@ -93,15 +117,10 @@ static void parse_inclusion_specifier(const std::string& word,
|
|||
saw_year ? 1 : 0).increment(*begin);
|
||||
}
|
||||
|
||||
interval_t interval_t::parse(std::istream& in,
|
||||
std::time_t * begin,
|
||||
std::time_t * end)
|
||||
void interval_t::parse(std::istream& in)
|
||||
{
|
||||
unsigned long years = 0;
|
||||
unsigned long months = 0;
|
||||
unsigned long seconds = 0;
|
||||
|
||||
std::string word;
|
||||
|
||||
while (! in.eof()) {
|
||||
in >> word;
|
||||
if (word == "every") {
|
||||
|
|
@ -165,57 +184,47 @@ interval_t interval_t::parse(std::istream& in,
|
|||
word = buf;
|
||||
}
|
||||
|
||||
parse_inclusion_specifier(word, begin, end);
|
||||
parse_inclusion_specifier(word, &begin, &end);
|
||||
|
||||
if (type == "last") {
|
||||
if (mon_spec) {
|
||||
if (begin)
|
||||
*begin = interval_t(0, -1, 0).increment(*begin);
|
||||
if (end)
|
||||
*end = interval_t(0, -1, 0).increment(*end);
|
||||
begin = interval_t(0, -1, 0).increment(begin);
|
||||
end = interval_t(0, -1, 0).increment(end);
|
||||
} else {
|
||||
if (begin)
|
||||
*begin = interval_t(0, 0, -1).increment(*begin);
|
||||
if (end)
|
||||
*end = interval_t(0, 0, -1).increment(*end);
|
||||
begin = interval_t(0, 0, -1).increment(begin);
|
||||
end = interval_t(0, 0, -1).increment(end);
|
||||
}
|
||||
}
|
||||
else if (type == "next") {
|
||||
if (mon_spec) {
|
||||
if (begin)
|
||||
*begin = interval_t(0, 1, 0).increment(*begin);
|
||||
if (end)
|
||||
*end = interval_t(0, 1, 0).increment(*end);
|
||||
begin = interval_t(0, 1, 0).increment(begin);
|
||||
end = interval_t(0, 1, 0).increment(end);
|
||||
} else {
|
||||
if (begin)
|
||||
*begin = interval_t(0, 0, 1).increment(*begin);
|
||||
if (end)
|
||||
*end = interval_t(0, 0, 1).increment(*end);
|
||||
begin = interval_t(0, 0, 1).increment(begin);
|
||||
end = interval_t(0, 0, 1).increment(end);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (word == "in") {
|
||||
in >> word;
|
||||
parse_inclusion_specifier(word, begin, end);
|
||||
parse_inclusion_specifier(word, &begin, &end);
|
||||
}
|
||||
else if (word == "from") {
|
||||
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");
|
||||
if (! in.eof())
|
||||
in >> word;
|
||||
}
|
||||
else if (word == "to") {
|
||||
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");
|
||||
}
|
||||
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)
|
||||
|
|
@ -308,3 +317,63 @@ bool quick_parse_date(char * date_str, std::time_t * result)
|
|||
}
|
||||
|
||||
} // 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 <ctime>
|
||||
#include <sstream>
|
||||
|
||||
namespace ledger {
|
||||
|
||||
struct interval_t
|
||||
{
|
||||
int years;
|
||||
int months;
|
||||
int seconds;
|
||||
unsigned int years;
|
||||
unsigned int months;
|
||||
unsigned int seconds;
|
||||
std::time_t begin;
|
||||
std::time_t end;
|
||||
|
||||
interval_t(int _seconds = 0, int _months = 0, int _years = 0)
|
||||
: years(_years), months(_months), seconds(_seconds) {
|
||||
interval_t(int _seconds = 0, int _months = 0, int _years = 0,
|
||||
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");
|
||||
}
|
||||
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
|
||||
~interval_t() {
|
||||
DEBUG_PRINT("ledger.memory.dtors", "dtor interval_t");
|
||||
|
|
@ -27,11 +38,10 @@ struct interval_t
|
|||
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);
|
||||
|
||||
static interval_t parse(std::istream& in,
|
||||
std::time_t * begin,
|
||||
std::time_t * end);
|
||||
void parse(std::istream& in);
|
||||
};
|
||||
|
||||
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)
|
||||
ptrs.push_back(formatter =
|
||||
new interval_transactions(formatter,
|
||||
config.report_interval,
|
||||
config.interval_begin));
|
||||
config.report_interval));
|
||||
else if (config.days_of_the_week)
|
||||
ptrs.push_back(formatter = new dow_transactions(formatter));
|
||||
}
|
||||
|
|
|
|||
5
main.py
5
main.py
|
|
@ -1,5 +1,6 @@
|
|||
import sys
|
||||
import os
|
||||
import time
|
||||
|
||||
from ledger import *
|
||||
|
||||
|
|
@ -29,3 +30,7 @@ handler = FilterTransactions (handler, "/Checking/")
|
|||
for entry in journal:
|
||||
for xact in entry:
|
||||
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_walk();
|
||||
void export_format();
|
||||
void export_datetime();
|
||||
|
||||
BOOST_PYTHON_MODULE(ledger) {
|
||||
export_amount();
|
||||
|
|
@ -35,4 +36,5 @@ BOOST_PYTHON_MODULE(ledger) {
|
|||
export_option();
|
||||
export_walk();
|
||||
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));
|
||||
|
||||
std::string datespec = buf;
|
||||
std::istringstream stream(datespec);
|
||||
interval_t::parse(stream, &node->constant_t, NULL);
|
||||
interval_t timespan(buf);
|
||||
node->constant_t = timespan.first();
|
||||
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)
|
||||
{
|
||||
std::time_t quant = interval.increment(begin);
|
||||
std::time_t quant = interval.increment(interval.begin);
|
||||
if (std::difftime(xact.entry->date, quant) > 0) {
|
||||
if (last_xact) {
|
||||
start = begin;
|
||||
start = interval.begin;
|
||||
finish = quant;
|
||||
flush();
|
||||
}
|
||||
|
|
@ -279,7 +279,7 @@ void interval_transactions::operator()(transaction_t& xact)
|
|||
while (std::difftime(xact.entry->date,
|
||||
temp = interval.increment(quant)) > 0)
|
||||
quant = temp;
|
||||
begin = quant;
|
||||
interval.begin = quant;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
std::time_t begin;
|
||||
interval_t interval;
|
||||
transaction_t * last_xact;
|
||||
|
||||
public:
|
||||
interval_transactions(item_handler<transaction_t> * handler,
|
||||
const interval_t& _interval,
|
||||
const std::time_t _begin = 0)
|
||||
: subtotal_transactions(handler), begin(_begin),
|
||||
interval(_interval), last_xact(NULL) {}
|
||||
const interval_t& _interval)
|
||||
: subtotal_transactions(handler), interval(_interval),
|
||||
last_xact(NULL) {}
|
||||
|
||||
virtual ~interval_transactions() {
|
||||
start = begin;
|
||||
finish = interval.increment(begin);
|
||||
start = interval.begin;
|
||||
finish = interval.increment(interval.begin);
|
||||
}
|
||||
|
||||
virtual void operator()(transaction_t& xact);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue