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