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 #include "qofdate-p.h"
00035 
00036 static QofLogModule log_module = QOF_MOD_TIME;
00037 
00038 struct QofTime64
00039 {
00040     QofTimeSecs qt_sec;
00041     glong qt_nsec;
00042     gboolean valid;
00043 };
00044 
00045 QofTime *
00046 qof_time_new (void)
00047 {
00048     QofTime *qt;
00049 
00050     qt = g_new0 (QofTime, 1);
00051     qt->valid = FALSE;
00052     return qt;
00053 }
00054 
00055 void
00056 qof_time_free (QofTime * qt)
00057 {
00058     if (qt == NULL)
00059         return;
00060     g_free (qt);
00061     qt = NULL;
00062 }
00063 
00064 void
00065 qof_time_add_secs (QofTime * qt, QofTimeSecs secs)
00066 {
00067     g_return_if_fail (qt);
00068     g_return_if_fail (qt->valid);
00069     qt->qt_sec += secs;
00070 }
00071 
00072 QofTime *
00073 qof_time_add_secs_copy (QofTime * qt, QofTimeSecs secs)
00074 {
00075     QofTime *copy;
00076 
00077     g_return_val_if_fail (qt, NULL);
00078     g_return_val_if_fail (qt->valid, NULL);
00079     copy = qof_time_copy (qt);
00080     copy->qt_sec += secs;
00081     return copy;
00082 }
00083 
00084 static QofTime *
00085 time_normalize (QofTime * qt)
00086 {
00087     g_return_val_if_fail (qt->valid, NULL);
00088     if ((qt->qt_sec < 0) && (qt->qt_nsec > QOF_NSECS))
00089     {
00090         qt->qt_sec -= (qt->qt_nsec / QOF_NSECS);
00091         qt->qt_nsec = qt->qt_nsec % QOF_NSECS;
00092     }
00093     if ((qt->qt_sec >= 0) && (qt->qt_nsec > QOF_NSECS))
00094     {
00095         qt->qt_sec += (qt->qt_nsec / QOF_NSECS);
00096         qt->qt_nsec = qt->qt_nsec % QOF_NSECS;
00097     }
00098     if ((qt->qt_sec < 0) && (qt->qt_nsec < -QOF_NSECS))
00099     {
00100         qt->qt_sec -= -(-qt->qt_nsec / QOF_NSECS);
00101         qt->qt_nsec = -(-qt->qt_nsec % QOF_NSECS);
00102     }
00103     if ((qt->qt_sec >= 0) && (qt->qt_nsec < -QOF_NSECS))
00104     {
00105         qt->qt_sec += -(-qt->qt_nsec / QOF_NSECS);
00106         qt->qt_nsec = -(-qt->qt_nsec % QOF_NSECS);
00107     }
00108     if (qt->qt_sec >= 0 && qt->qt_nsec < 0)
00109     {
00110         qt->qt_sec--;
00111         qt->qt_nsec = QOF_NSECS + qt->qt_nsec;
00112     }
00113     return qt;
00114 }
00115 
00116 void
00117 qof_time_set_secs (QofTime * qt, QofTimeSecs secs)
00118 {
00119     qt->qt_sec = secs;
00120     qt->valid = TRUE;
00121     time_normalize (qt);
00122 }
00123 
00124 void
00125 qof_time_set_nanosecs (QofTime * qt, glong nano)
00126 {
00127     qt->qt_nsec = nano;
00128     qt->valid = TRUE;
00129     time_normalize (qt);
00130 }
00131 
00132 QofTimeSecs
00133 qof_time_get_secs (const QofTime * qt)
00134 {
00135     g_return_val_if_fail (qt, 0);
00136     g_return_val_if_fail (qt->valid == TRUE, 0);
00137     return qt->qt_sec;
00138 }
00139 
00140 glong
00141 qof_time_get_nanosecs (const QofTime * qt)
00142 {
00143     g_return_val_if_fail (qt->valid == TRUE, 0);
00144     return qt->qt_nsec;
00145 }
00146 
00147 gboolean
00148 qof_time_equal (const QofTime * ta, const QofTime * tb)
00149 {
00150     if (ta == tb)
00151         return TRUE;
00152     if (!ta)
00153         return FALSE;
00154     if (!tb)
00155         return FALSE;
00156     g_return_val_if_fail (ta->valid && tb->valid, FALSE);
00157     if (ta->qt_sec != tb->qt_sec)
00158         return FALSE;
00159     if (ta->qt_nsec != tb->qt_nsec)
00160         return FALSE;
00161     return TRUE;
00162 }
00163 
00164 gint
00165 qof_time_cmp (const QofTime * ta, const QofTime * tb)
00166 {
00167     g_return_val_if_fail (ta->valid && tb->valid, -1);
00168     if (ta == tb)
00169         return 0;
00170     if (ta->qt_sec < tb->qt_sec)
00171         return -1;
00172     if (ta->qt_sec > tb->qt_sec)
00173         return 1;
00174     if (ta->qt_nsec < tb->qt_nsec)
00175         return -1;
00176     if (ta->qt_nsec > tb->qt_nsec)
00177         return 1;
00178     return 0;
00179 }
00180 
00181 QofTime *
00182 qof_time_diff (const QofTime * ta, const QofTime * tb)
00183 {
00184     QofTime *retval;
00185 
00186     g_return_val_if_fail (ta->valid && tb->valid, NULL);
00187     retval = g_new0 (QofTime, 1);
00188     retval->qt_sec = ta->qt_sec - tb->qt_sec;
00189     retval->qt_nsec = ta->qt_nsec - tb->qt_nsec;
00190     retval->valid = TRUE;
00191     time_normalize (retval);
00192     return retval;
00193 }
00194 
00195 QofTime *
00196 qof_time_abs (QofTime * qt)
00197 {
00198     g_return_val_if_fail (qt, NULL);
00199     return time_normalize (qt);
00200 }
00201 
00202 gboolean
00203 qof_time_is_valid (const QofTime * qt)
00204 {
00205     g_return_val_if_fail (qt, FALSE);
00206     return qt->valid;
00207 }
00208 
00209 QofTime *
00210 qof_time_set (QofTimeSecs t, glong nanosecs)
00211 {
00212     QofTime *qt;
00213 
00214     qt = qof_time_new ();
00215     qt->qt_sec = t;
00216     qt->qt_nsec = nanosecs;
00217     qt->valid = TRUE;
00218     time_normalize (qt);
00219     return qt;
00220 }
00221 
00222 QofTime *
00223 qof_time_copy (const QofTime *qt)
00224 {
00225     g_return_val_if_fail (qt, NULL);
00226     g_return_val_if_fail (qt->valid, NULL);
00227     return qof_time_set (qt->qt_sec, qt->qt_nsec);
00228 }
00229 
00230 QofTime *
00231 qof_time_from_time_t (time_t t, glong nanosecs)
00232 {
00233     return qof_time_set (t, nanosecs);
00234 }
00235 
00236 gboolean
00237 qof_time_to_time_t (QofTime * qt, time_t * t, glong * nanosecs)
00238 {
00239     if (!qt->valid)
00240         return FALSE;
00241     if (qt->qt_sec < 0)
00242         return FALSE;
00243     if (qt->qt_nsec > 0)
00244     {
00245         *nanosecs = qt->qt_nsec;
00246     }
00247     if ((sizeof (qt->qt_sec) > sizeof (time_t))
00248         && (qt->qt_sec > G_MAXINT32))
00249     {
00250         PERR (" QofTime too large for time_t on this platform.");
00251         return FALSE;
00252     }
00253     *t = qt->qt_sec;
00254     return TRUE;
00255 }
00256 
00257 QofTime *
00258 qof_time_from_tm (struct tm * qtm, glong nanosecs)
00259 {
00260     QofDate *qd;
00261     QofTime *qt;
00262 
00263     /* avoids use of gmtime_r and therefore time_t */
00264     qd = qof_date_from_struct_tm (qtm);
00265     qd->qd_nanosecs = nanosecs;
00266     qt = qof_date_to_qtime (qd);
00267     qof_date_free (qd);
00268     return qt;
00269 }
00270 
00271 gboolean
00272 qof_time_to_gtimeval (QofTime * qt, GTimeVal * gtv)
00273 {
00274     if (!qt->valid)
00275     {
00276         PERR (" invalid QofTime passed");
00277         return FALSE;
00278     }
00279     if (qt->qt_sec > G_MAXLONG)
00280     {
00281         PERR (" QofTime out of range for GTimeVal");
00282         return FALSE;
00283     }
00284     gtv->tv_sec = (glong) qt->qt_sec;
00285     gtv->tv_usec = qt->qt_nsec;
00286     return TRUE;
00287 }
00288 
00289 void
00290 qof_time_from_gtimeval (QofTime * qt, GTimeVal * gtv)
00291 {
00292     qt->qt_sec = (QofTimeSecs) gtv->tv_sec;
00293     qt->qt_nsec = gtv->tv_usec * 1000;
00294     qt->valid = TRUE;
00295     time_normalize (qt);
00296 }
00297 
00298 GDate *
00299 qof_time_to_gdate (QofTime * qt)
00300 {
00301     QofDate *qd;
00302     GDate *d;
00303 
00304     qd = qof_date_from_qtime (qt);
00305     d = g_date_new_dmy (qd->qd_mday, qd->qd_mon, qd->qd_year);
00306     if (g_date_valid (d))
00307         return d;
00308     return NULL;
00309 }
00310 
00311 QofTime *
00312 qof_time_from_gdate (GDate * date)
00313 {
00314     struct tm gtm;
00315     QofTime *qt;
00316     QofDate *qd;
00317 
00318     g_return_val_if_fail (date, NULL);
00319     g_date_to_struct_tm (date, &gtm);
00320     qd = qof_date_from_struct_tm (&gtm);
00321     qt = qof_date_to_qtime (qd);
00322     qof_date_free (qd);
00323     return qt;
00324 }
00325 
00326 gboolean
00327 qof_time_set_day_end (QofTime * qt)
00328 {
00329     if (!qof_time_set_day_start (qt))
00330         return FALSE;
00331     qt->qt_sec += (SECS_PER_DAY - 1);
00332     return TRUE;
00333 }
00334 
00335 gboolean
00336 qof_time_set_day_middle (QofTime * qt)
00337 {
00338     if (!qof_time_set_day_start (qt))
00339         return FALSE;
00340     qt->qt_sec += (SECS_PER_DAY / 2);
00341     return TRUE;
00342 }
00343 
00344 GTimeVal *
00345 qof_time_get_current_start (void)
00346 {
00347     GTimeVal *current;
00348     struct tm tm;
00349 
00351     current = g_new0 (GTimeVal, 1);
00352     g_get_current_time (current);
00353     /* OK to use time_t for current time. */
00354     tm = *gmtime_r (&current->tv_sec, &tm);
00355     current->tv_sec -= tm.tm_sec;
00356     current->tv_sec -= tm.tm_min * 60;
00357     current->tv_sec -= tm.tm_hour * 60 * 60;
00358     return current;
00359 }
00360 
00361 QofTime *
00362 qof_time_get_current (void)
00363 {
00364     QofTime *now;
00365     GTimeVal gnow;
00366 
00367     now = qof_time_new ();
00368     g_get_current_time (&gnow);
00369     qof_time_from_gtimeval (now, &gnow);
00370     return now;
00371 }
00372 
00373 gboolean
00374 qof_time_set_day_start (QofTime * qt)
00375 {
00376     QofDate *qd;
00377     QofTimeSecs c;
00378     
00379     g_return_val_if_fail (qt, FALSE);
00380     qd = qof_date_from_qtime (qt);
00381     if (qd->qd_year < 1970)
00382     {
00383         c = QOF_DAYS_TO_SEC(qd->qd_yday);
00384         c -= QOF_DAYS_TO_SEC(days_between (1970, qd->qd_year));
00385         c -= qd->qd_gmt_off;
00386         qt->qt_sec = c;
00387         qt->qt_nsec = 0;
00388     }
00389     if (qd->qd_year >= 1970)
00390     {
00391         c = QOF_DAYS_TO_SEC(qd->qd_yday);
00392         c += QOF_DAYS_TO_SEC(days_between (1970, qd->qd_year));
00393         c -= qd->qd_gmt_off;
00394         qt->qt_sec = c;
00395         qt->qt_nsec = 0;
00396     }
00397     qof_date_free (qd);
00398     return TRUE;
00399 }
00400 
00401 QofTime *
00402 qof_time_get_today_start (void)
00403 {
00404     QofTime *qt;
00405 
00406     qt = qof_time_get_current ();
00407     if (!qof_time_set_day_start (qt))
00408         return NULL;
00409     return qt;
00410 }
00411 
00412 QofTime *
00413 qof_time_get_today_end (void)
00414 {
00415     QofTime *qt;
00416 
00417     qt = qof_time_get_today_start ();
00418     qt->qt_sec += SECS_PER_DAY - 1;
00419     return qt;
00420 }
00421 
00422 guint8
00423 qof_time_last_mday (QofTime * qt)
00424 {
00425     GDate *d;
00426     GDateMonth m;
00427     GDateYear y;
00428 
00429     g_return_val_if_fail (qt, 0);
00430     d = qof_time_to_gdate (qt);
00431     if (!d)
00432         return 0;
00433     m = g_date_get_month (d);
00434     y = g_date_get_year (d);
00435     return g_date_get_days_in_month (m, y);
00436 }
00437 
00438 gboolean
00439 qof_time_to_dmy (QofTime * qt, guint8 * day, guint8 * month, 
00440                  guint16 * year)
00441 {
00442     GDate *d;
00443 
00444     d = qof_time_to_gdate (qt);
00445     if (!d)
00446         return FALSE;
00447     if (day)
00448         *day = g_date_get_day (d);
00449     if (month)
00450         *month = g_date_get_month (d);
00451     if (year)
00452         *year = g_date_get_year (d);
00453     return TRUE;
00454 }
00455 
00456 QofTime *
00457 qof_time_dmy_to_time (guint8 day, guint8 month, guint16 year)
00458 {
00459     GDate *d;
00460     QofTime *qt;
00461 
00462     g_return_val_if_fail (g_date_valid_dmy (day, month, year), NULL);
00463     d = g_date_new_dmy (day, month, year);
00464     qt = qof_time_from_gdate (d);
00465     return qt;
00466 }
00467 
00468 gchar *
00469 qof_time_stamp_now (void)
00470 {
00471     gint len;
00472     struct tm qtm;
00473     time_t t;
00474     gchar test[MAX_DATE_LENGTH];
00475     const gchar *fmt;
00476 
00477     ENTER (" ");
00478     t = time (NULL);
00479     qtm = *gmtime_r (&t, &qtm);
00480     fmt = qof_date_format_get_format (QOF_DATE_FORMAT_UTC);
00481     len = strftime (test, MAX_DATE_LENGTH, fmt, &qtm);
00482     if (len == 0 && test[0] != '\0')
00483     {
00484         LEAVE (" strftime failed.");
00485         return NULL;
00486     }
00487     LEAVE (" ");
00488     return g_strdup (test);
00489 }

Generated on Thu Jan 31 22:50:26 2008 for QOF by  doxygen 1.5.4