00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #define _GNU_SOURCE
00028 #define __EXTENSIONS__
00029
00030 #include "config.h"
00031 #include <glib.h>
00032
00033 #include <ctype.h>
00034
00035 #ifdef HAVE_LANGINFO_H
00036 #define HAVE_LANGINFO_D_FMT 1
00037 #endif
00038
00039 #ifdef HAVE_LANGINFO_D_FMT
00040 #include <langinfo.h>
00041 #endif
00042
00043 #include <stdio.h>
00044 #include <stdlib.h>
00045 #include <string.h>
00046 #include <time.h>
00047
00048 #include <glib.h>
00049
00050 #include "gnc-date.h"
00051 #include "qof.h"
00052
00053 #ifndef HAVE_STRPTIME
00054 #include "strptime.h"
00055 #endif
00056 #ifndef HAVE_LOCALTIME_R
00057 #include "localtime_r.h"
00058 #endif
00059
00060 #define NANOS_PER_SECOND 1000000000
00061
00062 #ifdef HAVE_LANGINFO_D_FMT
00063 # define GNC_D_FMT (nl_langinfo (D_FMT))
00064 # define GNC_D_T_FMT (nl_langinfo (D_T_FMT))
00065 # define GNC_T_FMT (nl_langinfo (T_FMT))
00066 #else
00067 # define GNC_D_FMT "%Y-%m-%d"
00068 # define GNC_D_T_FMT "%Y-%m-%d %r"
00069 # define GNC_T_FMT "%r"
00070 #endif
00071
00072
00073
00074 static QofDateFormat dateFormat = QOF_DATE_FORMAT_LOCALE;
00075 static QofDateFormat prevQofDateFormat = QOF_DATE_FORMAT_LOCALE;
00076
00077
00078 static QofLogModule log_module = QOF_MOD_ENGINE;
00079
00080
00081
00082
00083 const char*
00084 gnc_date_dateformat_to_string(QofDateFormat format)
00085 {
00086 switch (format) {
00087 case QOF_DATE_FORMAT_US:
00088 return "us";
00089 case QOF_DATE_FORMAT_UK:
00090 return "uk";
00091 case QOF_DATE_FORMAT_CE:
00092 return "ce";
00093 case QOF_DATE_FORMAT_ISO:
00094 return "iso";
00095 case QOF_DATE_FORMAT_UTC:
00096 return "utc";
00097 case QOF_DATE_FORMAT_LOCALE:
00098 return "locale";
00099 case QOF_DATE_FORMAT_CUSTOM:
00100 return "custom";
00101 default:
00102 return NULL;
00103 }
00104 }
00105
00106 gboolean
00107 gnc_date_string_to_dateformat(const char* fmt_str, QofDateFormat *format)
00108 {
00109 if (!fmt_str)
00110 return TRUE;
00111
00112 if (!strcmp(fmt_str, "us"))
00113 *format = QOF_DATE_FORMAT_US;
00114 else if (!strcmp(fmt_str, "uk"))
00115 *format = QOF_DATE_FORMAT_UK;
00116 else if (!strcmp(fmt_str, "ce"))
00117 *format = QOF_DATE_FORMAT_CE;
00118 else if (!strcmp(fmt_str, "utc"))
00119 *format = QOF_DATE_FORMAT_UTC;
00120 else if (!strcmp(fmt_str, "iso"))
00121 *format = QOF_DATE_FORMAT_ISO;
00122 else if (!strcmp(fmt_str, "locale"))
00123 *format = QOF_DATE_FORMAT_LOCALE;
00124 else if (!strcmp(fmt_str, "custom"))
00125 *format = QOF_DATE_FORMAT_CUSTOM;
00126 else
00127 return TRUE;
00128
00129 return FALSE;
00130 }
00131
00132
00133 const char*
00134 gnc_date_monthformat_to_string(GNCDateMonthFormat format)
00135 {
00136 switch (format) {
00137 case GNCDATE_MONTH_NUMBER:
00138 return "number";
00139 case GNCDATE_MONTH_ABBREV:
00140 return "abbrev";
00141 case GNCDATE_MONTH_NAME:
00142 return "name";
00143 default:
00144 return NULL;
00145 }
00146 }
00147
00148 gboolean
00149 gnc_date_string_to_monthformat(const char *fmt_str, GNCDateMonthFormat *format)
00150 {
00151 if (!fmt_str)
00152 return TRUE;
00153
00154 if (!strcmp(fmt_str, "number"))
00155 *format = GNCDATE_MONTH_NUMBER;
00156 else if (!strcmp(fmt_str, "abbrev"))
00157 *format = GNCDATE_MONTH_ABBREV;
00158 else if (!strcmp(fmt_str, "name"))
00159 *format = GNCDATE_MONTH_NAME;
00160 else
00161 return TRUE;
00162
00163 return FALSE;
00164 }
00165
00166
00167
00168
00169 static void
00170 timespec_normalize(Timespec *t)
00171 {
00172 if(t->tv_nsec > NANOS_PER_SECOND)
00173 {
00174 t->tv_sec+= (t->tv_nsec / NANOS_PER_SECOND);
00175 t->tv_nsec= t->tv_nsec % NANOS_PER_SECOND;
00176 }
00177
00178 if(t->tv_nsec < - NANOS_PER_SECOND)
00179 {
00180 t->tv_sec+= - (-t->tv_nsec / NANOS_PER_SECOND);
00181 t->tv_nsec = - (-t->tv_nsec % NANOS_PER_SECOND);
00182 }
00183
00184 if (t->tv_sec > 0 && t->tv_nsec < 0)
00185 {
00186 t->tv_sec--;
00187 t->tv_nsec = NANOS_PER_SECOND + t->tv_nsec;
00188 }
00189
00190 if (t->tv_sec < 0 && t->tv_nsec > 0)
00191 {
00192 t->tv_sec++;
00193 t->tv_nsec = - NANOS_PER_SECOND + t->tv_nsec;
00194 }
00195 return;
00196 }
00197
00198
00199 gboolean
00200 timespec_equal (const Timespec *ta, const Timespec *tb)
00201 {
00202 if(ta == tb) return TRUE;
00203 if(ta->tv_sec != tb->tv_sec) return FALSE;
00204 if(ta->tv_nsec != tb->tv_nsec) return FALSE;
00205 return TRUE;
00206 }
00207
00208 gint
00209 timespec_cmp(const Timespec *ta, const Timespec *tb)
00210 {
00211 if(ta == tb) return 0;
00212 if(ta->tv_sec < tb->tv_sec) return -1;
00213 if(ta->tv_sec > tb->tv_sec) return 1;
00214 if(ta->tv_nsec < tb->tv_nsec) return -1;
00215 if(ta->tv_nsec > tb->tv_nsec) return 1;
00216 return 0;
00217 }
00218
00219 Timespec
00220 timespec_diff(const Timespec *ta, const Timespec *tb)
00221 {
00222 Timespec retval;
00223 retval.tv_sec = ta->tv_sec - tb->tv_sec;
00224 retval.tv_nsec = ta->tv_nsec - tb->tv_nsec;
00225 timespec_normalize(&retval);
00226 return retval;
00227 }
00228
00229 Timespec
00230 timespec_abs(const Timespec *t)
00231 {
00232 Timespec retval = *t;
00233
00234 timespec_normalize(&retval);
00235 if (retval.tv_sec < 0)
00236 {
00237 retval.tv_sec = - retval.tv_sec;
00238 retval.tv_nsec = - retval.tv_nsec;
00239 }
00240
00241 return retval;
00242 }
00243
00244
00245
00246
00247
00248
00249 Timespec
00250 timespecCanonicalDayTime(Timespec t)
00251 {
00252 struct tm tm, *result;
00253 Timespec retval;
00254 time_t t_secs = t.tv_sec + (t.tv_nsec / NANOS_PER_SECOND);
00255 result = localtime(&t_secs);
00256 tm = *result;
00257 gnc_tm_set_day_middle(&tm);
00258 retval.tv_sec = mktime(&tm);
00259 retval.tv_nsec = 0;
00260 return retval;
00261 }
00262
00263 int gnc_date_my_last_mday (int month, int year)
00264 {
00265 static int last_day_of_month[2][12] = {
00266 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
00267 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
00268 };
00269
00270
00271 if (year % 2000 == 0) return last_day_of_month[1][month-1];
00272 if (year % 400 == 0 ) return last_day_of_month[0][month-1];
00273 if (year % 4 == 0 ) return last_day_of_month[1][month-1];
00274 return last_day_of_month[0][month-1];
00275 }
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 int date_get_last_mday(struct tm *tm)
00286 {
00287 return gnc_date_my_last_mday (tm->tm_mon+1, tm->tm_year+1900);
00288 }
00289
00290
00291
00292
00293
00294
00295
00296
00297 gboolean date_is_last_mday(struct tm *tm)
00298 {
00299 return(tm->tm_mday == date_get_last_mday(tm));
00300 }
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313 void date_add_months (struct tm *tm, int months, gboolean track_last_day)
00314 {
00315 gboolean was_last_day;
00316 int new_last_mday;
00317
00318
00319 was_last_day = date_is_last_mday(tm);
00320
00321
00322 tm->tm_mon += months;
00323 while (tm->tm_mon > 11) {
00324 tm->tm_mon -= 12;
00325 tm->tm_year++;
00326 }
00327
00328 if (!track_last_day)
00329 return;
00330
00331
00332 new_last_mday = date_get_last_mday(tm);
00333 if (was_last_day || (tm->tm_mday > new_last_mday))
00334 tm->tm_mday = new_last_mday;
00335 }
00336
00337
00338
00339
00340
00341
00342
00343 QofDateFormat qof_date_format_get (void)
00344 {
00345 return dateFormat;
00346 }
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359 void qof_date_format_set(QofDateFormat df)
00360 {
00361 if(df >= DATE_FORMAT_FIRST && df <= DATE_FORMAT_LAST)
00362 {
00363 prevQofDateFormat = dateFormat;
00364 dateFormat = df;
00365 }
00366 else
00367 {
00368 PERR("non-existent date format set attempted. Setting ISO default");
00369 prevQofDateFormat = dateFormat;
00370 dateFormat = QOF_DATE_FORMAT_ISO;
00371 }
00372
00373 return;
00374 }
00375
00376
00377
00378
00379
00380
00381
00382
00383 const gchar *qof_date_format_get_string(QofDateFormat df)
00384 {
00385 switch(df) {
00386 case QOF_DATE_FORMAT_US:
00387 return "%m/%d/%y";
00388 case QOF_DATE_FORMAT_UK:
00389 return "%d/%m/%y";
00390 case QOF_DATE_FORMAT_CE:
00391 return "%d.%m.%y";
00392 case QOF_DATE_FORMAT_UTC:
00393 return "%Y-%m-%dT%H:%M:%SZ";
00394 case QOF_DATE_FORMAT_ISO:
00395 return "%y-%m-%d";
00396 case QOF_DATE_FORMAT_LOCALE:
00397 default:
00398 return GNC_D_FMT;
00399 };
00400 }
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411 const gchar *qof_date_text_format_get_string(QofDateFormat df)
00412 {
00413 switch(df) {
00414 case QOF_DATE_FORMAT_US:
00415 return "%b %d, %y";
00416 case QOF_DATE_FORMAT_UK:
00417 case QOF_DATE_FORMAT_CE:
00418 return "%d %b, %y";
00419 case QOF_DATE_FORMAT_UTC:
00420 return "%Y-%m-%dT%H:%M:%SZ";
00421 case QOF_DATE_FORMAT_ISO:
00422 return "%y-%b-%d";
00423 case QOF_DATE_FORMAT_LOCALE:
00424 default:
00425 return GNC_D_FMT;
00426 };
00427 }
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444 size_t
00445 qof_print_date_dmy_buff (char * buff, size_t len, int day, int month, int year)
00446 {
00447 int flen;
00448 if (!buff) return 0;
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458 switch(dateFormat)
00459 {
00460 case QOF_DATE_FORMAT_UK:
00461 flen = g_snprintf (buff, len, "%2d/%2d/%-4d", day, month, year);
00462 break;
00463 case QOF_DATE_FORMAT_CE:
00464 flen = g_snprintf (buff, len, "%2d.%2d.%-4d", day, month, year);
00465 break;
00466 case QOF_DATE_FORMAT_LOCALE:
00467 {
00468 struct tm tm_str;
00469 time_t t;
00470
00471 tm_str.tm_mday = day;
00472 tm_str.tm_mon = month - 1;
00473 tm_str.tm_year = year - 1900;
00474
00475
00476 gnc_tm_set_day_start (&tm_str);
00477 t = mktime (&tm_str);
00478 localtime_r (&t, &tm_str);
00479 flen = strftime (buff, len, GNC_D_FMT, &tm_str);
00480 if (flen != 0)
00481 break;
00482 }
00483
00484 case QOF_DATE_FORMAT_ISO:
00485 case QOF_DATE_FORMAT_UTC:
00486 flen = g_snprintf (buff, len, "%04d-%02d-%02d", year, month, day);
00487 break;
00488 case QOF_DATE_FORMAT_US:
00489 default:
00490 flen = g_snprintf (buff, len, "%2d/%2d/%-4d", month, day, year);
00491 break;
00492 }
00493
00494 return flen;
00495 }
00496
00497 size_t
00498 qof_print_date_buff (char * buff, size_t len, time_t t)
00499 {
00500 struct tm *theTime;
00501
00502 if (!buff) return 0 ;
00503
00504 theTime = localtime (&t);
00505
00506 return qof_print_date_dmy_buff (buff, len,
00507 theTime->tm_mday,
00508 theTime->tm_mon + 1,
00509 theTime->tm_year + 1900);
00510 }
00511
00512 size_t
00513 qof_print_gdate( char *buf, size_t len, GDate *gd )
00514 {
00515 return qof_print_date_dmy_buff( buf, len,
00516 g_date_get_day(gd),
00517 g_date_get_month(gd),
00518 g_date_get_year(gd) );
00519 }
00520
00521 char *
00522 qof_print_date (time_t t)
00523 {
00524 char buff[MAX_DATE_LENGTH];
00525 qof_print_date_buff (buff, MAX_DATE_LENGTH, t);
00526 return g_strdup (buff);
00527 }
00528
00529 const char *
00530 gnc_print_date (Timespec ts)
00531 {
00532 static char buff[MAX_DATE_LENGTH];
00533 time_t t;
00534
00535 t = ts.tv_sec + (ts.tv_nsec / 1000000000.0);
00536
00537 qof_print_date_buff (buff, MAX_DATE_LENGTH, t);
00538
00539 return buff;
00540 }
00541
00542
00543
00544 size_t
00545 qof_print_hours_elapsed_buff (char * buff, size_t len, int secs, gboolean show_secs)
00546 {
00547 size_t flen;
00548 if (0 <= secs)
00549 {
00550 if (show_secs)
00551 {
00552 flen = g_snprintf(buff, len,
00553 "%02d:%02d:%02d", (int)(secs / 3600),
00554 (int)((secs % 3600) / 60), (int)(secs % 60));
00555 }
00556 else
00557 {
00558 flen = g_snprintf(buff, len,
00559 "%02d:%02d", (int)(secs / 3600),
00560 (int)((secs % 3600) / 60));
00561 }
00562 }
00563 else
00564 {
00565 if (show_secs)
00566 {
00567 flen = g_snprintf(buff, len,
00568 "-%02d:%02d:%02d", (int)(-secs / 3600),
00569 (int)((-secs % 3600) / 60), (int)(-secs % 60));
00570 }
00571 else
00572 {
00573 flen = g_snprintf(buff, len,
00574 "-%02d:%02d", (int)(-secs / 3600),
00575 (int)((-secs % 3600) / 60));
00576 }
00577 }
00578 return flen;
00579 }
00580
00581
00582
00583 size_t
00584 qof_print_minutes_elapsed_buff (char * buff, size_t len, int secs, gboolean show_secs)
00585 {
00586 size_t flen;
00587 if (0 <= secs)
00588 {
00589 if (show_secs)
00590 {
00591 flen = g_snprintf(buff, len,
00592 "%02d:%02d",
00593 (int)(secs / 60), (int)(secs % 60));
00594 }
00595 else
00596 {
00597 flen = g_snprintf(buff, len,
00598 "%02d", (int)(secs / 60));
00599 }
00600 }
00601 else
00602 {
00603 if (show_secs)
00604 {
00605 flen = g_snprintf(buff, len,
00606 "-%02d:%02d", (int)(-secs / 60), (int)(-secs % 60));
00607 }
00608 else
00609 {
00610 flen = g_snprintf(buff, len,
00611 "-%02d", (int)(-secs / 60));
00612 }
00613 }
00614 return flen;
00615 }
00616
00617
00618
00619 size_t
00620 qof_print_date_time_buff (char * buff, size_t len, time_t secs)
00621 {
00622 int flen;
00623 int day, month, year, hour, min, sec;
00624 struct tm ltm, gtm;
00625
00626 if (!buff) return 0;
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636 ltm = *localtime (&secs);
00637 day = ltm.tm_mday;
00638 month = ltm.tm_mon +1;
00639 year = ltm.tm_year +1900;
00640 hour = ltm.tm_hour;
00641 min = ltm.tm_min;
00642 sec = ltm.tm_sec;
00643
00644 switch(dateFormat)
00645 {
00646 case QOF_DATE_FORMAT_UK:
00647 flen = g_snprintf (buff, len, "%2d/%2d/%-4d %2d:%02d", day, month, year, hour, min);
00648 break;
00649 case QOF_DATE_FORMAT_CE:
00650 flen = g_snprintf (buff, len, "%2d.%2d.%-4d %2d:%02d", day, month, year, hour, min);
00651 break;
00652 case QOF_DATE_FORMAT_ISO:
00653 flen = g_snprintf (buff, len, "%04d-%02d-%02d %02d:%02d", year, month, day, hour, min);
00654 break;
00655 case QOF_DATE_FORMAT_UTC:
00656 {
00657 gtm = *gmtime (&secs);
00658 flen = strftime (buff, len, QOF_UTC_DATE_FORMAT, >m);
00659 break;
00660 }
00661 case QOF_DATE_FORMAT_LOCALE:
00662 {
00663 flen = strftime (buff, len, GNC_D_T_FMT, <m);
00664 }
00665 break;
00666
00667 case QOF_DATE_FORMAT_US:
00668 default:
00669 flen = g_snprintf (buff, len, "%2d/%2d/%-4d %2d:%02d", month, day, year, hour, min);
00670 break;
00671 }
00672 return flen;
00673 }
00674
00675 size_t
00676 qof_print_time_buff (char * buff, size_t len, time_t secs)
00677 {
00678 int flen;
00679 struct tm ltm, gtm;
00680
00681 if (!buff) return 0;
00682 if(dateFormat == QOF_DATE_FORMAT_UTC)
00683 {
00684 gtm = *gmtime (&secs);
00685 flen = strftime(buff, len, QOF_UTC_DATE_FORMAT, >m);
00686 return flen;
00687 }
00688 ltm = *localtime (&secs);
00689 flen = strftime (buff, len, GNC_T_FMT, <m);
00690
00691 return flen;
00692 }
00693
00694
00695
00696 int
00697 qof_is_same_day (time_t ta, time_t tb)
00698 {
00699 struct tm lta, ltb;
00700 lta = *localtime (&ta);
00701 ltb = *localtime (&tb);
00702 if (lta.tm_year == ltb.tm_year)
00703 {
00704 return (ltb.tm_yday - lta.tm_yday);
00705 }
00706 return (ltb.tm_year - lta.tm_year)*365;
00707 }
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733 static gboolean
00734 qof_scan_date_internal (const char *buff, int *day, int *month, int *year,
00735 QofDateFormat which_format)
00736 {
00737 char *dupe, *tmp, *first_field, *second_field, *third_field;
00738 int iday, imonth, iyear;
00739 struct tm *now, utc;
00740 time_t secs;
00741
00742 if (!buff) return(FALSE);
00743
00744 if(which_format == QOF_DATE_FORMAT_UTC)
00745 {
00746 if(strptime(buff, QOF_UTC_DATE_FORMAT, &utc)) {
00747 *day = utc.tm_mday;
00748 *month = utc.tm_mon + 1;
00749 *year = utc.tm_year + 1900;
00750 return TRUE;
00751 }
00752 else { return FALSE; }
00753 }
00754 dupe = g_strdup (buff);
00755
00756 tmp = dupe;
00757 first_field = NULL;
00758 second_field = NULL;
00759 third_field = NULL;
00760
00761
00762 if (tmp) {
00763 static char *delims = ".,-+/\\() ";
00764
00765 first_field = strtok (tmp, delims);
00766 if (first_field) {
00767 second_field = strtok (NULL, delims);
00768 if (second_field) {
00769 third_field = strtok (NULL, delims);
00770 }
00771 }
00772 }
00773
00774
00775 time (&secs);
00776 now = localtime (&secs);
00777 iday = now->tm_mday;
00778 imonth = now->tm_mon+1;
00779 iyear = now->tm_year+1900;
00780
00781
00782 switch (which_format)
00783 {
00784 case QOF_DATE_FORMAT_LOCALE:
00785 if (buff[0] != '\0')
00786 {
00787 struct tm thetime;
00788
00789
00790 memset(&thetime, -1, sizeof(struct tm));
00791 strptime (buff, GNC_D_FMT, &thetime);
00792
00793 if (third_field) {
00794
00795 iyear = thetime.tm_year + 1900;
00796 iday = thetime.tm_mday;
00797 imonth = thetime.tm_mon + 1;
00798 } else if (second_field) {
00799
00800 if (thetime.tm_year == -1) {
00801
00802 iday = thetime.tm_mday;
00803 imonth = thetime.tm_mon + 1;
00804 } else if (thetime.tm_mon != -1) {
00805
00806 imonth = atoi(first_field);
00807 iday = atoi(second_field);
00808 } else {
00809
00810 iday = atoi(first_field);
00811 imonth = atoi(second_field);
00812 }
00813 } else if (first_field) {
00814 iday = atoi(first_field);
00815 }
00816 }
00817 break;
00818 case QOF_DATE_FORMAT_UK:
00819 case QOF_DATE_FORMAT_CE:
00820 if (third_field) {
00821 iday = atoi(first_field);
00822 imonth = atoi(second_field);
00823 iyear = atoi(third_field);
00824 } else if (second_field) {
00825 iday = atoi(first_field);
00826 imonth = atoi(second_field);
00827 } else if (first_field) {
00828 iday = atoi(first_field);
00829 }
00830 break;
00831 case QOF_DATE_FORMAT_ISO:
00832 if (third_field) {
00833 iyear = atoi(first_field);
00834 imonth = atoi(second_field);
00835 iday = atoi(third_field);
00836 } else if (second_field) {
00837 imonth = atoi(first_field);
00838 iday = atoi(second_field);
00839 } else if (first_field) {
00840 iday = atoi(first_field);
00841 }
00842 break;
00843 case QOF_DATE_FORMAT_US:
00844 default:
00845 if (third_field) {
00846 imonth = atoi(first_field);
00847 iday = atoi(second_field);
00848 iyear = atoi(third_field);
00849 } else if (second_field) {
00850 imonth = atoi(first_field);
00851 iday = atoi(second_field);
00852 } else if (first_field) {
00853 iday = atoi(first_field);
00854 }
00855 break;
00856 }
00857
00858 g_free (dupe);
00859
00860 if ((12 < imonth) || (31 < iday))
00861 {
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875 if ((which_format != prevQofDateFormat) &&
00876 qof_scan_date_internal(buff, day, month, year, prevQofDateFormat))
00877 {
00878 return(TRUE);
00879 }
00880 if ((12 < imonth) && (12 >= iday))
00881 {
00882 int tmp = imonth; imonth = iday; iday = tmp;
00883 }
00884 else
00885 {
00886 return FALSE;
00887 }
00888 }
00889
00890
00891
00892 if (iyear < 100)
00893 iyear += ((int) ((now->tm_year+1950-iyear)/100)) * 100;
00894
00895 if (year) *year=iyear;
00896 if (month) *month=imonth;
00897 if (day) *day=iday;
00898 return(TRUE);
00899 }
00900
00901 gboolean
00902 qof_scan_date (const char *buff, int *day, int *month, int *year)
00903 {
00904 return qof_scan_date_internal(buff, day, month, year, dateFormat);
00905 }
00906
00907 gboolean
00908 qof_scan_date_secs (const char *buff, time_t *secs)
00909 {
00910 gboolean rc;
00911 int day, month, year;
00912
00913 rc = qof_scan_date_internal(buff, &day, &month, &year, dateFormat);
00914 if (secs) *secs = xaccDMYToSec (day, month, year);
00915
00916 return rc;
00917 }
00918
00919
00920
00921
00922 char dateSeparator (void)
00923 {
00924 static char locale_separator = '\0';
00925
00926 switch (dateFormat)
00927 {
00928 case QOF_DATE_FORMAT_CE:
00929 return '.';
00930 case QOF_DATE_FORMAT_ISO:
00931 case QOF_DATE_FORMAT_UTC:
00932 return '-';
00933 case QOF_DATE_FORMAT_US:
00934 case QOF_DATE_FORMAT_UK:
00935 default:
00936 return '/';
00937 case QOF_DATE_FORMAT_LOCALE:
00938 if (locale_separator != '\0')
00939 return locale_separator;
00940 else
00941 {
00942 unsigned char string[256];
00943 struct tm *tm;
00944 time_t secs;
00945 unsigned char *s;
00946
00947 secs = time(NULL);
00948 tm = localtime(&secs);
00949 strftime(string, sizeof(string), GNC_D_FMT, tm);
00950
00951 for (s = string; s != '\0'; s++)
00952 if (!isdigit(*s))
00953 return (locale_separator = *s);
00954 }
00955 }
00956
00957 return '\0';
00958 }
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972 char *
00973 xaccDateUtilGetStamp (time_t thyme)
00974 {
00975 struct tm *stm;
00976
00977 stm = localtime (&thyme);
00978
00979 return g_strdup_printf("%04d%02d%02d%02d%02d%02d",
00980 (stm->tm_year + 1900),
00981 (stm->tm_mon +1),
00982 stm->tm_mday,
00983 stm->tm_hour,
00984 stm->tm_min,
00985 stm->tm_sec
00986 );
00987 }
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999 char *
01000 xaccDateUtilGetStampNow (void)
01001 {
01002 time_t now;
01003 time (&now);
01004 return xaccDateUtilGetStamp (now);
01005 }
01006
01007
01008
01009
01010
01011
01012
01013 Timespec
01014 gnc_iso8601_to_timespec_gmt(const char *str)
01015 {
01016 char buf[4];
01017 gchar *dupe;
01018 Timespec ts;
01019 struct tm stm;
01020 long int nsec =0;
01021
01022 ts.tv_sec=0;
01023 ts.tv_nsec=0;
01024 if (!str) return ts;
01025 dupe = g_strdup(str);
01026 stm.tm_year = atoi(str) - 1900;
01027 str = strchr (str, '-'); if (str) { str++; } else { return ts; }
01028 stm.tm_mon = atoi(str) - 1;
01029 str = strchr (str, '-'); if (str) { str++; } else { return ts; }
01030 stm.tm_mday = atoi(str);
01031
01032 str = strchr (str, ' '); if (str) { str++; } else { return ts; }
01033 stm.tm_hour = atoi(str);
01034 str = strchr (str, ':'); if (str) { str++; } else { return ts; }
01035 stm.tm_min = atoi(str);
01036 str = strchr (str, ':'); if (str) { str++; } else { return ts; }
01037 stm.tm_sec = atoi (str);
01038
01039
01040
01041 if (strchr (str, '.'))
01042 {
01043 int decimals, i, multiplier=1000000000;
01044 str = strchr (str, '.') +1;
01045 decimals = strcspn (str, "+- ");
01046 for (i=0; i<decimals; i++) multiplier /= 10;
01047 nsec = atoi(str) * multiplier;
01048 }
01049 stm.tm_isdst = -1;
01050
01051
01052 str += strcspn (str, "+-");
01053 if (str)
01054 {
01055 buf[0] = str[0];
01056 buf[1] = str[1];
01057 buf[2] = str[2];
01058 buf[3] = 0;
01059 stm.tm_hour -= atoi(buf);
01060
01061 str +=3;
01062 if ('.' == *str) str++;
01063 if (isdigit ((unsigned char)*str) && isdigit ((unsigned char)*(str+1)))
01064 {
01065 int cyn;
01066
01067 if ('+' == buf[0]) { cyn = -1; } else { cyn = +1; }
01068 buf[0] = str[0];
01069 buf[1] = str[1];
01070 buf[2] = str[2];
01071 buf[3] = 0;
01072 stm.tm_min += cyn * atoi(buf);
01073 }
01074 }
01075
01076
01077
01078
01079
01080
01081
01082 {
01083 struct tm tmp_tm;
01084 struct tm tm;
01085 long int tz;
01086 int tz_hour;
01087 time_t secs;
01088
01089
01090
01091 tmp_tm = stm;
01092 tmp_tm.tm_isdst = -1;
01093
01094 secs = mktime (&tmp_tm);
01095
01096 if(secs < 0)
01097 {
01098
01099
01100 PWARN (" mktime failed to handle daylight saving: "
01101 "tm_hour=%d tm_year=%d tm_min=%d tm_sec=%d tm_isdst=%d for string=%s",
01102 stm.tm_hour, stm.tm_year, stm.tm_min,
01103 stm.tm_sec, stm.tm_isdst, dupe );
01104 tmp_tm.tm_hour++;
01105 secs = mktime (&tmp_tm);
01106 if (secs < 0)
01107 {
01108
01109
01110 tmp_tm.tm_hour -= 2;
01111 secs = mktime (&tmp_tm);
01112 }
01113 if (secs < 0)
01114 {
01115
01116 PERR (" unable to recover from buggy mktime ");
01117 g_free(dupe);
01118 return ts;
01119 }
01120 }
01121
01122
01123
01124
01125
01126
01127 tm = *localtime_r (&secs, &tm);
01128
01129 tz = gnc_timezone (&tmp_tm);
01130
01131 tz_hour = tz / 3600;
01132 stm.tm_hour -= tz_hour;
01133 stm.tm_min -= (tz % 3600) / 60;
01134 stm.tm_isdst = tmp_tm.tm_isdst;
01135 ts.tv_sec = mktime (&stm);
01136 if(ts.tv_sec < 0) {
01137 PWARN (" mktime failed to adjust calculated time:"
01138 " tm_hour=%d tm_year=%d tm_min=%d tm_sec=%d tm_isdst=%d",
01139 stm.tm_hour, stm.tm_year, stm.tm_min,
01140 stm.tm_sec, stm.tm_isdst );
01141
01142 ts.tv_sec = secs - tz;
01143 }
01144 ts.tv_nsec = nsec;
01145 }
01146 g_free(dupe);
01147 return ts;
01148 }
01149
01150
01151
01152
01153 char *
01154 gnc_timespec_to_iso8601_buff (Timespec ts, char * buff)
01155 {
01156 int len, tz_hour, tz_min;
01157 long int secs;
01158 char cyn;
01159 time_t tmp;
01160 struct tm parsed;
01161
01162 tmp = ts.tv_sec;
01163 localtime_r(&tmp, &parsed);
01164
01165 secs = gnc_timezone (&parsed);
01166 tz_hour = secs / 3600;
01167 tz_min = (secs % 3600) / 60;
01168
01169
01170
01171
01172 cyn = '-';
01173 if (0>tz_hour) { cyn = '+'; tz_hour = -tz_hour; }
01174
01175 len = sprintf (buff, "%4d-%02d-%02d %02d:%02d:%02d.%06ld %c%02d%02d",
01176 parsed.tm_year + 1900,
01177 parsed.tm_mon + 1,
01178 parsed.tm_mday,
01179 parsed.tm_hour,
01180 parsed.tm_min,
01181 parsed.tm_sec,
01182 ts.tv_nsec / 1000,
01183 cyn,
01184 tz_hour,
01185 tz_min);
01186
01187
01188 buff += len;
01189 return buff;
01190 }
01191
01192 int
01193 gnc_timespec_last_mday (Timespec t)
01194 {
01195 struct tm *result;
01196 time_t t_secs = t.tv_sec + (t.tv_nsec / NANOS_PER_SECOND);
01197 result = localtime(&t_secs);
01198 return date_get_last_mday (result);
01199 }
01200
01201 void
01202 gnc_timespec2dmy (Timespec t, int *day, int *month, int *year)
01203 {
01204 struct tm *result;
01205 time_t t_secs = t.tv_sec + (t.tv_nsec / NANOS_PER_SECOND);
01206 result = localtime(&t_secs);
01207
01208 if (day) *day = result->tm_mday;
01209 if (month) *month = result->tm_mon+1;
01210 if (year) *year = result->tm_year+1900;
01211 }
01212
01213
01214
01215
01216
01217
01218 time_t
01219 xaccDMYToSec (int day, int month, int year)
01220 {
01221 struct tm stm;
01222 time_t secs;
01223
01224 stm.tm_year = year - 1900;
01225 stm.tm_mon = month - 1;
01226 stm.tm_mday = day;
01227 gnc_tm_set_day_start(&stm);
01228
01229
01230 secs = mktime (&stm);
01231
01232 return secs;
01233 }
01234
01235
01236 #define THIRTY_TWO_YEARS 0x3c30fc00LL
01237
01238 static Timespec
01239 gnc_dmy2timespec_internal (int day, int month, int year, gboolean start_of_day)
01240 {
01241 Timespec result;
01242 struct tm date;
01243 long long secs = 0;
01244 long long era = 0;
01245
01246 year -= 1900;
01247
01248
01249
01250
01251 if ((2 > year) || (136 < year))
01252 {
01253 era = year / 32;
01254 year %= 32;
01255 if (0 > year) { year += 32; era -= 1; }
01256 }
01257
01258 date.tm_year = year;
01259 date.tm_mon = month - 1;
01260 date.tm_mday = day;
01261
01262 if (start_of_day)
01263 gnc_tm_set_day_start(&date);
01264 else
01265 gnc_tm_set_day_end(&date);
01266
01267
01268 secs = mktime (&date);
01269
01270 secs += era * THIRTY_TWO_YEARS;
01271
01272 result.tv_sec = secs;
01273 result.tv_nsec = 0;
01274
01275 return result;
01276 }
01277
01278 Timespec
01279 gnc_dmy2timespec (int day, int month, int year)
01280 {
01281 return gnc_dmy2timespec_internal (day, month, year, TRUE);
01282 }
01283
01284 Timespec
01285 gnc_dmy2timespec_end (int day, int month, int year)
01286 {
01287 return gnc_dmy2timespec_internal (day, month, year, FALSE);
01288 }
01289
01290
01291
01292
01293 long int
01294 gnc_timezone (struct tm *tm)
01295 {
01296 g_return_val_if_fail (tm != NULL, 0);
01297
01298 #ifdef HAVE_STRUCT_TM_GMTOFF
01299
01300
01301 return -(tm->tm_gmtoff);
01302 #else
01303
01304
01305
01306 return (long int)(timezone - (tm->tm_isdst > 0 ? 3600 : 0));
01307 #endif
01308 }
01309
01310
01311 void
01312 timespecFromTime_t( Timespec *ts, time_t t )
01313 {
01314 ts->tv_sec = t;
01315 ts->tv_nsec = 0;
01316 }
01317
01318 time_t
01319 timespecToTime_t (Timespec ts)
01320 {
01321 return ts.tv_sec;
01322 }
01323
01324 void
01325 gnc_tm_get_day_start (struct tm *tm, time_t time_val)
01326 {
01327
01328 tm = localtime_r(&time_val, tm);
01329 gnc_tm_set_day_start(tm);
01330 }
01331
01332 void
01333 gnc_tm_get_day_end (struct tm *tm, time_t time_val)
01334 {
01335
01336 tm = localtime_r(&time_val, tm);
01337 gnc_tm_set_day_end(tm);
01338 }
01339
01340 time_t
01341 gnc_timet_get_day_start (time_t time_val)
01342 {
01343 struct tm tm;
01344
01345 gnc_tm_get_day_start(&tm, time_val);
01346 return mktime(&tm);
01347 }
01348
01349 time_t
01350 gnc_timet_get_day_end (time_t time_val)
01351 {
01352 struct tm tm;
01353
01354 gnc_tm_get_day_end(&tm, time_val);
01355 return mktime(&tm);
01356 }
01357
01358
01359 #ifndef GNUCASH_MAJOR_VERSION
01360 time_t
01361 gnc_timet_get_day_start_gdate (GDate *date)
01362 {
01363 struct tm stm;
01364 time_t secs;
01365
01366 stm.tm_year = g_date_get_year (date) - 1900;
01367 stm.tm_mon = g_date_get_month (date) - 1;
01368 stm.tm_mday = g_date_get_day (date);
01369 gnc_tm_set_day_start(&stm);
01370
01371
01372 secs = mktime (&stm);
01373 return secs;
01374 }
01375
01376 time_t
01377 gnc_timet_get_day_end_gdate (GDate *date)
01378 {
01379 struct tm stm;
01380 time_t secs;
01381
01382 stm.tm_year = g_date_get_year (date) - 1900;
01383 stm.tm_mon = g_date_get_month (date) - 1;
01384 stm.tm_mday = g_date_get_day (date);
01385 gnc_tm_set_day_end(&stm);
01386
01387
01388 secs = mktime (&stm);
01389 return secs;
01390 }
01391 #endif
01392
01393
01394
01395 void
01396 gnc_tm_get_today_start (struct tm *tm)
01397 {
01398 gnc_tm_get_day_start(tm, time(NULL));
01399 }
01400
01401 void
01402 gnc_tm_get_today_end (struct tm *tm)
01403 {
01404 gnc_tm_get_day_end(tm, time(NULL));
01405 }
01406
01407 time_t
01408 gnc_timet_get_today_start (void)
01409 {
01410 struct tm tm;
01411
01412 gnc_tm_get_day_start(&tm, time(NULL));
01413 return mktime(&tm);
01414 }
01415
01416 time_t
01417 gnc_timet_get_today_end (void)
01418 {
01419 struct tm tm;
01420
01421 gnc_tm_get_day_end(&tm, time(NULL));
01422 return mktime(&tm);
01423 }
01424
01425 gboolean
01426 qof_date_add_days(Timespec *ts, gint days)
01427 {
01428 struct tm tm;
01429 time_t tt;
01430
01431 g_return_val_if_fail(ts, FALSE);
01432 tt = timespecToTime_t(*ts);
01433 #ifdef HAVE_GMTIME_R
01434 tm = *gmtime_r(&tt, &tm);
01435 #else
01436 tm = *gmtime(&tt);
01437 #endif
01438 tm.tm_mday += days;
01439
01440
01441 tt = mktime(&tm);
01442 if(tt < 0) { return FALSE; }
01443 timespecFromTime_t(ts, tt);
01444 return TRUE;
01445 }
01446
01447 gboolean
01448 qof_date_add_months(Timespec *ts, gint months, gboolean track_last_day)
01449 {
01450 struct tm tm;
01451 time_t tt;
01452 gint new_last_mday;
01453 gboolean was_last_day;
01454
01455 g_return_val_if_fail(ts, FALSE);
01456 tt = timespecToTime_t(*ts);
01457 #ifdef HAVE_GMTIME_R
01458 tm = *gmtime_r(&tt, &tm);
01459 #else
01460 tm = *gmtime(&tt);
01461 #endif
01462 was_last_day = date_is_last_mday(&tm);
01463 tm.tm_mon += months;
01464 while (tm.tm_mon > 11) {
01465 tm.tm_mon -= 12;
01466 tm.tm_year++;
01467 }
01468 if (track_last_day) {
01469
01470 new_last_mday = date_get_last_mday(&tm);
01471 if (was_last_day || (tm.tm_mday > new_last_mday)) {
01472 tm.tm_mday = new_last_mday;
01473 }
01474 }
01475 tt = mktime(&tm);
01476 if(tt < 0) { return FALSE; }
01477 timespecFromTime_t(ts, tt);
01478 return TRUE;
01479 }
01480
01481
01482