static	char	sccsid[]="%Z% %M% %I% %E% %U%";
/************************************************************************
*																		*
*	処理目的	： 日付処理												*
*																		*
*	処理概要	： 														*
*																		*
*************************************************************************/
#include <colmn.h>

extern CLCOMMON  CLcommon;
extern CLPRTBL   *pCLprocTable;
extern GlobalCt  *pGlobTable;
extern int giOptions[];

static char *month[]={"January","Jan","February","Feb","March","Mar","April","Apr",
	"May","May","June","Jun","July","Jul","August","Aug","September","Sep",
	"October","Oct","November","Nov","December","Dec",NULL,NULL};
static char *week[]={"Sunday","Sun","日曜","Monday","Mon","月曜",
	"Tuesday","Tue","火曜","Wednesday","Wed","水曜","Thursday","Thu","木曜",
	"Friday","Fri","金曜","Saturday","Sat","土曜",NULL,NULL,NULL};
static char char2ix[]={0,0,0,3,0,0,0,4,0,12,0,0,2,5,0,10,0,0,6,0,7,0,0,0,1,0};

/****************************************/
/*										*/
/****************************************/
char *cl_get_date_format()
{
	tdtInfoParm *pInfoParm;
	char *p,*pp,w[16];
	int  len;

	if (pGlobTable->options[18] & 0x01) {
		p = D_NAM_UNX_DATE_FORMAT;
		pp = D_UNX_DATE_FORMAT;
	}
	else {
		p = D_NAM_SQL_DATE_FORMAT;
		pp = D_SQL_DATE_FORMAT;
	}

	if (pInfoParm = cl_get_public_var(p)) {
		pp = w;
		if ((len=parm_to_char(pInfoParm,&pp,NULL)) < 0) return NULL;
	}
	return pp;
}

/****************************************/
/*										*/
/****************************************/
int cl_chk_date(d,s)
char *s, *d;
{
	static int y0=AKX_TIME_BASE;
	int len,ssp,n,ret,y,m,dm;
	char wd[20],c,yyyy[5],mm[3],dd[3],c1,c2;

	if (!s || !d) return -1;
	*d = yyyy[4] = mm[2] = dd[2] = '\0';
	ssp = 0;
	len = akxtgetw(s, &ssp, wd, sizeof(wd));	/* YYYY/MM/DD */
/*
printf("chk_date:1: len=%d wd=[%s]\n",len,wd);
*/
	ret = 0;
	if (len <= 0) {
		memcpy(yyyy,"0",2);
		memcpy(mm,"0",2);
		memcpy(dd,"0",2);
	}
	else if (len == 10) {	/* YYYY/MM/DD */
		if ((c1=wd[4])>='0' && c1<='9') return -2;
		if ((c2=wd[7])>='0' && c2<='9') return -2;
		sprintf(d,"%s ",wd);
		if (c1 != '/') ret  = 0x01;
		if (c2 != '/') ret |= 0x02;
		memcpy(yyyy,wd,4);
		memcpy(mm,wd+5,2);
		memcpy(dd,wd+8,2);
	}
	else {
		if (len == 8) {	/* YY/MM/DD or YYYYMMDD */
			if ((c=wd[2])<'0' || c>'9') {	/* YY/MM/DD */
				ret = akxccvn(10,wd,2,&n);
				if (ret) return -10;
				if (n >= 51) strcpy(yyyy,"19");
				else         strcpy(yyyy,"20");
				memcpy(yyyy+2,wd,2);
				memcpy(mm,wd+3,2);
				memcpy(dd,wd+6,2);
			}
			else {	/* YYYYMMDD */
				memcpy(yyyy,wd,4);
				memcpy(mm,wd+4,2);
				memcpy(dd,wd+6,2);
			}
		}
		else if (len == 7) {	/* YYYY/MM */
			if ((c=wd[4])<'0' || c>'9') {
				memcpy(yyyy,wd,4);
				memcpy(mm,wd+5,2);
				memcpy(dd,"01",2);
			}
			else return -3;
		}
		else if (len == 6) {	/* YYMMDD */
			ret = akxccvn(10,wd,2,&n);
			if (ret) return ret;
			if (n >= 51) strcpy(yyyy,"19");
			else         strcpy(yyyy,"20");
			memcpy(yyyy+2,wd,2);
			memcpy(mm,wd+2,2);
			memcpy(dd,wd+4,2);
		}
		else if (len == 5) {	/* YY/MM */
			if ((c=wd[2])<'0' || c>'9') {
				ret = akxccvn(10,wd,2,&n);
				if (ret) return ret;
				if (n >= 51) strcpy(yyyy,"19");
				else         strcpy(yyyy,"20");
				memcpy(yyyy+2,wd,2);
				memcpy(mm,wd+3,2);
				memcpy(dd,"01",2);
			}
			else return -4;
		}
		else if (len == 4) {	/* YYYY */
			memcpy(yyyy,wd,4);
			memcpy(mm,"01",2);
			memcpy(dd,"01",2);
		}
		else return -5;
	}
	/* 年のチェック */
	ret = akxccvn(10,yyyy,strlen(yyyy),&y);
/*
printf("chk_date:y: ret=%d y=%d\n",ret,y);
*/
	if (ret < 0) return ret;
	else if (ret > 0) return -ret-100;
	if (y < y0) {
		y = y0;
		akxcitoa(y,yyyy,10,5);
	}
	/* 月のチェック */
	ret = akxccvn(10,mm,strlen(mm),&m);
/*
printf("chk_date:m: ret=%d m=%d\n",ret,m);
*/
	if (ret < 0) return ret;
	else if (ret > 0) return -ret-100;
	if (m <= 0) {
		m = 1;
		memcpy(mm,"01",2);
	}
	else if (m > 12) {
		m = 12;
		memcpy(mm,"12",2);
	}
	/* 日のチェック */
	ret = akxccvn(10,dd,strlen(dd),&n);
/*
printf("chk_date:d: ret=%d d=%d\n",ret,n);
*/
	if (ret < 0) return ret;
	else if (ret > 0) return -ret-100;
	if (n <= 0) memcpy(dd,"01",2);
	else {
		dm = cl_days_of_month(y,m);
		if (n > dm) akxcitoa(dm,dd,10,3);
	}
	sprintf(d,"%s/%s/%s ",yyyy,mm,dd);

	len = akxtgetw(s, &ssp, wd, sizeof(wd));	/* HH:MM:SS */
/*
printf("chk_date:2: len=%d wd=[%s]\n",len,wd);
*/
	if (len <= 0) {
		strcpy(wd,"00:00:00");
	}
	else if (len == 8) {
		if ((c1=wd[2])>='0' && c1<='9') return -6;
		if ((c2=wd[5])>='0' && c2<='9') return -6;
		if (c1 != ':') ret |= 0x04;
		if (c2 != ':') ret |= 0x08;
	}
	else return -7;

	strcpy(d+11,wd);
/*
printf("chk_date:2: d=[%s]\n",d);
*/
	return ret;
}

