QOF  0.7.5
qoftime.c
1 /********************************************************************
2  * qoftime.c - QofTime, 64bit UTC time handling (seconds).
3  * Rewritten from scratch for QOF 0.7.0
4  *
5  * Fri May 5 15:05:24 2006
6  * Copyright 2006 Neil Williams
7  * linux@codehelp.co.uk
8  ********************************************************************/
9 /*
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
23  */
24 
25 #include "config.h"
26 #include <glib.h>
27 #include <math.h>
28 #include <ctype.h>
29 #include <time.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include "qof.h"
34 #include "qofdate-p.h"
35 
36 static QofLogModule log_module = QOF_MOD_TIME;
37 
38 struct QofTime64
39 {
40  QofTimeSecs qt_sec;
41  glong qt_nsec;
42  gboolean valid;
43 };
44 
45 QofTime *
47 {
48  QofTime *qt;
49 
50  qt = g_new0 (QofTime, 1);
51  qt->valid = FALSE;
52  return qt;
53 }
54 
55 void
57 {
58  if (qt == NULL)
59  return;
60  g_free (qt);
61  qt = NULL;
62 }
63 
64 void
66 {
67  g_return_if_fail (qt);
68  g_return_if_fail (qt->valid);
69  qt->qt_sec += secs;
70 }
71 
72 QofTime *
74 {
75  QofTime *copy;
76 
77  g_return_val_if_fail (qt, NULL);
78  g_return_val_if_fail (qt->valid, NULL);
79  copy = qof_time_copy (qt);
80  copy->qt_sec += secs;
81  return copy;
82 }
83 
84 static QofTime *
85 time_normalize (QofTime * qt)
86 {
87  g_return_val_if_fail (qt->valid, NULL);
88  if ((qt->qt_sec < 0) && (qt->qt_nsec > QOF_NSECS))
89  {
90  qt->qt_sec -= (qt->qt_nsec / QOF_NSECS);
91  qt->qt_nsec = qt->qt_nsec % QOF_NSECS;
92  }
93  if ((qt->qt_sec >= 0) && (qt->qt_nsec > QOF_NSECS))
94  {
95  qt->qt_sec += (qt->qt_nsec / QOF_NSECS);
96  qt->qt_nsec = qt->qt_nsec % QOF_NSECS;
97  }
98  if ((qt->qt_sec < 0) && (qt->qt_nsec < -QOF_NSECS))
99  {
100  qt->qt_sec -= -(-qt->qt_nsec / QOF_NSECS);
101  qt->qt_nsec = -(-qt->qt_nsec % QOF_NSECS);
102  }
103  if ((qt->qt_sec >= 0) && (qt->qt_nsec < -QOF_NSECS))
104  {
105  qt->qt_sec += -(-qt->qt_nsec / QOF_NSECS);
106  qt->qt_nsec = -(-qt->qt_nsec % QOF_NSECS);
107  }
108  if (qt->qt_sec >= 0 && qt->qt_nsec < 0)
109  {
110  qt->qt_sec--;
111  qt->qt_nsec = QOF_NSECS + qt->qt_nsec;
112  }
113  return qt;
114 }
115 
116 void
118 {
119  qt->qt_sec = secs;
120  qt->valid = TRUE;
121  time_normalize (qt);
122 }
123 
124 void
125 qof_time_set_nanosecs (QofTime * qt, glong nano)
126 {
127  qt->qt_nsec = nano;
128  qt->valid = TRUE;
129  time_normalize (qt);
130 }
131 
134 {
135  g_return_val_if_fail (qt, 0);
136  g_return_val_if_fail (qt->valid == TRUE, 0);
137  return qt->qt_sec;
138 }
139 
140 glong
142 {
143  g_return_val_if_fail (qt->valid == TRUE, 0);
144  return qt->qt_nsec;
145 }
146 
147 gboolean
148 qof_time_equal (const QofTime * ta, const QofTime * tb)
149 {
150  if (ta == tb)
151  return TRUE;
152  if (!ta)
153  return FALSE;
154  if (!tb)
155  return FALSE;
156  g_return_val_if_fail (ta->valid && tb->valid, FALSE);
157  if (ta->qt_sec != tb->qt_sec)
158  return FALSE;
159  if (ta->qt_nsec != tb->qt_nsec)
160  return FALSE;
161  return TRUE;
162 }
163 
164 gint
165 qof_time_cmp (const QofTime * ta, const QofTime * tb)
166 {
167  g_return_val_if_fail (ta->valid && tb->valid, -1);
168  if (ta == tb)
169  return 0;
170  if (ta->qt_sec < tb->qt_sec)
171  return -1;
172  if (ta->qt_sec > tb->qt_sec)
173  return 1;
174  if (ta->qt_nsec < tb->qt_nsec)
175  return -1;
176  if (ta->qt_nsec > tb->qt_nsec)
177  return 1;
178  return 0;
179 }
180 
181 QofTime *
182 qof_time_diff (const QofTime * ta, const QofTime * tb)
183 {
184  QofTime *retval;
185 
186  g_return_val_if_fail (ta->valid && tb->valid, NULL);
187  retval = g_new0 (QofTime, 1);
188  retval->qt_sec = ta->qt_sec - tb->qt_sec;
189  retval->qt_nsec = ta->qt_nsec - tb->qt_nsec;
190  retval->valid = TRUE;
191  time_normalize (retval);
192  return retval;
193 }
194 
195 QofTime *
197 {
198  g_return_val_if_fail (qt, NULL);
199  return time_normalize (qt);
200 }
201 
202 gboolean
203 qof_time_is_valid (const QofTime * qt)
204 {
205  g_return_val_if_fail (qt, FALSE);
206  return qt->valid;
207 }
208 
209 QofTime *
210 qof_time_set (QofTimeSecs t, glong nanosecs)
211 {
212  QofTime *qt;
213 
214  qt = qof_time_new ();
215  qt->qt_sec = t;
216  qt->qt_nsec = nanosecs;
217  qt->valid = TRUE;
218  time_normalize (qt);
219  return qt;
220 }
221 
222 QofTime *
224 {
225  g_return_val_if_fail (qt, NULL);
226  g_return_val_if_fail (qt->valid, NULL);
227  return qof_time_set (qt->qt_sec, qt->qt_nsec);
228 }
229 
230 QofTime *
231 qof_time_from_time_t (time_t t, glong nanosecs)
232 {
233  return qof_time_set (t, nanosecs);
234 }
235 
236 gboolean
237 qof_time_to_time_t (QofTime * qt, time_t * t, glong * nanosecs)
238 {
239  if (!qt->valid)
240  return FALSE;
241  if (qt->qt_sec < 0)
242  return FALSE;
243  if (qt->qt_nsec > 0)
244  {
245  *nanosecs = qt->qt_nsec;
246  }
247  if ((sizeof (qt->qt_sec) > sizeof (time_t))
248  && (qt->qt_sec > G_MAXINT32))
249  {
250  PERR (" QofTime too large for time_t on this platform.");
251  return FALSE;
252  }
253  *t = qt->qt_sec;
254  return TRUE;
255 }
256 
257 QofTime *
258 qof_time_from_tm (struct tm * qtm, glong nanosecs)
259 {
260  QofDate *qd;
261  QofTime *qt;
262 
263  /* avoids use of gmtime_r and therefore time_t */
264  qd = qof_date_from_struct_tm (qtm);
265  qd->qd_nanosecs = nanosecs;
266  qt = qof_date_to_qtime (qd);
267  qof_date_free (qd);
268  return qt;
269 }
270 
271 gboolean
272 qof_time_to_gtimeval (QofTime * qt, GTimeVal * gtv)
273 {
274  if (!qt->valid)
275  {
276  PERR (" invalid QofTime passed");
277  return FALSE;
278  }
279  if (qt->qt_sec > G_MAXLONG)
280  {
281  PERR (" QofTime out of range for GTimeVal");
282  return FALSE;
283  }
284  gtv->tv_sec = (glong) qt->qt_sec;
285  gtv->tv_usec = qt->qt_nsec;
286  return TRUE;
287 }
288 
289 void
290 qof_time_from_gtimeval (QofTime * qt, GTimeVal * gtv)
291 {
292  qt->qt_sec = (QofTimeSecs) gtv->tv_sec;
293  qt->qt_nsec = gtv->tv_usec * 1000;
294  qt->valid = TRUE;
295  time_normalize (qt);
296 }
297 
298 GDate *
300 {
301  QofDate *qd;
302  GDate *d;
303 
304  qd = qof_date_from_qtime (qt);
305  d = g_date_new_dmy (qd->qd_mday, qd->qd_mon, qd->qd_year);
306  if (g_date_valid (d))
307  return d;
308  return NULL;
309 }
310 
311 QofTime *
312 qof_time_from_gdate (GDate * date)
313 {
314  struct tm gtm;
315  QofTime *qt;
316  QofDate *qd;
317 
318  g_return_val_if_fail (date, NULL);
319  g_date_to_struct_tm (date, &gtm);
320  qd = qof_date_from_struct_tm (&gtm);
321  qt = qof_date_to_qtime (qd);
322  qof_date_free (qd);
323  return qt;
324 }
325 
326 gboolean
328 {
329  if (!qof_time_set_day_start (qt))
330  return FALSE;
331  qt->qt_sec += (SECS_PER_DAY - 1);
332  return TRUE;
333 }
334 
335 gboolean
337 {
338  if (!qof_time_set_day_start (qt))
339  return FALSE;
340  qt->qt_sec += (SECS_PER_DAY / 2);
341  return TRUE;
342 }
343 
344 GTimeVal *
346 {
347  GTimeVal *current;
348  struct tm tm;
349 
351  current = g_new0 (GTimeVal, 1);
352  g_get_current_time (current);
353  /* OK to use time_t for current time. */
354  tm = *gmtime_r (&current->tv_sec, &tm);
355  current->tv_sec -= tm.tm_sec;
356  current->tv_sec -= tm.tm_min * 60;
357  current->tv_sec -= tm.tm_hour * 60 * 60;
358  return current;
359 }
360 
361 QofTime *
363 {
364  QofTime *now;
365  GTimeVal gnow;
366 
367  now = qof_time_new ();
368  g_get_current_time (&gnow);
369  qof_time_from_gtimeval (now, &gnow);
370  return now;
371 }
372 
373 gboolean
375 {
376  QofDate *qd;
377  QofTimeSecs c;
378 
379  g_return_val_if_fail (qt, FALSE);
380  qd = qof_date_from_qtime (qt);
381  if (qd->qd_year < 1970)
382  {
383  c = QOF_DAYS_TO_SEC(qd->qd_yday);
384  c -= QOF_DAYS_TO_SEC(days_between (1970, qd->qd_year));
385  c -= qd->qd_gmt_off;
386  qt->qt_sec = c;
387  qt->qt_nsec = 0;
388  }
389  if (qd->qd_year >= 1970)
390  {
391  c = QOF_DAYS_TO_SEC(qd->qd_yday);
392  c += QOF_DAYS_TO_SEC(days_between (1970, qd->qd_year));
393  c -= qd->qd_gmt_off;
394  qt->qt_sec = c;
395  qt->qt_nsec = 0;
396  }
397  qof_date_free (qd);
398  return TRUE;
399 }
400 
401 QofTime *
403 {
404  QofTime *qt;
405 
406  qt = qof_time_get_current ();
407  if (!qof_time_set_day_start (qt))
408  return NULL;
409  return qt;
410 }
411 
412 QofTime *
414 {
415  QofTime *qt;
416 
417  qt = qof_time_get_today_start ();
418  qt->qt_sec += SECS_PER_DAY - 1;
419  return qt;
420 }
421 
422 guint8
424 {
425  GDate *d;
426  GDateMonth m;
427  GDateYear y;
428 
429  g_return_val_if_fail (qt, 0);
430  d = qof_time_to_gdate (qt);
431  if (!d)
432  return 0;
433  m = g_date_get_month (d);
434  y = g_date_get_year (d);
435  return g_date_get_days_in_month (m, y);
436 }
437 
438 gboolean
439 qof_time_to_dmy (QofTime * qt, guint8 * day, guint8 * month,
440  guint16 * year)
441 {
442  GDate *d;
443 
444  d = qof_time_to_gdate (qt);
445  if (!d)
446  return FALSE;
447  if (day)
448  *day = g_date_get_day (d);
449  if (month)
450  *month = g_date_get_month (d);
451  if (year)
452  *year = g_date_get_year (d);
453  return TRUE;
454 }
455 
456 QofTime *
457 qof_time_dmy_to_time (guint8 day, guint8 month, guint16 year)
458 {
459  GDate *d;
460  QofTime *qt;
461 
462  g_return_val_if_fail (g_date_valid_dmy (day, month, year), NULL);
463  d = g_date_new_dmy (day, month, year);
464  qt = qof_time_from_gdate (d);
465  return qt;
466 }
467 
468 gchar *
470 {
471  gint len;
472  struct tm qtm;
473  time_t t;
474  gchar test[MAX_DATE_LENGTH];
475  const gchar *fmt;
476 
477  ENTER (" ");
478  t = time (NULL);
479  qtm = *gmtime_r (&t, &qtm);
481  len = strftime (test, MAX_DATE_LENGTH, fmt, &qtm);
482  if (len == 0 && test[0] != '\0')
483  {
484  LEAVE (" strftime failed.");
485  return NULL;
486  }
487  LEAVE (" ");
488  return g_strdup (test);
489 }