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