QOF 0.8.4
|
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, >m); 00320 qd = qof_date_from_struct_tm (>m); 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 (¤t->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 }