/****************************************/
/*										*/
/****************************************/
static int _bin2byte(num,usec,n)
uchar *num;
int usec,n;
{
	int w;
	uchar *x=num+n-1;

	w = usec;
	*x-- = w & 0xff;
	w >>= 8;
	*x-- = w & 0xff;
	if (n >= 3) {
		w >>= 8;
		*x = w & 0xff;
	}
	return 0;
}

/****************************************/
/*										*/
/****************************************/
int cl_tm2mpa(ma,stm,usec)
MPA *ma;
struct tm *stm;
int usec;
{
	int w;

	if (!ma || !stm) return -1;
	*ma = *m_get_i(1);
	ma->num[6] = stm->tm_sec;			/* 秒 */
	ma->num[5] = stm->tm_min;			/* 分 */
	ma->num[4] = stm->tm_hour;			/* 時間 */
	ma->num[3] = stm->tm_mday;			/* 日 */
	ma->num[2] = stm->tm_mon + 1;		/* 月 */
#if 1	/* 2021.5.8 */
	w = stm->tm_year + AKX_TM_YEAR_BASE;
	ma->num[1] = w % 100;	/* __YY年 */
	ma->num[0] = w/100;		/* YY__年 */
#else
	ma->num[1] = stm->tm_year % 100;	/* 年 */
	ma->num[0] = stm->tm_year/100 + 19;	/* 年 */
#endif
	_bin2byte(&ma->num[7],usec,3);		/* マイクロ秒 */
	ma->num[10] = stm->tm_hour<12 ? 0 : 1;	/* AM / PM */
	ma->num[11] = stm->tm_wday;			/* 曜日 (0-6, 日曜 = 0) */
	_bin2byte(&ma->num[12],stm->tm_yday,2);	/* 年内通算日 (0-365, 1 月 1 日 = 0) */
	ma->exp = 6;
	ma->len = D_LEN_DATE;
/*
printf("cl_tm2mpa: num7=%02x %02x %02x\n",ma->num[7],ma->num[8],ma->num[9]);
*/
	return 0;
}

/****************************************/
/*										*/
/****************************************/
static int _byte2bin(num,n)
uchar *num;
int n;
{
	int w;
	uchar *x=num;

	w = *x++;
	w <<= 8;
	w |= *x++;
	if (n >= 3) {
		w <<= 8;
		w |= *x;
	}
	return w;
}

/****************************************/
/*										*/
/****************************************/
int cl_mpa2tm(stm,ma)
struct tm *stm;
MPA *ma;
{
	int w;

	if (!ma || !stm) return -1;
	memset(stm,0,sizeof(struct tm));
	stm->tm_sec  = ma->num[6];		/* 秒 */
	stm->tm_min  = ma->num[5];		/* 分 */
	stm->tm_hour = ma->num[4];		/* 時間 */
	stm->tm_mday = ma->num[3];		/* 日 */
	stm->tm_mon  = ma->num[2] - 1;	/* 月 */
#if 1	/* 2021.5.8 */
	w = ma->num[0]*100 + ma->num[1] - AKX_TM_YEAR_BASE;	/* 年 */
	if (w < 0) w = 0; 
	stm->tm_year = w;	/* 年 */
#else
	stm->tm_year = (ma->num[0]-19)*100 + ma->num[1];	/* 年 */
#endif
	stm->tm_wday = ma->num[11];		/* 曜日 (0-6, 日曜 = 0) */
	stm->tm_yday = ma->num[12]*100 + ma->num[13];		/* 年内通算日 (0-365)*/
	return _byte2bin(&ma->num[7],3);
}

/****************************************************/
/*	グレゴリウス暦1年1月1日からの経過日数を求める	*/
/****************************************************/
static time_t get_days(int y, int m, int d)
{
	time_t dy,c,dl,dm;

	/* 1・2月 ==> 前年の13・14月 */
	if (m <= 2) {
		y--;
		m += 12;
	}
	dy = 365 * ((time_t)y - 1);				/* 経過年数×365日 */
	c  = y / 100;
	dl = (y >> 2) - c + (c >> 2);	/* うるう年分 */
	dm = (m * 979 - 1033) >> 5;		/* 1月1日からm月1日までの日数 */
	return dy + dl + dm + d - 1;
}

/****************************************/
/*										*/
/****************************************/
static time_t get_seconds(int h, int m, int s)
{
	return ((time_t)h*60 + (time_t)m)*60 + (time_t)s;
}

/****************************************/
/*										*/
/****************************************/
static int _func_set_date_part(pInfoParmW,p1,len1,nparm,ppParm,ma)
tdtInfoParm *pInfoParmW;
char *p1;
int  len1,nparm;
tdtInfoParm *ppParm[];
MPA *ma;
{
	int  rc,len,uxflg;
	char w2[16],*p2,date[20];
	struct tm stm,*ptm;
	time_t tt;

	uxflg = 1;
	rc = -1;
	if (nparm >= 1) {
		p2 = w2;
		if ((len = parm_to_char(ppParm[0],&p2,NULL))<0) {
			return len;
		}
		else if (!*p2) p2 = cl_get_date_format();
	}
	else {
		p2 = cl_get_date_format();
	}
	if (!p2) return -1;
	len = strlen(p2);
 	rc = akxs_in_mem_opt(p2,len,"%",1,0);
/*
printf("_func_set_date_part: len=%d rc=%d\n",len,rc);
*/
	if (!rc) uxflg = 0;	/* p2 = _uxformat(p2,len);	*/

	if (uxflg) {
		tt = time(NULL);
		if (!(ptm = localtime(&tt))) return ECL_SCRIPT_ERROR;
		if (strptime(p1,p2,ptm))
/*
akxaxdump("_func_set_date_part: stm",&stm,sizeof(DATE));
*/
			rc = cl_tm2mpa(ma,ptm);
		else rc = -1;
	}
	else rc = cl_str2date(p1,len1,p2,len,ma);
	if (rc < 0) {
		return rc;
	}
/*
akxaxdump("_func_set_date_part: ma",ma,sizeof(MPA));
*/
	cl_set_parm_date(pInfoParmW,ma);
DEBUGOUT_InfoParm(151,"_func_set_date_part:",pInfoParmW,0,0);
	return 0;
}

