summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.cc14
-rw-r--r--config.h1
-rw-r--r--datetime.cc129
-rw-r--r--datetime.h28
-rw-r--r--main.cc3
-rw-r--r--main.py5
-rw-r--r--pyledger.cc2
-rw-r--r--valexpr.cc5
-rw-r--r--walk.cc6
-rw-r--r--walk.h12
10 files changed, 141 insertions, 64 deletions
diff --git a/config.cc b/config.cc
index 8e86c5a2..90ea4893 100644
--- a/config.cc
+++ b/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;
}
}
diff --git a/config.h b/config.h
index 2bfee4bd..4342d8c1 100644
--- a/config.h
+++ b/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;
diff --git a/datetime.cc b/datetime.cc
index 7aa26b13..0d39d3b3 100644
--- a/datetime.cc
+++ b/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
diff --git a/datetime.h b/datetime.h
index a3b0651a..51483172 100644
--- a/datetime.h
+++ b/datetime.h
@@ -4,18 +4,29 @@
#include "ledger.h"
#include <ctime>
+#include <sstream>
namespace ledger {
struct interval_t
{
- int years;
- int months;
- int seconds;
-
- interval_t(int _seconds = 0, int _months = 0, int _years = 0)
- : years(_years), months(_months), seconds(_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,
+ 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() {
@@ -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;
diff --git a/main.cc b/main.cc
index b2a9e7b8..861a252c 100644
--- a/main.cc
+++ b/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));
}
diff --git a/main.py b/main.py
index b39193d3..4b74307c 100644
--- a/main.py
+++ b/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))
diff --git a/pyledger.cc b/pyledger.cc
index 55cf0f3a..41910044 100644
--- a/pyledger.cc
+++ b/pyledger.cc
@@ -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();
}
diff --git a/valexpr.cc b/valexpr.cc
index d868f9b6..06f7dd09 100644
--- a/valexpr.cc
+++ b/valexpr.cc
@@ -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;
}
diff --git a/walk.cc b/walk.cc
index b98dd3f1..cfecf392 100644
--- a/walk.cc
+++ b/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);
diff --git a/walk.h b/walk.h
index 102ed10c..bc2a5592 100644
--- a/walk.h
+++ b/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);