GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-date.cpp
1/********************************************************************\
2 * gnc-date.cpp -- C interface for date and time *
3 * *
4 * Copyright 1997 Robin D. Clark <rclark@cs.hmc.edu> *
5 * Copyright 1998-2000, 2003 Linas Vepstas <linas@linas.org> *
6 * Copyright (C) 2005 David Hampton <hampton@employees.org> *
7 * Copyright 2011-2015 John Ralls <jralls@ceridwen.us *
8 * *
9 * This program is free software; you can redistribute it and/or *
10 * modify it under the terms of the GNU General Public License as *
11 * published by the Free Software Foundation; either version 2 of *
12 * the License, or (at your option) any later version. *
13 * *
14 * This program is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 * GNU General Public License for more details. *
18 * *
19 * You should have received a copy of the GNU General Public License*
20 * along with this program; if not, contact: *
21 * *
22 * Free Software Foundation Voice: +1-617-542-5942 *
23 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
24 * Boston, MA 02110-1301, USA gnu@gnu.org *
25 * *
26\********************************************************************/
27
28#include <glib.h>
29
30#include <config.h>
31#include <libintl.h>
32#include <stdlib.h>
33#include "platform.h"
34#include "qof.h"
35
36#ifdef HAVE_LANGINFO_D_FMT
37# include <langinfo.h>
38#endif
39#ifndef HAVE_STRPTIME
40#include <strptime.h>
41#endif
42#ifdef G_OS_WIN32
43# include <windows.h>
44#endif
45
46#include <cinttypes>
47#include <unicode/calendar.h>
48#include "unicode/dtitvfmt.h"
49#include "unicode/smpdtfmt.h"
50
51#include "gnc-date.h"
52#include "gnc-date-p.h"
53#include "gnc-datetime.hpp"
54#include "gnc-timezone.hpp"
55#define BOOST_ERROR_CODE_HEADER_ONLY
56#include <boost/date_time/local_time/local_time.hpp>
57
58#define N_(string) string //So that xgettext will find it
59
60#ifdef HAVE_LANGINFO_D_FMT
61# define GNC_D_FMT (nl_langinfo (D_FMT))
62# define GNC_D_T_FMT (nl_langinfo (D_T_FMT))
63# define GNC_T_FMT (nl_langinfo (T_FMT))
64#elif defined(G_OS_WIN32)
65# define GNC_D_FMT (qof_win32_get_time_format(QOF_WIN32_PICTURE_DATE))
66# define GNC_T_FMT (qof_win32_get_time_format(QOF_WIN32_PICTURE_TIME))
67# define GNC_D_T_FMT (qof_win32_get_time_format(QOF_WIN32_PICTURE_DATETIME))
68#else
69# define GNC_D_FMT "%Y-%m-%d"
70# define GNC_D_T_FMT "%Y-%m-%d %r"
71# define GNC_T_FMT "%r"
72#endif
73
75#ifdef G_OS_WIN32
76 /* The default date format for use with strftime in Win32. */
77 N_("%B %#d, %Y")
78#else
79 /* The default date format for use with strftime in other OS. */
80 /* Translators: call "man strftime" for possible values. */
81 N_("%B %e, %Y")
82#endif
83 ;
84
85/* This is now user configured through the gnome options system() */
86static QofDateFormat dateFormat = QOF_DATE_FORMAT_LOCALE;
87static QofDateFormat prevQofDateFormat = QOF_DATE_FORMAT_LOCALE;
88
90static int dateCompletionBackMonths = 6;
91
92/* This static indicates the debugging module that this .o belongs to. */
93static QofLogModule log_module = QOF_MOD_ENGINE;
94
95/****************** Posix Replacement Functions ***************************/
96void
97gnc_tm_free (struct tm* time)
98{
99 free(time);
100}
101
102struct tm*
104{
105 auto time = static_cast<struct tm*>(calloc(1, sizeof(struct tm)));
106 if (gnc_localtime_r (secs, time) == nullptr)
107 {
108 gnc_tm_free (time);
109 return nullptr;
110 }
111 return time;
112}
113
114struct tm*
115gnc_localtime_r (const time64 *secs, struct tm* time)
116{
117 try
118 {
119 *time = static_cast<struct tm>(GncDateTime(*secs));
120 return time;
121 }
122 catch(std::invalid_argument&)
123 {
124 return nullptr;
125 }
126}
127
128static void
129normalize_time_component (int *inner, int *outer, int divisor)
130{
131 while (*inner < 0)
132 {
133 --(*outer);
134 *inner += divisor;
135 }
136 while (*inner >= divisor)
137 {
138 ++(*outer);
139 *inner -= divisor;
140 }
141}
142
143static void
144normalize_struct_tm (struct tm* time)
145{
146 gint year = time->tm_year + 1900;
147 gint last_day;
148
149 /* Gregorian_date throws if it gets an out-of-range year
150 * so clamp year into gregorian_date's range.
151 */
152 if (year < 1400) year += 1400;
153 if (year > 9999) year %= 10000;
154
155 normalize_time_component (&(time->tm_sec), &(time->tm_min), 60);
156 normalize_time_component (&(time->tm_min), &(time->tm_hour), 60);
157 normalize_time_component (&(time->tm_hour), &(time->tm_mday), 24);
158 normalize_time_component (&(time->tm_mon), &year, 12);
159
160 // auto month_in_range = []int (int m){ return (m + 12) % 12; }
161 while (time->tm_mday < 1)
162 {
163 normalize_time_component (&(--time->tm_mon), &year, 12);
164 last_day = gnc_date_get_last_mday (time->tm_mon, year);
165 time->tm_mday += last_day;
166 }
167 last_day = gnc_date_get_last_mday (time->tm_mon, year);
168 while (time->tm_mday > last_day)
169 {
170 time->tm_mday -= last_day;
171 normalize_time_component(&(++time->tm_mon), &year, 12);
172 last_day = gnc_date_get_last_mday (time->tm_mon, year);
173 }
174 time->tm_year = year - 1900;
175}
176
177struct tm*
178gnc_gmtime (const time64 *secs)
179{
180 try
181 {
182 GncDateTime gncdt(*secs);
183 auto time = static_cast<struct tm*>(calloc(1, sizeof(struct tm)));
184 *time = gncdt.utc_tm();
185 return time;
186 }
187 catch(std::invalid_argument&)
188 {
189 return nullptr;
190 }
191
192}
193
194gint
196{
197 /* icu's day of week is 1 based. Using 0 here to mean unset or error while setting */
198 static int cached_result = 0;
199
200 if (!cached_result)
201 {
202 UErrorCode err = U_ZERO_ERROR;
203 auto cal = icu::Calendar::createInstance (err);
204 if (!cal)
205 {
206 PERR("ICU error: %s\n", u_errorName (err));
207 return 0;
208 }
209
210 /* 1 for sunday, 2 for monday, etc. */
211 cached_result = cal->getFirstDayOfWeek (err);
212 delete cal;
213 }
214
215 return cached_result;
216}
217
218time64
219gnc_mktime (struct tm* time)
220{
221 try
222 {
223 normalize_struct_tm (time);
224 GncDateTime gncdt(*time);
225 *time = static_cast<struct tm>(gncdt);
226 return static_cast<time64>(gncdt);
227 }
228 catch(std::invalid_argument&)
229 {
230 return 0;
231 }
232}
233
234time64
235gnc_timegm (struct tm* time)
236{
237 try
238 {
239 normalize_struct_tm(time);
240 GncDateTime gncdt(*time);
241 *time = static_cast<struct tm>(gncdt);
242 time->tm_sec -= gncdt.offset();
243 normalize_struct_tm(time);
244#ifdef HAVE_STRUCT_TM_GMTOFF
245 time->tm_gmtoff = 0;
246#endif
247 return static_cast<time64>(gncdt) - gncdt.offset();
248 }
249 catch(std::invalid_argument&)
250 {
251 return 0;
252 }
253}
254
255char*
256gnc_ctime (const time64 *secs)
257{
258 return gnc_print_time64(*secs, "%a %b %d %H:%M:%S %Y");
259}
260
261time64
263{
264 GncDateTime gncdt;
265 auto time = static_cast<time64>(gncdt);
266 if (tbuf != nullptr)
267 *tbuf = time;
268 return time;
269}
270
271gdouble
272gnc_difftime (const time64 secs1, const time64 secs2)
273{
274 PWARN ("gnc_difftime is deprecated");
275 return (double)secs1 - (double)secs2;
276}
277
278/****************************************************************************/
279
280const char*
282{
283 switch (format)
284 {
286 return "us";
288 return "uk";
290 return "ce";
292 return "iso";
294 return "utc";
296 return "locale";
298 return "custom";
300 return "unset";
301 default:
302 return nullptr;
303 }
304}
305
306gboolean
307gnc_date_string_to_dateformat(const char* fmt_str, QofDateFormat *format)
308{
309 if (!fmt_str)
310 return TRUE;
311
312 if (!strcmp(fmt_str, "us"))
313 *format = QOF_DATE_FORMAT_US;
314 else if (!strcmp(fmt_str, "uk"))
315 *format = QOF_DATE_FORMAT_UK;
316 else if (!strcmp(fmt_str, "ce"))
317 *format = QOF_DATE_FORMAT_CE;
318 else if (!strcmp(fmt_str, "utc"))
319 *format = QOF_DATE_FORMAT_UTC;
320 else if (!strcmp(fmt_str, "iso"))
321 *format = QOF_DATE_FORMAT_ISO;
322 else if (!strcmp(fmt_str, "locale"))
323 *format = QOF_DATE_FORMAT_LOCALE;
324 else if (!strcmp(fmt_str, "custom"))
325 *format = QOF_DATE_FORMAT_CUSTOM;
326 else if (!strcmp(fmt_str, "unset"))
327 *format = QOF_DATE_FORMAT_UNSET;
328 else
329 return TRUE;
330
331 return FALSE;
332}
333
334const char*
335gnc_date_monthformat_to_string(GNCDateMonthFormat format)
336{
337 //avoid UB if format is out of range
338 switch (static_cast<uint8_t>(format))
339 {
340 case GNCDATE_MONTH_NUMBER:
341 return "number";
342 case GNCDATE_MONTH_ABBREV:
343 return "abbrev";
344 case GNCDATE_MONTH_NAME:
345 return "name";
346 default:
347 return nullptr;
348 }
349}
350
351gboolean
352gnc_date_string_to_monthformat(const char *fmt_str, GNCDateMonthFormat *format)
353{
354 if (!fmt_str)
355 return TRUE;
356
357 if (!strcmp(fmt_str, "number"))
358 *format = GNCDATE_MONTH_NUMBER;
359 else if (!strcmp(fmt_str, "abbrev"))
360 *format = GNCDATE_MONTH_ABBREV;
361 else if (!strcmp(fmt_str, "name"))
362 *format = GNCDATE_MONTH_NAME;
363 else
364 return TRUE;
365
366 return FALSE;
367}
368
369char*
370gnc_print_time64(time64 time, const char* format)
371{
372 try
373 {
374 GncDateTime gncdt(time);
375 auto sstr = gncdt.format(format);
376 //ugly C allocation so that the ptr can be freed at the other end
377 char* cstr = static_cast<char*>(malloc(sstr.length() + 1));
378 memset(cstr, 0, sstr.length() + 1);
379 strncpy(cstr, sstr.c_str(), sstr.length());
380 return cstr;
381 }
382 catch(std::runtime_error& err)
383 {
384 PWARN("Error processing time64 %" PRId64 ": %s", time, err.what());
385 return nullptr;
386 }
387 catch(std::logic_error& err)
388 {
389 PWARN("Error processing time64 %" PRId64 ": %s", time, err.what());
390 return nullptr;
391 }
392}
393
394/********************************************************************\
395\********************************************************************/
396
397
398/* Converts any time on a day to midday that day.
399
400 * given a timepair contains any time on a certain day (local time)
401 * converts it to be midday that day.
402 */
403time64
405{
406 struct tm tm;
407 gnc_localtime_r(&t, &tm);
408 gnc_tm_set_day_middle(&tm);
409 return gnc_mktime (&tm);
410}
411
412/* NB: month is 0-11, year is 0001 - 9999. */
413int gnc_date_get_last_mday (int month, int year)
414{
415 static int last_day_of_month[12] =
416 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
417
418 g_assert(month >= 0 && month < 12);
419
420 // To be a leap year, the year number must be divisible by four,
421 // except for end-of-century years, which must be divisible by 400.
422
423 return last_day_of_month[month] +
424 (month == 1 && year % 4 == 0 && !(year % 100 == 0 && year % 400 != 0) ?
425 1 : 0);
426}
427
429{
430 return dateFormat;
431}
432
434{
435//avoid UB if df is out of range
436 auto dfi{static_cast<uint8_t>(df)};
437 if (dfi >= DATE_FORMAT_FIRST && dfi <= DATE_FORMAT_LAST)
438 {
439 prevQofDateFormat = dateFormat;
440 dateFormat = df;
441 }
442 else
443 {
444 /* hack alert - Use a neutral default. */
445 PERR("non-existent date format set attempted. Setting ISO default");
446 prevQofDateFormat = dateFormat;
447 dateFormat = QOF_DATE_FORMAT_ISO;
448 }
449
450 return;
451}
452
453/* set date completion method
454
455set dateCompletion to one of QOF_DATE_COMPLETION_THISYEAR (for
456completing the year to the current calendar year) or
457QOF_DATE_COMPLETION_SLIDING (for using a sliding 12-month window). The
458sliding window starts 'backmonth' months before the current month (0-11).
459checks to make sure it's a legal value
460
461param QofDateCompletion: indicates preferred completion method
462param int: the number of months to go back in time (0-11)
463
464return void
465
466Globals: dateCompletion dateCompletionBackMonths
467*/
469{
472 {
473 dateCompletion = dc;
474 }
475 else
476 {
477 /* hack alert - Use a neutral default. */
478 PERR("non-existent date completion set attempted. Setting current year completion as default");
479 dateCompletion = QOF_DATE_COMPLETION_THISYEAR;
480 }
481
482 if (backmonths < 0)
483 {
484 backmonths = 0;
485 }
486 else if (backmonths > 11)
487 {
488 backmonths = 11;
489 }
490 dateCompletionBackMonths = backmonths;
491
492 return;
493}
494
495/*
496 qof_date_format_get_string
497 get the date format string for the current format
498 returns: string
499
500 Globals: dateFormat
501*/
503{
504 switch (df)
505 {
507 return "%m/%d/%Y";
509 return "%d/%m/%Y";
511 return "%d.%m.%Y";
513 return "%Y-%m-%dT%H:%M:%SZ";
515 return "%Y-%m-%d";
516 case QOF_DATE_FORMAT_UNSET: // use global
517 return qof_date_format_get_string (dateFormat);
519 default:
520 break;
521 };
522 return GNC_D_FMT;
523}
524
526{
527 switch (df)
528 {
530 return "%b %d, %Y";
533 return "%d %b %Y";
535 return "%Y-%m-%dT%H:%M:%SZ";
537 return "%Y-%b-%d";
538 case QOF_DATE_FORMAT_UNSET: // use global
539 return qof_date_text_format_get_string (dateFormat);
541 default:
542 break;
543 };
544 return GNC_D_FMT;
545}
546
547size_t
548qof_print_date_dmy_buff (char * buff, const size_t len, int day, int month, int year)
549{
550 if (!buff) return 0;
551
552 try
553 {
554 GncDate date(year, month, day);
555 std::string str = date.format(qof_date_format_get_string(dateFormat));
556 strncpy(buff, str.c_str(), len);
557 if (str.length() >= len)
558 buff[len - 1] = '\0';
559 }
560 catch(std::logic_error& err)
561 {
562 PWARN("Error processing year-month-day %d-%d-%d: %s",
563 year, month, day, err.what());
564 }
565 catch(std::runtime_error& err)
566 {
567 PWARN("Error processing year-month-day %d-%d-%d: %s",
568 year, month, day, err.what());
569 }
570 return strlen(buff);
571}
572
573size_t
574qof_print_date_buff (char * buff, const size_t len, time64 t)
575{
576 if (!buff) return 0;
577
578 try
579 {
580 GncDateTime gncdt(t);
581 std::string str = gncdt.format(qof_date_format_get_string(dateFormat));
582 strncpy(buff, str.c_str(), len);
583 if (str.length() >= len)
584 buff[len - 1] = '\0';
585 }
586 catch(std::logic_error& err)
587 {
588 PWARN("Error processing time64 %" PRId64 ": %s", t, err.what());
589 }
590 catch(std::runtime_error& err)
591 {
592 PWARN("Error processing time64 %" PRId64 ": %s", t, err.what());
593 }
594 return strlen(buff);
595}
596
597size_t
598qof_print_gdate( char *buf, size_t len, const GDate *gd )
599{
600 GDate date;
601 g_date_clear (&date, 1);
602 date = *gd;
603 return qof_print_date_dmy_buff( buf, len,
604 g_date_get_day(&date),
605 g_date_get_month(&date),
606 g_date_get_year(&date) );
607}
608
609char *
611{
612 char buff[MAX_DATE_LENGTH + 1];
613 memset (buff, 0, sizeof (buff));
615 return g_strdup (buff);
616}
617
618static icu::DateIntervalFormat*
619get_icu_date_interval_formatter ()
620{
621 static std::unique_ptr<icu::DateIntervalFormat> difmt;
622 if (!difmt)
623 {
624 auto locale = icu::Locale::getDefault();
625 UErrorCode status = U_ZERO_ERROR;
626 difmt.reset(icu::DateIntervalFormat::createInstance(UDAT_YEAR_NUM_MONTH_DAY, locale, status));
627 if (U_FAILURE(status))
628 {
629 PWARN ("icu::DateIntervalFormat::createInstance error %d", status);
630 return nullptr;
631 }
632 }
633 return difmt.get();
634}
635
636static gchar*
637icu_date_interval_format (time64 from_date, time64 to_date)
638{
639 auto difmt = get_icu_date_interval_formatter();
640 if (!difmt)
641 return nullptr;
642
643 if (from_date > to_date)
644 std::swap(from_date, to_date);
645
646 icu::DateInterval interval (from_date * 1000.0, to_date * 1000.0);
647 icu::UnicodeString result;
648 icu::FieldPosition fp;
649 UErrorCode status = U_ZERO_ERROR;
650 difmt->format (&interval, result, fp, status);
651 if (U_FAILURE(status))
652 {
653 PWARN("Error formatting interval: %d", status);
654 return nullptr;
655 }
656
657 std::string interval_string;
658 result.toUTF8String(interval_string);
659
660 return g_strdup (interval_string.c_str());
661}
662
663gchar*
664gnc_date_interval_format (time64 from_date, time64 to_date)
665{
666 gchar* rv = nullptr;
667
669 rv = icu_date_interval_format (from_date, to_date);
670
671 // not using locale, or icu failure
672 if (!rv)
673 {
674 gchar from_buff[MAX_DATE_LENGTH+1], to_buff[MAX_DATE_LENGTH+1];
675 qof_print_date_buff (from_buff, MAX_DATE_LENGTH, from_date);
676 qof_print_date_buff (to_buff, MAX_DATE_LENGTH, to_date);
677 rv = g_strdup_printf (gettext("%s to %s"), from_buff, to_buff);
678 }
679
680 return rv;
681}
682
683/* ============================================================== */
684
685/* return the greatest integer <= a/b; works for b > 0 and positive or
686 negative a. */
687static int
688floordiv(int a, int b)
689{
690 if (a >= 0)
691 {
692 return a / b;
693 }
694 else
695 {
696 return - ((-a - 1) / b) - 1;
697 }
698}
699
700/* Normalize the localized date format to avoid date scanning issues.
701 *
702 * The 'O' and 'E' format modifiers are for localized input/output
703 * characters. Remove them as we are always using Arabic numbers.
704 */
705static inline std::string
706normalize_format (const std::string& format)
707{
708 bool is_pct = false;
709 std::string normalized;
710 std::remove_copy_if(
711 format.begin(), format.end(), back_inserter(normalized),
712 [&is_pct](char e){
713 bool r = (is_pct && (e == 'E' || e == 'O' || e == '-'));
714 is_pct = e == '%';
715 return r;
716 });
717 return normalized;
718}
719
720/* Convert a string into day, month and year integers
721
722 Convert a string into day / month / year integers according to
723 the current dateFormat value.
724
725 This function will always parse a single number as the day of
726 the month, regardless of the ordering of the dateFormat value.
727 Two numbers will always be parsed as the day and the month, in
728 the same order that they appear in the dateFormat value. Three
729 numbers are parsed exactly as specified in the dateFormat field.
730
731 Fully formatted UTC timestamp strings are converted separately.
732
733 param buff - pointer to date string
734 param day - will store day of the month as 1 ... 31
735 param month - will store month of the year as 1 ... 12
736 param year - will store the year (4-digit)
737
738 return TRUE if date appeared to be valid.
739
740 Globals: global dateFormat value
741*/
742static gboolean
743qof_scan_date_internal (const char *buff, int *day, int *month, int *year,
744 QofDateFormat which_format)
745{
746 char *dupe, *tmp, *first_field, *second_field, *third_field;
747 int iday, imonth, iyear;
748 int now_day, now_month, now_year;
749 struct tm *now, utc;
750 time64 secs;
751
752 if (!buff) return(FALSE);
753
754 if (which_format == QOF_DATE_FORMAT_UTC)
755 {
756 if (strptime(buff, QOF_UTC_DATE_FORMAT, &utc)
757 || strptime (buff, "%Y-%m-%d", &utc))
758 {
759 *day = utc.tm_mday;
760 *month = utc.tm_mon + 1;
761 *year = utc.tm_year + 1900;
762 return TRUE;
763 }
764 else
765 {
766 return FALSE;
767 }
768 }
769 dupe = g_strdup (buff);
770
771 tmp = dupe;
772 first_field = nullptr;
773 second_field = nullptr;
774 third_field = nullptr;
775
776 /* Use strtok to find delimiters */
777 if (tmp)
778 {
779 static const char *delims = ".,-+/\\()년월年月 ";
780
781 first_field = strtok (tmp, delims);
782 if (first_field)
783 {
784 second_field = strtok (nullptr, delims);
785 if (second_field)
786 {
787 third_field = strtok (nullptr, delims);
788 }
789 }
790 }
791
792 /* today's date */
793 gnc_time (&secs);
794 now = gnc_localtime (&secs);
795 if (!now)
796 return FALSE;
797 now_day = now->tm_mday;
798 now_month = now->tm_mon + 1;
799 now_year = now->tm_year + 1900;
800 gnc_tm_free (now);
801
802 /* set defaults: if day or month appear to be blank, use today's date */
803 iday = now_day;
804 imonth = now_month;
805 iyear = -1;
806
807 /* get numeric values */
808 switch (which_format)
809 {
811 if (buff[0] != '\0')
812 {
813 struct tm thetime;
814 /* Parse time string. */
815 memset(&thetime, -1, sizeof(struct tm));
816 char *strv = strptime (buff, normalize_format(GNC_D_FMT).c_str(),
817 &thetime);
818
819 if (third_field)
820 {
821 if (!strv) // Parse failed, continuing gives the wrong result.
822 return FALSE;
823
824 /* Easy. All three values were parsed. */
825 iyear = thetime.tm_year + 1900;
826 iday = thetime.tm_mday;
827 imonth = thetime.tm_mon + 1;
828 }
829 else if (second_field)
830 {
831 /* Hard. Two values parsed. Figure out the ordering. */
832 if (thetime.tm_year == -1)
833 {
834 /* %m-%d or %d-%m. Don't care. Already parsed correctly. */
835 iday = thetime.tm_mday;
836 imonth = thetime.tm_mon + 1;
837 }
838 else if (thetime.tm_mon != -1)
839 {
840 /* Must be %Y-%m-%d. Reparse as %m-%d.*/
841 imonth = atoi(first_field);
842 iday = atoi(second_field);
843 }
844 else
845 {
846 /* Must be %Y-%d-%m. Reparse as %d-%m. */
847 iday = atoi(first_field);
848 imonth = atoi(second_field);
849 }
850 }
851 else if (first_field)
852 {
853 iday = atoi(first_field);
854 }
855 }
856 break;
859 if (third_field)
860 {
861 iday = atoi(first_field);
862 imonth = atoi(second_field);
863 iyear = atoi(third_field);
864 }
865 else if (second_field)
866 {
867 iday = atoi(first_field);
868 imonth = atoi(second_field);
869 }
870 else if (first_field)
871 {
872 iday = atoi(first_field);
873 }
874 break;
876 if (third_field)
877 {
878 iyear = atoi(first_field);
879 imonth = atoi(second_field);
880 iday = atoi(third_field);
881 }
882 else if (second_field)
883 {
884 imonth = atoi(first_field);
885 iday = atoi(second_field);
886 }
887 else if (first_field)
888 {
889 iday = atoi(first_field);
890 }
891 break;
893 default:
894 if (third_field)
895 {
896 imonth = atoi(first_field);
897 iday = atoi(second_field);
898 iyear = atoi(third_field);
899 }
900 else if (second_field)
901 {
902 imonth = atoi(first_field);
903 iday = atoi(second_field);
904 }
905 else if (first_field)
906 {
907 iday = atoi(first_field);
908 }
909 break;
910 }
911
912 g_free (dupe);
913
914 if ((imonth == 0) || (iday == 0))
915 return FALSE;
916
917 if ((12 < imonth) || (31 < iday))
918 {
919 /*
920 * Ack! Thppfft! Someone just fed this routine a string in the
921 * wrong date format. This is known to happen if a register
922 * window is open when changing the date format. Try the
923 * previous date format. If that doesn't work, see if we can
924 * exchange month and day. If that still doesn't work,
925 * bail and give the caller what they asked for (garbage)
926 * parsed in the new format.
927 *
928 * Note: This test cannot detect any format change that only
929 * swaps month and day field, if the day is 12 or less. This is
930 * deemed acceptable given the obscurity of this bug.
931 */
932 if ((which_format != prevQofDateFormat) &&
933 qof_scan_date_internal(buff, day, month, year, prevQofDateFormat))
934 {
935 return(TRUE);
936 }
937 if ((12 < imonth) && (12 >= iday))
938 {
939 int tmp = imonth;
940 imonth = iday;
941 iday = tmp;
942 }
943 else
944 {
945 return FALSE;
946 }
947 }
948
949 /* if no year was entered, choose a year according to the
950 dateCompletion preference. If it is
951 QOF_DATE_COMPLETION_THISYEAR, use the current year, else if it
952 is QOF_DATE_COMPLETION_SLIDING, use a sliding window that
953 starts dateCompletionBackMonths before the current month.
954
955 We go by whole months, rather than days, because presumably
956 this is less confusing.
957 */
958
959 if (iyear == -1)
960 {
961 if (dateCompletion == QOF_DATE_COMPLETION_THISYEAR)
962 {
963 iyear = now_year; /* use the current year */
964 }
965 else
966 {
967 iyear = now_year - floordiv(imonth - now_month +
968 dateCompletionBackMonths, 12);
969 }
970 }
971
972 /* If the year entered is smaller than 100, assume we mean the current
973 century (and are not revising some roman emperor's books) */
974 if (iyear < 100)
975 iyear += ((int) ((now_year + 50 - iyear) / 100)) * 100;
976
977 /* Fix up any goofy dates */
978 struct tm tm{};
979 tm.tm_year = iyear - 1900;
980 tm.tm_mon = imonth - 1;
981 tm.tm_mday = iday;
982 normalize_struct_tm(&tm);
983
984 if (year) *year = tm.tm_year + 1900;
985 if (month) *month = tm.tm_mon + 1;
986 if (day) *day = tm.tm_mday;
987 return(TRUE);
988}
989
990gboolean
991qof_scan_date (const char *buff, int *day, int *month, int *year)
992{
993 return qof_scan_date_internal(buff, day, month, year, dateFormat);
994}
995
996/* Return the field separator for the current date format
997return date character
998*/
999char dateSeparator (void)
1000{
1001 static char locale_separator = '\0';
1002
1003 switch (dateFormat)
1004 {
1005 case QOF_DATE_FORMAT_CE:
1006 return '.';
1009 return '-';
1010 case QOF_DATE_FORMAT_US:
1011 case QOF_DATE_FORMAT_UK:
1012 default:
1013 return '/';
1015 if (locale_separator != '\0')
1016 return locale_separator;
1017 else
1018 {
1019 /* Make a guess */
1020 gchar string[256];
1021 struct tm tm;
1022 time64 secs;
1023 gchar *s;
1024
1025 secs = gnc_time (nullptr);
1026 gnc_localtime_r(&secs, &tm);
1027 auto normalized_fmt =
1028 normalize_format(qof_date_format_get_string(dateFormat));
1029 qof_strftime(string, sizeof(string), normalized_fmt.c_str(), &tm);
1030
1031 for (s = string; *s != '\0'; s++)
1032 if (!isdigit(*s))
1033 return (locale_separator = *s);
1034 }
1035 break;
1036 }
1037 return '\0';
1038}
1039
1040/* The following functions have Win32 forms in qof-win32.c */
1041#ifndef G_OS_WIN32
1042gchar *
1043qof_time_format_from_utf8(const gchar *utf8_format)
1044{
1045 gchar *retval;
1046 GError *error = nullptr;
1047
1048 retval = g_locale_from_utf8(utf8_format, -1, nullptr, nullptr, &error);
1049
1050 if (!retval)
1051 {
1052 g_warning("Could not convert format '%s' from UTF-8: %s", utf8_format,
1053 error->message);
1054 g_error_free(error);
1055 }
1056 return retval;
1057}
1058
1059gchar *
1060qof_formatted_time_to_utf8(const gchar *locale_string)
1061{
1062 gchar *retval;
1063 GError *error = nullptr;
1064
1065 retval = g_locale_to_utf8(locale_string, -1, nullptr, nullptr, &error);
1066
1067 if (!retval)
1068 {
1069 g_warning("Could not convert '%s' to UTF-8: %s", locale_string,
1070 error->message);
1071 g_error_free(error);
1072 }
1073 return retval;
1074}
1075#endif /* G_OS_WIN32 */
1076
1077static gchar *
1078qof_format_time(const gchar *format, const struct tm *tm)
1079{
1080 gchar *locale_format, *tmpbuf, *retval;
1081 gsize tmplen, tmpbufsize;
1082
1083 g_return_val_if_fail(format, 0);
1084 g_return_val_if_fail(tm, 0);
1085
1086 locale_format = qof_time_format_from_utf8(format);
1087 if (!locale_format)
1088 return nullptr;
1089
1090 tmpbufsize = MAX(128, strlen(locale_format) * 2);
1091 while (TRUE)
1092 {
1093 tmpbuf = static_cast<gchar*>(g_malloc(tmpbufsize));
1094
1095 /* Set the first byte to something other than '\0', to be able to
1096 * recognize whether strftime actually failed or just returned "".
1097 */
1098 tmpbuf[0] = '\1';
1099 tmplen = strftime(tmpbuf, tmpbufsize, locale_format, tm);
1100
1101 if (tmplen == 0 && tmpbuf[0] != '\0')
1102 {
1103 g_free(tmpbuf);
1104 tmpbufsize *= 2;
1105
1106 if (tmpbufsize > 65536)
1107 {
1108 g_warning("Maximum buffer size for qof_format_time "
1109 "exceeded: giving up");
1110 g_free(locale_format);
1111
1112 return nullptr;
1113 }
1114 }
1115 else
1116 {
1117 break;
1118 }
1119 }
1120 g_free(locale_format);
1121
1122 retval = qof_formatted_time_to_utf8(tmpbuf);
1123 g_free(tmpbuf);
1124
1125 return retval;
1126}
1127
1128gsize
1129qof_strftime(gchar *buf, gsize max, const gchar *format, const struct tm *tm)
1130{
1131 gsize convlen, retval;
1132 gchar *convbuf;
1133
1134 g_return_val_if_fail(buf, 0);
1135 g_return_val_if_fail(max > 0, 0);
1136 g_return_val_if_fail(format, 0);
1137 g_return_val_if_fail(tm, 0);
1138
1139 convbuf = qof_format_time(format, tm);
1140 if (!convbuf)
1141 {
1142 buf[0] = '\0';
1143 return 0;
1144 }
1145
1146 convlen = strlen(convbuf);
1147
1148 if (max <= convlen)
1149 {
1150 /* Ensure only whole characters are copied into the buffer. */
1151 gchar *end = g_utf8_find_prev_char(convbuf, convbuf + max);
1152 g_assert(end != nullptr);
1153 convlen = end - convbuf;
1154
1155 /* Return 0 because the buffer isn't large enough. */
1156 retval = 0;
1157 }
1158 else
1159 {
1160 retval = convlen;
1161 }
1162
1163 memcpy(buf, convbuf, convlen);
1164 buf[convlen] = '\0';
1165 g_free(convbuf);
1166
1167 return retval;
1168}
1169
1170/********************************************************************\
1171\********************************************************************/
1172
1173gchar *
1175{
1176 auto timestamp = GncDateTime::timestamp();
1177 return g_strdup(timestamp.c_str());
1178}
1179
1180/********************************************************************\
1181 * iso 8601 datetimes should look like 1998-07-02 11:00:00.68-05
1182\********************************************************************/
1183/* Unfortunately, not all strptime or struct tm implementations
1184 * support timezones, so we have to do this with sscanf.
1185 */
1186
1187#define ISO_DATE_FORMAT "%d-%d-%d %d:%d:%lf%s"
1188time64
1189gnc_iso8601_to_time64_gmt(const char *cstr)
1190{
1191 if (!cstr) return INT64_MAX;
1192 try
1193 {
1194 GncDateTime gncdt(cstr);
1195 return static_cast<time64>(gncdt);
1196 }
1197 catch(std::logic_error& err)
1198 {
1199 PWARN("Error processing %s: %s", cstr, err.what());
1200 return INT64_MAX;
1201 }
1202 catch(std::runtime_error& err)
1203 {
1204 PWARN("Error processing time64 %s: %s", cstr, err.what());
1205 return INT64_MAX;
1206 }
1207}
1208
1209/********************************************************************\
1210\********************************************************************/
1211
1212char *
1214{
1215 if (!buff) return nullptr;
1216 try
1217 {
1218 GncDateTime gncdt(time);
1219 auto sstr = gncdt.format_iso8601();
1220
1221 memset(buff, 0, sstr.length() + 1);
1222 strncpy(buff, sstr.c_str(), sstr.length());
1223 return buff + sstr.length();
1224 }
1225 catch(std::logic_error& err)
1226 {
1227 PWARN("Error processing time64 %" PRId64 ": %s", time, err.what());
1228 return buff;
1229 }
1230 catch(std::runtime_error& err)
1231 {
1232 PWARN("Error processing time64 %" PRId64 ": %s", time, err.what());
1233 return buff;
1234 }
1235}
1236
1237#define THIRTY_TWO_YEARS 0x3c30fc00LL
1238
1239static time64
1240gnc_dmy2time64_internal (int day, int month, int year, DayPart day_part)
1241{
1242 try
1243 {
1244 auto date = GncDate(year, month, day);
1245 return static_cast<time64>(GncDateTime (date, day_part));
1246 }
1247 catch(const std::logic_error& err)
1248 {
1249 PWARN("Date computation error from Y-M-D %d-%d-%d: %s",
1250 year, month, day, err.what());
1251 return INT64_MAX;
1252 }
1253 catch(const std::runtime_error& err)
1254 {
1255 PWARN("Date computation error from Y-M-D %d-%d-%d: %s",
1256 year, month, day, err.what());
1257 return INT64_MAX;
1258 }
1259}
1260
1261time64
1262gnc_dmy2time64 (int day, int month, int year)
1263{
1264 return gnc_dmy2time64_internal (day, month, year, DayPart::start);
1265}
1266
1267time64
1268gnc_dmy2time64_end (int day, int month, int year)
1269{
1270 return gnc_dmy2time64_internal (day, month, year, DayPart::end);
1271}
1272
1273time64
1274gnc_dmy2time64_neutral (int day, int month, int year)
1275{
1276 return gnc_dmy2time64_internal (day, month, year, DayPart::neutral);
1277}
1278
1279
1280/* The GDate setter functions all in the end use g_date_set_time_t,
1281 * which in turn relies on localtime and is therefore subject to the
1282 * 2038 bug.
1283 */
1285{
1286 GDate result;
1287
1288 g_date_clear (&result, 1);
1289 GncDateTime time(t);
1290 auto date = time.date().year_month_day();
1291 g_date_set_dmy (&result, date.day, static_cast<GDateMonth>(date.month),
1292 date.year);
1293 g_assert(g_date_valid (&result));
1294
1295 return result;
1296}
1297
1299{
1300 GDate* rv = g_date_new ();
1302 return rv;
1303}
1304
1305void
1307{
1308 g_return_if_fail (gd != nullptr);
1309 auto ymd = GncDate().year_month_day();
1310 g_date_set_dmy (gd, ymd.day, static_cast<GDateMonth>(ymd.month), ymd.year);
1311}
1312
1313void
1315{
1316 struct tm tm;
1317 gnc_localtime_r(&time, &tm);
1318 g_date_set_dmy (gd, tm.tm_mday,
1319 static_cast<GDateMonth>(tm.tm_mon + 1),
1320 tm.tm_year + 1900);
1321}
1322
1324{
1325 return gnc_dmy2time64_neutral (g_date_get_day(&d),
1326 g_date_get_month(&d),
1327 g_date_get_year(&d));
1328}
1329
1330static void
1331gnc_tm_get_day_start (struct tm *tm, time64 time_val)
1332{
1333 /* Get the equivalent time structure */
1334 if (!gnc_localtime_r(&time_val, tm))
1335 return;
1336 gnc_tm_set_day_start(tm);
1337}
1338
1339void
1341{
1342 auto time_val{gnc_dmy2time64_internal(tm->tm_mday, tm->tm_mon + 1,
1343 tm->tm_year + 1900, DayPart::neutral)};
1344 gnc_localtime_r(&time_val, tm);
1345}
1346
1347static void
1348gnc_tm_get_day_neutral (struct tm *tm, time64 time_val)
1349{
1350 /* Get the equivalent time structure */
1351 if (!gnc_localtime_r(&time_val, tm))
1352 return;
1354}
1355
1356static void
1357gnc_tm_get_day_end (struct tm *tm, time64 time_val)
1358{
1359 /* Get the equivalent time structure */
1360 if (!gnc_localtime_r(&time_val, tm))
1361 return;
1362 gnc_tm_set_day_end(tm);
1363}
1364
1365time64
1367{
1368 struct tm tm;
1369 time64 new_time;
1370
1371 gnc_tm_get_day_start(&tm, time_val);
1372 new_time = gnc_mktime(&tm);
1373 return new_time;
1374}
1375
1376time64
1378{
1379 struct tm tm;
1380 gnc_localtime_r(&time_val, &tm);
1381 return gnc_dmy2time64_internal(tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900,
1382 DayPart::neutral);
1383}
1384
1385time64
1387{
1388 struct tm tm;
1389 time64 new_time;
1390
1391 gnc_tm_get_day_end(&tm, time_val);
1392 new_time = gnc_mktime(&tm);
1393 return new_time;
1394}
1395
1396/* ======================================================== */
1397
1398void
1400{
1401 gnc_tm_get_day_start(tm, gnc_time(nullptr));
1402}
1403
1404void
1406{
1407 gnc_tm_get_day_neutral(tm, gnc_time(nullptr));
1408}
1409
1410void
1412{
1413 gnc_tm_get_day_end(tm, gnc_time(nullptr));
1414}
1415
1416time64
1418{
1419 struct tm tm;
1420
1421 gnc_tm_get_day_start(&tm, gnc_time(nullptr));
1422 return gnc_mktime(&tm);
1423}
1424
1425time64
1427{
1428 struct tm tm;
1429
1430 gnc_tm_get_day_end(&tm, gnc_time(nullptr));
1431 return gnc_mktime(&tm);
1432}
1433
1434void
1435gnc_dow_abbrev(gchar *buf, int buf_len, int dow)
1436{
1437 struct tm my_tm;
1438 int i;
1439
1440 memset(buf, 0, buf_len);
1441 memset(&my_tm, 0, sizeof(struct tm));
1442 my_tm.tm_wday = dow;
1443 i = qof_strftime(buf, buf_len, "%a", &my_tm);
1444 buf[i] = 0;
1445}
1446
1447/* *******************************************************************
1448 * GValue handling
1449 ********************************************************************/
1450
1451static Time64*
1452time64_boxed_copy_func (Time64 *in_time64)
1453{
1454 Time64* newvalue = g_new (Time64, 1);
1455 *newvalue = *in_time64;
1456
1457 return newvalue;
1458}
1459
1460static void
1461time64_boxed_free_func (Time64 *in_time64)
1462{
1463 g_free (in_time64);
1464}
1465
1466G_DEFINE_BOXED_TYPE (Time64, time64, time64_boxed_copy_func, time64_boxed_free_func)
1467
1468/* ================================================= */
1469
1470gboolean
1471gnc_gdate_equal(gconstpointer gda, gconstpointer gdb)
1472{
1473 return (g_date_compare( (GDate*)gda, (GDate*)gdb ) == 0 ? TRUE : FALSE);
1474}
1475
1476guint
1477gnc_gdate_hash( gconstpointer gd )
1478{
1479 gint val = (g_date_get_year( (GDate*)gd ) * 10000)
1480 + (g_date_get_month( (GDate*)gd ) * 100)
1481 + g_date_get_day( (GDate*)gd );
1482 return g_int_hash( &val );
1483}
1484
1485/* ================================================= */
1486
1487time64
1489{
1490 struct tm stm;
1491 time64 secs;
1492
1493 /* First convert to a 'struct tm' */
1494 g_date_to_struct_tm (date, &stm);
1495
1496 /* Then convert to number of seconds */
1497 secs = gnc_mktime (&stm);
1498 return secs;
1499}
1500
1501time64
1503{
1504 struct tm stm;
1505 time64 secs;
1506
1507 /* First convert to a 'struct tm' */
1508 g_date_to_struct_tm(date, &stm);
1509
1510 /* Force to th last second of the day */
1511 stm.tm_hour = 23;
1512 stm.tm_min = 59;
1513 stm.tm_sec = 59;
1514 stm.tm_isdst = -1;
1515
1516 /* Then convert to number of seconds */
1517 secs = gnc_mktime (&stm);
1518 return secs;
1519}
1520
1521/* ================================================= */
1522
1523void
1525{
1526 g_date_set_day(date, 1);
1527}
1528
1536void
1538{
1539 /* First set the start of next month. */
1540 g_date_set_day(date, 1);
1541 g_date_add_months(date, 1);
1542
1543 /* Then back up one day */
1544 g_date_subtract_days(date, 1);
1545}
1546
1554void
1556{
1557 g_date_set_day(date, 1);
1558 g_date_subtract_months(date, 1);
1559}
1560
1568void
1570{
1571 /* This will correctly handle the varying month lengths */
1572 g_date_set_day(date, 1);
1573 g_date_subtract_days(date, 1);
1574}
1575
1576/* ================================================= */
1577
1578void
1580{
1581 gint months;
1582
1583 /* Set the date to the first day of the specified month. */
1584 g_date_set_day(date, 1);
1585
1586 /* Back up 0-2 months */
1587 months = (g_date_get_month(date) - G_DATE_JANUARY) % 3;
1588 g_date_subtract_months(date, months);
1589}
1590
1591void
1593{
1594 const GDateMonth months[] = {G_DATE_MARCH, G_DATE_JUNE,
1595 G_DATE_SEPTEMBER, G_DATE_DECEMBER};
1596 const GDateDay days[] = {31, 30, 30, 31};
1597 int quarter = (g_date_get_month (date) - 1) / 3;
1598
1599 g_date_set_month (date, months[quarter]);
1600 g_date_set_day (date, days[quarter]);
1601}
1602
1603void
1605{
1606 g_date_subtract_months(date, 3);
1608}
1609
1610void
1612{
1613 g_date_subtract_months(date, 3);
1615}
1616
1617/* ================================================= */
1618
1619void
1621{
1622 g_date_set_month(date, G_DATE_JANUARY);
1623 g_date_set_day(date, 1);
1624}
1625
1626void
1628{
1629 g_date_set_month(date, G_DATE_DECEMBER);
1630 g_date_set_day(date, 31);
1631}
1632
1633void
1635{
1637 g_date_subtract_years(date, 1);
1638}
1639
1640void
1642{
1644 g_date_subtract_years(date, 1);
1645}
1646
1647/* ================================================= */
1648
1649void
1651 const GDate *fy_end)
1652{
1653 GDate temp;
1654 gboolean new_fy;
1655
1656 g_return_if_fail(date);
1657 g_return_if_fail(fy_end);
1658
1659 /* Compute the FY end that occurred this CY */
1660 temp = *fy_end;
1661 g_date_set_year(&temp, g_date_get_year(date));
1662
1663 /* Has it already passed? */
1664 new_fy = (g_date_compare(date, &temp) > 0);
1665
1666 /* Set start date */
1667 *date = temp;
1668 g_date_add_days(date, 1);
1669 if (!new_fy)
1670 g_date_subtract_years(date, 1);
1671}
1672
1673void
1675 const GDate *fy_end)
1676{
1677 GDate temp;
1678 gboolean new_fy;
1679
1680 g_return_if_fail(date);
1681 g_return_if_fail(fy_end);
1682
1683 /* Compute the FY end that occurred this CY */
1684 temp = *fy_end;
1685 g_date_set_year(&temp, g_date_get_year(date));
1686
1687 /* Has it already passed? */
1688 new_fy = (g_date_compare(date, &temp) > 0);
1689
1690 /* Set end date */
1691 *date = temp;
1692 if (new_fy)
1693 g_date_add_years(date, 1);
1694}
1695
1696void
1698 const GDate *fy_end)
1699{
1700 g_return_if_fail(date);
1701 g_return_if_fail(fy_end);
1702
1703 gnc_gdate_set_fiscal_year_start(date, fy_end);
1704 g_date_subtract_years(date, 1);
1705}
1706
1707void
1709 const GDate *fy_end)
1710{
1711 g_return_if_fail(date);
1712 g_return_if_fail(fy_end);
1713
1714 gnc_gdate_set_fiscal_year_end(date, fy_end);
1715 g_date_subtract_years(date, 1);
1716}
1717
1718Testfuncs*
1719gnc_date_load_funcs (void)
1720{
1721 Testfuncs *tf = g_slice_new (Testfuncs);
1722 return tf;
1723}
GnuCash DateTime class.
std::string format_iso8601() const
Format the GncDateTime into a gnucash-style iso8601 string in UTC.
struct tm utc_tm() const
Obtain a struct tm representing the time in UTC.
std::string format(const char *format) const
Format the GncDateTime into a std::string.
static std::string timestamp()
Get an undelimited string representing the current date and time.
long offset() const
Obtain the UTC offset in seconds.
GnuCash Date class.
gnc_ymd year_month_day() const
Get the year, month, and day from the date as a gnc_ymd.
Date and Time handling routines.
time64 gnc_mktime(struct tm *time)
calculate seconds from the epoch given a time struct
Definition gnc-date.cpp:219
int gnc_date_get_last_mday(int month, int year)
Get the numerical last date of the month.
Definition gnc-date.cpp:413
void gnc_tm_set_day_neutral(struct tm *tm)
The gnc_tm_set_day_neutral() inline routine will set the appropriate fields in the struct tm to indic...
gboolean gnc_gdate_equal(gconstpointer gda, gconstpointer gdb)
Compares two GDate*'s for equality; useful for using GDate*'s as GHashTable keys.
void gnc_gdate_set_prev_year_end(GDate *date)
This function modifies a GDate to set it to the last day of the year prior to the one in which it fal...
void gnc_gdate_set_year_end(GDate *date)
This function modifies a GDate to set it to the last day of the year in which it falls.
time64 gnc_timegm(struct tm *time)
calculate seconds from the epoch given a time struct
Definition gnc-date.cpp:235
void qof_date_format_set(QofDateFormat df)
The qof_date_format_set() routine sets date format to one of US, UK, CE, OR ISO.
Definition gnc-date.cpp:433
const gchar * qof_date_text_format_get_string(QofDateFormat df)
This function returns a strftime formatting string for printing a date using words and numbers (e....
Definition gnc-date.cpp:525
gdouble gnc_difftime(const time64 secs1, const time64 secs2)
Find the difference in seconds between two time values (deprecated)
Definition gnc-date.cpp:272
void gnc_gdate_set_prev_month_end(GDate *date)
Convert a GDate to the last day of the prebvious month.
char * gnc_time64_to_iso8601_buff(time64 time, char *buff)
The gnc_time64_to_iso8601_buff() routine takes the input UTC time64 value and prints it as an ISO-860...
void gnc_gdate_set_year_start(GDate *date)
This function modifies a GDate to set it to the first day of the year in which it falls.
#define MAX_DATE_LENGTH
The maximum length of a string created by the date printers.
Definition gnc-date.h:108
void gnc_dow_abbrev(gchar *buf, int buf_len, int dow)
Localized DOW abbreviation.
char * gnc_ctime(const time64 *secs)
Return a string representation of a date from a 64-bit time value.
Definition gnc-date.cpp:256
struct tm * gnc_localtime_r(const time64 *secs, struct tm *time)
fill out a time struct from a 64-bit time value adjusted for the current time zone.
Definition gnc-date.cpp:115
char dateSeparator(void)
dateSeparator Return the field separator for the current date format
Definition gnc-date.cpp:999
void qof_date_completion_set(QofDateCompletion dc, int backmonths)
The qof_date_completion_set() routing sets the date completion method to one of QOF_DATE_COMPLETION_T...
Definition gnc-date.cpp:468
void gnc_gdate_set_time64(GDate *gd, time64 time)
Set a GDate to a time64.
guint gnc_gdate_hash(gconstpointer gd)
Provides a "hash" of a GDate* value; useful for using GDate*'s as GHashTable keys.
#define QOF_UTC_DATE_FORMAT
Constants.
Definition gnc-date.h:119
void gnc_tm_get_today_neutral(struct tm *tm)
The gnc_tm_get_today_start() routine takes a pointer to a struct tm and fills it in with the timezone...
gboolean qof_scan_date(const char *buff, int *day, int *month, int *year)
qof_scan_date Convert a string into day / month / year integers according to the current dateFormat v...
Definition gnc-date.cpp:991
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
QofDateFormat qof_date_format_get(void)
The qof_date_format_get routine returns the date format that the date printing will use when printing...
Definition gnc-date.cpp:428
void gnc_gdate_set_prev_year_start(GDate *date)
This function modifies a GDate to set it to the first day of the year prior to the one in which it fa...
void gnc_gdate_set_quarter_start(GDate *date)
This function modifies a GDate to set it to the first day of the quarter in which it falls.
size_t qof_print_date_buff(char *buff, const size_t len, time64 t)
Convenience: calls through to qof_print_date_dmy_buff().
Definition gnc-date.cpp:574
time64 gnc_time64_get_day_neutral(time64 time_val)
The gnc_time64_get_day_neutral() routine will take the given time in seconds and adjust it to 10:59:0...
char * qof_print_date(time64 t)
Convenience; calls through to qof_print_date_dmy_buff().
Definition gnc-date.cpp:610
GNCDateMonthFormat
This is how to format the month, as a number, an abbreviated string, or the full name.
Definition gnc-date.h:149
time64 gnc_time64_get_day_start(time64 time_val)
The gnc_time64_get_day_start() routine will take the given time in seconds and adjust it to the first...
GDate * gnc_g_date_new_today()
Returns a newly allocated date of the current clock time, taken from time(2).
time64 gnc_time64_get_today_start(void)
The gnc_time64_get_today_start() routine returns a time64 value corresponding to the first second of ...
QofDateFormat
Enum for determining a date format.
Definition gnc-date.h:123
time64 gnc_time64_get_day_end(time64 time_val)
The gnc_time64_get_day_end() routine will take the given time in seconds and adjust it to the last se...
void gnc_gdate_set_quarter_end(GDate *date)
This function modifies a GDate to set it to the last day of the quarter in which it falls.
void gnc_gdate_set_fiscal_year_start(GDate *date, const GDate *fy_end)
This function modifies a GDate to set it to the first day of the fiscal year in which it falls.
void gnc_tm_get_today_end(struct tm *tm)
The gnc_tm_get_today_end() routine takes a pointer to a struct tm and fills it in with the last secon...
const char * gnc_date_dateformat_to_string(QofDateFormat format)
The string->value versions return FALSE on success and TRUE on failure.
Definition gnc-date.cpp:281
void gnc_gdate_set_prev_quarter_end(GDate *date)
This function modifies a GDate to set it to the last day of the quarter prior to the one in which it ...
void gnc_gdate_set_month_start(GDate *date)
This function modifies a GDate to set it to the first day of the month in which it falls.
gint gnc_start_of_week(void)
returns an integer corresponding to locale start of week
Definition gnc-date.cpp:195
void gnc_gdate_set_prev_fiscal_year_start(GDate *date, const GDate *fy_end)
This function modifies a GDate to set it to the first day of the fiscal year prior to the one in whic...
void gnc_gdate_set_today(GDate *gd)
Set a GDate to the current day.
char * gnc_print_time64(time64 time, const char *format)
print a time64 as a date string per format
Definition gnc-date.cpp:370
QofDateCompletion
Enum for date completion modes (for dates entered without year)
Definition gnc-date.h:139
time64 gdate_to_time64(GDate d)
Turns a GDate into a time64, returning the first second of the day.
void gnc_tm_free(struct tm *time)
free a struct tm* created with gnc_localtime() or gnc_gmtime()
Definition gnc-date.cpp:97
GDate time64_to_gdate(time64 t)
Returns the GDate in which the time64 occurs.
void gnc_gdate_set_prev_quarter_start(GDate *date)
This function modifies a GDate to set it to the first day of the quarter prior to the one in which it...
time64 gnc_time(time64 *tbuf)
get the current time
Definition gnc-date.cpp:262
struct tm * gnc_localtime(const time64 *secs)
fill out a time struct from a 64-bit time value.
Definition gnc-date.cpp:103
const gchar * qof_date_format_get_string(QofDateFormat df)
This function returns a strftime formatting string for printing an all numeric date (e....
Definition gnc-date.cpp:502
void gnc_gdate_set_month_end(GDate *date)
Convert a GDate to the last day of the month.
time64 gnc_time64_get_day_end_gdate(const GDate *date)
The gnc_time64_get_day_end() routine will take the given time in GLib GDate format and adjust it to t...
struct tm * gnc_gmtime(const time64 *secs)
fill out a time struct from a 64-bit time value
Definition gnc-date.cpp:178
size_t qof_print_gdate(char *buf, size_t len, const GDate *gd)
Convenience; calls through to qof_print_date_dmy_buff().
Definition gnc-date.cpp:598
time64 gnc_time64_get_day_start_gdate(const GDate *date)
The gnc_time64_get_day_start() routine will take the given time in GLib GDate format and adjust it to...
const char * gnc_default_strftime_date_format
The default date format for use with strftime.
Definition gnc-date.cpp:74
time64 time64CanonicalDayTime(time64 t)
convert a time64 on a certain day (localtime) to the time64 representing midday on that day.
Definition gnc-date.cpp:404
void gnc_gdate_set_fiscal_year_end(GDate *date, const GDate *fy_end)
This function modifies a GDate to set it to the last day of the fiscal year in which it falls.
void gnc_tm_get_today_start(struct tm *tm)
The gnc_tm_get_today_start() routine takes a pointer to a struct tm and fills it in with the first se...
time64 gnc_time64_get_today_end(void)
The gnc_time64_get_today_end() routine returns a time64 value corresponding to the last second of tod...
gsize qof_strftime(gchar *buf, gsize max, const gchar *format, const struct tm *tm)
qof_strftime calls qof_format_time to print a given time and afterwards tries to put the result into ...
void gnc_gdate_set_prev_month_start(GDate *date)
Convert a GDate to the first day of the prebvious month.
gchar * gnc_date_timestamp(void)
Make a timestamp in YYYYMMDDHHMMSS format.
void gnc_gdate_set_prev_fiscal_year_end(GDate *date, const GDate *fy_end)
This function modifies a GDate to set it to the last day of the fiscal year prior to the one in which...
@ QOF_DATE_FORMAT_US
United states: mm/dd/yyyy.
Definition gnc-date.h:124
@ QOF_DATE_FORMAT_LOCALE
Take from locale information.
Definition gnc-date.h:128
@ QOF_DATE_FORMAT_UNSET
No Fancy Date Format, use Global.
Definition gnc-date.h:131
@ QOF_DATE_FORMAT_UTC
UTC: 2004-12-12T23:39:11Z.
Definition gnc-date.h:129
@ QOF_DATE_FORMAT_CE
Continental Europe: dd.mm.yyyy.
Definition gnc-date.h:126
@ QOF_DATE_FORMAT_UK
Britain: dd/mm/yyyy.
Definition gnc-date.h:125
@ QOF_DATE_FORMAT_CUSTOM
Used by the check printing code.
Definition gnc-date.h:130
@ QOF_DATE_FORMAT_ISO
ISO: yyyy-mm-dd.
Definition gnc-date.h:127
@ QOF_DATE_COMPLETION_THISYEAR
use current year
Definition gnc-date.h:140
@ QOF_DATE_COMPLETION_SLIDING
use sliding 12-month window
Definition gnc-date.h:141
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250