GnuCash  4.8a-176-g88ecf8dd1
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 }void
1238 
1240 {
1241  GDate *today = gnc_g_date_new_today ();
1242  g_date_set_julian (gd, g_date_get_julian (today));
1243  g_date_free (today);
1244 }
1245 
1246 void
1247 gnc_gdate_set_time64 (GDate* gd, time64 time)
1248 {
1249  struct tm tm;
1250  gnc_localtime_r(&time, &tm);
1251  g_date_set_dmy (gd, tm.tm_mday,
1252  static_cast<GDateMonth>(tm.tm_mon + 1),
1253  tm.tm_year + 1900);
1254 }
1255 
1257 {
1258  return gnc_dmy2time64_neutral (g_date_get_day(&d),
1259  g_date_get_month(&d),
1260  g_date_get_year(&d));
1261 }
1262 
1263 static void
1264 gnc_tm_get_day_start (struct tm *tm, time64 time_val)
1265 {
1266  /* Get the equivalent time structure */
1267  if (!gnc_localtime_r(&time_val, tm))
1268  return;
1269  gnc_tm_set_day_start(tm);
1270 }
1271 
1272 void
1273 gnc_tm_set_day_neutral (struct tm *tm)
1274 {
1275  auto time_val{gnc_dmy2time64_internal(tm->tm_mday, tm->tm_mon + 1,
1276  tm->tm_year + 1900, DayPart::neutral)};
1277  gnc_localtime_r(&time_val, tm);
1278 }
1279 
1280 static void
1281 gnc_tm_get_day_neutral (struct tm *tm, time64 time_val)
1282 {
1283  /* Get the equivalent time structure */
1284  if (!gnc_localtime_r(&time_val, tm))
1285  return;
1287 }
1288 
1289 static void
1290 gnc_tm_get_day_end (struct tm *tm, time64 time_val)
1291 {
1292  /* Get the equivalent time structure */
1293  if (!gnc_localtime_r(&time_val, tm))
1294  return;
1295  gnc_tm_set_day_end(tm);
1296 }
1297 
1298 time64
1300 {
1301  struct tm tm;
1302  time64 new_time;
1303 
1304  gnc_tm_get_day_start(&tm, time_val);
1305  new_time = gnc_mktime(&tm);
1306  return new_time;
1307 }
1308 
1309 time64
1311 {
1312  struct tm tm;
1313  gnc_localtime_r(&time_val, &tm);
1314  return gnc_dmy2time64_internal(tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900,
1315  DayPart::neutral);
1316 }
1317 
1318 time64
1320 {
1321  struct tm tm;
1322  time64 new_time;
1323 
1324  gnc_tm_get_day_end(&tm, time_val);
1325  new_time = gnc_mktime(&tm);
1326  return new_time;
1327 }
1328 
1329 /* ======================================================== */
1330 
1331 void
1332 gnc_tm_get_today_start (struct tm *tm)
1333 {
1334  gnc_tm_get_day_start(tm, time(NULL));
1335 }
1336 
1337 void
1338 gnc_tm_get_today_end (struct tm *tm)
1339 {
1340  gnc_tm_get_day_end(tm, time(NULL));
1341 }
1342 
1343 time64
1345 {
1346  struct tm tm;
1347 
1348  gnc_tm_get_day_start(&tm, time(NULL));
1349  return gnc_mktime(&tm);
1350 }
1351 
1352 time64
1354 {
1355  struct tm tm;
1356 
1357  gnc_tm_get_day_end(&tm, time(NULL));
1358  return gnc_mktime(&tm);
1359 }
1360 
1361 void
1362 gnc_dow_abbrev(gchar *buf, int buf_len, int dow)
1363 {
1364  struct tm my_tm;
1365  int i;
1366 
1367  memset(buf, 0, buf_len);
1368  memset(&my_tm, 0, sizeof(struct tm));
1369  my_tm.tm_wday = dow;
1370  i = qof_strftime(buf, buf_len, "%a", &my_tm);
1371  buf[i] = 0;
1372 }
1373 
1374 /* *******************************************************************
1375  * GValue handling
1376  ********************************************************************/
1377 
1378 static gpointer
1379 time64_boxed_copy_func (gpointer in_time64)
1380 {
1381  Time64* newvalue;
1382 
1383  newvalue = static_cast<Time64*>(g_malloc (sizeof (Time64)));
1384  memcpy (newvalue, in_time64, sizeof(Time64));
1385 
1386  return newvalue;
1387 }
1388 
1389 static void
1390 time64_boxed_free_func (gpointer in_time64)
1391 {
1392  g_free (in_time64);
1393 }
1394 
1395 GType
1396 time64_get_type( void )
1397 {
1398  static GType type = 0;
1399 
1400  if ( type == 0 )
1401  {
1402  type = g_boxed_type_register_static( "time64",
1403  time64_boxed_copy_func,
1404  time64_boxed_free_func );
1405  }
1406  return type;
1407 }
1408 
1409 /* ================================================= */
1410 
1411 gboolean
1412 gnc_gdate_equal(gconstpointer gda, gconstpointer gdb)
1413 {
1414  return (g_date_compare( (GDate*)gda, (GDate*)gdb ) == 0 ? TRUE : FALSE);
1415 }
1416 
1417 guint
1418 gnc_gdate_hash( gconstpointer gd )
1419 {
1420  gint val = (g_date_get_year( (GDate*)gd ) * 10000)
1421  + (g_date_get_month( (GDate*)gd ) * 100)
1422  + g_date_get_day( (GDate*)gd );
1423  return g_int_hash( &val );
1424 }
1425 
1426 /* ================================================= */
1427 
1428 time64
1430 {
1431  struct tm stm;
1432  time64 secs;
1433 
1434  /* First convert to a 'struct tm' */
1435  g_date_to_struct_tm (date, &stm);
1436 
1437  /* Then convert to number of seconds */
1438  secs = gnc_mktime (&stm);
1439  return secs;
1440 }
1441 
1442 time64
1443 gnc_time64_get_day_end_gdate (const GDate *date)
1444 {
1445  struct tm stm;
1446  time64 secs;
1447 
1448  /* First convert to a 'struct tm' */
1449  g_date_to_struct_tm(date, &stm);
1450 
1451  /* Force to th last second of the day */
1452  stm.tm_hour = 23;
1453  stm.tm_min = 59;
1454  stm.tm_sec = 59;
1455  stm.tm_isdst = -1;
1456 
1457  /* Then convert to number of seconds */
1458  secs = gnc_mktime (&stm);
1459  return secs;
1460 }
1461 
1462 /* ================================================= */
1463 
1464 void
1466 {
1467  g_date_set_day(date, 1);
1468 }
1469 
1477 void
1479 {
1480  /* First set the start of next month. */
1481  g_date_set_day(date, 1);
1482  g_date_add_months(date, 1);
1483 
1484  /* Then back up one day */
1485  g_date_subtract_days(date, 1);
1486 }
1487 
1495 void
1497 {
1498  g_date_set_day(date, 1);
1499  g_date_subtract_months(date, 1);
1500 }
1501 
1509 void
1511 {
1512  /* This will correctly handle the varying month lengths */
1513  g_date_set_day(date, 1);
1514  g_date_subtract_days(date, 1);
1515 }
1516 
1517 /* ================================================= */
1518 
1519 void
1521 {
1522  gint months;
1523 
1524  /* Set the date to the first day of the specified month. */
1525  g_date_set_day(date, 1);
1526 
1527  /* Back up 0-2 months */
1528  months = (g_date_get_month(date) - G_DATE_JANUARY) % 3;
1529  g_date_subtract_months(date, months);
1530 }
1531 
1532 void
1534 {
1535  gint months;
1536 
1537  /* Set the date to the first day of the specified month. */
1538  g_date_set_day(date, 1);
1539 
1540  /* Add 1-3 months to get the first day of the next quarter.*/
1541  months = (g_date_get_month(date) - G_DATE_JANUARY) % 3;
1542  g_date_add_months(date, 3 - months);
1543 
1544  /* Now back up one day */
1545  g_date_subtract_days(date, 1);
1546 }
1547 
1548 void
1550 {
1552  g_date_subtract_months(date, 3);
1553 }
1554 
1555 void
1557 {
1559  g_date_subtract_months(date, 3);
1560 }
1561 
1562 /* ================================================= */
1563 
1564 void
1566 {
1567  g_date_set_month(date, G_DATE_JANUARY);
1568  g_date_set_day(date, 1);
1569 }
1570 
1571 void
1573 {
1574  g_date_set_month(date, G_DATE_DECEMBER);
1575  g_date_set_day(date, 31);
1576 }
1577 
1578 void
1580 {
1582  g_date_subtract_years(date, 1);
1583 }
1584 
1585 void
1587 {
1588  gnc_gdate_set_year_end(date);
1589  g_date_subtract_years(date, 1);
1590 }
1591 
1592 /* ================================================= */
1593 
1594 void
1596  const GDate *fy_end)
1597 {
1598  GDate temp;
1599  gboolean new_fy;
1600 
1601  g_return_if_fail(date);
1602  g_return_if_fail(fy_end);
1603 
1604  /* Compute the FY end that occurred this CY */
1605  temp = *fy_end;
1606  g_date_set_year(&temp, g_date_get_year(date));
1607 
1608  /* Has it already passed? */
1609  new_fy = (g_date_compare(date, &temp) > 0);
1610 
1611  /* Set start date */
1612  *date = temp;
1613  g_date_add_days(date, 1);
1614  if (!new_fy)
1615  g_date_subtract_years(date, 1);
1616 }
1617 
1618 void
1620  const GDate *fy_end)
1621 {
1622  GDate temp;
1623  gboolean new_fy;
1624 
1625  g_return_if_fail(date);
1626  g_return_if_fail(fy_end);
1627 
1628  /* Compute the FY end that occurred this CY */
1629  temp = *fy_end;
1630  g_date_set_year(&temp, g_date_get_year(date));
1631 
1632  /* Has it already passed? */
1633  new_fy = (g_date_compare(date, &temp) > 0);
1634 
1635  /* Set end date */
1636  *date = temp;
1637  if (new_fy)
1638  g_date_add_years(date, 1);
1639 }
1640 
1641 void
1643  const GDate *fy_end)
1644 {
1645  g_return_if_fail(date);
1646  g_return_if_fail(fy_end);
1647 
1648  gnc_gdate_set_fiscal_year_start(date, fy_end);
1649  g_date_subtract_years(date, 1);
1650 }
1651 
1652 void
1654  const GDate *fy_end)
1655 {
1656  g_return_if_fail(date);
1657  g_return_if_fail(fy_end);
1658 
1659  gnc_gdate_set_fiscal_year_end(date, fy_end);
1660  g_date_subtract_years(date, 1);
1661 }
1662 
1663 Testfuncs*
1664 gnc_date_load_funcs (void)
1665 {
1666  Testfuncs *tf = g_slice_new (Testfuncs);
1667  return tf;
1668 }
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:1619
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:1412
#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:1418
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:1520
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:1239
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:1510
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:1332
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_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:1586
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:1579
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:1299
void gnc_dow_abbrev(gchar *buf, int buf_len, int dow)
Localized DOW abbreviation.
Definition: gnc-date.cpp:1362
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:1344
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:1256
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:1465
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:1653
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:1595
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:1572
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:1247
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:1478
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:1443
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:1642
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:1533
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:1353
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:1556
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:1319
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:1338
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:1273
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:1429
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:1549
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:1565
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:59am...
Definition: gnc-date.cpp:1310
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:1496