/****************************************/
/*										*/
/****************************************/
int cl_func_to_date(pInfoParmW,nparm,ppParm)
tdtInfoParm *pInfoParmW;
int nparm;
tdtInfoParm *ppParm[];
{
	MPA maz,*ma;
	int  len1,rc;
	char w1[16],*p1,date[20];

	p1 = w1;
	if ((len1=parm_to_char(ppParm[0],&p1,NULL)) < 0) {
		return len1;
	}
	if (nparm < 2) {
		rc = cl_chk_date(date,p1);	/* YYYY/MM/DD HH:MI:SS */
/*
printf("cl_func_to_date: rc=%d\n",rc);
*/
		if (rc < 0) return rc;
/*
printf("cl_func_to_date: rc=%x date=[%s]\n",rc,date);
*/
		if (rc & 0x01) date[ 4] = '/';
		if (rc & 0x02) date[ 7] = '/';
		if (rc & 0x04) date[13] = ':';
		if (rc & 0x08) date[16] = ':';
/*
printf("cl_func_to_date: date=[%s]\n",date);
*/
		p1 = date;
		len1 = strlen(p1);
	}
	ma = (MPA *)cl_get_tmpMPA(&maz);
	clgetsysdate(ma);
	ma->num[D_LEN_DATE] = 1;
	return _func_set_date_part(pInfoParmW,p1,len1,nparm-1,ppParm+1,ma);
}

/****************************************/
/*										*/
/****************************************/
int cl_func_set_date_part(pInfoParmW,nparm,ppParm)
tdtInfoParm *pInfoParmW;
int nparm;
tdtInfoParm *ppParm[];
{
	MPA maz,*ma;
	int ret,len1;
	char w1[16],*p1;
	long t1;

	ma = (MPA *)cl_get_tmpMPA(&maz);
	ret = cl_get_parm_date(ppParm[0],ma,"cl_func_set_part_date");
/*
printf("cl_func_set_date_part: ret=%d\n",ret);
*/
	if (!ret) {
		p1 = w1;
		if ((len1=parm_to_char(ppParm[1],&p1,NULL)) < 0) return len1;
		ma->num[D_LEN_DATE] = 0;
		ret = _func_set_date_part(pInfoParmW,p1,len1,nparm-2,ppParm+2,ma);
	}
	return ret;
}

/****************************************/
/*										*/
/****************************************/
int cl_date2uxstr(p2,len,p1,ma)
char *p1,*p2;
int  len;
MPA  *ma;
{
	struct tm stm;
/*
printf("cl_date2str: len=%d p1=%08x\n",len,p1);
*/
	if (!p2 || !ma || len<1) return -1;
	if (!p1) p1 = D_UNX_DATE_FORMAT;
	cl_mpa2tm(&stm,ma);
	strftime(p2,len,p1,&stm);
/*
printf("cl_date2str: p2=[%s]\n",p2);
*/
	return strlen(p2);
}

/****************************************/
/*										*/
/****************************************/
int cl_func_to_char(pInfoParmW,nparm,ppParm)
tdtInfoParm *pInfoParmW;
int nparm;
tdtInfoParm *ppParm[];
{
	int  rc,len,uxflg,len2;
	char *p1,*p2;
	tdtInfoParm *pParm;
	char *pWork;
	int pre;

	pre = 0;
	uxflg = 1;
	rc = -1;
	p1 = NULL;
	pParm = ppParm[0];
/*
printf("cl_func_to_char: nparm=%d attr=%d\n",nparm,pParm->pi_attr);
*/
	if (pParm->pi_attr == DEF_ZOK_DATE) {
		if (nparm >= 2) {
			if ((len = parm_to_char(ppParm[1],&p1,NULL))<0) {
				return len;
			}
			else if (!*p1) p1 = cl_get_date_format();
		}
		else p1 = cl_get_date_format();
		len = strlen(p1);
		if (!p1) return -1;
 		rc = akxs_in_mem_opt(p1,len,"%",1,0);
/*
printf("cl_func_to_char: len=%d rc=%d\n",len,rc);
*/
		if (!rc) uxflg = 0;
		len2 = strlen(p1);
		len2 = len2*2 + 4;
		if (!(p2 = cl_tmp_const_malloc(len2+1))) return -1;
		if (uxflg) cl_date2uxstr(p2,len2,p1,pParm->pi_data);
		else cl_date2str(p2,len2,p1,len,pParm->pi_data);
		len2 = strlen(p2);
	}
	else {
		if ((len2 = parm_to_char(pParm,&p1,NULL))<0) {
			return len2;
		}
		p2 = p1;
/*
printf("cl_func_to_char: len2=%d p2=[%s]\n",len2,p2);
*/
		if (nparm >= 2) {
			if (rc = cl_get_parm_bin(ppParm[1],&pre,"to_char.p2")) return rc;
			if (pre < 0) {
				/* %s: 精度(%d)が誤っています。 */
				ERROROUT2(FORMAT(464),"cl_func_to_char",pre);
				return ECL_SCRIPT_ERROR;
			}
			else if (pre > 0) {
				if (pre <= len2) {
					*(p2+pre) = '\0';
				}
				else {
					if (!(p2 = cl_tmp_const_malloc(pre+1))) return -1;
					memcpy(p2,p1,len2);
					memset(p2+len2,' ',pre-len2);
					*(p2+pre)='\0';
				}
				len2 = pre;
			}
		}
	}
/*
printf("cl_func_to_char: len2=%d p2=[%s]\n",len2,p2);
*/
	cl_set_parm_char(pInfoParmW,p2,len2);
	if (pre > 0) {
		pInfoParmW->pi_len = pre;
		pInfoParmW->pi_aux[0] = DEF_ZOK_CHAR;
	}
	return 0;
}

