Projekt

Allgemein

Profil

Herunterladen (17,8 KB) Statistiken
| Zweig: | Markierung: | Revision:
/***************************************************************************
begin : Tue Jul 07 2009
copyright : (C) 2009 by Martin Preuss
email : martin@libchipcard.de

***************************************************************************
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
* MA 02111-1307 USA *
* *
***************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif


#include "gwendate_p.h"
#include "i18n_l.h"

#include <gwenhywfar/debug.h>
#include <gwenhywfar/misc.h>


#include <time.h>
#include <ctype.h>



static const uint8_t daysInMonth[12]= {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};




GWEN_DATE *GWEN_Date_fromGregorian(int y, int m, int d)
{
GWEN_DATE *gd;

if (m<1 || m>12 || d<1 || d>31) {
DBG_ERROR(GWEN_LOGDOMAIN, "Bad date values (erroneous year=%d, month=%d, day=%d)", y, m, d);
return NULL;
}

GWEN_NEW_OBJECT(GWEN_DATE, gd);
gd->year=y;
gd->month=m;
gd->day=d;
gd->julian=(1461*(y+4800+(m-14)/12))/4+
(367*(m-2-12*((m-14)/12)))/12-
(3*((y+4900+(m-14)/12)/100))/4+
d-32075;

snprintf(gd->asString, sizeof(gd->asString)-1,
"%04d%02d%02d",
gd->year, gd->month, gd->day);
gd->asString[sizeof(gd->asString)-1]=0;

return gd;
}



void GWEN_Date_setJulian(GWEN_DATE *gd, int julian)
{
int l, n, i, j, len;

l=julian+68569;
n=(4*l)/146097;
l=l-(146097*n+3)/4;
i=(4000*(l+1))/1461001;
l=l-(1461*i)/4+31;
j=(80*l)/2447;
gd->day=l-(2447*j)/80;
l=j/11;
gd->month=j+2-(12*l);
gd->year=100*(n-49)+i+l;
gd->julian=julian;

len=snprintf(gd->asString, sizeof(gd->asString)-1,
"%04d%02d%02d",
gd->year, gd->month, gd->day);
gd->asString[sizeof(gd->asString)-1]=0;
if (sizeof(gd->asString)-1 < len)
DBG_ERROR(GWEN_LOGDOMAIN, "truncated date string [%s]", gd->asString);
}



void GWEN_Date_AddDays(GWEN_DATE *gd, int days)
{
GWEN_Date_setJulian(gd, gd->julian+days);
}



void GWEN_Date_SubDays(GWEN_DATE *gd, int days)
{
GWEN_Date_setJulian(gd, gd->julian-days);
}



GWEN_DATE *GWEN_Date_fromJulian(int julian)
{
GWEN_DATE *gd;

GWEN_NEW_OBJECT(GWEN_DATE, gd);
GWEN_Date_setJulian(gd, julian);
return gd;
}



GWEN_DATE *GWEN_Date_fromLocalTime(time_t t)
{
struct tm *ltm;

ltm=localtime(&t);
if (ltm) {
GWEN_DATE *gd;

gd=GWEN_Date_fromGregorian(ltm->tm_year+1900, ltm->tm_mon+1, ltm->tm_mday);
return gd;
}

return NULL;
}



time_t GWEN_Date_toLocalTime(const GWEN_DATE *gd)
{
struct tm ti;
struct tm *tp;
time_t tt;

tt=time(0);
tp=localtime(&tt);
assert(tp);
memmove(&ti, tp, sizeof(ti));
ti.tm_sec=0;
ti.tm_min=0;
ti.tm_hour=0;
ti.tm_year=gd->year-1900;
ti.tm_mon=gd->month-1;
ti.tm_mday=gd->day;
ti.tm_yday=0;
ti.tm_wday=0;
tt=mktime(&ti);
assert(tt!=(time_t)-1);
return tt;
}



GWEN_DATE *GWEN_Date_fromGmTime(time_t t)
{
struct tm *ltm;

ltm=gmtime(&t);
if (ltm) {
GWEN_DATE *gd;

gd=GWEN_Date_fromGregorian(ltm->tm_year+1900, ltm->tm_mon+1, ltm->tm_mday);
return gd;
}

return NULL;
}




GWEN_DATE *GWEN_Date_CurrentDate(void)
{
time_t l;

time(&l);
return GWEN_Date_fromLocalTime(l);
}



GWEN_DATE *GWEN_Date_dup(const GWEN_DATE *ogd)
{
GWEN_DATE *gd;

assert(ogd);

GWEN_NEW_OBJECT(GWEN_DATE, gd);
#if 0
gd->year=ogd->year;
gd->month=ogd->month;
gd->day=ogd->day;
gd->julian=ogd->julian;
memmove(gd->asString, ogd->asString, sizeof(gd->asString));
#else
memmove(gd, ogd, sizeof(GWEN_DATE));
#endif
return gd;
}



GWEN_DATE *GWEN_Date_fromString(const char *s)
{
int y, m, d;

if (3==sscanf(s, "%04d%02d%02d", &y, &m, &d)) {
GWEN_DATE *result = GWEN_Date_fromGregorian(y, m, d);
if (!result)
DBG_INFO(GWEN_LOGDOMAIN, "Bad date string [%s]", s);
return result;
}
else {
DBG_INFO(GWEN_LOGDOMAIN, "Bad date string [%s]", s);
return NULL;
}
}



void GWEN_Date_free(GWEN_DATE *gd)
{
if (gd) {
GWEN_FREE_OBJECT(gd);
}
}



int GWEN_Date_IsLeapYear(int y)
{
return ((y%4==0) && (y%100!=0)) || (y%400==0);
}




int GWEN_Date_DaysInMonth(const GWEN_DATE *gd)
{
assert(gd);
if (gd->month==2 &&
((((gd->year%4)==0) && ((gd->year)%100!=0)) || ((gd->year)%400==0)))
/* February in a leap year */
return 29;
else
return daysInMonth[gd->month-1];
}



