gwenhywfar  4.7.0beta
gwendate.c
Go to the documentation of this file.
1 /***************************************************************************
2  begin : Tue Jul 07 2009
3  copyright : (C) 2009 by Martin Preuss
4  email : martin@libchipcard.de
5 
6  ***************************************************************************
7  * *
8  * This library is free software; you can redistribute it and/or *
9  * modify it under the terms of the GNU Lesser General Public *
10  * License as published by the Free Software Foundation; either *
11  * version 2.1 of the License, or (at your option) any later version. *
12  * *
13  * This library is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16  * Lesser General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU Lesser General Public *
19  * License along with this library; if not, write to the Free Software *
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21  * MA 02111-1307 USA *
22  * *
23  ***************************************************************************/
24 
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28 
29 
30 #include "gwendate_p.h"
31 #include "i18n_l.h"
32 
33 #include <gwenhywfar/debug.h>
34 #include <gwenhywfar/misc.h>
35 
36 
37 #include <time.h>
38 #include <ctype.h>
39 
40 
41 
42 static const uint8_t daysInMonth[12]={
43  31,28,31,30,31,30,31,31,30,31,30,31
44 };
45 
46 
47 
48 
49 GWEN_DATE *GWEN_Date_fromGregorian(int y, int m, int d) {
50  GWEN_DATE *gd;
51 
52  if (m<1 || m>12 || d<1 || d>31) {
53  DBG_ERROR(GWEN_LOGDOMAIN, "Bad date format");
54  return NULL;
55  }
56 
58  gd->year=y;
59  gd->month=m;
60  gd->day=d;
61  gd->julian=(1461*(y+4800+(m-14)/12))/4+
62  (367*(m-2-12*((m-14)/12)))/12-
63  (3*((y+4900+(m-14)/12)/100))/4+
64  d-32075;
65 
66  snprintf(gd->asString, sizeof(gd->asString)-1,
67  "%04d%02d%02d",
68  gd->year, gd->month, gd->day);
69  gd->asString[sizeof(gd->asString)-1]=0;
70 
71  return gd;
72 }
73 
74 
75 
77  GWEN_DATE *gd;
78  int l, n, i, j;
79 
81  l=julian+68569;
82  n=(4*l)/146097;
83  l=l-(146097*n+3)/4;
84  i=(4000*(l+1))/1461001;
85  l=l-(1461*i)/4+31;
86  j=(80*l)/2447;
87  gd->day=l-(2447*j)/80;
88  l=j/11;
89  gd->month=j+2-(12*l);
90  gd->year=100*(n-49)+i+l;
91  gd->julian=julian;
92 
93  snprintf(gd->asString, sizeof(gd->asString)-1,
94  "%04d%02d%02d",
95  gd->year, gd->month, gd->day);
96  gd->asString[sizeof(gd->asString)-1]=0;
97 
98  return gd;
99 }
100 
101 
102 
104  struct tm *ltm;
105 
106  ltm=localtime(&t);
107  if (ltm) {
108  GWEN_DATE *gd;
109 
110  gd=GWEN_Date_fromGregorian(ltm->tm_year+1900, ltm->tm_mon+1, ltm->tm_mday);
111  return gd;
112  }
113 
114  return NULL;
115 }
116 
117 
118 
120  struct tm *ltm;
121 
122  ltm=gmtime(&t);
123  if (ltm) {
124  GWEN_DATE *gd;
125 
126  gd=GWEN_Date_fromGregorian(ltm->tm_year+1900, ltm->tm_mon+1, ltm->tm_mday);
127  return gd;
128  }
129 
130  return NULL;
131 }
132 
133 
134 
135 
137  time_t l;
138 
139  time(&l);
140  return GWEN_Date_fromLocalTime(l);
141 }
142 
143 
144 
146  assert(ogd);
147  return GWEN_Date_fromGregorian(ogd->year, ogd->month, ogd->day);
148 }
149 
150 
151 
153  int y, m, d;
154 
155  if (3==sscanf(s, "%04d%02d%02d", &y, &m, &d)) {
156  return GWEN_Date_fromGregorian(y, m, d);
157  }
158  else {
159  DBG_ERROR(GWEN_LOGDOMAIN, "Bad date [%s]", s);
160  return NULL;
161  }
162 }
163 
164 
165 
167  if (gd) {
168  GWEN_FREE_OBJECT(gd);
169  }
170 }
171 
172 
173 
175  return ((y%4==0) && (y%100!=0)) || (y%400==0);
176 }
177 
178 
179 
180 
182  assert(gd);
183  if (gd->month==2 &&
184  ((((gd->year%4)==0) && ((gd->year)%100!=0)) || ((gd->year)%400==0)))
185  /* February in a leap year */
186  return 29;
187  else
188  return daysInMonth[gd->month-1];
189 }
190 
191 
192 
194  GWEN_DATE *gd11;
195  int result;
196 
197  assert(gd);
198 
199  gd11=GWEN_Date_fromGregorian(gd->year, 1, 1);
200  result=(gd->julian)-(gd11->julian);
201  GWEN_Date_free(gd11);
202 
203  return result;
204 }
205 
206 
207 
208 int GWEN_Date_GetYear(const GWEN_DATE *gd) {
209  assert(gd);
210  return gd->year;
211 }
212 
213 
214 
216  assert(gd);
217  return gd->month;
218 }
219 
220 
221 
222 int GWEN_Date_GetDay(const GWEN_DATE *gd) {
223  assert(gd);
224  return gd->day;
225 }
226 
227 
228 
230  assert(gd);
231  return gd->julian;
232 }
233 
234 
235 
236 int GWEN_Date_WeekDay(const GWEN_DATE *gd) {
237  assert(gd);
238  return (gd->julian+1)%7; /* 0=Sunday */
239 }
240 
241 
242 
243 const char *GWEN_Date_GetString(const GWEN_DATE *gd) {
244  assert(gd);
245  return gd->asString;
246 }
247 
248 
249 
250 int GWEN_Date_Compare(const GWEN_DATE *gd1, const GWEN_DATE *gd0) {
251  if (gd0 && gd1) {
252  if (gd1->julian==gd0->julian)
253  return 0;
254  else if (gd1->julian>gd0->julian)
255  return 1;
256  else
257  return -1;
258  }
259  else if (gd0)
260  return 1;
261  else if (gd1)
262  return -1;
263  else
264  return 0;
265 }
266 
267 
268 
269 int GWEN_Date_Diff(const GWEN_DATE *gd1, const GWEN_DATE *gd0) {
270  assert(gd1);
271  assert(gd0);
272 
273  return gd1->julian-gd0->julian;
274 }
275 
276 
277 
279  GWEN_BUFFER *tbuf;
280  GWEN_DATE *gd;
281 
282  tbuf=GWEN_Buffer_new(0, 32, 0, 1);
283  GWEN_Time_toString(ti, "YYYYMMDD", tbuf);
285  GWEN_Buffer_free(tbuf);
286 
287  return gd;
288 }
289 
290 
291 
292 
293 GWEN_DATE *GWEN_Date_fromStringWithTemplate(const char *s, const char *tmpl){
294  int year, month, day;
295  const char *p;
296  const char *t;
297  GWEN_DATE *gwt;
298 
299  assert(s);
300  assert(tmpl);
301  year=month=day=0;
302 
303  p=s;
304  t=tmpl;
305  while(*t && *p) {
306  int i;
307 
308  if (*t=='*') {
309  t++;
310  if (!*t) {
311  DBG_ERROR(GWEN_LOGDOMAIN, "Bad pattern: Must not end with \"*\"");
312  return 0;
313  }
314  i=0;
315  while(*p) {
316  if (!isdigit((int)*p))
317  break;
318  if (*p==*t)
319  break;
320  i*=10;
321  i+=(*p)-'0';
322  p++;
323  } /* while */
324  }
325  else {
326  if (isdigit((int)*p))
327  i=(*p)-'0';
328  else
329  i=-1;
330  p++;
331  }
332 
333  if (i==-1 && strchr("YMD", *t)!=NULL) {
335  "No more digits at [%s], continuing", t);
336  p--;
337  }
338  else {
339  switch(*t) {
340  case 'Y':
341  if (i==-1) {
342  DBG_INFO(GWEN_LOGDOMAIN, "here");
343  return 0;
344  }
345  year*=10;
346  year+=i;
347  break;
348  case 'M':
349  if (i==-1) {
350  DBG_INFO(GWEN_LOGDOMAIN, "here");
351  return 0;
352  }
353  month*=10;
354  month+=i;
355  break;
356  case 'D':
357  if (i==-1) {
358  DBG_INFO(GWEN_LOGDOMAIN, "here");
359  return 0;
360  }
361  day*=10;
362  day+=i;
363  break;
364  default:
366  "Unknown character in template, will skip in both strings");
367  break;
368  }
369  }
370  t++;
371  } /* while */
372 
373  if (year<100)
374  year+=2000;
375 
377  "Got this date/time: %04d/%02d/%02d",
378  year, month, day);
379 
380  /* get time in local time */
381  gwt=GWEN_Date_fromGregorian(year, month, day);
382  if (!gwt) {
383  DBG_INFO(GWEN_LOGDOMAIN, "here");
384  return 0;
385  }
386  return gwt;
387 }
388 
389 
390 
391 
392 
393 GWEN_LIST_FUNCTIONS(GWEN_DATE_TMPLCHAR, GWEN_DateTmplChar)
394 
395 
396 GWEN_DATE_TMPLCHAR *GWEN_DateTmplChar_new(char c) {
397  GWEN_DATE_TMPLCHAR *e;
398 
399  GWEN_NEW_OBJECT(GWEN_DATE_TMPLCHAR, e);
400  GWEN_LIST_INIT(GWEN_DATE_TMPLCHAR, e);
401  e->character=c;
402  switch(c) {
403  case 'Y': e->maxCount=4; break;
404  case 'M': e->maxCount=2; break;
405  case 'D': e->maxCount=2; break;
406  case 'W': e->maxCount=1; break;
407  case 'w':
408  default: e->maxCount=GWEN_DATE_TMPL_MAX_COUNT; break;
409  }
410 
411  return e;
412 }
413 
414 
415 
416 void GWEN_DateTmplChar_free(GWEN_DATE_TMPLCHAR *e) {
417  if (e) {
418  free(e->content);
419  GWEN_LIST_FINI(GWEN_DATE_TMPLCHAR, e);
420  GWEN_FREE_OBJECT(e);
421  }
422 }
423 
424 
425 
426 GWEN_DATE_TMPLCHAR *GWEN_Date__findTmplChar(GWEN_DATE_TMPLCHAR_LIST *ll, char c) {
427  GWEN_DATE_TMPLCHAR *e;
428 
429  e=GWEN_DateTmplChar_List_First(ll);
430  while(e) {
431  if (e->character==c)
432  break;
433  e=GWEN_DateTmplChar_List_Next(e);
434  }
435 
436  return e;
437 }
438 
439 
440 
441 
442 void GWEN_Date__sampleTmplChars(GWEN_UNUSED const GWEN_DATE *t, const char *tmpl,
444  GWEN_DATE_TMPLCHAR_LIST *ll) {
445  const char *s;
446 
447  s=tmpl;
448  while(*s) {
449  if (strchr("YMDWw", *s)) {
450  GWEN_DATE_TMPLCHAR *e;
451 
452  e=GWEN_Date__findTmplChar(ll, *s);
453  if (!e) {
454  /* new entry, create it */
455  e=GWEN_DateTmplChar_new(*s);
456  GWEN_DateTmplChar_List_Add(e, ll);
457  }
458  assert(e);
459  e->count++;
460  }
461  else {
462  DBG_DEBUG(GWEN_LOGDOMAIN, "Unknown character in template (%02x)",
463  *s);
464  }
465  s++;
466  }
467 }
468 
469 
470 
471 void GWEN_Date__fillTmplChars(const GWEN_DATE *t, GWEN_DATE_TMPLCHAR_LIST *ll) {
472  GWEN_DATE_TMPLCHAR *e;
473 
474 
475  e=GWEN_DateTmplChar_List_First(ll);
476  while(e) {
477  int v;
478 
479  if (e->character=='w') {
480  const char *s=NULL;
481 
482  switch(GWEN_Date_WeekDay(t)) {
483  case 0: s=I18N("Sunday"); break;
484  case 1: s=I18N("Monday"); break;
485  case 2: s=I18N("Tuesday"); break;
486  case 3: s=I18N("Wednesday"); break;
487  case 4: s=I18N("Thursday"); break;
488  case 5: s=I18N("Friday"); break;
489  case 6: s=I18N("Saturday"); break;
490  }
491  assert(s);
492  e->content=strdup(s);
493  e->nextChar=0;
494  }
495  else {
496  char buffer[32];
497  int clen;
498 
499  switch(e->character) {
500  case 'Y':
501  v=t->year;
502  break;
503  case 'M':
504  v=t->month;
505  break;
506  case 'D':
507  v=t->day;
508  break;
509  case 'W':
510  v=GWEN_Date_WeekDay(t);
511  break;
512  default:
513  v=-1;
514  break;
515  }
516  if (v==-1) {
517  DBG_ERROR(GWEN_LOGDOMAIN, "Unknown character, should not happen here");
518  abort();
519  }
520  buffer[0]=0;
521  snprintf(buffer, sizeof(buffer)-1, "%0*d", e->maxCount, v);
522  buffer[sizeof(buffer)-1]=0;
523  e->content=strdup(buffer);
524  /* adjust counter if there are more than maxCount template chars */
525  clen=strlen(e->content);
526  if (e->count>clen)
527  e->count=clen;
528  e->nextChar=clen-(e->count);
529  }
530 
531  e=GWEN_DateTmplChar_List_Next(e);
532  }
533 }
534 
535 
536 
537 
538 int GWEN_Date_toStringWithTemplate(const GWEN_DATE *t, const char *tmpl, GWEN_BUFFER *buf) {
539  GWEN_DATE_TMPLCHAR_LIST *ll;
540  const char *s;
541 
542  ll=GWEN_DateTmplChar_List_new();
543  GWEN_Date__sampleTmplChars(t, tmpl, buf, ll);
545 
546  s=tmpl;
547  while(*s) {
548  if (strchr("YMDWw", *s)) {
549  GWEN_DATE_TMPLCHAR *e;
550  char c;
551 
552  e=GWEN_Date__findTmplChar(ll, *s);
553  assert(e);
554  assert(e->content);
555  if (s[1]=='*') {
556  /* append full string */
557  GWEN_Buffer_AppendString(buf, e->content);
558  /* skip asterisk */
559  s++;
560  }
561  else {
562  c=e->content[e->nextChar];
563  if (c!=0) {
564  GWEN_Buffer_AppendByte(buf, c);
565  e->nextChar++;
566  }
567  }
568  }
569  else
570  GWEN_Buffer_AppendByte(buf, *s);
571  s++;
572  }
573  GWEN_DateTmplChar_List_free(ll);
574  return 0;
575 }
576 
577 
578 
579 int GWEN_Date_toDb(const GWEN_DATE *dt, GWEN_DB_NODE *db) {
580  const char *s;
581 
582  assert(dt);
583  s=GWEN_Date_GetString(dt);
585  return 0;
586 }
587 
588 
589 
591  const char *s;
592 
593  s=GWEN_DB_GetCharValue(db, "dateString", 0, NULL);
594  if (s && *s) {
595  GWEN_DATE *dt;
596 
597  dt=GWEN_Date_fromString(s);
598  if (dt==NULL) {
599  DBG_INFO(GWEN_LOGDOMAIN, "Invalid date [%s]", s);
600  return NULL;
601  }
602 
603  return dt;
604  }
605  else {
606  DBG_VERBOUS(GWEN_LOGDOMAIN, "no or empty date");
607  return NULL;
608  }
609 }
610 
611 
612 
613 
614 
615 
616