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