/****************************************/
/*										*/
/****************************************/
int cl_get_parm_date(pInfoParmW,ma,msg)
tdtInfoParm *pInfoParmW;
MPA *ma;
char *msg;
{
	int  attr,size,rc;
	time_t tt;
	long lValue;
	struct  tm *stm;
	tdtInfoParm tInfoParm;

	if (!pInfoParmW || !ma) return -1;
	if (!msg) msg="";

	attr = pInfoParmW->pi_attr;
	size = pInfoParmW->pi_dlen;
	if (attr == DEF_ZOK_DATE) {
		memcpy(ma,pInfoParmW->pi_data,size);
	}
	else if (attr == DEF_ZOK_CHAR) {
		if (rc=cl_func_to_date(&tInfoParm,1,&pInfoParmW)) return rc;
		memcpy(ma,tInfoParm.pi_data,sizeofMPA());
	}
	else {
		if ((rc=cl_get_parm_long(pInfoParmW,&lValue,msg)) < 0) return rc;
		else if (rc > 0) return ECL_SCRIPT_ERROR;
		tt = lValue;
		stm = localtime(&tt);
		cl_tm2mpa(ma,stm);
	}
	return 0;
}

/****************************************/
/*										*/
/****************************************/
int cl_set_parm_date(pInfoParmW,ma)
tdtInfoParm *pInfoParmW;
MPA *ma;
{
	int rc;

	if (!pInfoParmW || !ma) return -1;
	rc = cl_set_parm_mpa(pInfoParmW,ma);
	pInfoParmW->pi_attr = DEF_ZOK_DATE;
	return rc;
}

/****************************************/
/*										*/
/****************************************/
static int get_time_intval(pInfoParm)
tdtInfoParm *pInfoParm;
{
	int  rc,len;
	char *p1,c1,wrk[5];
	long lValue;

	if (pInfoParm->pi_attr == DEF_ZOK_CHAR) {
		rc = atoi(p1=pInfoParm->pi_data);
		if (rc) return rc;
		len = X_MIN(pInfoParm->pi_dlen,4);
		akxcuppern(wrk,p1,len);
		c1 = wrk[0];
		if (c1=='M' && wrk[1]=='I') c1 = 'N';
		if (c1 == 'Y') rc = 1;
		else if (c1 == 'M') rc = 2;
		else if (c1 == 'D') rc = 3;
		else if (c1 == 'W') rc = 8;
		else if (c1 == 'H') rc = 4;
		else if (c1 == 'N') rc = 5;
		else if (c1 == 'S') rc = 6;
		else if (c1 == 'Q') rc = 7;
	}
	else {
		if ((rc=cl_get_parm_long(pInfoParm,&lValue,"get_time_intval")) < 0) return rc;
		else if (rc > 0) return ECL_SCRIPT_ERROR;
		rc = lValue;
	}
/*
printf("get_time_intval: rc=%d\n",rc);
*/
	return rc;
}

/****************************************/
/*										*/
/****************************************/
int cl_get_term_index(pInfoParm)
tdtInfoParm *pInfoParm;
{
	return get_time_intval(pInfoParm);
}

/****************************************/
/*										*/
/****************************************/
char cl_get_term_char(index)
int index;
{
	static char *term="YMDHNS";
	char c;

	if (index>=1 && index<=6) c = *(term+index-1);
	else c = 'D';
	return c;
}

/****************************************/
/*										*/
/****************************************/
static int _func_date_add(MPA *ma, long lValue, int n)
{
	struct tm stm,*ptm;
	time_t tt;

	cl_mpa2tm(&stm,ma);

	switch (n) {
		case 1:	stm.tm_year += lValue;	break;
		case 2:	stm.tm_mon  += lValue;	break;
		case 3:	stm.tm_mday += lValue;	break;
		case 4:	stm.tm_hour += lValue;	break;
		case 5:	stm.tm_min  += lValue;	break;
		case 6:	stm.tm_sec  += lValue;	break;
		case 7:	stm.tm_mon  += lValue*3;	break;
		case 8:	stm.tm_mday += lValue*7;	break;
		default: return ECL_SCRIPT_ERROR;
	}
	tt = mktime(&stm);
	if (!(ptm = localtime(&tt))) return ECL_SCRIPT_ERROR;
	cl_tm2mpa(ma,ptm);

	return 0;
}

/****************************************/
/*										*/
/****************************************/
static int _func_add_to_date(pInfoParmW,nparm,ppParm,iDATE,iINTVAL,iADD)
tdtInfoParm *pInfoParmW;
int nparm;
tdtInfoParm *ppParm[];
int iDATE,iINTVAL,iADD;
{
	int  rc,n;
	struct tm stm,*ptm;
	time_t tt;
	MPA  maz,*ma;
	long lValue;

	if ((n=get_time_intval(ppParm[iINTVAL])) < 0) return n;
	else if (!n) return ECL_SCRIPT_ERROR;

	if ((rc=cl_get_parm_long(ppParm[iADD],&lValue,"date_add")) < 0) return rc;
	else if (rc > 0) return ECL_SCRIPT_ERROR;
/*
printf("cl_func_date_add: lValue=%d\n",lValue);
*/
	ma = (MPA *)cl_get_tmpMPA(&maz);
	if (rc=cl_get_parm_date(ppParm[iDATE],ma,"date_add")) return rc;

	if (rc=_func_date_add(ma,lValue,n)) return rc;

	rc = cl_set_parm_date(pInfoParmW,ma);
DEBUGOUT_InfoParm(151,"cl_date_add: rc=%d",pInfoParmW,rc,0);
	return rc;
}

/****************************************/
/*result = DATE_ADD(時間間隔の文字, 増分値, 日付) */
/*										*/
/****************************************/
int cl_func_date_add(pInfoParmW,nparm,ppParm)
tdtInfoParm *pInfoParmW;
int nparm;
tdtInfoParm *ppParm[];
{
	return _func_add_to_date(pInfoParmW,nparm,ppParm,2,0,1);
}

