28 #include <glib/gprintf.h>
32 #include "qofdate-p.h"
35 #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
36 #define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
38 static GHashTable *DateFormatTable = NULL;
39 static gboolean QofDateInit = FALSE;
41 static gchar locale_separator =
'\0';
45 static const guint16 days_in_year[2][14] =
47 { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
48 { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
50 static const guint8 days_in_months[2][13] =
52 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
53 { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
57 typedef struct QofDateEntry_s
63 gboolean locale_specific;
71 DateFormatTable = g_hash_table_new (g_direct_hash, g_direct_equal);
74 QofDateEntry *d = g_new0 (QofDateEntry, 1);
75 d->format =
"%m/%d/%Y";
79 d->locale_specific = FALSE;
80 g_hash_table_insert (DateFormatTable, GINT_TO_POINTER (d->df), d);
83 QofDateEntry *d = g_new0 (QofDateEntry, 1);
84 d->format =
"%d/%m/%Y";
88 d->locale_specific = FALSE;
89 g_hash_table_insert (DateFormatTable, GINT_TO_POINTER (d->df), d);
92 QofDateEntry *d = g_new0 (QofDateEntry, 1);
93 d->format =
"%d.%m.%Y";
97 d->locale_specific = FALSE;
98 g_hash_table_insert (DateFormatTable, GINT_TO_POINTER (d->df), d);
101 QofDateEntry *d = g_new0 (QofDateEntry, 1);
106 d->locale_specific = FALSE;
107 g_hash_table_insert (DateFormatTable, GINT_TO_POINTER (d->df), d);
110 QofDateEntry *d = g_new0 (QofDateEntry, 1);
115 d->locale_specific = FALSE;
116 g_hash_table_insert (DateFormatTable, GINT_TO_POINTER (d->df), d);
119 QofDateEntry *d = g_new0 (QofDateEntry, 1);
122 d->separator = locale_separator;
124 d->locale_specific = TRUE;
125 g_hash_table_insert (DateFormatTable, GINT_TO_POINTER (d->df), d);
128 QofDateEntry *d = g_new0 (QofDateEntry, 1);
131 d->separator = locale_separator;
133 d->locale_specific = TRUE;
134 g_hash_table_insert (DateFormatTable, GINT_TO_POINTER (d->df), d);
137 QofDateEntry *d = g_new0(QofDateEntry,1);
138 d->format =
"%Y-%m-%d %H:%M:%S.%N %z";
142 d->locale_specific = FALSE;
143 g_hash_table_insert (DateFormatTable, GINT_TO_POINTER(d->df), d);
149 hash_value_free (gpointer key __attribute__ ((unused)), gpointer value,
150 gpointer data __attribute__ ((unused)))
160 g_hash_table_foreach (DateFormatTable, hash_value_free, NULL);
161 g_hash_table_destroy (DateFormatTable);
171 g_return_val_if_fail (mday != 0, 0);
172 g_return_val_if_fail (month != 0, 0);
173 g_return_val_if_fail (month <= 12, 0);
174 g_return_val_if_fail (month >= 1, 0);
175 g_return_val_if_fail (year != 0, 0);
177 g_return_val_if_fail (mday <=
179 return days_in_year[leap][month] + mday;
185 g_return_val_if_fail (month != 0, 0);
186 g_return_val_if_fail (month <= 12, 0);
187 g_return_val_if_fail (month >= 1, 0);
188 g_return_val_if_fail (year != 0, 0);
195 g_return_val_if_fail (qd, FALSE);
196 g_return_val_if_fail (qd->
qd_valid, FALSE);
210 g_return_val_if_fail (QofDateInit, FALSE);
211 g_return_val_if_fail (str, FALSE);
212 g_return_val_if_fail (strlen (str) != 0, FALSE);
214 ENTER (
" str=%s", str);
217 LEAVE (
" '%s' is too long! Max=%d str_len=%d",
224 check = *gmtime_r (&now, &check);
228 if (len == 0 && test[0] !=
'\0')
230 LEAVE (
" strftime could not understand '%s'", str);
236 LEAVE (
" %s creates a string '%s' that is too long!"
240 *identifier = g_hash_table_size (DateFormatTable) + 1;
242 QofDateEntry *d = g_new0 (QofDateEntry, 1);
245 d->separator = locale_separator;
247 g_hash_table_insert (DateFormatTable, GINT_TO_POINTER (d->df), d);
249 LEAVE (
" successful");
258 g_return_val_if_fail (QofDateInit, NULL);
259 d = g_hash_table_lookup (DateFormatTable, GINT_TO_POINTER (format));
262 PERR (
" unknown format: '%d'", format);
273 g_return_val_if_fail (QofDateInit, FALSE);
276 d = g_hash_table_lookup (DateFormatTable, GINT_TO_POINTER (format));
279 PERR (
" unknown format: '%d'", format);
283 g_hash_table_insert (DateFormatTable, GINT_TO_POINTER (format), d);
298 g_return_val_if_fail (QofDateInit, FALSE);
299 d = g_hash_table_lookup (DateFormatTable, GINT_TO_POINTER (df));
302 PERR (
" unknown format: '%d'", df);
314 g_return_val_if_fail (QofDateInit, NULL);
315 d = g_hash_table_lookup (DateFormatTable, GINT_TO_POINTER (df));
318 PERR (
" unknown format: '%d'", df);
329 g_return_val_if_fail (QofDateInit, locale_separator);
330 d = g_hash_table_lookup (DateFormatTable, GINT_TO_POINTER (df));
333 PERR (
" unknown format: '%d'", df);
334 return locale_separator;
344 g_return_val_if_fail (QofDateInit, FALSE);
347 DEBUG (
" Prevented attempt to override a default format");
350 if (g_ascii_isdigit (sep))
352 d = g_hash_table_lookup (DateFormatTable, GINT_TO_POINTER (df));
355 PERR (
" unknown format: '%d'", df);
359 g_hash_table_insert (DateFormatTable, GINT_TO_POINTER (df), d);
370 lookup_name (gpointer key __attribute__ ((unused)), gpointer value,
376 i = (
struct iter *) data;
377 d = (QofDateEntry *) value;
407 g_hash_table_foreach (DateFormatTable, lookup_name, &i);
412 date_normalise (
QofDate * date)
416 g_return_val_if_fail (date, NULL);
478 while (date->
qd_mday < (leap*-1))
546 set_day_of_the_week (date);
562 gchar * G_GNUC_UNUSED check;
565 error = ERR_NO_ERROR;
568 check = strptime_internal (str, format, date, &error);
570 if (error != ERR_NO_ERROR)
576 date = date_normalise (date);
587 g_return_val_if_fail (QofDateInit, NULL);
588 g_return_val_if_fail (date, NULL);
589 g_return_val_if_fail (date->
qd_valid, NULL);
590 d = g_hash_table_lookup (DateFormatTable,
591 GINT_TO_POINTER (df));
592 g_return_val_if_fail (d, NULL);
596 if (result == 0 && temp[0] !=
'\0')
598 PERR (
" qof extended strftime failed");
601 return g_strndup(temp, result);
644 g_return_if_fail (date);
652 g_return_val_if_fail (date, FALSE);
653 date = date_normalise (date);
656 PERR (
" unknown QofDate error");
717 g_return_val_if_fail (stm, NULL);
723 d->
qd_mon = stm->tm_mon + 1;
724 d->
qd_year = stm->tm_year + 1900;
731 d = date_normalise(d);
739 g_return_val_if_fail (qd, FALSE);
740 g_return_val_if_fail (stm, FALSE);
741 g_return_val_if_fail (qd->
qd_valid, FALSE);
744 PERR (
" date too large for struct tm");
751 stm->tm_mon = qd->
qd_mon - 1;
752 stm->tm_year = qd->
qd_year - 1900;
758 if (nanosecs != NULL)
766 g_return_val_if_fail (qd, FALSE);
767 g_return_val_if_fail (gd, FALSE);
768 g_return_val_if_fail (qd->
qd_valid, FALSE);
769 if (qd->
qd_year >= G_MAXUINT16)
771 PERR (
" QofDate out of range of GDate");
776 PERR (
" GDate failed to allow day, month and/or year");
788 g_return_val_if_fail (g_date_valid (date), NULL);
790 qd->
qd_year = g_date_get_year (date);
791 qd->
qd_mon = g_date_get_month (date);
792 qd->
qd_mday = g_date_get_day (date);
793 qd = date_normalise (qd);
805 g_return_if_fail (qd);
806 g_return_if_fail (time);
830 while (days < 0 || days >= (__isleap (y) ? 366 : 365))
833 yg = y + days / 365 - (days % 365 < 0);
835 days -= ((yg - y) * 365
836 + LEAPS_THRU_END_OF (yg - 1)
837 - LEAPS_THRU_END_OF (y - 1));
843 for (y = 12; days < (glong) ip[y]; --y)
853 count_leapseconds (time_t interval)
859 utc = *gmtime_r (&interval, &utc);
860 altered = mktime (&utc);
861 return altered - interval;
866 extract_interval (
const QofTime *qt)
877 leap_seconds = ((t > l) || (t < 0)) ?
878 count_leapseconds (l) :
879 count_leapseconds (t);
887 gint leap_extra_secs;
891 g_return_val_if_fail (qt, NULL);
892 g_return_val_if_fail (qof_time_is_valid (qt), NULL);
895 setenv (
"TZ",
"GMT", 1);
897 leap_extra_secs = extract_interval (qt);
898 qof_date_offset (qt, leap_extra_secs, qd);
909 days_between (gint64 year1, gint64 year2)
911 gint64 i, start, end, l;
916 start = (year1 < year2) ? year1 : year2;
917 end = (year2 < year1) ? year1: year2;
918 for (i = start; i < end; i++)
931 g_return_val_if_fail (qd, NULL);
932 g_return_val_if_fail (qd->
qd_valid, NULL);
1002 g_return_val_if_fail (qd, FALSE);
1010 gboolean track_last_day)
1012 g_return_val_if_fail (qd, FALSE);
1014 qd->
qd_mon += months % 12;
1026 qof_date_set_day_end (
QofDate * qd)
1036 qof_date_set_day_start (
QofDate * qd)
1038 g_return_val_if_fail (qd, FALSE);
1047 qof_date_set_day_middle (
QofDate * qd)
1049 g_return_val_if_fail (qd, FALSE);