25 #include <gnc-datetime.hpp> 35 #define N_(string) string //So that xgettext will find it 46 enum RelativeDateOffset
60 RelativeDateType m_type;
61 RelativeDateOffset m_offset;
62 const char* m_storage;
63 const char* m_display;
64 const char* m_description;
75 static const std::array<GncRelativeDate, 31> reldates
78 RelativeDatePeriod::TODAY,
79 RelativeDateType::LAST,
80 RelativeDateOffset::NONE,
83 N_(
"The current date.")
86 RelativeDatePeriod::ONE_WEEK_AGO,
87 RelativeDateType::LAST,
88 RelativeDateOffset::WEEK,
94 RelativeDatePeriod::ONE_WEEK_AHEAD,
95 RelativeDateType::NEXT,
96 RelativeDateOffset::WEEK,
102 RelativeDatePeriod::ONE_MONTH_AGO,
103 RelativeDateType::LAST,
104 RelativeDateOffset::MONTH,
110 RelativeDatePeriod::ONE_MONTH_AHEAD,
111 RelativeDateType::NEXT,
112 RelativeDateOffset::MONTH,
114 N_(
"One Month Ahead"),
115 N_(
"One Month Ahead.")
118 RelativeDatePeriod::THREE_MONTHS_AGO,
119 RelativeDateType::LAST,
120 RelativeDateOffset::THREE,
122 N_(
"Three Months Ago"),
123 N_(
"Three Months Ago.")
126 RelativeDatePeriod::THREE_MONTHS_AHEAD,
127 RelativeDateType::NEXT,
128 RelativeDateOffset::THREE,
129 "three-months-ahead",
130 N_(
"Three Months Ahead"),
131 N_(
"Three Months Ahead.")
134 RelativeDatePeriod::SIX_MONTHS_AGO,
135 RelativeDateType::LAST,
136 RelativeDateOffset::SIX,
138 N_(
"Six Months Ago"),
139 N_(
"Six Months Ago.")
142 RelativeDatePeriod::SIX_MONTHS_AHEAD,
143 RelativeDateType::NEXT,
144 RelativeDateOffset::SIX,
146 N_(
"Six Months Ahead"),
147 N_(
"Six Months Ahead.")
150 RelativeDatePeriod::ONE_YEAR_AGO,
151 RelativeDateType::LAST,
152 RelativeDateOffset::YEAR,
158 RelativeDatePeriod::ONE_YEAR_AHEAD,
159 RelativeDateType::NEXT,
160 RelativeDateOffset::YEAR,
162 N_(
"One Year Ahead"),
163 N_(
"One Year Ahead.")
166 RelativeDatePeriod::START_THIS_MONTH,
167 RelativeDateType::START,
168 RelativeDateOffset::MONTH,
170 N_(
"Start of this month"),
171 N_(
"First day of the current month.")
174 RelativeDatePeriod::END_THIS_MONTH,
175 RelativeDateType::END,
176 RelativeDateOffset::MONTH,
178 N_(
"End of this month"),
179 N_(
"Last day of the current month.")
182 RelativeDatePeriod::START_PREV_MONTH,
183 RelativeDateType::START,
184 RelativeDateOffset::MONTH,
186 N_(
"Start of previous month"),
187 N_(
"First day of the previous month.")
190 RelativeDatePeriod::END_PREV_MONTH,
191 RelativeDateType::END,
192 RelativeDateOffset::MONTH,
194 N_(
"End of previous month"),
195 N_(
"Last day of previous month.")
198 RelativeDatePeriod::START_NEXT_MONTH,
199 RelativeDateType::START,
200 RelativeDateOffset::MONTH,
202 N_(
"Start of next month"),
203 N_(
"First day of the next month.")
206 RelativeDatePeriod::END_NEXT_MONTH,
207 RelativeDateType::END,
208 RelativeDateOffset::MONTH,
210 N_(
"End of next month"),
211 N_(
"Last day of next month.")
214 RelativeDatePeriod::START_CURRENT_QUARTER,
215 RelativeDateType::START,
216 RelativeDateOffset::QUARTER,
217 "start-current-quarter",
218 N_(
"Start of current quarter"),
219 N_(
"First day of the current quarterly accounting period.")
222 RelativeDatePeriod::END_CURRENT_QUARTER,
223 RelativeDateType::END,
224 RelativeDateOffset::QUARTER,
225 "end-current-quarter",
226 N_(
"End of current quarter"),
227 N_(
"Last day of the current quarterly accounting period.")
230 RelativeDatePeriod::START_PREV_QUARTER,
231 RelativeDateType::START,
232 RelativeDateOffset::QUARTER,
233 "start-prev-quarter",
234 N_(
"Start of previous quarter"),
235 N_(
"First day of the previous quarterly accounting period.")
238 RelativeDatePeriod::END_PREV_QUARTER,
239 RelativeDateType::END,
240 RelativeDateOffset::QUARTER,
242 N_(
"End of previous quarter"),
243 N_(
"Last day of previous quarterly accounting period.")
246 RelativeDatePeriod::START_NEXT_QUARTER,
247 RelativeDateType::START,
248 RelativeDateOffset::QUARTER,
249 "start-next-quarter",
250 N_(
"Start of next quarter"),
251 N_(
"First day of the next quarterly accounting period.")
254 RelativeDatePeriod::END_NEXT_QUARTER,
255 RelativeDateType::END,
256 RelativeDateOffset::QUARTER,
258 N_(
"End of next quarter"),
259 N_(
"Last day of next quarterly accounting period.")
262 RelativeDatePeriod::START_CAL_YEAR,
263 RelativeDateType::START,
264 RelativeDateOffset::YEAR,
266 N_(
"Start of this year"),
267 N_(
"First day of the current calendar year.")
270 RelativeDatePeriod::END_CAL_YEAR,
271 RelativeDateType::END,
272 RelativeDateOffset::YEAR,
274 N_(
"End of this year"),
275 N_(
"Last day of the current calendar year.")
278 RelativeDatePeriod::START_PREV_YEAR,
279 RelativeDateType::START,
280 RelativeDateOffset::YEAR,
282 N_(
"Start of previous year"),
283 N_(
"First day of the previous calendar year.")
286 RelativeDatePeriod::END_PREV_YEAR,
287 RelativeDateType::END,
288 RelativeDateOffset::YEAR,
290 N_(
"End of previous year"),
291 N_(
"Last day of the previous calendar year.")
294 RelativeDatePeriod::START_NEXT_YEAR,
295 RelativeDateType::START,
296 RelativeDateOffset::YEAR,
298 N_(
"Start of next year"),
299 N_(
"First day of the next calendar year.")
302 RelativeDatePeriod::END_NEXT_YEAR,
303 RelativeDateType::END,
304 RelativeDateOffset::YEAR,
306 N_(
"End of next year"),
307 N_(
"Last day of the next calendar year.")
310 RelativeDatePeriod::START_ACCOUNTING_PERIOD,
311 RelativeDateType::START,
312 RelativeDateOffset::YEAR,
313 "start-prev-fin-year",
314 N_(
"Start of accounting period"),
315 N_(
"First day of the accounting period, as set in the global preferences.")
318 RelativeDatePeriod::END_ACCOUNTING_PERIOD,
319 RelativeDateType::END,
320 RelativeDateOffset::YEAR,
322 N_(
"End of accounting period"),
323 N_(
"Last day of the accounting period, as set in the global preferences.")
330 assert (reldates[static_cast<int>(per)].m_period == per);
331 return reldates[
static_cast<int>(per)];
337 if (per == RelativeDatePeriod::ABSOLUTE)
339 auto reldate = checked_reldate(per);
340 return reldate.m_type == RelativeDateType::LAST ||
341 reldate.m_type == RelativeDateType::NEXT;
347 if (per == RelativeDatePeriod::ABSOLUTE)
349 return checked_reldate(per).m_type == RelativeDateType::START;
355 if (per == RelativeDatePeriod::ABSOLUTE)
357 return checked_reldate(per).m_type == RelativeDateType::END;
363 if (per == RelativeDatePeriod::ABSOLUTE)
365 return checked_reldate(per).m_storage;
371 if (per == RelativeDatePeriod::ABSOLUTE)
373 return checked_reldate(per).m_display;
378 if (per == RelativeDatePeriod::ABSOLUTE)
380 return checked_reldate(per).m_description;
386 auto per = std::find_if(reldates.begin(), reldates.end(),
387 [str](
auto rel) ->
bool 389 return strcmp(str, rel.m_storage) == 0;
391 return per != reldates.end() ? per->m_period : RelativeDatePeriod::ABSOLUTE;
397 auto rdate{checked_reldate(per)};
398 return per == RelativeDatePeriod::START_PREV_YEAR ||
399 per == RelativeDatePeriod::END_PREV_YEAR ||
400 per == RelativeDatePeriod::START_PREV_QUARTER ||
401 per == RelativeDatePeriod::END_PREV_QUARTER ||
402 per == RelativeDatePeriod::START_PREV_MONTH ||
403 per == RelativeDatePeriod::END_PREV_MONTH ||
404 rdate.m_type == LAST;
410 auto rdate{checked_reldate(per)};
411 return per == RelativeDatePeriod::START_NEXT_YEAR ||
412 per == RelativeDatePeriod::END_NEXT_YEAR ||
413 per == RelativeDatePeriod::START_NEXT_QUARTER ||
414 per == RelativeDatePeriod::END_NEXT_QUARTER ||
415 per == RelativeDatePeriod::START_NEXT_MONTH ||
416 per == RelativeDatePeriod::END_NEXT_MONTH ||
417 rdate.m_type == NEXT;
420 static RelativeDateOffset
423 return checked_reldate(per).m_offset;
426 static constexpr
int days_in_month[12]{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
433 normalize_reldate_tm(
struct tm& now)
435 auto factor{abs(now.tm_mon) / 12};
436 now.tm_mon /= factor > 0 ? factor : 1;
437 now.tm_year += now.tm_mon < 0 ? -factor: factor;
439 auto days = [](
auto month,
int year)
441 auto mon{month % 12 + (month < 0 ? 12 : 0)};
442 auto num_days{days_in_month[mon]};
444 if (mon == 1 && year % 4 == 0 && !(year % 100 == 0 && (year + 1900) % 400 != 0))
449 while (now.tm_mday < 1)
450 now.tm_mday += days(--now.tm_mon, now.tm_year);
452 while (now.tm_mday > days(now.tm_mon, now.tm_year))
453 now.tm_mday -= days(now.tm_mon++, now.tm_year);
455 while (now.tm_mon < 0)
460 while (now.tm_mon > 11)
470 if (now.tm_mday > days_in_month[now.tm_mon])
471 now.tm_mday -= days_in_month[now.tm_mon++];
475 reldate_set_day_and_time(
struct tm& now, RelativeDateType type)
477 if (type == RelativeDateType::START)
479 gnc_tm_set_day_start(&now);
482 else if (type == RelativeDateType::END)
485 auto year_delta = now.tm_mon / 12 + now.tm_mon < 0 ? -1 : 0;
486 auto month = now.tm_mon - 12 * year_delta;
487 auto year = now.tm_year + year_delta + 1900;
489 gnc_tm_set_day_end(&now);
497 if (period == RelativeDatePeriod::TODAY)
499 if (period == RelativeDatePeriod::START_ACCOUNTING_PERIOD)
500 return gnc_accounting_period_fiscal_start();
501 if (period == RelativeDatePeriod::END_ACCOUNTING_PERIOD)
502 return gnc_accounting_period_fiscal_end();
505 if (period == RelativeDatePeriod::TODAY)
506 return static_cast<time64>(now_t);
507 auto now{
static_cast<tm
>(now_t)};
508 auto acct_per{
static_cast<tm
>(
GncDateTime(gnc_accounting_period_fiscal_start()))};
510 if (acct_per.tm_mon == now.tm_mon && acct_per.tm_mday == now.tm_mday)
514 acct_per.tm_mday = 0;
517 switch(reldate_offset(period))
519 case RelativeDateOffset::NONE:
522 case RelativeDateOffset::YEAR:
523 if (reldate_is_prev(period))
525 else if (reldate_is_next(period))
532 case RelativeDateOffset::SIX:
533 if (reldate_is_prev(period))
535 else if (reldate_is_next(period))
538 case RelativeDateOffset::QUARTER:
540 auto delta = (now.tm_mon > acct_per.tm_mon ?
541 now.tm_mon - acct_per.tm_mon :
542 acct_per.tm_mon - now.tm_mon) % 3;
543 now.tm_mon = now.tm_mon - delta;
546 case RelativeDateOffset::THREE:
547 if (reldate_is_prev(period))
549 else if (reldate_is_next(period))
554 case RelativeDateOffset::MONTH:
555 if (reldate_is_prev(period))
557 else if (reldate_is_next(period))
560 case RelativeDateOffset::WEEK:
561 if (reldate_is_prev(period))
563 else if (reldate_is_next(period))
566 reldate_set_day_and_time(now, checked_reldate(period).m_type);
567 normalize_reldate_tm(now);
std::ostream & operator<<(std::ostream &ostr, RelativeDatePeriod per)
Add the display string to the provided std::ostream.
RelativeDatePeriod gnc_relative_date_from_storage_string(const char *str)
Convert a relative date storage string back to a RelativeDatePeriod value.
const char * gnc_relative_date_display_string(RelativeDatePeriod per)
Provide the string representation of a relative date for displaying value to a user.
const char * gnc_relative_date_description(RelativeDatePeriod per)
Provide the description of a relative date.
int gnc_date_get_last_mday(int month, int year)
Get the numerical last date of the month.
time64 gnc_relative_date_to_time64(RelativeDatePeriod period)
Convert a RelativeDatePeriod value to a concrete time64 by applying the value to the current time...
bool gnc_relative_date_is_ending(RelativeDatePeriod per)
Report whether the relative date represents the end of a date range.
bool gnc_relative_date_is_single(RelativeDatePeriod per)
Report whether the relative date represents a period offset to today's date rather than the beginning...
RelativeDatePeriod
Reporting periods relative to the current date.
General utilities for dealing with accounting periods.
bool gnc_relative_date_is_starting(RelativeDatePeriod per)
Report whether the relative date represents the beginning of a date range.
const char * gnc_relative_date_storage_string(RelativeDatePeriod per)
Provide the string representation of a relative date for persisting the value.
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Relative date enumeration and manipulation functions.