/****************************************/
/*result = ADD_TO_DATE(日付, 時間間隔の文字, 増分値) */
/*										*/
/****************************************/
int cl_func_add_to_date(pInfoParmW,nparm,ppParm)
tdtInfoParm *pInfoParmW;
int nparm;
tdtInfoParm *ppParm[];
{
	return _func_add_to_date(pInfoParmW,nparm,ppParm,0,1,2);
}

/****************************************/
/*										*/
/****************************************/
int cl_date_add_term(MPA *ma, long lValue, int n)
{
	return _func_date_add(ma,lValue,n);
}

/****************************************/
/*										*/
/****************************************/
int cl_func_date_diff(pInfoParmW,nparm,ppParm)
tdtInfoParm *pInfoParmW;
int nparm;
tdtInfoParm *ppParm[];
{
	int rc,n,n0;
	MPA ma1z,ma2z,*ma,*ma1,*ma2;
#if 1	/* 2018.7.23 */
	double tt,d;
#else
	time_t tt;
#endif
/*
result = date_diff ( 時間間隔の文字, 日付1, 日付2 )
*/
	if ((n0=get_time_intval(ppParm[0])) < 0) return n;
	else if (!n0) return ECL_SCRIPT_ERROR;

	ma1 = (MPA *)cl_get_tmpMPA(&ma1z);
	ma2 = (MPA *)cl_get_tmpMPA(&ma2z);
	if (rc=cl_get_parm_date(ppParm[1],ma1,"date_diff1")) return rc;
	if (rc=cl_get_parm_date(ppParm[2],ma2,"date_diff2")) return rc;

	if ((n=n0) == 7) n = 2;
	else if (n == 8) n = 3;
	rc = cl_date_diff_sub(&tt,n,ma1,ma2);
#if 1	/* 2018.7.23 */
	if (n0 >= 7) {
		if (n0 == 7) d = 3.0;
		else d = 7.0;
		tt /= d;
	}
	cl_set_parm_double(pInfoParmW,tt);
#else
	if (n0 <= 6) {
		cl_set_parm_long(pInfoParmW,tt);
	}
	else {
		m_l2mpa(tt,&ma1);
		if (n0 == 7) ma = m_get_i(3);
		else ma = m_get_i(7);
		m_div(&ma2,&ma1,ma);
		cl_set_parm_mpa(pInfoParmW,&ma2);
	}
#endif
	return rc;
}

/****************************************/
/*										*/
/****************************************/
int cl_date_diff_sub(ptt,n,ma1,ma2)
#if 1	/* 2018.7.23 */
double *ptt;
#else
time_t *ptt;
#endif
int n;
MPA *ma1,*ma2;
{
	int rc,y1,y2,t;
#if 1	/* 2018.7.23 */
	time_t  ss1,ss2;
	double  tt1,tt2,tt;
#else
	time_t  tt1,tt2,tt,ss1,ss2;
#endif

	if (!ptt || !ma1 || !ma2) return -1;
	tt = 0;
	y1 = ma1->num[0]*100 + ma1->num[1];
	y2 = ma2->num[0]*100 + ma2->num[1];
	if (n >= 3) {
		tt1 = get_days(y1,ma1->num[2],ma1->num[3]);
		tt2 = get_days(y2,ma2->num[2],ma2->num[3]);
	}
	if (n <= 3) {
		ss1 = get_seconds(ma1->num[4],ma1->num[5],ma1->num[6]);
		ss2 = get_seconds(ma2->num[4],ma2->num[5],ma2->num[6]);
		if (n == 1) {
			tt = y1 - y2;
			tt1 = get_days(1,ma1->num[2],ma1->num[3]);
			tt2 = get_days(1,ma2->num[2],ma2->num[3]);
			tt1 -= tt2;
			if (ss1 < ss2) tt1--;
			if (tt1 < 0) tt--;
		}
		else if (n == 2) {
			tt = (y1*12 + ma1->num[2]) - (y2*12 + ma2->num[2]);
			tt1 = get_days(1,1,ma1->num[3]);
			tt2 = get_days(1,1,ma2->num[3]);
			tt1 -= tt2;
			if (ss1 < ss2) tt1--;
			if (tt1 < 0) tt--;
		}
		else {
			tt = tt1 - tt2;
			if (ss1 < ss2) tt--;
		}
	}
	else {
#if 1	/* 2018.7.23 */
		if (n == 4) {
			ss1 = get_seconds(0,ma1->num[5],ma1->num[6]);
			ss2 = get_seconds(0,ma2->num[5],ma2->num[6]);
			tt = (tt1 - tt2)*24.0 + ma1->num[4] - ma2->num[4];
			if (ss1 < ss2) tt--;
		}
		else if (n == 5) {
			tt = ((tt1 - tt2)*24.0 + ma1->num[4] - ma2->num[4])*60.0
			   + ma1->num[5] - ma2->num[5];
			if (ma1->num[6] < ma2->num[6]) tt--;
		}
		else if (n == 6) {
			tt = (((tt1 - tt2)*24.0 + ma1->num[4] - ma2->num[4])*60.0
			       + ma1->num[5] - ma2->num[6])*60.0 + ma1->num[6] - ma2->num[6];
		}
#else
		if (n == 4) {
			ss1 = get_seconds(0,ma1->num[5],ma1->num[6]);
			ss2 = get_seconds(0,ma2->num[5],ma2->num[6]);
			tt = (tt1*24 + ma1->num[4]) - (tt2*24 + ma2->num[4]);
			if (ss1 < ss2) tt--;
		}
		else if (n == 5) {
			tt = ((tt1*24 + ma1->num[4])*60 + ma1->num[5])
			   - ((tt2*24 + ma2->num[4])*60 + ma2->num[5]);
			if (ma1->num[6] < ma2->num[6]) tt--;
		}
		else if (n == 6) {
			tt = (((tt1*24 + ma1->num[4])*60 + ma1->num[5])*60 + ma1->num[6])
			   - (((tt2*24 + ma2->num[4])*60 + ma2->num[5])*60 + ma2->num[6]);
		}
#endif
		else {
			return ECL_SCRIPT_ERROR;
		}
	}
	*ptt = tt;
	return 0;
}

