gwenhywfar  4.3.1
gwendate.c
Go to the documentation of this file.
00001 /***************************************************************************
00002     begin       : Tue Jul 07 2009
00003     copyright   : (C) 2009 by Martin Preuss
00004     email       : martin@libchipcard.de
00005 
00006  ***************************************************************************
00007  *                                                                         *
00008  *   This library is free software; you can redistribute it and/or         *
00009  *   modify it under the terms of the GNU Lesser General Public            *
00010  *   License as published by the Free Software Foundation; either          *
00011  *   version 2.1 of the License, or (at your option) any later version.    *
00012  *                                                                         *
00013  *   This library is distributed in the hope that it will be useful,       *
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00016  *   Lesser General Public License for more details.                       *
00017  *                                                                         *
00018  *   You should have received a copy of the GNU Lesser General Public      *
00019  *   License along with this library; if not, write to the Free Software   *
00020  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
00021  *   MA  02111-1307  USA                                                   *
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     /* February in a leap year */
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; /* 0=Sunday */
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       } /* while */
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   } /* while */
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   /* get time in local time */
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         /* new entry, create it */
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       /* adjust counter if there are more than maxCount template chars */
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         /* append full string */
00557         GWEN_Buffer_AppendString(buf, e->content);
00558         /* skip asterisk */
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