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(){
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
00308 DBG_DEBUG(GWEN_LOGDOMAIN,
00309 "Got this date/time: %04d/%02d/%02d, %02d:%02d:%02d",
00310 year, month-1, day, hour, min, sec);
00311
00312
00313 gwt=GWEN_Time_new(year, month-1, day, hour, min, sec, inUtc);
00314 if (!gwt) {
00315 DBG_INFO(GWEN_LOGDOMAIN, "here");
00316 return 0;
00317 }
00318 return gwt;
00319 }
00320
00321
00322
00323 GWEN_TIME *GWEN_Time_fromString(const char *s, const char *tmpl){
00324 return GWEN_Time__fromString(s, tmpl, 0);
00325 }
00326
00327
00328
00329 GWEN_TIME *GWEN_Time_fromUtcString(const char *s, const char *tmpl){
00330 return GWEN_Time__fromString(s, tmpl, 1);
00331 }
00332
00333
00334
00335 GWEN_TIME *GWEN_Time_new(int year,
00336 int month,
00337 int day,
00338 int hour,
00339 int min,
00340 int sec,
00341 int inUtc){
00342 uint32_t s;
00343
00344 if (inUtc)
00345 s=GWEN_Time__mktimeUtc(year, month, day, hour, min, sec);
00346 else {
00347 struct tm ti;
00348 struct tm *tp;
00349 time_t tt;
00350
00351 tt=time(0);
00352 tp=localtime(&tt);
00353 assert(tp);
00354 memmove(&ti, tp, sizeof(ti));
00355 ti.tm_sec=sec;
00356 ti.tm_min=min;
00357 ti.tm_hour=hour;
00358 if (year<100) {
00359 if (year<72)
00360 year+=2000;
00361 year+=1900;
00362 }
00363 ti.tm_year=year-1900;
00364 ti.tm_mon=month;
00365 ti.tm_mday=day;
00366 ti.tm_yday=0;
00367 ti.tm_wday=0;
00368 tt=mktime(&ti);
00369 assert(tt!=(time_t)-1);
00370 s=(uint32_t)tt;
00371 }
00372 return GWEN_Time_fromSeconds(s);
00373 }
00374
00375
00376
00377 uint32_t GWEN_Time__mktimeUtc(int year,
00378 int month,
00379 int day,
00380 int hour,
00381 int min,
00382 int sec) {
00383 uint32_t result;
00384 int i;
00385 int isLeap;
00386 const uint32_t hoursecs=60*60;
00387 const uint32_t daysecs=24*hoursecs;
00388 const uint32_t yearsecs=365*daysecs;
00389 const uint32_t monthDays[12]=
00390 {
00391 31, 28, 31, 30,
00392 31, 30, 31, 31,
00393 30, 31, 30, 31
00394 };
00395
00396 result=(year-1970)*yearsecs;
00397
00398 for (i=1970; i<year; i++)
00399 if ((((i % 4)==0) &&
00400 ((i % 100)!=0)) ||
00401 ((i % 400)==0))
00402 result+=daysecs;
00403
00404 isLeap=((((year % 4)==0) &&
00405 ((year % 100)!=0)) ||
00406 ((year % 400)==0));
00407
00408 for (i=0; i<month; i++)
00409 if (isLeap && i==1)
00410 result+=29*daysecs;
00411 else
00412 result+=monthDays[i]*daysecs;
00413
00414 result+=(day-1)*daysecs;
00415 result+=(hour*hoursecs);
00416 result+=min*60;
00417 result+=sec;
00418
00419 return result;
00420 }
00421
00422
00423
00424 GWEN_TIME *GWEN_Time_dup(const GWEN_TIME *t){
00425 GWEN_TIME *newT;
00426
00427 assert(t);
00428 GWEN_NEW_OBJECT(GWEN_TIME, newT);
00429 newT->secs=t->secs;
00430 newT->msecs=t->msecs;
00431 return newT;
00432 }
00433
00434
00435
00436 void GWEN_Time_free(GWEN_TIME *t){
00437 if (t) {
00438 GWEN_FREE_OBJECT(t);
00439 }
00440 }
00441
00442
00443
00444 double GWEN_Time_Diff(const GWEN_TIME *t1, const GWEN_TIME *t0){
00445 double d;
00446
00447 assert(t1);
00448 assert(t0);
00449
00450 d=1000.0*((double)(t1->secs)-(double)(t0->secs));
00451 d+=(double)((double)(t1->msecs)-(double)(t0->msecs));
00452
00453 return d;
00454 }
00455
00456
00457
00458 double GWEN_Time_DiffSeconds(const GWEN_TIME *t1, const GWEN_TIME *t0){
00459 double d;
00460
00461 assert(t1);
00462 assert(t0);
00463
00464 d=(double)(t1->secs)-(double)(t0->secs);
00465 d+=((double)((double)(t1->msecs)-(double)(t0->msecs)))/1000.0;
00466
00467 return d;
00468 }
00469
00470
00471
00472 int GWEN_Time_Compare(const GWEN_TIME *t1, const GWEN_TIME *t0){
00473 if (t1 && t0) {
00474 if (t1->secs<t0->secs)
00475 return -1;
00476 else if (t1->secs>t0->secs)
00477 return 1;
00478 else {
00479 if (t1->msecs<t0->msecs)
00480 return -1;
00481 else if (t1->msecs>t0->msecs)
00482 return 1;
00483 else
00484 return 0;
00485 }
00486 }
00487 else if (t1)
00488 return 1;
00489 else if (t0)
00490 return -1;
00491
00492 return 0;
00493 }
00494
00495
00496
00497 double GWEN_Time_Milliseconds(const GWEN_TIME *t){
00498 assert(t);
00499 return (double)((t->secs*1000)+(t->msecs));
00500 }
00501
00502
00503
00504 uint32_t GWEN_Time_Seconds(const GWEN_TIME *t){
00505 assert(t);
00506 return t->secs;
00507 }
00508
00509
00510
00511 int GWEN_Time_GetBrokenDownTime(const GWEN_TIME *t,
00512 int *hours,
00513 int *mins,
00514 int *secs){
00515 struct tm *tb;
00516 time_t tt;
00517
00518 assert(t);
00519 tt=t->secs;
00520 tb=localtime(&tt);
00521 if (!tb) {
00522 DBG_ERROR(GWEN_LOGDOMAIN, "localtime(): %s", strerror(errno));
00523 return -1;
00524 }
00525 *hours=tb->tm_hour;
00526 *mins=tb->tm_min;
00527 *secs=tb->tm_sec;
00528 return 0;
00529 }
00530
00531
00532
00533 int GWEN_Time_GetBrokenDownUtcTime(const GWEN_TIME *t,
00534 int *hours,
00535 int *mins,
00536 int *secs){
00537 struct tm *tb;
00538 time_t tt;
00539
00540 assert(t);
00541 tt=t->secs;
00542 tb=gmtime(&tt);
00543 if (!tb) {
00544 DBG_ERROR(GWEN_LOGDOMAIN, "gmtime(): %s", strerror(errno));
00545 return -1;
00546 }
00547 *hours=tb->tm_hour;
00548 *mins=tb->tm_min;
00549 *secs=tb->tm_sec;
00550 return 0;
00551 }
00552
00553
00554
00555 int GWEN_Time_GetBrokenDownDate(const GWEN_TIME *t,
00556 int *days,
00557 int *month,
00558 int *year){
00559 struct tm *tb;
00560 time_t tt;
00561
00562 assert(t);
00563 tt=t->secs;
00564 tb=localtime(&tt);
00565 if (!tb) {
00566 DBG_ERROR(GWEN_LOGDOMAIN, "localtime(): %s", strerror(errno));
00567 return -1;
00568 }
00569 *days=tb->tm_mday;
00570 *month=tb->tm_mon;
00571 *year=tb->tm_year+1900;
00572 return 0;
00573 }
00574
00575
00576
00577 int GWEN_Time_GetBrokenDownUtcDate(const GWEN_TIME *t,
00578 int *days,
00579 int *month,
00580 int *year){
00581 struct tm *tb;
00582 time_t tt;
00583
00584 assert(t);
00585 tt=t->secs;
00586 tb=gmtime(&tt);
00587 if (!tb) {
00588 DBG_ERROR(GWEN_LOGDOMAIN, "gmtime(): %s", strerror(errno));
00589 return -1;
00590 }
00591 *days=tb->tm_mday;
00592 *month=tb->tm_mon;
00593 *year=tb->tm_year+1900;
00594 return 0;
00595 }
00596
00597
00598
00599
00600 struct tm GWEN_Time_toTm(const GWEN_TIME *t) {
00601 struct tm *tb;
00602 time_t tt;
00603
00604 assert(t);
00605 tt=t->secs;
00606 tb=localtime(&tt);
00607 return *tb;
00608 }
00609
00610 time_t GWEN_Time_toTime_t(const GWEN_TIME *t) {
00611 assert(t);
00612 return t->secs;
00613 }
00614
00615
00616
00617
00618 GWEN_TIME_TMPLCHAR *GWEN_TimeTmplChar_new(char c) {
00619 GWEN_TIME_TMPLCHAR *e;
00620
00621 GWEN_NEW_OBJECT(GWEN_TIME_TMPLCHAR, e);
00622 GWEN_LIST_INIT(GWEN_TIME_TMPLCHAR, e);
00623 e->character=c;
00624 return e;
00625 }
00626
00627
00628
00629 void GWEN_TimeTmplChar_free(GWEN_TIME_TMPLCHAR *e) {
00630 if (e) {
00631 free(e->content);
00632 GWEN_LIST_FINI(GWEN_TIME_TMPLCHAR, e);
00633 GWEN_FREE_OBJECT(e);
00634 }
00635 }
00636
00637
00638 GWEN_TIME_TMPLCHAR *GWEN_Time__findTmplChar(GWEN_TIME_TMPLCHAR_LIST *ll,
00639 char c) {
00640 GWEN_TIME_TMPLCHAR *e;
00641
00642 e=GWEN_TimeTmplChar_List_First(ll);
00643 while(e) {
00644 if (e->character==c)
00645 break;
00646 e=GWEN_TimeTmplChar_List_Next(e);
00647 }
00648
00649 return e;
00650 }
00651
00652
00653
00654
00655 void GWEN_Time__sampleTmplChars(GWEN_UNUSED const GWEN_TIME *t, const char *tmpl,
00656 GWEN_UNUSED GWEN_BUFFER *buf,
00657 GWEN_TIME_TMPLCHAR_LIST *ll) {
00658 const char *s;
00659
00660 s=tmpl;
00661 while(*s) {
00662 if (strchr("YMDhms", *s)) {
00663 GWEN_TIME_TMPLCHAR *e;
00664
00665 e=GWEN_Time__findTmplChar(ll, *s);
00666 if (!e) {
00667
00668 e=GWEN_TimeTmplChar_new(*s);
00669 GWEN_TimeTmplChar_List_Add(e, ll);
00670 }
00671 assert(e);
00672 e->count++;
00673 }
00674 else {
00675 DBG_DEBUG(GWEN_LOGDOMAIN, "Unknown character in template (%02x)",
00676 *s);
00677 }
00678 s++;
00679 }
00680 }
00681
00682
00683
00684 void GWEN_Time__fillTmplChars(const GWEN_TIME *t,
00685 GWEN_TIME_TMPLCHAR_LIST *ll,
00686 int useUtc) {
00687 GWEN_TIME_TMPLCHAR *e;
00688 int year, month, day, hour, minute, second;
00689
00690 if (useUtc) {
00691 GWEN_Time_GetBrokenDownUtcDate(t, &day, &month, &year);
00692 GWEN_Time_GetBrokenDownUtcTime(t, &hour, &minute, &second);
00693 }
00694 else {
00695 GWEN_Time_GetBrokenDownDate(t, &day, &month, &year);
00696 GWEN_Time_GetBrokenDownTime(t, &hour, &minute, &second);
00697 }
00698
00699 e=GWEN_TimeTmplChar_List_First(ll);
00700 while(e) {
00701 int v;
00702 char buffer[32];
00703
00704 switch(e->character) {
00705 case 'Y': v=year; break;
00706 case 'M': v=month+1; break;
00707 case 'D': v=day; break;
00708 case 'h': v=hour; break;
00709 case 'm': v=minute; break;
00710 case 's': v=second; break;
00711 default: v=-1; break;
00712 }
00713 if (v==-1) {
00714 DBG_ERROR(GWEN_LOGDOMAIN, "Unknown character, should not happen here");
00715 abort();
00716 }
00717 buffer[0]=0;
00718 snprintf(buffer, sizeof(buffer)-1, "%0*d", GWEN_TIME_TMPL_MAX_COUNT, v);
00719 buffer[sizeof(buffer)-1]=0;
00720 e->content=strdup(buffer);
00721 e->nextChar=strlen(e->content)-(e->count);
00722 e=GWEN_TimeTmplChar_List_Next(e);
00723 }
00724 }
00725
00726
00727
00728
00729 int GWEN_Time__toString(const GWEN_TIME *t, const char *tmpl,
00730 GWEN_BUFFER *buf, int useUtc) {
00731 GWEN_TIME_TMPLCHAR_LIST *ll;
00732 const char *s;
00733
00734 ll=GWEN_TimeTmplChar_List_new();
00735 GWEN_Time__sampleTmplChars(t, tmpl, buf, ll);
00736 GWEN_Time__fillTmplChars(t, ll, useUtc);
00737
00738 s=tmpl;
00739 while(*s) {
00740 if (strchr("YMDhms", *s)) {
00741 GWEN_TIME_TMPLCHAR *e;
00742 char c;
00743
00744 e=GWEN_Time__findTmplChar(ll, *s);
00745 assert(e);
00746 assert(e->content);
00747 c=e->content[e->nextChar++];
00748 assert(c);
00749 GWEN_Buffer_AppendByte(buf, c);
00750 }
00751 else
00752 GWEN_Buffer_AppendByte(buf, *s);
00753 s++;
00754 }
00755 GWEN_TimeTmplChar_List_free(ll);
00756 return 0;
00757 }
00758
00759
00760
00761 int GWEN_Time_toString(const GWEN_TIME *t, const char *tmpl,
00762 GWEN_BUFFER *buf) {
00763 return GWEN_Time__toString(t, tmpl, buf, 0);
00764 }
00765
00766
00767
00768 int GWEN_Time_toUtcString(const GWEN_TIME *t, const char *tmpl,
00769 GWEN_BUFFER *buf) {
00770 return GWEN_Time__toString(t, tmpl, buf, 1);
00771 }
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781