/****************************************/
/*										*/
/****************************************/
int cl_func_add_months(pInfoParmW,nparm,ppParm)
tdtInfoParm *pInfoParmW;
int nparm;
tdtInfoParm *ppParm[];
{
	tdtInfoParm *ppParmW[3],tInfoParm;
/*
result = add_months(日付, 月数)
*/
	cl_set_parm_char(&tInfoParm,"M",1);
	ppParmW[0] = &tInfoParm;
	ppParmW[1] = ppParm[1];
	ppParmW[2] = ppParm[0];
	return cl_func_date_add(pInfoParmW,3,ppParmW);
}

/****************************************/
/*										*/
/****************************************/
int cl_is_leap_year(y)
int y;
{
	int rc;

	rc = 0;
	if (!(y % 400)) rc = 1;
	else if (!(y % 4)) {
		if (y % 100) rc = 1;
	}
	return rc;
}

/****************************************/
/*										*/
/****************************************/
int cl_days_of_month(yyyy,mm)
int yyyy,mm;
{
	static uchar mon[12]={31,28,31,30,31,30,31,31,30,31,30,31};
	int dd;

	if (yyyy < 0) yyyy = 0;
	if (mm < 1) mm = 1;
	else if (mm > 12) mm = 12;
	dd = mon[mm-1];
	if (mm == 2) {
		if (cl_is_leap_year(yyyy)) dd++;
	}
	return dd;
}

/****************************************/
/*										*/
/****************************************/
int cl_func_last_day(pInfoParmW,nparm,ppParm)
tdtInfoParm *pInfoParmW;
int nparm;
tdtInfoParm *ppParm[];
{
	int  rc,m,d;
	MPA  maz,*ma;
/*
result = add_months(日付, 月数)
*/
	ma = (MPA *)cl_get_tmpMPA(&maz);
	if (rc=cl_get_parm_date(ppParm[0],ma,"last_day")) return rc;
	ma->num[3] = cl_days_of_month(ma->num[0]*100 + ma->num[1],ma->num[2]);
	ma->num[4] = ma->num[5] = ma->num[6] = 0;
	return cl_set_parm_date(pInfoParmW,ma);
}

/****************************************/
/*										*/
/****************************************/
int cl_cmpt_date(pInfoParmW,pOperator,pInfoParm1,pInfoParm2)
tdtInfoParm *pInfoParmW,*pInfoParm1,*pInfoParm2;
char *pOperator;
{
	char *_fn_="cl_cmpt_date";
	int    rc,atr1,atr2,exception_save;
	long   lValue;
	char   op;
	double dtt;
	MPA    maz,*pma1,*pma2,*ma;
	tdtInfoParm *pInfo1,*pInfo2;
	DATE   stm,*ptm;
	time_t tt1,tt2,tt;

	exception_save = pGlobTable->exception;
	pGlobTable->exception = MATH_ETC_ERROR_EXCEPTION;
	op = *pOperator;
	if (op!='+' && op!='-') {
		ERROROUT2(FORMAT(238),_fn_,pOperator);	/* %s: 演算(%s)は使用できません。*/
		return ECL_SCRIPT_ERROR;
	}
	atr1 = pInfoParm1->pi_attr;
	atr2 = pInfoParm2->pi_attr;
	if (atr1==DEF_ZOK_DATE && atr2==DEF_ZOK_DATE) {
		if (op != '-') {
			ERROROUT2(FORMAT(238),_fn_,pOperator);	/* %s: 演算(%s)は使用できません。*/
			return ECL_SCRIPT_ERROR;
		}
		rc = cl_date_diff_sub(&dtt,3,pInfoParm1->pi_data,pInfoParm2->pi_data);
		cl_set_parm_double(pInfoParmW,dtt);
	}
	else {
		if (atr1 != DEF_ZOK_DATE) {
			pInfo1 = pInfoParm2;
			pInfo2 = pInfoParm1;
		}
		else if (atr2 != DEF_ZOK_DATE) {
			pInfo1 = pInfoParm1;
			pInfo2 = pInfoParm2;
		}
		else {
			return ECL_SCRIPT_ERROR;
		}
		if ((rc=cl_get_parm_long(pInfo2,&lValue,"date_math")) < 0) return rc;
		else if (rc > 0) return ECL_SCRIPT_ERROR;
		ma = (MPA *)cl_get_tmpMPA(&maz);
		memcpy(ma,pInfo1->pi_data,sizeofMPA());
		cl_mpa2tm(&stm,ma);
		if (op == '+') stm.tm_mday += lValue;		/* 日 */
		else           stm.tm_mday -= lValue;		/* 日 */
		tt1 = mktime(&stm);
		if (!(ptm = localtime(&tt1))) return ECL_SCRIPT_ERROR;
		cl_tm2mpa(ma,ptm);
		cl_set_parm_mpa(pInfoParmW,ma);
		pInfoParmW->pi_attr = DEF_ZOK_DATE;
	}
	pGlobTable->exception = exception_save;
	return rc;
}

/****************************************/
/*										*/
/****************************************/
static int _date2str(ix,len,opt,p,ma)
int  ix,len,opt;
char *p;
MPA  *ma;
{
	int t,n;
	char *form,w[7],ww[13];
/*
printf("_date2str: ix=%d len=%d opt=%d\n",ix,len,opt);
*/
	if (ix == 1) {
		t = ma->num[1];
		if (len >= 3) {
			if (len > 3) form = "%04d";
			else form = "%d";
			t += ma->num[0]*100;
		}
		else {
			if (len > 1) form = "%02d";
			else form = "%d";
		}
		sprintf(p,form,t);
	}
	else if (ix <= 6) {
		if (len > 1) form = "%02d";
		else form = "%d";
		t = ma->num[ix];
		if (opt) t %= 12;
		sprintf(p,form,t);
	}
	else  if (ix == 7){
#if 1	/* 2021.6.1 */
		if (len > 6) len = 6;
		sprintf(w,"%d",_byte2bin(&ma->num[ix],3));
		n = strlen(w);
/*
printf("_date2str: len=%d n=%d\n",len,n);
*/
		if (n >= len) strcpy(p,w);
		else {
			strcpy(ww,"000000");
			strcpy(ww+6,w);
			memzcpy(p,ww+6+n-len,len);
		}
#else
		sprintf(w,"%06d",_byte2bin(&ma->num[ix],3));
		memnzcpy(p,w,len,7);
#endif
	}
	else  if (ix == 10){
		if (ma->num[ix]) form = "PM";
		else form = "AM";
		strcpy(p,form);
	}
	else {	/* if (ix == 12) */
		sprintf(p,"%d",_byte2bin(&ma->num[ix],2));
	}
/*
printf("_date2str: p=[%s]\n",p);
*/
	return strlen(p);
}

