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 #ifdef HAVE_CONFIG_H
00026 # include <config.h>
00027 #endif
00028
00029
00030 #include "gwendate_p.h"
00031 #include "i18n_l.h"
00032
00033 #include <gwenhywfar/debug.h>
00034 #include <gwenhywfar/misc.h>
00035
00036
00037 #include <time.h>
00038 #include <ctype.h>
00039
00040
00041
00042 static const uint8_t daysInMonth[12]={
00043 31,28,31,30,31,30,31,31,30,31,30,31
00044 };
00045
00046
00047
00048
00049 GWEN_DATE *GWEN_Date_fromGregorian(int y, int m, int d) {
00050 GWEN_DATE *gd;
00051
00052 if (m<1 || m>12 || d<1 || d>31) {
00053 DBG_ERROR(GWEN_LOGDOMAIN, "Bad date format");
00054 return NULL;
00055 }
00056
00057 GWEN_NEW_OBJECT(GWEN_DATE, gd);
00058 gd->year=y;
00059 gd->month=m;
00060 gd->day=d;
00061 gd->julian=(1461*(y+4800+(m-14)/12))/4+
00062 (367*(m-2-12*((m-14)/12)))/12-
00063 (3*((y+4900+(m-14)/12)/100))/4+
00064 d-32075;
00065
00066 snprintf(gd->asString, sizeof(gd->asString)-1,
00067 "%04d%02d%02d",
00068 gd->year, gd->month, gd->day);
00069 gd->asString[sizeof(gd->asString)-1]=0;
00070
00071 return gd;
00072 }
00073
00074
00075
00076 GWEN_DATE *GWEN_Date_fromJulian(int julian) {
00077 GWEN_DATE *gd;
00078 int l, n, i, j;
00079
00080 GWEN_NEW_OBJECT(GWEN_DATE, gd);
00081 l=julian+68569;
00082 n=(4*l)/146097;
00083 l=l-(146097*n+3)/4;
00084 i=(4000*(l+1))/1461001;
00085 l=l-(1461*i)/4+31;
00086 j=(80*l)/2447;
00087 gd->day=l-(2447*j)/80;
00088 l=j/11;
00089 gd->month=j+2-(12*l);
00090 gd->year=100*(n-49)+i+l;
00091 gd->julian=julian;
00092
00093 snprintf(gd->asString, sizeof(gd->asString)-1,
00094 "%04d%02d%02d",
00095 gd->year, gd->month, gd->day);
00096 gd->asString[sizeof(gd->asString)-1]=0;
00097
00098 return gd;
00099 }
00100
00101
00102
00103 GWEN_DATE *GWEN_Date_fromLocalTime(time_t t) {
00104 struct tm *ltm;
00105
00106 ltm=localtime(&t);
00107 if (ltm) {
00108 GWEN_DATE *gd;
00109
00110 gd=GWEN_Date_fromGregorian(ltm->tm_year+1900, ltm->tm_mon+1, ltm->tm_mday);
00111 return gd;
00112 }
00113
00114 return NULL;
00115 }
00116
00117
00118
00119 GWEN_DATE *GWEN_Date_fromGmTime(time_t t) {
00120 struct tm *ltm;
00121
00122 ltm=gmtime(&t);
00123 if (ltm) {
00124 GWEN_DATE *gd;
00125
00126 gd=GWEN_Date_fromGregorian(ltm->tm_year+1900, ltm->tm_mon+1, ltm->tm_mday);
00127 return gd;
00128 }
00129
00130 return NULL;
00131 }
00132
00133
00134
00135
00136 GWEN_DATE *GWEN_Date_CurrentDate(void) {
00137 time_t l;
00138
00139 time(&l);
00140 return GWEN_Date_fromLocalTime(l);
00141 }
00142
00143
00144
00145 GWEN_DATE *GWEN_Date_dup(const GWEN_DATE *ogd) {
00146 assert(ogd);
00147 return GWEN_Date_fromGregorian(ogd->year, ogd->month, ogd->day);
00148 }
00149
00150
00151
00152 GWEN_DATE *GWEN_Date_fromString(const char *s) {
00153 int y, m, d;
00154
00155 if (3==sscanf(s, "%04d%02d%02d", &y, &m, &d)) {
00156 return GWEN_Date_fromGregorian(y, m, d);
00157 }
00158 else {
00159 DBG_ERROR(GWEN_LOGDOMAIN, "Bad date [%s]", s);
00160 return NULL;
00161 }
00162 }
00163
00164
00165
00166 void GWEN_Date_free(GWEN_DATE *gd) {
00167 if (gd) {
00168 GWEN_FREE_OBJECT(gd);
00169 }
00170 }
00171
00172
00173
00174 int GWEN_Date_IsLeapYear(int y) {
00175 return ((y%4==0) && (y%100!=0)) || (y%400==0);
00176 }
00177
00178
00179
00180
00181 int GWEN_Date_DaysInMonth(const GWEN_DATE *gd) {
00182 assert(gd);
00183 if (gd->month==2 &&
00184 ((((gd->year%4)==0) && ((gd->year)%100!=0)) || ((gd->year)%400==0)))
00185
00186 return 29;
00187 else
00188 return daysInMonth[gd->month-1];
00189 }
00190
00191
00192
00193 int GWEN_Date_DaysInYear(const GWEN_DATE *gd) {
00194 GWEN_DATE *gd11;
00195 int result;
00196
00197 assert(gd);
00198
00199 gd11=GWEN_Date_fromGregorian(gd->year, 1, 1);
00200 result=(gd->julian)-(gd11->julian);
00201 GWEN_Date_free(gd11);
00202
00203 return result;
00204 }
00205
00206
00207
00208 int GWEN_Date_GetYear(const GWEN_DATE *gd) {
00209 assert(gd);
00210 return gd->year;
00211 }
00212
00213
00214
00215 int GWEN_Date_GetMonth(const GWEN_DATE *gd) {
00216 assert(gd);
00217 return gd->month;
00218 }
00219
00220
00221
00222 int GWEN_Date_GetDay(const GWEN_DATE *gd) {
00223 assert(gd);
00224 return gd->day;
00225 }
00226
00227
00228
00229 int GWEN_Date_GetJulian(const GWEN_DATE *gd) {
00230 assert(gd);
00231 return gd->julian;
00232 }
00233
00234
00235
00236 int GWEN_Date_WeekDay(const GWEN_DATE *gd) {
00237 assert(gd);
00238 return (gd->julian+1)%7;
00239 }
00240
00241
00242
00243 const char *GWEN_Date_GetString(const GWEN_DATE *gd) {
00244 assert(gd);
00245 return gd->asString;
00246 }
00247
00248
00249
00250 int GWEN_Date_Compare(const GWEN_DATE *gd1, const GWEN_DATE *gd0) {
00251 if (gd0 && gd1) {
00252 if (gd1->julian==gd0->julian)
00253 return 0;
00254 else if (gd1->julian>gd0->julian)
00255 return 1;
00256 else
00257 return -1;
00258 }
00259 else if (gd0)
00260 return 1;
00261 else if (gd1)
00262 return -1;
00263 else
00264 return 0;
00265 }
00266
00267
00268
00269 int GWEN_Date_Diff(const GWEN_DATE *gd1, const GWEN_DATE *gd0) {
00270 assert(gd1);
00271 assert(gd0);
00272
00273 return gd1->julian-gd0->julian;
00274 }
00275
00276
00277
00278 GWEN_DATE *GWEN_Date_fromTime(const GWEN_TIME *ti) {
00279 GWEN_BUFFER *tbuf;
00280 GWEN_DATE *gd;
00281
00282 tbuf=GWEN_Buffer_new(0, 32, 0, 1);
00283 GWEN_Time_toString(ti, "YYYYMMDD", tbuf);
00284 gd=GWEN_Date_fromString(GWEN_Buffer_GetStart(tbuf));
00285 GWEN_Buffer_free(tbuf);
00286
00287 return gd;
00288 }
00289
00290
00291
00292
00293 GWEN_DATE *GWEN_Date_fromStringWithTemplate(const char *s, const char *tmpl){
00294 int year, month, day;
00295 const char *p;
00296 const char *t;
00297 GWEN_DATE *gwt;
00298
00299 assert(s);
00300 assert(tmpl);
00301 year=month=day=0;
00302
00303 p=s;
00304 t=tmpl;
00305 while(*t && *p) {
00306 int i;
00307
00308 if (*t=='*') {
00309 t++;
00310 if (!*t) {
00311 DBG_ERROR(GWEN_LOGDOMAIN, "Bad pattern: Must not end with \"*\"");
00312 return 0;
00313 }
00314 i=0;
00315 while(*p) {
00316 if (!isdigit((int)*p))
00317 break;
00318 if (*p==*t)
00319 break;
00320 i*=10;
00321 i+=(*p)-'0';
00322 p++;
00323 }
00324 }
00325 else {
00326 if (isdigit((int)*p))
00327 i=(*p)-'0';
00328 else
00329 i=-1;
00330 p++;
00331 }
00332
00333 if (i==-1 && strchr("YMD", *t)!=NULL) {
00334 DBG_INFO(GWEN_LOGDOMAIN,
00335 "No more digits at [%s], continueing", t);
00336 p--;
00337 }
00338 else {
00339 switch(*t) {
00340 case 'Y':
00341 if (i==-1) {
00342 DBG_INFO(GWEN_LOGDOMAIN, "here");
00343 return 0;
00344 }
00345 year*=10;
00346 year+=i;
00347 break;
00348 case 'M':
00349 if (i==-1) {
00350 DBG_INFO(GWEN_LOGDOMAIN, "here");
00351 return 0;
00352 }
00353 month*=10;
00354 month+=i;
00355 break;
00356 case 'D':
00357 if (i==-1) {
00358 DBG_INFO(GWEN_LOGDOMAIN, "here");
00359 return 0;
00360 }
00361 day*=10;
00362 day+=i;
00363 break;
00364 default:
00365 DBG_VERBOUS(GWEN_LOGDOMAIN,
00366 "Unknown character in template, will skip in both strings");
00367 break;
00368 }
00369 }
00370 t++;
00371 }
00372
00373 if (year<100)
00374 year+=2000;
00375
00376 DBG_DEBUG(GWEN_LOGDOMAIN,
00377 "Got this date/time: %04d/%02d/%02d",
00378 year, month, day);
00379
00380
00381 gwt=GWEN_Date_fromGregorian(year, month, day);
00382 if (!gwt) {
00383 DBG_INFO(GWEN_LOGDOMAIN, "here");
00384 return 0;
00385 }
00386 return gwt;
00387 }
00388
00389
00390
00391
00392
00393 GWEN_LIST_FUNCTIONS(GWEN_DATE_TMPLCHAR, GWEN_DateTmplChar)
00394
00395
00396 GWEN_DATE_TMPLCHAR *GWEN_DateTmplChar_new(char c) {
00397 GWEN_DATE_TMPLCHAR *e;
00398
00399 GWEN_NEW_OBJECT(GWEN_DATE_TMPLCHAR, e);
00400 GWEN_LIST_INIT(GWEN_DATE_TMPLCHAR, e);
00401 e->character=c;
00402 switch(c) {
00403 case 'Y': e->maxCount=4; break;
00404 case 'M': e->maxCount=2; break;
00405 case 'D': e->maxCount=2; break;
00406 case 'W': e->maxCount=1; break;
00407 case 'w':
00408 default: e->maxCount=GWEN_DATE_TMPL_MAX_COUNT; break;
00409 }
00410
00411 return e;
00412 }
00413
00414
00415
00416 void GWEN_DateTmplChar_free(GWEN_DATE_TMPLCHAR *e) {
00417 if (e) {
00418 free(e->content);
00419 GWEN_LIST_FINI(GWEN_DATE_TMPLCHAR, e);
00420 GWEN_FREE_OBJECT(e);
00421 }
00422 }
00423
00424
00425
00426 GWEN_DATE_TMPLCHAR *GWEN_Date__findTmplChar(GWEN_DATE_TMPLCHAR_LIST *ll, char c) {
00427 GWEN_DATE_TMPLCHAR *e;
00428
00429 e=GWEN_DateTmplChar_List_First(ll);
00430 while(e) {
00431 if (e->character==c)
00432 break;
00433 e=GWEN_DateTmplChar_List_Next(e);
00434 }
00435
00436 return e;
00437 }
00438
00439
00440
00441
00442 void GWEN_Date__sampleTmplChars(GWEN_UNUSED const GWEN_DATE *t, const char *tmpl,
00443 GWEN_UNUSED GWEN_BUFFER *buf,
00444 GWEN_DATE_TMPLCHAR_LIST *ll) {
00445 const char *s;
00446
00447 s=tmpl;
00448 while(*s) {
00449 if (strchr("YMDWw", *s)) {
00450 GWEN_DATE_TMPLCHAR *e;
00451
00452 e=GWEN_Date__findTmplChar(ll, *s);
00453 if (!e) {
00454
00455 e=GWEN_DateTmplChar_new(*s);
00456 GWEN_DateTmplChar_List_Add(e, ll);
00457 }
00458 assert(e);
00459 e->count++;
00460 }
00461 else {
00462 DBG_DEBUG(GWEN_LOGDOMAIN, "Unknown character in template (%02x)",
00463 *s);
00464 }
00465 s++;
00466 }
00467 }
00468
00469
00470
00471 void GWEN_Date__fillTmplChars(const GWEN_DATE *t, GWEN_DATE_TMPLCHAR_LIST *ll) {
00472 GWEN_DATE_TMPLCHAR *e;
00473
00474
00475 e=GWEN_DateTmplChar_List_First(ll);
00476 while(e) {
00477 int v;
00478
00479 if (e->character=='w') {
00480 const char *s=NULL;
00481
00482 switch(GWEN_Date_WeekDay(t)) {
00483 case 0: s=I18N("Sunday"); break;
00484 case 1: s=I18N("Monday"); break;
00485 case 2: s=I18N("Tuesday"); break;
00486 case 3: s=I18N("Wednesday"); break;
00487 case 4: s=I18N("Thursday"); break;
00488 case 5: s=I18N("Friday"); break;
00489 case 6: s=I18N("Saturday"); break;
00490 }
00491 assert(s);
00492 e->content=strdup(s);
00493 e->nextChar=0;
00494 }
00495 else {
00496 char buffer[32];
00497 int clen;
00498
00499 switch(e->character) {
00500 case 'Y':
00501 v=t->year;
00502 break;
00503 case 'M':
00504 v=t->month;
00505 break;
00506 case 'D':
00507 v=t->day;
00508 break;
00509 case 'W':
00510 v=GWEN_Date_WeekDay(t);
00511 break;
00512 default:
00513 v=-1;
00514 break;
00515 }
00516 if (v==-1) {
00517 DBG_ERROR(GWEN_LOGDOMAIN, "Unknown character, should not happen here");
00518 abort();
00519 }
00520 buffer[0]=0;
00521 snprintf(buffer, sizeof(buffer)-1, "%0*d", e->maxCount, v);
00522 buffer[sizeof(buffer)-1]=0;
00523 e->content=strdup(buffer);
00524
00525 clen=strlen(e->content);
00526 if (e->count>clen)
00527 e->count=clen;
00528 e->nextChar=clen-(e->count);
00529 }
00530
00531 e=GWEN_DateTmplChar_List_Next(e);
00532 }
00533 }
00534
00535
00536
00537
00538 int GWEN_Date_toStringWithTemplate(const GWEN_DATE *t, const char *tmpl, GWEN_BUFFER *buf) {
00539 GWEN_DATE_TMPLCHAR_LIST *ll;
00540 const char *s;
00541
00542 ll=GWEN_DateTmplChar_List_new();
00543 GWEN_Date__sampleTmplChars(t, tmpl, buf, ll);
00544 GWEN_Date__fillTmplChars(t, ll);
00545
00546 s=tmpl;
00547 while(*s) {
00548 if (strchr("YMDWw", *s)) {
00549 GWEN_DATE_TMPLCHAR *e;
00550 char c;
00551
00552 e=GWEN_Date__findTmplChar(ll, *s);
00553 assert(e);
00554 assert(e->content);
00555 if (s[1]=='*') {
00556
00557 GWEN_Buffer_AppendString(buf, e->content);
00558
00559 s++;
00560 }
00561 else {
00562 c=e->content[e->nextChar];
00563 if (c!=0) {
00564 GWEN_Buffer_AppendByte(buf, c);
00565 e->nextChar++;
00566 }
00567 }
00568 }
00569 else
00570 GWEN_Buffer_AppendByte(buf, *s);
00571 s++;
00572 }
00573 GWEN_DateTmplChar_List_free(ll);
00574 return 0;
00575 }
00576
00577
00578
00579
00580
00581
00582
00583
00584