diff options
Diffstat (limited to 'src/times.h')
-rw-r--r-- | src/times.h | 519 |
1 files changed, 420 insertions, 99 deletions
diff --git a/src/times.h b/src/times.h index 77f25d9e..826937bb 100644 --- a/src/times.h +++ b/src/times.h @@ -59,7 +59,6 @@ inline bool is_valid(const datetime_t& moment) { } typedef boost::gregorian::date date_t; -typedef boost::gregorian::date_duration date_duration_t; typedef boost::gregorian::date_iterator date_iterator_t; inline bool is_valid(const date_t& moment) { @@ -85,19 +84,19 @@ 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, - optional<date_t::year_type> current_year = none); +typedef optional<date_t::year_type> optional_year; + +datetime_t parse_datetime(const char * str, optional_year current_year = none); inline datetime_t parse_datetime(const std::string& str, - optional<date_t::year_type> current_year = none) { + optional_year current_year = none) { return parse_datetime(str.c_str(), current_year); } -date_t parse_date(const char * str, - optional<date_t::year_type> current_year = none); +date_t parse_date(const char * str, optional_year current_year = none); inline date_t parse_date(const std::string& str, - optional<date_t::year_type> current_year = none) { + optional_year current_year = none) { return parse_date(str.c_str(), current_year); } @@ -138,105 +137,423 @@ inline void to_xml(std::ostream& out, const date_t& when, } } -class date_interval_t : public equality_comparable<date_interval_t> +struct date_traits_t { -public: - struct duration_t - { - enum skip_quantum_t { - DAYS, WEEKS, MONTHS, YEARS - } quantum; - int length; - - duration_t() : quantum(DAYS), length(0) { - TRACE_CTOR(date_interval_t::duration_t, ""); - } - duration_t(skip_quantum_t _quantum, int _length) - : quantum(_quantum), length(_length) { - TRACE_CTOR(date_interval_t::duration_t, "skip_quantum_t, int"); - } - duration_t(const duration_t& dur) - : quantum(dur.quantum), length(dur.length) { - TRACE_CTOR(date_interval_t::duration_t, "copy"); + bool has_year; + bool has_month; + bool has_day; + + date_traits_t(bool _has_year = false, + bool _has_month = false, + bool _has_day = false) + : has_year(_has_year), has_month(_has_month), has_day(_has_day) { + TRACE_CTOR(date_traits_t, "bool, bool, bool"); + } + date_traits_t(const date_traits_t& traits) + : has_year(traits.has_year), + has_month(traits.has_month), + has_day(traits.has_day) { + TRACE_CTOR(date_traits_t, "copy"); + } + ~date_traits_t() throw() { + TRACE_DTOR(date_traits_t); + } + + date_traits_t& operator=(const date_traits_t& traits) { + has_year = traits.has_year; + has_month = traits.has_month; + has_day = traits.has_day; + return *this; + } + + bool operator==(const date_traits_t& traits) const { + return (has_year == traits.has_year && + has_month == traits.has_month && + has_day == traits.has_day); + } + +#if defined(HAVE_BOOST_SERIALIZATION) +private: + /** Serialization. */ + + friend class boost::serialization::access; + + template<class Archive> + void serialize(Archive& ar, const unsigned int /* version */) { + ar & has_year; + ar & has_month; + ar & has_day; + } +#endif // HAVE_BOOST_SERIALIZATION +}; + +struct date_duration_t +{ + enum skip_quantum_t { + DAYS, WEEKS, MONTHS, QUARTERS, YEARS + } quantum; + int length; + + date_duration_t() : quantum(DAYS), length(0) { + TRACE_CTOR(date_duration_t, ""); + } + date_duration_t(skip_quantum_t _quantum, int _length) + : quantum(_quantum), length(_length) { + TRACE_CTOR(date_duration_t, "skip_quantum_t, int"); + } + date_duration_t(const date_duration_t& dur) + : quantum(dur.quantum), length(dur.length) { + TRACE_CTOR(date_duration_t, "copy"); + } + ~date_duration_t() throw() { + TRACE_DTOR(date_duration_t); + } + + date_t add(const date_t& date) const { + switch (quantum) { + case DAYS: + return date + gregorian::days(length); + case WEEKS: + return date + gregorian::weeks(length); + case MONTHS: + return date + gregorian::months(length); + case QUARTERS: + return date + gregorian::months(length * 3); + case YEARS: + return date + gregorian::years(length); + default: + assert(false); return date_t(); } - ~duration_t() throw() { - TRACE_DTOR(date_interval_t::duration_t); - } - - date_t add(const date_t& date) const { - switch (quantum) { - case DAYS: - return date + gregorian::days(length); - case WEEKS: - return date + gregorian::weeks(length); - case MONTHS: - return date + gregorian::months(length); - case YEARS: - return date + gregorian::years(length); - default: - assert(false); return date_t(); - } + } + + date_t subtract(const date_t& date) const { + switch (quantum) { + case DAYS: + return date - gregorian::days(length); + case WEEKS: + return date - gregorian::weeks(length); + case MONTHS: + return date - gregorian::months(length); + case QUARTERS: + return date - gregorian::months(length * 3); + case YEARS: + return date - gregorian::years(length); + default: + assert(false); return date_t(); } + } + + string to_string() const { + std::ostringstream out; + + out << length << ' '; - date_t subtract(const date_t& date) const { - switch (quantum) { - case DAYS: - return date - gregorian::days(length); - case WEEKS: - return date - gregorian::weeks(length); - case MONTHS: - return date - gregorian::months(length); - case YEARS: - return date - gregorian::years(length); - default: - assert(false); return date_t(); - } + switch (quantum) { + case DAYS: out << "day"; break; + case WEEKS: out << "week"; break; + case MONTHS: out << "month"; break; + case QUARTERS: out << "quarter"; break; + case YEARS: out << "year"; break; + default: + assert(false); + break; } + if (length > 1) + out << 's'; + + return out.str(); + } + + static date_t find_nearest(const date_t& date, skip_quantum_t skip); + +#if defined(HAVE_BOOST_SERIALIZATION) +private: + /** Serialization. */ + + friend class boost::serialization::access; + + template<class Archive> + void serialize(Archive& ar, const unsigned int /* version */) { + ar & quantum; + ar & length; + } +#endif // HAVE_BOOST_SERIALIZATION +}; + +class date_specifier_t +{ + friend class date_parser_t; + +#if 0 + typedef date_t::year_type year_type; +#else + typedef unsigned short year_type; +#endif + typedef date_t::month_type month_type; + typedef date_t::day_type day_type; + typedef date_t::day_of_week_type day_of_week_type; + + optional<year_type> year; + optional<month_type> month; + optional<day_type> day; + optional<day_of_week_type> wday; + +public: + date_specifier_t(const optional<year_type>& _year = none, + const optional<month_type>& _month = none, + const optional<day_type>& _day = none, + const optional<day_of_week_type>& _wday = none) + : year(_year), month(_month), day(_day), wday(_wday) { + TRACE_CTOR(date_specifier_t, + "year_type, month_type, day_type, day_of_week_type"); + } + date_specifier_t(const date_t& date, + const optional<date_traits_t>& traits = none) { + TRACE_CTOR(date_specifier_t, "date_t, date_traits_t"); + if (! traits || traits->has_year) + year = date.year(); + if (! traits || traits->has_month) + month = date.month(); + if (! traits || traits->has_day) + day = date.day(); + } + date_specifier_t(const date_specifier_t& other) + : year(other.year), month(other.month), + day(other.day), wday(other.wday) { + TRACE_CTOR(date_specifier_t, "copy"); + } + ~date_specifier_t() throw() { + TRACE_DTOR(date_specifier_t); + } + + date_t begin(const optional_year& current_year = none) const; + date_t end(const optional_year& current_year = none) const; + + bool is_within(const date_t& date, + const optional_year& current_year = none) const { + return date >= begin(current_year) && date < end(current_year); + } + + optional<date_duration_t> implied_duration() const { + if (day || wday) + return date_duration_t(date_duration_t::DAYS, 1); + else if (month) + return date_duration_t(date_duration_t::MONTHS, 1); + else if (year) + return date_duration_t(date_duration_t::YEARS, 1); + else + return none; + } + + string to_string() const { + std::ostringstream out; + + if (year) + out << " year " << *year; + if (month) + out << " month " << *month; + if (day) + out << " day " << *day; + if (wday) + out << " wday " << *wday; + + return out.str(); + } + #if defined(HAVE_BOOST_SERIALIZATION) - private: - /** Serialization. */ +private: + /** Serialization. */ - friend class boost::serialization::access; + friend class boost::serialization::access; - template<class Archive> - void serialize(Archive& ar, const unsigned int /* version */) { - ar & quantum; - ar & length; + template<class Archive> + void serialize(Archive& ar, const unsigned int /* version */) { + ar & year; + ar & month; + ar & day; + ar & wday; + } +#endif // HAVE_BOOST_SERIALIZATION +}; + +class date_range_t +{ + friend class date_parser_t; + + optional<date_specifier_t> range_begin; + optional<date_specifier_t> range_end; + + bool end_inclusive; + +public: + date_range_t(const optional<date_specifier_t>& _range_begin = none, + const optional<date_specifier_t>& _range_end = none) + : range_begin(_range_begin), range_end(_range_end), + end_inclusive(false) { + TRACE_CTOR(date_range_t, "date_specifier_t, date_specifier_t"); + } + date_range_t(const date_range_t& other) + : range_begin(other.range_begin), range_end(other.range_end), + end_inclusive(other.end_inclusive) { + TRACE_CTOR(date_range_t, "date_range_t"); + } + ~date_range_t() throw() { + TRACE_DTOR(date_range_t); + } + + optional<date_t> begin(const optional_year& current_year = none) const { + if (range_begin) + return range_begin->begin(current_year); + else + return none; + } + optional<date_t> end(const optional_year& current_year = none) const { + if (range_end) { + if (end_inclusive) + return range_end->end(current_year); + else + return range_end->begin(current_year); + } else { + return none; } + } + + bool is_within(const date_t& date, + const optional_year& current_year = none) const { + optional<date_t> b = begin(current_year); + optional<date_t> e = end(current_year); + bool after_begin = b ? date >= *b : true; + bool before_end = e ? date < *e : true; + return after_begin && before_end; + } + + string to_string() const { + std::ostringstream out; + + if (range_begin) + out << "from" << range_begin->to_string(); + if (range_end) + out << " to" << range_end->to_string(); + + return out.str(); + } + +#if defined(HAVE_BOOST_SERIALIZATION) +private: + /** Serialization. */ + + friend class boost::serialization::access; + + template<class Archive> + void serialize(Archive& ar, const unsigned int /* version */) { + ar & range_begin; + ar & range_end; + ar & end_inclusive; + } #endif // HAVE_BOOST_SERIALIZATION - }; - - static date_t add_duration(const date_t& date, - const duration_t& duration); - static date_t subtract_duration(const date_t& date, - const duration_t& duration); - - optional<date_t> start; - bool aligned; - optional<duration_t> skip_duration; - std::size_t factor; - optional<date_t> next; - optional<duration_t> duration; - optional<date_t> end_of_duration; - optional<date_t> end; - - explicit date_interval_t() : aligned(false), factor(1) { +}; + +class date_specifier_or_range_t +{ + typedef variant<int, date_specifier_t, date_range_t> value_type; + + value_type specifier_or_range; + +public: + date_specifier_or_range_t() { + TRACE_CTOR(date_specifier_or_range_t, ""); + } + date_specifier_or_range_t(const date_specifier_or_range_t& other) + : specifier_or_range(other.specifier_or_range) { + TRACE_CTOR(date_specifier_or_range_t, "copy"); + } + date_specifier_or_range_t(const date_specifier_t& specifier) + : specifier_or_range(specifier) { + TRACE_CTOR(date_specifier_or_range_t, "date_specifier_t"); + } + date_specifier_or_range_t(const date_range_t& range) + : specifier_or_range(range) { + TRACE_CTOR(date_specifier_or_range_t, "date_range_t"); + } + ~date_specifier_or_range_t() throw() { + TRACE_DTOR(date_specifier_or_range_t); + } + + optional<date_t> begin(const optional_year& current_year = none) const { + if (specifier_or_range.type() == typeid(date_specifier_t)) + return boost::get<date_specifier_t>(specifier_or_range).begin(current_year); + else if (specifier_or_range.type() == typeid(date_range_t)) + return boost::get<date_range_t>(specifier_or_range).begin(current_year); + else + return none; + } + optional<date_t> end(const optional_year& current_year = none) const { + if (specifier_or_range.type() == typeid(date_specifier_t)) + return boost::get<date_specifier_t>(specifier_or_range).end(current_year); + else if (specifier_or_range.type() == typeid(date_range_t)) + return boost::get<date_range_t>(specifier_or_range).end(current_year); + else + return none; + } + + + string to_string() const { + std::ostringstream out; + + if (specifier_or_range.type() == typeid(date_specifier_t)) + out << "in" << boost::get<date_specifier_t>(specifier_or_range).to_string(); + else if (specifier_or_range.type() == typeid(date_range_t)) + out << boost::get<date_range_t>(specifier_or_range).to_string(); + + return out.str(); + } + +#if defined(HAVE_BOOST_SERIALIZATION) +private: + /** Serialization. */ + + friend class boost::serialization::access; + + template<class Archive> + void serialize(Archive& ar, const unsigned int /* version */) { + ar & specifier_or_range; + } +#endif // HAVE_BOOST_SERIALIZATION +}; + +class date_interval_t : public equality_comparable<date_interval_t> +{ +public: + static date_t add_duration(const date_t& date, + const date_duration_t& duration); + static date_t subtract_duration(const date_t& date, + const date_duration_t& duration); + + optional<date_specifier_or_range_t> range; + + optional<date_t> start; // the real start, after adjustment + optional<date_t> finish; // the real end, likewise + bool aligned; + optional<date_t> next; + optional<date_duration_t> duration; + optional<date_t> end_of_duration; + + explicit date_interval_t() : aligned(false) { TRACE_CTOR(date_interval_t, ""); } - date_interval_t(const string& str) : aligned(false), factor(1) { + date_interval_t(const string& str) : aligned(false) { TRACE_CTOR(date_interval_t, "const string&"); parse(str); } date_interval_t(const date_interval_t& other) - : start(other.start), + : range(other.range), + start(other.start), + finish(other.finish), aligned(other.aligned), - skip_duration(other.skip_duration), - factor(other.factor), next(other.next), duration(other.duration), - end_of_duration(other.end_of_duration), - end(other.end) { + end_of_duration(other.end_of_duration) { TRACE_CTOR(date_interval_t, "copy"); } ~date_interval_t() throw() { @@ -252,17 +569,19 @@ public: return is_valid(); } - void parse(std::istream& in); - - void parse(const string& str) { - std::istringstream in(str); - parse(in); + optional<date_t> begin(const optional_year& current_year = none) const { + return start ? start : (range ? range->begin(current_year) : none); } + optional<date_t> end(const optional_year& current_year = none) const { + return finish ? finish : (range ? range->end(current_year) : none); + } + + void parse(const string& str); - void resolve_end(); - void stabilize(const optional<date_t>& date = none); + void resolve_end(); + void stabilize(const optional<date_t>& date = none); - bool is_valid() const { + bool is_valid() const { return start; } @@ -280,6 +599,8 @@ public: date_interval_t& operator++(); + void dump(std::ostream& out, optional_year current_year = none); + #if defined(HAVE_BOOST_SERIALIZATION) private: /** Serialization. */ @@ -288,14 +609,13 @@ private: template<class Archive> void serialize(Archive& ar, const unsigned int /* version */) { + ar & range; ar & start; + ar & finish; ar & aligned; - ar & skip_duration; - ar & factor; ar & next; ar & duration; ar & end_of_duration; - ar & end; } #endif // HAVE_BOOST_SERIALIZATION }; @@ -303,8 +623,9 @@ private: void times_initialize(); void times_shutdown(); -std::ostream& operator<<(std::ostream& out, - const date_interval_t::duration_t& duration); +void show_period_tokens(std::ostream& out, const string& arg); + +std::ostream& operator<<(std::ostream& out, const date_duration_t& duration); } // namespace ledger |