/****************************************/
/*										*/
/****************************************/
static char _chk_YMDHNS(char *s0,int slen0,int val[],char **p0)
{
	static char *keya[]={"MONTH","MON","HH24","H24","HH12","H12","DAY","DY",NULL};
	static char keyx[]={0,0, 0,1, 2,0, 1,0, 2,1, 1,1, 0,0, 0,1};
	char *s,cc,c,**key,*keyn,*p;
	int  opt,n,slen,klen;

	s = s0;
	slen = slen0;
	cc = *s;
	key = keya;
	keyn = keyx;
	opt = n = 0;
	while (p=*key++) {
		klen = strlen(p);
		if (!memcmp(s,p,klen)) {
/*
printf("cl_date2str: p=[%s]\n",p);
*/
			if (!strcmp(p,"DY") && slen>klen && *(s+klen)=='Y') ;
			else {
				s += klen;
				slen -= klen;
				n = *keyn++;
				opt = *keyn++;
				break;
			}
		}
		keyn += 2;
	}
/*
printf("cl_date2str: n=%d opt=%d\n",n,opt);
*/
	if (!p && !n) {
		opt = 0;
		s++;
		slen--;
		n = 1;
		while (slen > 0) {
			c = *s;
			if (c != cc) break;
			s++;
			slen--;
			n++;
		}
		if (cc == 'M') {
			if (n == 1) {
				if (slen>0) {
					if (c == 'I') {
						cc = 'N';
						slen--;
						n++;	/* add 2021.6.1 */
					}
				}
			}
		}
		else if (cc=='D' && n==3) cc = 'J';
	}
	val[0] = slen0 - slen;
	val[1] = n;
	val[2] = opt;
	*p0 = p;
	return cc;
}

/****************************************/
/*	p2		: 出力エリア				*/
/*	len2	: p2のサイズ(byte) 終端'\0'を含まない	*/
/*	s0		: 日付フォーマット			*/
/*	slen0	: s0のサイズ(byte)			*/
/*	ma		: 日付データ				*/
/****************************************/
int cl_date2str(p2,len2,s0,slen0,ma)
char *s0,*p2;
int  len2,slen0;
MPA  *ma;
{
	static char wrk[256],*p0=NULL;
	char *dp,*p,c,cc,*d,*s,c1,**key,*keyn,*form,*ss,cs;
	int i,len,n,slen,opt,klen,val[3];
	SSPL_S ssp;

	if (!p2 || len2<=0 || !s0 || slen0<=0) return -1;
	if ((len=akxmemwork(slen0+1,&dp,&p0,wrk,sizeof(wrk))) < 0) return -1;
/*
printf("cl_date2str: slen0=%d s0=[%s]\n",slen0,s0);
*/
	ss = s0;
	akxcuppern(dp,ss,slen0);
	s = dp;
/*
printf("cl_date2str: s=[%s]\n",s);
*/
	d = p2;
	slen = slen0;
	len = len2;
	while (slen>0 && len>0) {
		if ((n=akxqkanjilen(s)) == 1) {
			c1 = *s;
			cs = *ss;
			c = c1;
			if (c1=='\\' || c1=='`') {
				s++;
				ss++;
				if ((n=akxqkanjilen(s)) > 1) continue;
				*d++ = *ss++;
				s++;
				slen--;
				len--;
			}
			else if (c1=='"' || c1=='\'') {
				ssp.wdmax = slen0;
				ssp.wd = dp + slen0*2;
				ssp.sp = 0;
				n = akxtgwnsl(ss,slen,&ssp,NULL,0x07);
				memcpy(d,ssp.wd,n);
				ss += ssp.sp;
				s += ssp.sp;
				slen -= ssp.sp;
				d += n;
				len -= n;
			}
			else if (strchr("YMDHNSPU",c)) {
/*
printf("cl_date2str: s=[%s]\n",s);
*/
				cc = _chk_YMDHNS(s,slen,val,&p);
				n = val[1];
				slen -= val[0];
				s += val[0];
				ss += val[0];
				opt = val[2];
				if (p && !n) {
					if (cc == 'M') p = month[(ma->num[2]-1)*2+opt];
					else           p = week[ma->num[11]*3+opt];
					klen = strlen(p);
					memcpy(d,p,klen);
					d += klen;
					len -= klen;
				}
				else {
					n = _date2str(char2ix[cc-'A'],n,opt,d,ma);
					d += n;
					len -= n;
				}
			}
			else {
				s++;
				ss++;
				slen--;
				*d++ = cs;
				len--;
			}
		}
		else {
			memcpy(d,ss,n);
			d += n;
			s += n;
			ss += n;
			slen -= n;
			len -= n;
		}
	}
	*d = '\0';
/*
printf("cl_date2str=[%s]\n",p2);
*/
	return 0;
}