int GWEN_Date_DaysInYear(const GWEN_DATE *gd)
{
GWEN_DATE *gd11;
int result;

assert(gd);

gd11=GWEN_Date_fromGregorian(gd->year, 1, 1);
result=(gd->julian)-(gd11->julian);
GWEN_Date_free(gd11);

return result;
}



int GWEN_Date_GetYear(const GWEN_DATE *gd)
{
assert(gd);
return gd->year;
}



int GWEN_Date_GetMonth(const GWEN_DATE *gd)
{
assert(gd);
return gd->month;
}



int GWEN_Date_GetDay(const GWEN_DATE *gd)
{
assert(gd);
return gd->day;
}



int GWEN_Date_GetJulian(const GWEN_DATE *gd)
{
assert(gd);
return gd->julian;
}



int GWEN_Date_WeekDay(const GWEN_DATE *gd)
{
assert(gd);
return (gd->julian+1)%7; /* 0=Sunday */
}



const char *GWEN_Date_GetString(const GWEN_DATE *gd)
{
assert(gd);
return gd->asString;
}



int GWEN_Date_Compare(const GWEN_DATE *gd1, const GWEN_DATE *gd0)
{
if (gd0 && gd1) {
if (gd1->julian==gd0->julian)
return 0;
else if (gd1->julian>gd0->julian)
return 1;
else
return -1;
}
else if (gd0)
return 1;
else if (gd1)
return -1;
else
return 0;
}



int GWEN_Date_Diff(const GWEN_DATE *gd1, const GWEN_DATE *gd0)
{
assert(gd1);
assert(gd0);

return gd1->julian-gd0->julian;
}



GWEN_DATE *GWEN_Date_fromTime(const GWEN_TIME *ti)
{
GWEN_BUFFER *tbuf;
GWEN_DATE *gd;

tbuf=GWEN_Buffer_new(0, 32, 0, 1);
GWEN_Time_toString(ti, "YYYYMMDD", tbuf);
gd=GWEN_Date_fromString(GWEN_Buffer_GetStart(tbuf));
GWEN_Buffer_free(tbuf);

return gd;
}




