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
00028
00029 #ifdef HAVE_CONFIG_H
00030 # include <config.h>
00031 #endif
00032
00033 #define DISABLE_DEBUGLOG
00034
00035
00036 #include "gwentime_p.h"
00037 #include <gwenhywfar/gwentime.h>
00038 #include <gwenhywfar/debug.h>
00039
00040 #include <time.h>
00041 #include <ctype.h>
00042 #include <errno.h>
00043 #include <string.h>
00044
00045
00046 GWEN_LIST_FUNCTIONS(GWEN_TIME_TMPLCHAR, GWEN_TimeTmplChar)
00047
00048
00049
00050 GWEN_TIME *GWEN_CurrentTime(void){
00051 GWEN_TIME *t;
00052
00053 GWEN_NEW_OBJECT(GWEN_TIME, t);
00054 if (GWEN_Time__GetCurrentTime(t)) {
00055 DBG_ERROR(GWEN_LOGDOMAIN, "Could not get current time");
00056 GWEN_Time_free(t);
00057 return 0;
00058 }
00059 return t;
00060 }
00061
00062
00063
00064 GWEN_TIME *GWEN_Time_fromSeconds(uint32_t secs) {
00065 GWEN_TIME *t;
00066
00067 GWEN_NEW_OBJECT(GWEN_TIME, t);
00068 t->secs=secs;
00069 return t;
00070 }
00071
00072
00073
00074 int GWEN_Time_AddSeconds(GWEN_TIME *ti,
00075 uint32_t secs) {
00076 uint32_t i;
00077
00078 assert(ti);
00079 i=ti->secs+secs;
00080 if (i<ti->secs) {
00081 DBG_INFO(GWEN_LOGDOMAIN,
00082 "Overflow when adding %u seconds", secs);
00083 return GWEN_ERROR_INVALID;
00084 }
00085 ti->secs=i;
00086 return 0;
00087 }
00088
00089
00090
00091 int GWEN_Time_SubSeconds(GWEN_TIME *ti,
00092 uint32_t secs) {
00093 assert(ti);
00094
00095 if (ti->secs<secs) {
00096 DBG_INFO(GWEN_LOGDOMAIN,
00097 "Underflow when subtracting %u seconds",
00098 secs);
00099 return GWEN_ERROR_INVALID;
00100 }
00101 ti->secs-=secs;
00102 return 0;
00103 }
00104
00105
00106 void GWEN_Time__SetSecsAndMSecs(GWEN_TIME *ti,
00107 uint32_t secs,
00108 uint32_t msecs){
00109 assert(ti);
00110 ti->secs=secs;
00111 ti->msecs=msecs;
00112 }
00113
00114
00115
00116 int GWEN_Time_toDb(const GWEN_TIME *t, GWEN_DB_NODE *db) {
00117 GWEN_DB_NODE *dbT;
00118 int i1, i2, i3;
00119
00120 assert(t);
00121 assert(db);
00122 dbT=GWEN_DB_GetGroup(db, GWEN_DB_FLAGS_DEFAULT, "date");
00123 GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
00124 "inUtc", 1);
00125
00126 assert(dbT);
00127 if (GWEN_Time_GetBrokenDownUtcDate(t, &i1, &i2, &i3)) {
00128 DBG_INFO(GWEN_LOGDOMAIN, "Could not break down date");
00129 return -1;
00130 }
00131 GWEN_DB_SetIntValue(dbT, GWEN_DB_FLAGS_OVERWRITE_VARS,
00132 "day", i1);
00133 GWEN_DB_SetIntValue(dbT, GWEN_DB_FLAGS_OVERWRITE_VARS,
00134 "month", i2+1);
00135 GWEN_DB_SetIntValue(dbT, GWEN_DB_FLAGS_OVERWRITE_VARS,
00136 "year", i3);
00137
00138 dbT=GWEN_DB_GetGroup(db, GWEN_DB_FLAGS_DEFAULT, "time");
00139 assert(dbT);
00140 if (GWEN_Time_GetBrokenDownUtcTime(t, &i1, &i2, &i3)) {
00141 DBG_INFO(GWEN_LOGDOMAIN, "Could not break down time");
00142 return -1;
00143 }
00144 GWEN_DB_SetIntValue(dbT, GWEN_DB_FLAGS_OVERWRITE_VARS,
00145 "hour", i1);
00146 GWEN_DB_SetIntValue(dbT, GWEN_DB_FLAGS_OVERWRITE_VARS,
00147 "min", i2);
00148 GWEN_DB_SetIntValue(dbT, GWEN_DB_FLAGS_OVERWRITE_VARS,
00149 "sec", i3);
00150
00151 return 0;
00152 }
00153
00154
00155
00156 GWEN_TIME *GWEN_Time_fromDb(GWEN_DB_NODE *db) {
00157 GWEN_TIME *t;
00158 GWEN_DB_NODE *dbT;
00159 int day, month, year;
00160 int hour, min, sec;
00161 int inUtc;
00162
00163 day=month=year=0;
00164 hour=min=sec=0;
00165
00166 inUtc=GWEN_DB_GetIntValue(db, "inUtc", 0, 0);
00167 dbT=GWEN_DB_GetGroup(db, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "date");
00168 if (dbT) {
00169 day=GWEN_DB_GetIntValue(dbT, "day", 0, 0);
00170 month=GWEN_DB_GetIntValue(dbT, "month", 0, 1)-1;
00171 year=GWEN_DB_GetIntValue(dbT, "year", 0, 0);
00172 if (!day || !year) {
00173 DBG_INFO(GWEN_LOGDOMAIN, "Bad date in DB");
00174 return 0;
00175 }
00176 }
00177
00178 dbT=GWEN_DB_GetGroup(db, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "time");
00179 if (dbT) {
00180 hour=GWEN_DB_GetIntValue(dbT, "hour", 0, 0);
00181 min=GWEN_DB_GetIntValue(dbT, "min", 0, 0);
00182 sec=GWEN_DB_GetIntValue(dbT, "sec", 0, 0);
00183 }
00184
00185 DBG_VERBOUS(GWEN_LOGDOMAIN,
00186 "Creating time from this: %04d/%02d/%02d - %02d:%02d:%02d (%d)",
00187 year, month, day, hour, min, sec, inUtc);
00188 t=GWEN_Time_new(year, month, day, hour, min, sec, inUtc);
00189 if (!t) {
00190 DBG_INFO(GWEN_LOGDOMAIN, "Bad date/time");
00191 return 0;
00192 }
00193
00194 return t;
00195 }
00196
00197
00198
00199 GWEN_TIME *GWEN_Time__fromString(const char *s, const char *tmpl, int inUtc){
00200 int year, month, day;
00201 int hour, min, sec;
00202 const char *p;
00203 const char *t;
00204 GWEN_TIME *gwt;
00205
00206 assert(s);
00207 assert(tmpl);
00208 year=month=day=0;
00209 hour=min=sec=0;
00210
00211 p=s;
00212 t=tmpl;
00213 while(*t && *p) {
00214 int i;
00215
00216 if (*t=='*') {
00217 t++;
00218 if (!*t) {
00219 DBG_ERROR(GWEN_LOGDOMAIN, "Bad pattern: Must not end with \"*\"");
00220 return 0;
00221 }
00222 i=0;
00223 while(*p) {
00224 if (!isdigit((int)*p))
00225 break;
00226 if (*p==*t)
00227 break;
00228 i*=10;
00229 i+=(*p)-'0';
00230 p++;
00231 }
00232 }
00233 else {
00234 if (isdigit((int)*p))
00235 i=(*p)-'0';
00236 else
00237 i=-1;
00238 p++;
00239 }
00240
00241 if (i==-1 && strchr("YMDhms", *t)!=NULL) {
00242 DBG_INFO(GWEN_LOGDOMAIN,
00243 "No more digits at [%s], continueing", t);
00244 p--;
00245 }
00246 else {
00247 switch(*t) {
00248 case 'Y':
00249 if (i==-1) {
00250 DBG_INFO(GWEN_LOGDOMAIN, "here");
00251 return 0;
00252 }
00253 year*=10;
00254 year+=i;
00255 break;
00256 case 'M':
00257 if (i==-1) {
00258 DBG_INFO(GWEN_LOGDOMAIN, "here");
00259 return 0;
00260 }
00261 month*=10;
00262 month+=i;
00263 break;
00264 case 'D':
00265 if (i==-1) {
00266 DBG_INFO(GWEN_LOGDOMAIN, "here");
00267 return 0;
00268 }
00269 day*=10;
00270 day+=i;
00271 break;
00272 case 'h':
00273 if (i==-1) {
00274 DBG_INFO(GWEN_LOGDOMAIN, "here");
00275 return 0;
00276 }
00277 hour*=10;
00278 hour+=i;
00279 break;
00280 case 'm':
00281 if (i==-1) {
00282 DBG_INFO(GWEN_LOGDOMAIN, "here");
00283 return 0;
00284 }
00285 min*=10;
00286 min+=i;
00287 break;
00288 case 's':
00289 if (i==-1) {
00290 DBG_INFO(GWEN_LOGDOMAIN, "here");
00291 return 0;
00292 }
00293 sec*=10;
00294 sec+=i;
00295 break;
00296 default:
00297 DBG_VERBOUS(GWEN_LOGDOMAIN,
00298 "Unknown character in template, will skip in both strings");
00299 break;
00300 }
00301 }
00302 t++;
00303 }
00304
00305 if (year<100)
00306 year+=2000;
00307 if (day==0)
00308 day=1;
00309
00310 DBG_DEBUG(GWEN_LOGDOMAIN,
00311 "Got this date/time: %04d/%02d/%02d, %02d:%02d:%02d",
00312 year, month-1, day, hour, min, sec);
00313
00314
00315 gwt=GWEN_Time_new(year, month-1, day, hour, min, sec, inUtc);
00316 if (!gwt) {
00317 DBG_INFO(GWEN_LOGDOMAIN, "here");
00318 return 0;
00319 }
00320 return gwt;
00321 }
00322
00323
00324
00325 GWEN_TIME *GWEN_Time_fromString(const char *s, const char *tmpl){
00326 return GWEN_Time__fromString(s, tmpl, 0);
00327 }
00328
00329
00330
00331 GWEN_TIME *GWEN_Time_fromUtcString(const char *s, const char *tmpl){
00332 return GWEN_Time__fromString(s, tmpl, 1);
00333 }
00334
00335
00336
00337 GWEN_TIME *GWEN_Time_new(int year,
00338 int month,
00339 int day,
00340 int hour,
00341 int min,
00342 int sec,
00343 int inUtc){
00344 uint32_t s;
00345
00346 if (inUtc)
00347 s=GWEN_Time__mktimeUtc(year, month, day, hour, min, sec);
00348 else {
00349 struct tm ti;
00350 struct tm *tp;
00351 time_t tt;
00352
00353 tt=time(0);
00354 tp=localtime(&tt);
00355 assert(tp);
00356 memmove(&ti, tp, sizeof(ti));
00357 ti.tm_sec=sec;
00358 ti.tm_min=min;
00359 ti.tm_hour=hour;
00360 if (year<100) {
00361 if (year<72)
00362 year+=2000;
00363 year+=1900;
00364 }
00365 ti.tm_year=year-1900;
00366 ti.tm_mon=month;
00367 ti.tm_mday=day;
00368 ti.tm_yday=0;
00369 ti.tm_wday=0;
00370 tt=mktime(&ti);
00371 assert(tt!=(time_t)-1);
00372 s=(uint32_t)tt;
00373 }
00374 return GWEN_Time_fromSeconds(s);
00375 }
00376
00377
00378
00379 uint32_t GWEN_Time__mktimeUtc(int year,
00380 int month,
00381 int day,
00382 int hour,
00383 int min,
00384 int sec) {
00385 uint32_t result;
00386 int i;
00387 int isLeap;
00388 const uint32_t hoursecs=60*60;
00389 const uint32_t daysecs=24*hoursecs;
00390 const uint32_t yearsecs=365*daysecs;
00391 const uint32_t monthDays[12]=
00392 {
00393 31, 28, 31, 30,
00394 31, 30, 31, 31,
00395 30, 31, 30, 31
00396 };
00397
00398 result=(year-1970)*yearsecs;
00399
00400 for (i=1970; i<year; i++)
00401 if ((((i % 4)==0) &&
00402 ((i % 100)!=0)) ||
00403 ((i % 400)==0))
00404 result+=daysecs;
00405
00406 isLeap=((((year % 4)==0) &&
00407 ((year % 100)!=0)) ||
00408 ((year % 400)==0));
00409
00410 for (i=0; i<month; i++)
00411 if (isLeap && i==1)
00412 result+=29*daysecs;
00413 else
00414 result+=monthDays[i]*daysecs;
00415
00416 result+=(day-1)*daysecs;
00417 result+=(hour*hoursecs);
00418 result+=min*60;
00419 result+=sec;
00420
00421 return result;
00422 }
00423
00424
00425
00426 GWEN_TIME *GWEN_Time_dup(const GWEN_TIME *t){
00427 GWEN_TIME *newT;
00428
00429 assert(t);
00430 GWEN_NEW_OBJECT(GWEN_TIME, newT);
00431 newT->secs=t->secs;
00432 newT->msecs=t->msecs;
00433 return newT;
00434 }
00435
00436
00437
00438 void GWEN_Time_free(GWEN_TIME *t){
00439 if (t) {
00440 GWEN_FREE_OBJECT(t);
00441 }
00442 }
00443
00444
00445
00446 double GWEN_Time_Diff(const GWEN_TIME *t1, const GWEN_TIME *t0){
00447 double d;
00448
00449 assert(t1);
00450 assert(t0);
00451
00452 d=1000.0*((double)(t1->secs)-(double)(t0->secs));
00453 d+=(double)((double)(t1->msecs)-(double)(t0->msecs));
00454
00455 return d;
00456 }
00457
00458
00459
00460 double GWEN_Time_DiffSeconds(const GWEN_TIME *t1, const GWEN_TIME *t0){
00461 double d;
00462
00463 assert(t1);
00464 assert(t0);
00465
00466 d=(double)(t1->secs)-(double)(t0->secs);
00467 d+=((double)((double)(t1->msecs)-(double)(t0->msecs)))/1000.0;
00468
00469 return d;
00470 }
00471
00472
00473
00474 int GWEN_Time_Compare(const GWEN_TIME *t1, const GWEN_TIME *t0){
00475 if (t1 && t0) {
00476 if (t1->secs<t0->secs)
00477 return -1;
00478 else if (t1->secs>t0->secs)
00479 return 1;
00480 else {
00481 if (t1->msecs<t0->msecs)
00482 return -1;
00483 else if (t1->msecs>t0->msecs)
00484 return 1;
00485 else
00486 return 0;
00487 }
00488 }
00489 else if (t1)
00490 return 1;
00491 else if (t0)
00492 return -1;
00493
00494 return 0;
00495 }
00496
00497
00498
00499 double GWEN_Time_Milliseconds(const GWEN_TIME *t){
00500 assert(t);
00501 return (double)((t->secs*1000)+(t->msecs));
00502 }
00503
00504
00505
00506 uint32_t GWEN_Time_Seconds(const GWEN_TIME *t){
00507 assert(t);
00508 return t->secs;
00509 }
00510
00511
00512
00513 int GWEN_Time_GetBrokenDownTime(const GWEN_TIME *t,
00514 int *hours,
00515 int *mins,
00516 int *secs){
00517 struct tm *tb;
00518 time_t tt;
00519
00520 assert(t);
00521 tt=t->secs;
00522 tb=localtime(&tt);
00523 if (!tb) {
00524 DBG_ERROR(GWEN_LOGDOMAIN, "localtime(): %s", strerror(errno));
00525 return -1;
00526 }
00527 *hours=tb->tm_hour;
00528 *mins=tb->tm_min;
00529 *secs=tb->tm_sec;
00530 return 0;
00531 }
00532
00533
00534
00535 int GWEN_Time_GetBrokenDownUtcTime(const GWEN_TIME *t,
00536 int *hours,
00537 int *mins,
00538 int *secs){
00539 struct tm *tb;
00540 time_t tt;
00541
00542 assert(t);
00543 tt=t->secs;
00544 tb=gmtime(&tt);
00545 if (!tb) {
00546 DBG_ERROR(GWEN_LOGDOMAIN, "gmtime(): %s", strerror(errno));
00547 return -1;
00548 }
00549 *hours=tb->tm_hour;
00550 *mins=tb->tm_min;
00551 *secs=tb->tm_sec;
00552 return 0;
00553 }
00554
00555
00556
00557 int GWEN_Time_GetBrokenDownDate(const GWEN_TIME *t,
00558 int *days,
00559 int *month,
00560 int *year){
00561 struct tm *tb;
00562 time_t tt;
00563
00564 assert(t);
00565 tt=t->secs;
00566 tb=localtime(&tt);
00567 if (!tb) {
00568 DBG_ERROR(GWEN_LOGDOMAIN, "localtime(): %s", strerror(errno));
00569 return -1;
00570 }
00571 *days=tb->tm_mday;
00572 *month=tb->tm_mon;
00573 *year=tb->tm_year+1900;
00574 return 0;
00575 }
00576
00577
00578
00579 int GWEN_Time_GetBrokenDownUtcDate(const GWEN_TIME *t,
00580 int *days,
00581 int *month,
00582 int *year){
00583 struct tm *tb;
00584 time_t tt;
00585
00586 assert(t);
00587 tt=t->secs;
00588 tb=gmtime(&tt);
00589 if (!tb) {
00590 DBG_ERROR(GWEN_LOGDOMAIN, "gmtime(): %s", strerror(errno));
00591 return -1;
00592 }
00593 *days=tb->tm_mday;
00594 *month=tb->tm_mon;
00595 *year=tb->tm_year+1900;
00596 return 0;
00597 }
00598
00599
00600
00601
00602 struct tm GWEN_Time_toTm(const GWEN_TIME *t) {
00603 struct tm *tb;
00604 time_t tt;
00605
00606 assert(t);
00607 tt=t->secs;
00608 tb=localtime(&tt);
00609 return *tb;
00610 }
00611
00612 time_t GWEN_Time_toTime_t(const GWEN_TIME *t) {
00613 assert(t);
00614 return t->secs;
00615 }
00616
00617
00618
00619
00620 GWEN_TIME_TMPLCHAR *GWEN_TimeTmplChar_new(char c) {
00621 GWEN_TIME_TMPLCHAR *e;
00622
00623 GWEN_NEW_OBJECT(GWEN_TIME_TMPLCHAR, e);
00624 GWEN_LIST_INIT(GWEN_TIME_TMPLCHAR, e);
00625 e->character=c;
00626 return e;
00627 }
00628
00629
00630
00631 void GWEN_TimeTmplChar_free(GWEN_TIME_TMPLCHAR *e) {
00632 if (e) {
00633 free(e->content);
00634 GWEN_LIST_FINI(GWEN_TIME_TMPLCHAR, e);
00635 GWEN_FREE_OBJECT(e);
00636 }
00637 }
00638
00639
00640 GWEN_TIME_TMPLCHAR *GWEN_Time__findTmplChar(GWEN_TIME_TMPLCHAR_LIST *ll,
00641 char c) {
00642 GWEN_TIME_TMPLCHAR *e;
00643
00644 e=GWEN_TimeTmplChar_List_First(ll);
00645 while(e) {
00646 if (e->character==c)
00647 break;
00648 e=GWEN_TimeTmplChar_List_Next(e);
00649 }
00650
00651 return e;
00652 }
00653
00654
00655
00656
00657 void GWEN_Time__sampleTmplChars(GWEN_UNUSED const GWEN_TIME *t, const char *tmpl,
00658 GWEN_UNUSED GWEN_BUFFER *buf,
00659 GWEN_TIME_TMPLCHAR_LIST *ll) {
00660 const char *s;
00661
00662 s=tmpl;
00663 while(*s) {
00664 if (strchr("YMDhms", *s)) {
00665 GWEN_TIME_TMPLCHAR *e;
00666
00667 e=GWEN_Time__findTmplChar(ll, *s);
00668 if (!e) {
00669
00670 e=GWEN_TimeTmplChar_new(*s);
00671 GWEN_TimeTmplChar_List_Add(e, ll);
00672 }
00673 assert(e);
00674 e->count++;
00675 }
00676 else {
00677 DBG_DEBUG(GWEN_LOGDOMAIN, "Unknown character in template (%02x)",
00678 *s);
00679 }
00680 s++;
00681 }
00682 }
00683
00684
00685
00686 void GWEN_Time__fillTmplChars(const GWEN_TIME *t,
00687 GWEN_TIME_TMPLCHAR_LIST *ll,
00688 int useUtc) {
00689 GWEN_TIME_TMPLCHAR *e;
00690 int year, month, day, hour, minute, second;
00691
00692 if (useUtc) {
00693 GWEN_Time_GetBrokenDownUtcDate(t, &day, &month, &year);
00694 GWEN_Time_GetBrokenDownUtcTime(t, &hour, &minute, &second);
00695 }
00696 else {
00697 GWEN_Time_GetBrokenDownDate(t, &day, &month, &year);
00698 GWEN_Time_GetBrokenDownTime(t, &hour, &minute, &second);
00699 }
00700
00701 e=GWEN_TimeTmplChar_List_First(ll);
00702 while(e) {
00703 int v;
00704 char buffer[32];
00705
00706 switch(e->character) {
00707 case 'Y': v=year; break;
00708 case 'M': v=month+1; break;
00709 case 'D': v=day; break;
00710 case 'h': v=hour; break;
00711 case 'm': v=minute; break;
00712 case 's': v=second; break;
00713 default: v=-1; break;
00714 }
00715 if (v==-1) {
00716 DBG_ERROR(GWEN_LOGDOMAIN, "Unknown character, should not happen here");
00717 abort();
00718 }
00719 buffer[0]=0;
00720 snprintf(buffer, sizeof(buffer)-1, "%0*d", GWEN_TIME_TMPL_MAX_COUNT, v);
00721 buffer[sizeof(buffer)-1]=0;
00722 e->content=strdup(buffer);
00723 e->nextChar=strlen(e->content)-(e->count);
00724 e=GWEN_TimeTmplChar_List_Next(e);
00725 }
00726 }
00727
00728
00729
00730
00731 int GWEN_Time__toString(const GWEN_TIME *t, const char *tmpl,
00732 GWEN_BUFFER *buf, int useUtc) {
00733 GWEN_TIME_TMPLCHAR_LIST *ll;
00734 const char *s;
00735
00736 ll=GWEN_TimeTmplChar_List_new();
00737 GWEN_Time__sampleTmplChars(t, tmpl, buf, ll);
00738 GWEN_Time__fillTmplChars(t, ll, useUtc);
00739
00740 s=tmpl;
00741 while(*s) {
00742 if (strchr("YMDhms", *s)) {
00743 GWEN_TIME_TMPLCHAR *e;
00744 char c;
00745
00746 e=GWEN_Time__findTmplChar(ll, *s);
00747 assert(e);
00748 assert(e->content);
00749 if (s[1]=='*') {
00750
00751 GWEN_Buffer_AppendString(buf, e->content);
00752
00753 s++;
00754 }
00755 else {
00756 c=e->content[e->nextChar++];
00757 assert(c);
00758 GWEN_Buffer_AppendByte(buf, c);
00759 }
00760 }
00761 else
00762 GWEN_Buffer_AppendByte(buf, *s);
00763 s++;
00764 }
00765 GWEN_TimeTmplChar_List_free(ll);
00766 return 0;
00767 }
00768
00769
00770
00771 int GWEN_Time_toString(const GWEN_TIME *t, const char *tmpl,
00772 GWEN_BUFFER *buf) {
00773 return GWEN_Time__toString(t, tmpl, buf, 0);
00774 }
00775
00776
00777
00778 int GWEN_Time_toUtcString(const GWEN_TIME *t, const char *tmpl,
00779 GWEN_BUFFER *buf) {
00780 return GWEN_Time__toString(t, tmpl, buf, 1);
00781 }
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791