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