GWEN_DATE *GWEN_Date_fromStringWithTemplate(const char *s, const char *tmpl)
{
int year, month, day;
const char *p;
const char *t;
GWEN_DATE *gwt;

assert(s);
assert(tmpl);
year=month=day=0;

p=s;
t=tmpl;
while (*t && *p) {
int i;

if (*t=='*') {
t++;
if (!*t) {
DBG_ERROR(GWEN_LOGDOMAIN, "Bad pattern: Must not end with \"*\"");
return 0;
}
i=0;
while (*p) {
if (!isdigit((int)*p))
break;
if (*p==*t)
break;
i*=10;
i+=(*p)-'0';
p++;
} /* while */
}
else {
if (isdigit((int)*p))
i=(*p)-'0';
else
i=-1;
p++;
}

if (i==-1 && strchr("YMD", *t)!=NULL) {
DBG_INFO(GWEN_LOGDOMAIN,
"No more digits at [%s], continuing", t);
p--;
}
else {
switch (*t) {
case 'Y':
if (i==-1) {
DBG_INFO(GWEN_LOGDOMAIN, "here");
return 0;
}
year*=10;
year+=i;
break;
case 'M':
if (i==-1) {
DBG_INFO(GWEN_LOGDOMAIN, "here");
return 0;
}
month*=10;
month+=i;
break;
case 'D':
if (i==-1) {
DBG_INFO(GWEN_LOGDOMAIN, "here");
return 0;
}
day*=10;
day+=i;
break;
default:
DBG_VERBOUS(GWEN_LOGDOMAIN,
"Unknown character in template, will skip in both strings");
break;
}
}
t++;
} /* while */

if (year<100)
year+=2000;

DBG_DEBUG(GWEN_LOGDOMAIN,
"Got this date/time: %04d/%02d/%02d",
year, month, day);

/* get time in local time */
gwt=GWEN_Date_fromGregorian(year, month, day);
if (!gwt) {
DBG_ERROR(GWEN_LOGDOMAIN, "Bad date string [%s]", s);
return 0;
}
return gwt;
}





GWEN_LIST_FUNCTIONS(GWEN_DATE_TMPLCHAR, GWEN_DateTmplChar)


GWEN_DATE_TMPLCHAR *GWEN_DateTmplChar_new(char c)
{
GWEN_DATE_TMPLCHAR *e;

GWEN_NEW_OBJECT(GWEN_DATE_TMPLCHAR, e);
GWEN_LIST_INIT(GWEN_DATE_TMPLCHAR, e);
e->character=c;
switch (c) {
case 'Y':
e->maxCount=4;
break;
case 'M':
e->maxCount=2;
break;
case 'D':
e->maxCount=2;
break;
case 'W':
e->maxCount=1;
break;
case 'w':
default:
e->maxCount=GWEN_DATE_TMPL_MAX_COUNT;
break;
}

return e;
}



void GWEN_DateTmplChar_free(GWEN_DATE_TMPLCHAR *e)
{
if (e) {
free(e->content);
GWEN_LIST_FINI(GWEN_DATE_TMPLCHAR, e);
GWEN_FREE_OBJECT(e);
}
}



GWEN_DATE_TMPLCHAR *GWEN_Date__findTmplChar(GWEN_DATE_TMPLCHAR_LIST *ll, char c)
{
GWEN_DATE_TMPLCHAR *e;

e=GWEN_DateTmplChar_List_First(ll);
while (e) {
if (e->character==c)
break;
e=GWEN_DateTmplChar_List_Next(e);
}

return e;
}




void GWEN_Date__sampleTmplChars(GWEN_UNUSED const GWEN_DATE *t, const char *tmpl,
GWEN_UNUSED GWEN_BUFFER *buf,
GWEN_DATE_TMPLCHAR_LIST *ll)
{
const char *s;

s=tmpl;
while (*s) {
if (strchr("YMDWw", *s)) {
GWEN_DATE_TMPLCHAR *e;

e=GWEN_Date__findTmplChar(ll, *s);
if (!e) {
/* new entry, create it */
e=GWEN_DateTmplChar_new(*s);
GWEN_DateTmplChar_List_Add(e, ll);
}
assert(e);
e->count++;
}
else {
DBG_DEBUG(GWEN_LOGDOMAIN, "Unknown character in template (%02x)",
*s);
}
s++;
}
}



