qoftime.c

00001 /********************************************************************
00002  *       qoftime.c - QofTime, 64bit UTC time handling (seconds).
00003  *       Rewritten from scratch for QOF 0.7.0
00004  *
00005  *  Fri May  5 15:05:24 2006
00006  *  Copyright  2006  Neil Williams
00007  *  linux@codehelp.co.uk
00008  ********************************************************************/
00009 /*
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA  02110-1301,  USA
00023  */
00024 
00025 #include "config.h"
00026 #include <glib.h>
00027 #include <math.h>
00028 #include <ctype.h>
00029 #include <time.h>
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include "qof.h"
00034 
00035 static QofLogModule log_module = QOF_MOD_TIME;
00036 
00037 struct QofTime64
00038 {
00039     QofTimeSecs qt_sec;
00040     glong qt_nsec;
00041     gboolean valid;
00042 };
00043 
00044 QofTime *
00045 qof_time_new (void)
00046 {
00047     QofTime *qt;
00048 
00049     qt = g_new0 (QofTime, 1);
00050     qt->valid = FALSE;
00051     return qt;
00052 }
00053 
00054 void
00055 qof_time_free (QofTime * qt)
00056 {
00057     if (qt == NULL)
00058         return;
00059     g_free (qt);
00060     qt = NULL;
00061 }
00062 
00063 void
00064 qof_time_add_secs (QofTime * qt, QofTimeSecs secs)
00065 {
00066     g_return_if_fail (qt);
00067     g_return_if_fail (qt->valid);
00068     qt->qt_sec += secs;
00069 }
00070 
00071 QofTime *
00072 qof_time_add_secs_copy (QofTime * qt, QofTimeSecs secs)
00073 {
00074     QofTime *copy;
00075 
00076     g_return_val_if_fail (qt, NULL);
00077     g_return_val_if_fail (qt->valid, NULL);
00078     copy = qof_time_copy (qt);
00079     copy->qt_sec += secs;
00080     return copy;
00081 }
00082 
00083 static QofTime *
00084 time_normalize (QofTime * qt)
00085 {
00086     g_return_val_if_fail (qt->valid, NULL);
00087     if ((qt->qt_sec < 0) && (qt->qt_nsec > QOF_NSECS))
00088     {
00089         qt->qt_sec -= (qt->qt_nsec / QOF_NSECS);
00090         qt->qt_nsec = qt->qt_nsec % QOF_NSECS;
00091     }
00092     if ((qt->qt_sec >= 0) && (qt->qt_nsec > QOF_NSECS))
00093     {
00094         qt->qt_sec += (qt->qt_nsec / QOF_NSECS);
00095         qt->qt_nsec = qt->qt_nsec % QOF_NSECS;
00096     }
00097     if ((qt->qt_sec < 0) && (qt->qt_nsec < -QOF_NSECS))
00098     {
00099         qt->qt_sec -= -(-qt->qt_nsec / QOF_NSECS);
00100         qt->qt_nsec = -(-qt->qt_nsec % QOF_NSECS);
00101     }
00102     if ((qt->qt_sec >= 0) && (qt->qt_nsec < -QOF_NSECS))
00103     {
00104         qt->qt_sec += -(-qt->qt_nsec / QOF_NSECS);
00105         qt->qt_nsec = -(-qt->qt_nsec % QOF_NSECS);
00106     }
00107     if (qt->qt_sec >= 0 && qt->qt_nsec < 0)
00108     {
00109         qt->qt_sec--;
00110         qt->qt_nsec = QOF_NSECS + qt->qt_nsec;
00111     }
00112     return qt;
00113 }
00114 
00115 void
00116 qof_time_set_secs (QofTime * qt, QofTimeSecs secs)
00117 {
00118     qt->qt_sec = secs;
00119     qt->valid = TRUE;
00120     time_normalize (qt);
00121 }
00122 
00123 void
00124 qof_time_set_nanosecs (QofTime * qt, glong nano)
00125 {
00126     qt->qt_nsec = nano;
00127     qt->valid = TRUE;
00128     time_normalize (qt);
00129 }
00130 
00131 QofTimeSecs
00132 qof_time_get_secs (const QofTime * qt)
00133 {
00134     g_return_val_if_fail (qt, 0);
00135     g_return_val_if_fail (qt->valid == TRUE, 0);
00136     return qt->qt_sec;
00137 }
00138 
00139 glong
00140 qof_time_get_nanosecs (const QofTime * qt)
00141 {
00142     g_return_val_if_fail (qt->valid == TRUE, 0);
00143     return qt->qt_nsec;
00144 }
00145 
00146 gboolean
00147 qof_time_equal (const QofTime * ta, const QofTime * tb)
00148 {
00149     if (ta == tb)
00150         return TRUE;
00151     if (!ta)
00152         return FALSE;
00153     if (!tb)
00154         return FALSE;
00155     g_return_val_if_fail (ta->valid && tb->valid, FALSE);
00156     if (ta->qt_sec != tb->qt_sec)
00157         return FALSE;
00158     if (ta->qt_nsec != tb->qt_nsec)
00159         return FALSE;
00160     return TRUE;
00161 }
00162 
00163 gint
00164 qof_time_cmp (const QofTime * ta, const QofTime * tb)
00165 {
00166     g_return_val_if_fail (ta->valid && tb->valid, -1);
00167     if (ta == tb)
00168         return 0;
00169     if (ta->qt_sec < tb->qt_sec)
00170         return -1;
00171     if (ta->qt_sec > tb->qt_sec)
00172         return 1;
00173     if (ta->qt_nsec < tb->qt_nsec)
00174         return -1;
00175     if (ta->qt_nsec > tb->qt_nsec)
00176         return 1;
00177     return 0;
00178 }
00179 
00180 QofTime *
00181 qof_time_diff (const QofTime * ta, const QofTime * tb)
00182 {
00183     QofTime *retval;
00184 
00185     g_return_val_if_fail (ta->valid && tb->valid, NULL);
00186     retval = g_new0 (QofTime, 1);
00187     retval->qt_sec = ta->qt_sec - tb->qt_sec;
00188     retval->qt_nsec = ta->qt_nsec - tb->qt_nsec;
00189     retval->valid = TRUE;
00190     time_normalize (retval);
00191     return retval;
00192 }
00193 
00194 QofTime *
00195 qof_time_abs (QofTime * qt)
00196 {
00197     g_return_val_if_fail (qt, NULL);
00198     return time_normalize (qt);
00199 }
00200 
00201 gboolean
00202 qof_time_is_valid (const QofTime * qt)
00203 {
00204     g_return_val_if_fail (qt, FALSE);
00205     return qt->valid;
00206 }
00207 
00208 QofTime *
00209 qof_time_set (QofTimeSecs t, glong nanosecs)
00210 {
00211     QofTime *qt;
00212 
00213     qt = qof_time_new ();
00214     qt->qt_sec = t;
00215     qt->qt_nsec = nanosecs;
00216     qt->valid = TRUE;
00217     time_normalize (qt);
00218     return qt;
00219 }
00220 
00221 QofTime *
00222 qof_time_copy (const QofTime *qt)
00223 {
00224     g_return_val_if_fail (qt, NULL);
00225     g_return_val_if_fail (qt->valid, NULL);
00226     return qof_time_set (qt->qt_sec, qt->qt_nsec);
00227 }
00228 
00229 QofTime *
00230 qof_time_from_time_t (time_t t, glong nanosecs)
00231 {
00232     return qof_time_set (t, nanosecs);
00233 }
00234 
00235 gboolean
00236 qof_time_to_time_t (QofTime * qt, time_t * t, glong * nanosecs)
00237 {
00238     if (!qt->valid)
00239         return FALSE;
00240     if (qt->qt_sec < 0)
00241         return FALSE;
00242     if (qt->qt_nsec > 0)
00243     {
00244         *nanosecs = qt->qt_nsec;
00245     }
00246     if ((sizeof (qt->qt_sec) > sizeof (time_t))
00247         && (qt->qt_sec > G_MAXINT32))
00248     {
00249         PERR (" QofTime too large for time_t on this platform.");
00250         return FALSE;
00251     }
00252     *t = qt->qt_sec;
00253     return TRUE;
00254 }
00255 
00256 QofTime *
00257 qof_time_from_tm (struct tm * qtm, glong nanosecs)
00258 {
00259     QofDate *qd;
00260     QofTime *qt;
00261 
00262     /* avoids use of gmtime_r and therefore time_t */
00263     qd = qof_date_from_struct_tm (qtm);
00264     qd->qd_nanosecs = nanosecs;
00265     qt = qof_date_to_qtime (qd);
00266     qof_date_free (qd);
00267     return qt;
00268 }
00269 
00270 gboolean
00271 qof_time_to_gtimeval (QofTime * qt, GTimeVal * gtv)
00272 {
00273     if (!qt->valid)
00274     {
00275         PERR (" invalid QofTime passed");
00276         return FALSE;
00277     }
00278     if (qt->qt_sec > G_MAXLONG)
00279     {
00280         PERR (" QofTime out of range for GTimeVal");
00281         return FALSE;
00282     }
00283     gtv->tv_sec = (glong) qt->qt_sec;
00284     gtv->tv_usec = qt->qt_nsec;
00285     return TRUE;
00286 }
00287 
00288 void
00289 qof_time_from_gtimeval (QofTime * qt, GTimeVal * gtv)
00290 {
00291     qt->qt_sec = (QofTimeSecs) gtv->tv_sec;
00292     qt->qt_nsec = gtv->tv_usec * 1000;
00293     qt->valid = TRUE;
00294     time_normalize (qt);
00295 }
00296 
00297 GDate *
00298 qof_time_to_gdate (QofTime * qt)
00299 {
00300     GDate *d;
00301     time_t t;
00302     glong nsecs;
00303     gboolean success;
00304     struct tm utc;
00305 
00315     success = qof_time_to_time_t (qt, &t, &nsecs);
00316     if (!success)
00317         return NULL;
00318     utc = *gmtime_r (&t, &utc);
00319     d = g_date_new_dmy (utc.tm_mday, utc.tm_mon + 1, 
00320         utc.tm_year + 1900);
00321     if (g_date_valid (d))
00322         return d;
00323     return NULL;
00324 }
00325 
00326 QofTime *
00327 qof_time_from_gdate (GDate * date)
00328 {
00329     GTimeVal *current, from_date;
00330     GDate *now;
00331     gint days_between;
00332     gint64 secs_between;
00333     QofTime *qt;
00334 
00335     g_return_val_if_fail (date, NULL);
00336     current = qof_time_get_current_start ();
00337     now = g_date_new ();
00338     g_date_set_time_val (now, current);
00339     /* if date is in the future, days_between is negative */
00340     days_between = g_date_days_between (date, now);
00341     qt = qof_time_new ();
00342     qof_time_from_gtimeval (qt, &from_date);
00343     secs_between = days_between * SECS_PER_DAY;
00344     qof_time_set_secs (qt, current->tv_sec - secs_between);
00345     qof_time_set_nanosecs (qt, 0);
00346     return qt;
00347 }
00348 
00349 gboolean
00350 qof_time_set_day_end (QofTime * qt)
00351 {
00352     if (!qof_time_set_day_start (qt))
00353         return FALSE;
00354     qt->qt_sec += (SECS_PER_DAY - 1);
00355     return TRUE;
00356 }
00357 
00358 gboolean
00359 qof_time_set_day_middle (QofTime * qt)
00360 {
00361     if (!qof_time_set_day_start (qt))
00362         return FALSE;
00363     qt->qt_sec += (SECS_PER_DAY / 2);
00364     return TRUE;
00365 }
00366 
00367 GTimeVal *
00368 qof_time_get_current_start (void)
00369 {
00370     GTimeVal *current;
00371     struct tm tm;
00372 
00374     current = g_new0 (GTimeVal, 1);
00375     g_get_current_time (current);
00376     /* OK to use time_t for current time. */
00377     tm = *gmtime_r (&current->tv_sec, &tm);
00378     current->tv_sec -= tm.tm_sec;
00379     current->tv_sec -= tm.tm_min * 60;
00380     current->tv_sec -= tm.tm_hour * 60 * 60;
00381     return current;
00382 }
00383 
00384 QofTime *
00385 qof_time_get_current (void)
00386 {
00387     QofTime *now;
00388     GTimeVal gnow;
00389 
00390     now = qof_time_new ();
00391     g_get_current_time (&gnow);
00392     qof_time_from_gtimeval (now, &gnow);
00393     return now;
00394 }
00395 
00396 gboolean
00397 qof_time_set_day_start (QofTime * qt)
00398 {
00399     GDate *d, *now;
00400     GTimeVal *current, from_date;
00401     gint days_between;
00402 
00404     g_return_val_if_fail (qt, FALSE);
00405     d = qof_time_to_gdate (qt);
00406     if (!d)
00407         return FALSE;
00408     now = g_date_new ();
00409     current = qof_time_get_current_start ();
00410     g_date_set_time_val (now, current);
00411     /* if date is in the future, days_between is negative */
00412     days_between = g_date_days_between (d, now);
00413     from_date.tv_sec = current->tv_sec - (days_between * SECS_PER_DAY);
00414     from_date.tv_usec = 0;
00415     qof_time_from_gtimeval (qt, &from_date);
00416     g_date_free (d);
00417     g_free (current);
00418     return TRUE;
00419 }
00420 
00421 QofTime *
00422 qof_time_get_today_start (void)
00423 {
00424     QofTime *qt;
00425     GDate *d;
00426     GTimeVal val;
00427 
00428     qt = qof_time_new ();
00429     g_get_current_time (&val);
00430     d = g_date_new ();
00431     g_date_set_time_val (d, &val);
00432     qt = qof_time_from_gdate (d);
00433     return qt;
00434 }
00435 
00436 QofTime *
00437 qof_time_get_today_end (void)
00438 {
00439     QofTime *qt;
00440 
00441     qt = qof_time_get_today_start ();
00442     qt->qt_sec += SECS_PER_DAY - 1;
00443     return qt;
00444 }
00445 
00446 guint8
00447 qof_time_last_mday (QofTime * qt)
00448 {
00449     GDate *d;
00450     GDateMonth m;
00451     GDateYear y;
00452 
00453     g_return_val_if_fail (qt, 0);
00454     d = qof_time_to_gdate (qt);
00455     if (!d)
00456         return 0;
00457     m = g_date_get_month (d);
00458     y = g_date_get_year (d);
00459     return g_date_get_days_in_month (m, y);
00460 }
00461 
00462 gboolean
00463 qof_time_to_dmy (QofTime * qt, guint8 * day, guint8 * month, 
00464                  guint16 * year)
00465 {
00466     GDate *d;
00467 
00468     d = qof_time_to_gdate (qt);
00469     if (!d)
00470         return FALSE;
00471     if (day)
00472         *day = g_date_get_day (d);
00473     if (month)
00474         *month = g_date_get_month (d);
00475     if (year)
00476         *year = g_date_get_year (d);
00477     return TRUE;
00478 }
00479 
00480 QofTime *
00481 qof_time_dmy_to_time (guint8 day, guint8 month, guint16 year)
00482 {
00483     GDate *d;
00484     QofTime *qt;
00485 
00486     g_return_val_if_fail (g_date_valid_dmy (day, month, year), NULL);
00487     d = g_date_new_dmy (day, month, year);
00488     qt = qof_time_from_gdate (d);
00489     return qt;
00490 }
00491 
00492 gchar *
00493 qof_time_stamp_now (void)
00494 {
00495     gint len;
00496     struct tm qtm;
00497     time_t t;
00498     gchar test[MAX_DATE_LENGTH];
00499     const gchar *fmt;
00500 
00501     ENTER (" ");
00502     t = time (NULL);
00503     qtm = *gmtime_r (&t, &qtm);
00504     fmt = qof_date_format_get_format (QOF_DATE_FORMAT_UTC);
00505     len = strftime (test, MAX_DATE_LENGTH, fmt, &qtm);
00506     if (len == 0 && test[0] != '\0')
00507     {
00508         LEAVE (" strftime failed.");
00509         return NULL;
00510     }
00511     LEAVE (" ");
00512     return g_strdup (test);
00513 }

Generated on Mon May 21 17:42:21 2007 for QOF by  doxygen 1.5.1