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