void GWEN_Date__fillTmplChars(const GWEN_DATE *t, GWEN_DATE_TMPLCHAR_LIST *ll)
{
GWEN_DATE_TMPLCHAR *e;


e=GWEN_DateTmplChar_List_First(ll);
while (e) {
int v;

if (e->character=='w') {
const char *s=NULL;

switch (GWEN_Date_WeekDay(t)) {
case 0:
s=I18N("Sunday");
break;
case 1:
s=I18N("Monday");
break;
case 2:
s=I18N("Tuesday");
break;
case 3:
s=I18N("Wednesday");
break;
case 4:
s=I18N("Thursday");
break;
case 5:
s=I18N("Friday");
break;
case 6:
s=I18N("Saturday");
break;
}
assert(s);
e->content=strdup(s);
e->nextChar=0;
}
else {
char buffer[32];
int clen;

switch (e->character) {
case 'Y':
v=t->year;
break;
case 'M':
v=t->month;
break;
case 'D':
v=t->day;
break;
case 'W':
v=GWEN_Date_WeekDay(t);
break;
default:
v=-1;
break;
}
if (v==-1) {
DBG_ERROR(GWEN_LOGDOMAIN, "Unknown character, should not happen here");
abort();
}
buffer[0]=0;
snprintf(buffer, sizeof(buffer)-1, "%0*d", e->maxCount, v);
buffer[sizeof(buffer)-1]=0;
e->content=strdup(buffer);
/* adjust counter if there are more than maxCount template chars */
clen=strlen(e->content);
if (e->count>clen)
e->count=clen;
e->nextChar=clen-(e->count);
}

e=GWEN_DateTmplChar_List_Next(e);
}
}




int GWEN_Date_toStringWithTemplate(const GWEN_DATE *t, const char *tmpl, GWEN_BUFFER *buf)
{
GWEN_DATE_TMPLCHAR_LIST *ll;
const char *s;

ll=GWEN_DateTmplChar_List_new();
GWEN_Date__sampleTmplChars(t, tmpl, buf, ll);
GWEN_Date__fillTmplChars(t, ll);

s=tmpl;
while (*s) {
if (strchr("YMDWw", *s)) {
GWEN_DATE_TMPLCHAR *e;
char c;

e=GWEN_Date__findTmplChar(ll, *s);
assert(e);
assert(e->content);
if (s[1]=='*') {
/* append full string */
GWEN_Buffer_AppendString(buf, e->content);
/* skip asterisk */
s++;
}
else {
c=e->content[e->nextChar];
if (c!=0) {
GWEN_Buffer_AppendByte(buf, c);
e->nextChar++;
}
}
}
else
GWEN_Buffer_AppendByte(buf, *s);
s++;
}
GWEN_DateTmplChar_List_free(ll);
return 0;
}



int GWEN_Date_toDb(const GWEN_DATE *dt, GWEN_DB_NODE *db)
{
const char *s;

assert(dt);
s=GWEN_Date_GetString(dt);
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "dateString", s);
return 0;
}



GWEN_DATE *GWEN_Date_fromDb(GWEN_DB_NODE *db)
{
const char *s;

s=GWEN_DB_GetCharValue(db, "dateString", 0, NULL);
if (s && *s) {
GWEN_DATE *dt;

dt=GWEN_Date_fromString(s);
if (dt==NULL) {
DBG_INFO(GWEN_LOGDOMAIN, "Invalid date [%s]", s);
return NULL;
}

return dt;
}
else {
DBG_VERBOUS(GWEN_LOGDOMAIN, "no or empty date");
return NULL;
}
}



GWEN_DATE *GWEN_Date_GetThisMonthStart(const GWEN_DATE *dt)
{
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), GWEN_Date_GetMonth(dt), 1);
}



GWEN_DATE *GWEN_Date_GetThisMonthEnd(const GWEN_DATE *dt)
{
int day;

switch (GWEN_Date_GetMonth(dt)) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
day=31;
break;
case 2:
if (GWEN_Date_IsLeapYear(GWEN_Date_GetYear(dt)))
day=29;
else
day=28;
break;

case 4:
case 6:
case 9:
case 11:
day=30;
break;

default:
DBG_ERROR(GWEN_LOGDOMAIN, "Invalid month (%d)", GWEN_Date_GetMonth(dt));
abort();
break;
}
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), GWEN_Date_GetMonth(dt), day);
}



GWEN_DATE *GWEN_Date_GetThisQuarterYearStart(const GWEN_DATE *dt)
{
int m;

m=GWEN_Date_GetMonth(dt)>>2;
switch (m) {
case 0:
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), 1, 1);
case 1:
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), 4, 1);
case 2:
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), 7, 1);
case 3:
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), 10, 1);
}

return NULL;
}



GWEN_DATE *GWEN_Date_GetThisQuarterYearEnd(const GWEN_DATE *dt)
{
int m;

m=GWEN_Date_GetMonth(dt)>>2;
switch (m) {
case 0:
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), 3, 31);
case 1:
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), 6, 30);
case 2:
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), 9, 30);
case 3:
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), 12, 31);
}

