Loading...
Searching...
No Matches
times.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2003-2023, John Wiegley. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * - Neither the name of New Artisans LLC nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
44#pragma once
45
46#include "utils.h"
47
48namespace ledger {
49
50DECLARE_EXCEPTION(datetime_error, std::runtime_error);
51DECLARE_EXCEPTION(date_error, std::runtime_error);
52
53typedef boost::posix_time::ptime datetime_t;
54typedef datetime_t::time_duration_type time_duration_t;
55
56inline bool is_valid(const datetime_t& moment) {
57 return ! moment.is_not_a_date_time();
58}
59
60typedef boost::gregorian::date date_t;
61typedef boost::gregorian::date_iterator date_iterator_t;
62
63inline bool is_valid(const date_t& moment) {
64 return ! moment.is_not_a_date();
65}
66
68
69#ifdef BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK
70#define TRUE_CURRENT_TIME() (boost::posix_time::microsec_clock::local_time())
71#define CURRENT_TIME() (epoch ? *epoch : TRUE_CURRENT_TIME())
72#else
73#define TRUE_CURRENT_TIME() (boost::posix_time::second_clock::local_time())
74#define CURRENT_TIME() (epoch ? *epoch : TRUE_CURRENT_TIME())
75#endif
76#define CURRENT_DATE() \
77 (epoch ? epoch->date() : boost::gregorian::day_clock::local_day())
78
79extern date_time::weekdays start_of_week;
80
82string_to_day_of_week(const std::string& str);
84string_to_month_of_year(const std::string& str);
85
86datetime_t parse_datetime(const char * str);
87
88inline datetime_t parse_datetime(const std::string& str) {
89 return parse_datetime(str.c_str());
90}
91
92date_t parse_date(const char * str);
93
94inline date_t parse_date(const std::string& str) {
95 return parse_date(str.c_str());
96}
97
101
102std::string format_datetime(const datetime_t& when,
104 const optional<const char *>& format = none);
105void set_datetime_format(const char * format);
106
107std::string format_date(const date_t& when,
109 const optional<const char *>& format = none);
110void set_date_format(const char * format);
111void set_input_date_format(const char * format);
112
113inline void put_datetime(property_tree::ptree& pt, const datetime_t& when) {
114 pt.put_value(format_datetime(when, FMT_WRITTEN));
115}
116
117inline void put_date(property_tree::ptree& pt, const date_t& when) {
118 pt.put_value(format_date(when, FMT_WRITTEN));
119}
120
122{
126
128 bool _has_month = false,
129 bool _has_day = false)
131 TRACE_CTOR(date_traits_t, "bool, bool, bool");
132 }
142
145 has_month = traits.has_month;
146 has_day = traits.has_day;
147 return *this;
148 }
149
150 bool operator==(const date_traits_t& traits) const {
151 return (has_year == traits.has_year &&
152 has_month == traits.has_month &&
153 has_day == traits.has_day);
154 }
155};
156
158{
163
178
179 date_t add(const date_t& date) const {
180 switch (quantum) {
181 case DAYS:
182 return date + gregorian::days(length);
183 case WEEKS:
184 return date + gregorian::weeks(length);
185 case MONTHS:
186 return date + gregorian::months(length);
187 case QUARTERS:
188 return date + gregorian::months(length * 3);
189 case YEARS:
190 return date + gregorian::years(length);
191 }
192#if !defined(__clang__)
193 return date_t();
194#endif
195 }
196
197 date_t subtract(const date_t& date) const {
198 switch (quantum) {
199 case DAYS:
200 return date - gregorian::days(length);
201 case WEEKS:
202 return date - gregorian::weeks(length);
203 case MONTHS:
204 return date - gregorian::months(length);
205 case QUARTERS:
206 return date - gregorian::months(length * 3);
207 case YEARS:
208 return date - gregorian::years(length);
209 }
210#if !defined(__clang__)
211 return date_t();
212#endif
213 }
214
215 string to_string() const {
216 std::ostringstream out;
217
218 out << length << ' ';
219
220 switch (quantum) {
221 case DAYS: out << "day"; break;
222 case WEEKS: out << "week"; break;
223 case MONTHS: out << "month"; break;
224 case QUARTERS: out << "quarter"; break;
225 case YEARS: out << "year"; break;
226 }
227
228 if (length > 1)
229 out << 's';
230
231 return out.str();
232 }
233
235};
236
238{
239 friend class date_parser_t;
240
241public:
242#if 0
243 typedef date_t::year_type year_type;
244#else
245 typedef unsigned short year_type;
246#endif
247 typedef date_t::month_type month_type;
248 typedef date_t::day_type day_type;
249 typedef date_t::day_of_week_type day_of_week_type;
250
251protected:
256
257public:
264 "year_type, month_type, day_type, day_of_week_type");
265 }
268 if (! traits || traits->has_year)
269 year = date.year();
270 if (! traits || traits->has_month)
271 month = date.month();
272 if (! traits || traits->has_day)
273 day = date.day();
274
275 TRACE_CTOR(date_specifier_t, "date_t, date_traits_t");
276 }
285
286 date_t begin() const;
287 date_t end() const;
288
289 bool is_within(const date_t& date) const {
290 return date >= begin() && date < end();
291 }
292
294 if (day || wday)
296 else if (month)
298 else if (year)
300 else
301 return none;
302 }
303
304 string to_string() const {
305 std::ostringstream out;
306
307 if (year)
308 out << " year " << *year;
309 if (month)
310 out << " month " << *month;
311 if (day)
312 out << " day " << *day;
313 if (wday)
314 out << " wday " << *wday;
315
316 return out.str();
317 }
318};
319
321{
322 friend class date_parser_t;
323
324 optional<date_specifier_t> range_begin;
326
327 bool end_inclusive;
328
329public:
332 : range_begin(_range_begin), range_end(_range_end),
333 end_inclusive(false) {
334 TRACE_CTOR(date_range_t, "date_specifier_t, date_specifier_t");
335 }
337 : range_begin(other.range_begin), range_end(other.range_end),
338 end_inclusive(other.end_inclusive) {
339 TRACE_CTOR(date_range_t, "date_range_t");
340 }
344
346 if (range_begin)
347 return range_begin->begin();
348 else
349 return none;
350 }
352 if (range_end) {
353 if (end_inclusive)
354 return range_end->end();
355 else
356 return range_end->begin();
357 } else {
358 return none;
359 }
360 }
361
362 bool is_within(const date_t& date) const {
365 bool after_begin = b ? date >= *b : true;
366 bool before_end = e ? date < *e : true;
367 return after_begin && before_end;
368 }
369
370 string to_string() const {
371 std::ostringstream out;
372
373 if (range_begin)
374 out << "from" << range_begin->to_string();
375 if (range_end)
376 out << " to" << range_end->to_string();
377
378 return out.str();
379 }
380};
381
383{
385
386 value_type specifier_or_range;
387
388public:
393 : specifier_or_range(other.specifier_or_range) {
395 }
397 : specifier_or_range(specifier) {
398 TRACE_CTOR(date_specifier_or_range_t, "date_specifier_t");
399 }
401 : specifier_or_range(range) {
402 TRACE_CTOR(date_specifier_or_range_t, "date_range_t");
403 }
407
409 if (specifier_or_range.type() == typeid(date_specifier_t))
410 return boost::get<date_specifier_t>(specifier_or_range).begin();
411 else if (specifier_or_range.type() == typeid(date_range_t))
412 return boost::get<date_range_t>(specifier_or_range).begin();
413 else
414 return none;
415 }
417 if (specifier_or_range.type() == typeid(date_specifier_t))
418 return boost::get<date_specifier_t>(specifier_or_range).end();
419 else if (specifier_or_range.type() == typeid(date_range_t))
420 return boost::get<date_range_t>(specifier_or_range).end();
421 else
422 return none;
423 }
424
425
426 string to_string() const {
427 std::ostringstream out;
428
429 if (specifier_or_range.type() == typeid(date_specifier_t))
430 out << "in" << boost::get<date_specifier_t>(specifier_or_range).to_string();
431 else if (specifier_or_range.type() == typeid(date_range_t))
432 out << boost::get<date_range_t>(specifier_or_range).to_string();
433
434 return out.str();
435 }
436};
437
438class date_interval_t : public equality_comparable<date_interval_t>
439{
440public:
445
447
448 optional<date_t> start; // the real start, after adjustment
449 optional<date_t> finish; // the real end, likewise
454 bool since_specified = false;
455
458 }
459 date_interval_t(const string& str) : aligned(false) {
460 parse(str);
461 TRACE_CTOR(date_interval_t, "const string&");
462 }
477
478 bool operator==(const date_interval_t& other) const {
479 return (start == other.start &&
480 (! start || *start == *other.start));
481 }
482 bool operator<(const date_interval_t& other) const {
483 return (start == other.start &&
484 (! start || *start < *other.start));
485 }
486
487 operator bool() const {
488 return is_valid();
489 }
490
492 return start ? start : (range ? range->begin() : none);
493 }
495 return finish ? finish : (range ? range->end() : none);
496 }
497
498 void parse(const string& str);
499
501 void stabilize(const optional<date_t>& date = none, bool align_intervals = false);
502
503 bool is_valid() const {
504 return static_cast<bool>(start);
505 }
506
511 const bool align_intervals = false,
512 const bool allow_shift = true);
514 return find_period(date, false, false);
515 }
516
518 if (end_of_duration)
519 return *end_of_duration - gregorian::days(1);
520 else
521 return none;
522 }
523
525
526 void dump(std::ostream& out);
527};
528
531
532void show_period_tokens(std::ostream& out, const string& arg);
533
534std::ostream& operator<<(std::ostream& out, const date_duration_t& duration);
535
536} // namespace ledger
General utility facilities used by Ledger.
#define TRACE_DTOR(cls)
Definition utils.h:144
#define TRACE_CTOR(cls, args)
Definition utils.h:143
#define CURRENT_DATE()
Definition times.h:76
#define DECLARE_EXCEPTION(name, kind)
Definition error.h:88
optional< date_time::months_of_year > string_to_month_of_year(const std::string &str)
void put_date(property_tree::ptree &pt, const date_t &when)
Definition times.h:117
std::string format_datetime(const datetime_t &when, const format_type_t format_type=FMT_PRINTED, const optional< const char * > &format=none)
void set_date_format(const char *format)
optional< datetime_t > epoch
gregorian::date date
Definition utils.h:64
datetime_t::time_duration_type time_duration_t
Definition times.h:54
bool is_valid(const datetime_t &moment)
Definition times.h:56
void set_input_date_format(const char *format)
boost::gregorian::date date_t
Definition times.h:60
boost::gregorian::date_iterator date_iterator_t
Definition times.h:61
void put_datetime(property_tree::ptree &pt, const datetime_t &when)
Definition times.h:113
std::string format_date(const date_t &when, const format_type_t format_type=FMT_PRINTED, const optional< const char * > &format=none)
date_time::weekdays start_of_week
std::ostream & operator<<(std::ostream &out, const account_t &account)
void show_period_tokens(std::ostream &out, const string &arg)
T & downcast(U &object)
Definition utils.h:468
optional< date_time::weekdays > string_to_day_of_week(const std::string &str)
void times_shutdown()
void set_datetime_format(const char *format)
datetime_t parse_datetime(const char *str)
format_type_t
Definition times.h:98
@ FMT_CUSTOM
Definition times.h:99
@ FMT_WRITTEN
Definition times.h:99
@ FMT_PRINTED
Definition times.h:99
boost::posix_time::ptime datetime_t
Definition times.h:53
date_t parse_date(const char *str)
void times_initialize()
bool operator==(const date_traits_t &traits) const
Definition times.h:150
date_traits_t(const date_traits_t &traits)
Definition times.h:133
date_traits_t & operator=(const date_traits_t &traits)
Definition times.h:143
date_traits_t(bool _has_year=false, bool _has_month=false, bool _has_day=false)
Definition times.h:127
date_t add(const date_t &date) const
Definition times.h:179
static date_t find_nearest(const date_t &date, skip_quantum_t skip)
enum ledger::date_duration_t::skip_quantum_t quantum
date_t subtract(const date_t &date) const
Definition times.h:197
date_duration_t(const date_duration_t &dur)
Definition times.h:171
date_duration_t(skip_quantum_t _quantum, int _length)
Definition times.h:167
string to_string() const
Definition times.h:215
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)
Definition times.h:258
optional< month_type > month
Definition times.h:253
string to_string() const
Definition times.h:304
optional< day_of_week_type > wday
Definition times.h:255
bool is_within(const date_t &date) const
Definition times.h:289
optional< date_duration_t > implied_duration() const
Definition times.h:293
optional< year_type > year
Definition times.h:252
date_t::day_type day_type
Definition times.h:248
date_t::month_type month_type
Definition times.h:247
date_t::day_of_week_type day_of_week_type
Definition times.h:249
unsigned short year_type
Definition times.h:245
optional< day_type > day
Definition times.h:254
friend class date_parser_t
Definition times.h:239
date_specifier_t(const date_specifier_t &other)
Definition times.h:277
date_specifier_t(const date_t &date, const optional< date_traits_t > &traits=none)
Definition times.h:266
date_range_t(const optional< date_specifier_t > &_range_begin=none, const optional< date_specifier_t > &_range_end=none)
Definition times.h:330
optional< date_t > end() const
Definition times.h:351
optional< date_t > begin() const
Definition times.h:345
bool is_within(const date_t &date) const
Definition times.h:362
date_range_t(const date_range_t &other)
Definition times.h:336
friend class date_parser_t
Definition times.h:322
string to_string() const
Definition times.h:370
optional< date_t > end() const
Definition times.h:416
date_specifier_or_range_t(const date_range_t &range)
Definition times.h:400
optional< date_t > begin() const
Definition times.h:408
date_specifier_or_range_t(const date_specifier_t &specifier)
Definition times.h:396
date_specifier_or_range_t(const date_specifier_or_range_t &other)
Definition times.h:392
optional< date_t > begin() const
Definition times.h:491
void dump(std::ostream &out)
optional< date_t > start
Definition times.h:448
optional< date_t > finish
Definition times.h:449
bool is_valid() const
Definition times.h:503
void stabilize(const optional< date_t > &date=none, bool align_intervals=false)
static date_t subtract_duration(const date_t &date, const date_duration_t &duration)
date_interval_t & operator++()
bool operator<(const date_interval_t &other) const
Definition times.h:482
optional< date_t > end() const
Definition times.h:494
optional< date_t > end_of_duration
Definition times.h:453
optional< date_t > next
Definition times.h:451
date_interval_t(const string &str)
Definition times.h:459
void parse(const string &str)
static date_t add_duration(const date_t &date, const date_duration_t &duration)
bool operator==(const date_interval_t &other) const
Definition times.h:478
date_interval_t(const date_interval_t &other)
Definition times.h:463
optional< date_t > inclusive_end() const
Definition times.h:517
bool within_period(const date_t &date=(epoch ? epoch->date() :boost::gregorian::day_clock::local_day()))
Definition times.h:513
optional< date_specifier_or_range_t > range
Definition times.h:446
bool find_period(const date_t &date=(epoch ? epoch->date() :boost::gregorian::day_clock::local_day()), const bool align_intervals=false, const bool allow_shift=true)
Find the current or next period containing date.
optional< date_duration_t > duration
Definition times.h:452