/****************************************/
/*										*/
/****************************************/
static int _str2date(ix,n,len,opt,p,ma)
int  ix,n,len,opt;
char *p;
MPA  *ma;
{
	int t1,t2,ret;
	char *form;
/*
printf("_str2date: ix=%d n=%d len=%d opt=%d p=[%s]\n",ix,n,len,opt,p);
*/
	if (ix == 10) {
		ret = 3;
		t1 = 0;
		if (!memcmp(p,"PM",2)) t1 = 1;
		else if (memcmp(p,"AM",2)) ret = -2;
		ma->num[ix] = t1;
	}
	else {
		ret = akxccvn(10,p,len,&t1);
/*
printf("_str2date: akxccvn ret=%d t1=%d\n",ret,t1);
*/
		if (ret < 0) {
			return ret;
		}
		if (ix == 1) {
			t2 = t1 % 100;
			t1 /= 100;
			if (n <= 2) {
				if (t2 >= 51) t1 = 20;
				else t1 = 19;
			}
			ma->num[0] = t1;
			ma->num[1] = t2;
/*
printf("_str2date: YY=%d YY=%d\n",ma->num[0],ma->num[1]);
*/
		}
		else if (ix <= 6) {
			t2 = t1 % 100;
			ma->num[ix] = t2;
		}
		else  if (ix == 7){
			_bin2byte(&ma->num[ix],t1,3);
		}
		else {	/* if (ix == 12) */
			ma->num[2] = 1;
			ma->num[3] = 1;
			ret = _func_date_add(ma,t1,3);
		}
	}

	return ret;
}

/****************************************/
/*										*/
/****************************************/
int cl_str2date(p2,len2,s0,slen0,ma)
char *s0,*p2;
int  len2,slen0;
MPA  *ma;
{
	static char wrk[256],*p0=NULL;
	char *dp,*p,c,cc,*d,*s,c1,**key,*keyn,*form,*ss,cs;
	int i,len,n,slen,opt,klen,m,ret,ix,set_h,set_ampm,max_ix,mod_h,val[3],iCLEAR;
	SSPL_S ssp;

	if (!p2 || len2<=0 || !s0 || slen0<=0) return -1;
	if ((len=akxmemwork(slen0+1,&dp,&p0,wrk,sizeof(wrk))) < 0) return -1;
/*
printf("cl_str2date: len2=%d p2=[%s]\n",len2,p2);
printf("cl_str2date: slen0=%d s0=[%s]\n",slen0,s0);
*/
	iCLEAR = ma->num[D_LEN_DATE] & 0x01;
	ss = s0;
	akxcuppern(dp,ss,slen0);
	s = dp;
/*
printf("cl_str2date: s=[%s]\n",s);
*/
	d = p2;
	slen = slen0;
	len = len2;
	set_ampm = set_h = max_ix = ret = 0;
	while (slen>0 && len>0) {
		if ((n=akxqkanjilen(s)) == 1) {
			c1 = *s;
			cs = *ss;
/*
printf("cl_str2date: slen=%d len=%d n=%d c1=[%c] cs=[%c] *d=[%c]\n",slen,len,n,c1,cs,*d);
*/
			c = c1;
			if (c1=='\\' || c1=='`') {
				s++;
				ss++;
				if ((n=akxqkanjilen(s)) > 1) continue;
				if (*d++ != *ss++) break;
				s++;
				slen--;
				len--;
			}
			else if (c1=='"' || c1=='\'') {
				ssp.wdmax = slen0;
				ssp.wd = dp + slen0*2;
				ssp.sp = 0;
				n = akxtgwnsl(ss,slen,&ssp,NULL,0x07);
				if (memcmp(d,ssp.wd,n)) break;
				ss += ssp.sp;
				s += ssp.sp;
				slen -= ssp.sp;
				d += n;
				len -= n;
			}
			else if (strchr("YMDHNSPU",c)) {
/*
printf("cl_date2str: s=[%s]\n",s);
*/
				cc = _chk_YMDHNS(s,slen,val,&p);
				n = val[1];
				slen -= val[0];
				s += val[0];
				ss += val[0];
				opt = val[2];
/*
printf("cl_date2str: cc=[%c] n=%d opt=%d p=%08x\n",cc,n,opt,p);
*/
				if (p && !n) {
					if (cc == 'M') {
						key = month + opt;
						m = 2;
						ix = 2;
						i = 1;
					}
					else {
						break;
					}
					while (p=*key++) {
						klen = strlen(p);
						if (!memcmp(d,p,klen)) {
							break;
						}
						key += m;
						i++;
					}
					if (!p) break;
					d += klen;
					len -= klen;
					ma->num[ix] = i;
					if (max_ix < ix) max_ix = ix;
					
				}
				else {
/*
printf("cl_str2date: slen=%d len=%d c=[%c]\n",slen,len,*s);
*/
					if (slen<=0 || !strchr("YMDHNSPU",*s)) m = len;
					else m = n;
					ix = char2ix[cc-'A'];
					ret = _str2date(ix,n,m,opt,d,ma);
					if (ret < 0) break;
					else if (ret > 0) n = ret - 1;
					else n = m;
					d += n;
					len -= n;
					mod_h = 0;
					if (ix == 10) {	/* AM/PM */
						set_ampm = 1;
						if (set_h) mod_h = 1;
					}
					else if (ix == 4) {	/* H */
						set_h = 1;
						if (set_ampm) mod_h = 1;
					}
					if (mod_h) {
						if (ma->num[10]) {	/* PM */
							if (ma->num[4] <= 12) ma->num[4] += 12;
						}
						else {
							if (ma->num[4] > 12) break;
						}
					}
					if (ix<=7 && max_ix<ix) max_ix = ix;
					if (ix==12 && max_ix<3) max_ix = 3;
				}
			}
			else {
				if (*d != cs) break;	/* move 2021.5.9 */
				s++;
				ss++;
				slen--;
			/*	if (*d != cs) break;	*/
				d++;
				len--;
			}
		}
		else {
			if (memcmp(d,ss,n)) break;
			d += n;
			s += n;
			ss += n;
			slen -= n;
			len -= n;
		}
	}
	if (slen>0 && len>0) {
				/* cl_str2date: 日付文字列(%c)と書式(%c)が一致しないところがあります。*/
		ERROROUT2(FORMAT(609),*d,cs);
		ret = -1;
	}
	else if (iCLEAR) {
		if (!max_ix) {
			ma->num[0] = AKX_TIME_BASE/100;
			ma->num[1] = AKX_TIME_BASE % 100;
			max_ix = 1;
		}
		for (i=max_ix+1;i<=6;i++) {
			n = i<=3 ? 1 : 0;
			ma->num[i] = n;
		}
		if (max_ix == 6) _bin2byte(&ma->num[7],0,3);		/* マイクロ秒 */
	}
/*
printf("cl_str2date: slen=%d len=%d ret=%d]\n",slen,len,ret);
*/
	return ret;
}