return NULL;
}



GWEN_DATE *GWEN_Date_GetThisHalfYearStart(const GWEN_DATE *dt)
{
if (GWEN_Date_GetMonth(dt)<7)
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), 1, 1);
else
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), 7, 1);
}



GWEN_DATE *GWEN_Date_GetThisHalfYearEnd(const GWEN_DATE *dt)
{
if (GWEN_Date_GetMonth(dt)<7)
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), 6, 30);
else
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), 12, 31);
}



GWEN_DATE *GWEN_Date_GetThisYearStart(const GWEN_DATE *dt)
{
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), 1, 1);
}



GWEN_DATE *GWEN_Date_GetThisYearEnd(const GWEN_DATE *dt)
{
return GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), 12, 31);
}



GWEN_DATE *GWEN_Date_GetLastMonthStart(const GWEN_DATE *dt)
{
GWEN_DATE *tmpDate;
GWEN_DATE *result;
int j;

tmpDate=GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), GWEN_Date_GetMonth(dt), 1);
j=GWEN_Date_GetJulian(tmpDate)-1;
GWEN_Date_free(tmpDate);
tmpDate=GWEN_Date_fromJulian(j);
result=GWEN_Date_fromGregorian(GWEN_Date_GetYear(tmpDate), GWEN_Date_GetMonth(tmpDate), 1);
GWEN_Date_free(tmpDate);
return result;
}



GWEN_DATE *GWEN_Date_GetLastMonthEnd(const GWEN_DATE *dt)
{
GWEN_DATE *tmpDate;
int j;

tmpDate=GWEN_Date_fromGregorian(GWEN_Date_GetYear(dt), GWEN_Date_GetMonth(dt), 1);
j=GWEN_Date_GetJulian(tmpDate)-1;
GWEN_Date_free(tmpDate);
return GWEN_Date_fromJulian(j);
}



GWEN_DATE *GWEN_Date_GetLastQuarterYearStart(const GWEN_DATE *dt)
{
GWEN_DATE *tmpDate;
GWEN_DATE *result;

tmpDate=GWEN_Date_GetLastQuarterYearEnd(dt);
result=GWEN_Date_GetThisQuarterYearStart(tmpDate);
GWEN_Date_free(tmpDate);
return result;
}



GWEN_DATE *GWEN_Date_GetLastQuarterYearEnd(const GWEN_DATE *dt)
{
GWEN_DATE *tmpDate;
int j;

tmpDate=GWEN_Date_GetThisQuarterYearStart(dt);
j=GWEN_Date_GetJulian(tmpDate)-1;
GWEN_Date_free(tmpDate);
return GWEN_Date_fromJulian(j);
}



GWEN_DATE *GWEN_Date_GetLastHalfYearStart(const GWEN_DATE *dt)
{
GWEN_DATE *tmpDate;
GWEN_DATE *result;

tmpDate=GWEN_Date_GetLastHalfYearEnd(dt);
result=GWEN_Date_GetThisHalfYearStart(tmpDate);
GWEN_Date_free(tmpDate);
return result;
}



GWEN_DATE *GWEN_Date_GetLastHalfYearEnd(const GWEN_DATE *dt)
{
GWEN_DATE *tmpDate;
int j;

tmpDate=GWEN_Date_GetThisHalfYearStart(dt);
j=GWEN_Date_GetJulian(tmpDate)-1;
GWEN_Date_free(tmpDate);
return GWEN_Date_fromJulian(j);
}



GWEN_DATE *GWEN_Date_GetLastYearStart(const GWEN_DATE *dt)
{
GWEN_DATE *tmpDate;
GWEN_DATE *result;

tmpDate=GWEN_Date_GetLastYearEnd(dt);
result=GWEN_Date_GetThisYearStart(tmpDate);
GWEN_Date_free(tmpDate);
return result;
}



GWEN_DATE *GWEN_Date_GetLastYearEnd(const GWEN_DATE *dt)
{
GWEN_DATE *tmpDate;
int j;

tmpDate=GWEN_Date_GetThisYearStart(dt);
j=GWEN_Date_GetJulian(tmpDate)-1;
GWEN_Date_free(tmpDate);
return GWEN_Date_fromJulian(j);
}








(5-5/21)