[INTERPRETER]
* BUG: Week() now works correctly outside of UTC. git-svn-id: svn://localhost/gambas/trunk@7611 867c0c6c-44f3-4631-809d-bfa615b0a4ec
This commit is contained in:
parent
c1eb854159
commit
61064b6f6e
3 changed files with 224 additions and 221 deletions
|
@ -67,6 +67,7 @@ static const short days_in_year[2][14] =
|
|||
|
||||
static double _start_time;
|
||||
|
||||
|
||||
// Returns 1 for a leap year, 0 else
|
||||
|
||||
static int date_is_leap_year(short year)
|
||||
|
@ -80,6 +81,7 @@ static int date_is_leap_year(short year)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static bool date_is_valid(DATE_SERIAL *date)
|
||||
{
|
||||
return ((date->year == 0
|
||||
|
@ -90,6 +92,7 @@ static bool date_is_valid(DATE_SERIAL *date)
|
|||
&& (date->sec >= 0) && (date->sec <= 59));
|
||||
}
|
||||
|
||||
|
||||
static short date_to_julian_year(short year)
|
||||
{
|
||||
if (year < 0)
|
||||
|
@ -98,6 +101,7 @@ static short date_to_julian_year(short year)
|
|||
return year - DATE_YEAR_MIN - 1;
|
||||
}
|
||||
|
||||
|
||||
static short date_from_julian_year(short year)
|
||||
{
|
||||
if (year < (-DATE_YEAR_MIN))
|
||||
|
@ -106,6 +110,7 @@ static short date_from_julian_year(short year)
|
|||
return year + DATE_YEAR_MIN + 1;
|
||||
}
|
||||
|
||||
|
||||
void DATE_init(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
@ -118,6 +123,7 @@ void DATE_init(void)
|
|||
//DATE_init_local();
|
||||
}
|
||||
|
||||
|
||||
void DATE_init_local(void)
|
||||
{
|
||||
// Prevent glibc for calling stat("/etc/localtime") again and again...
|
||||
|
@ -127,6 +133,7 @@ void DATE_init_local(void)
|
|||
tzset();
|
||||
}
|
||||
|
||||
|
||||
DATE_SERIAL *DATE_split(VALUE *value)
|
||||
{
|
||||
static int last_nday, last_nmsec;
|
||||
|
@ -271,7 +278,7 @@ void DATE_from_time(time_t time, int usec, VALUE *val)
|
|||
{
|
||||
static struct tm tm;
|
||||
static time_t last_time = (time_t)-1;
|
||||
|
||||
|
||||
DATE_SERIAL date;
|
||||
|
||||
if (time != last_time)
|
||||
|
@ -306,6 +313,7 @@ void DATE_now(VALUE *val)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
int DATE_to_string(char *buffer, VALUE *value)
|
||||
{
|
||||
DATE_SERIAL *date;
|
||||
|
@ -313,7 +321,7 @@ int DATE_to_string(char *buffer, VALUE *value)
|
|||
|
||||
if (value->_date.date == 0 && value->_date.time == 0)
|
||||
return 0;
|
||||
|
||||
|
||||
date = DATE_split(value);
|
||||
|
||||
if (value->_date.date == 0)
|
||||
|
@ -368,7 +376,7 @@ static bool read_integer(int *number)
|
|||
|
||||
buffer_pos++;
|
||||
}
|
||||
|
||||
|
||||
if (minus)
|
||||
nbr = (-nbr);
|
||||
|
||||
|
@ -600,13 +608,14 @@ int DATE_comp_value(VALUE *date1, VALUE *date2)
|
|||
double DATE_to_double(struct timeval *time, int from_start)
|
||||
{
|
||||
double result = (double)time->tv_sec + (double)time->tv_usec / 1E6;
|
||||
|
||||
|
||||
if (from_start)
|
||||
result -= _start_time;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool DATE_timer(double *result, int from_start)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
@ -616,20 +625,12 @@ bool DATE_timer(double *result, int from_start)
|
|||
*result = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
*result = DATE_to_double(&tv, from_start);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void DATE_void_value(VALUE *value)
|
||||
{
|
||||
value->type = T_DATE;
|
||||
value->_date.time = 0;
|
||||
value->_date.date = 0;
|
||||
}
|
||||
|
||||
|
||||
void DATE_add(VALUE *date, int period, int val)
|
||||
{
|
||||
int64_t add_time = 0;
|
||||
|
@ -869,6 +870,7 @@ int DATE_diff(VALUE *date1, VALUE *date2, int period)
|
|||
return diff;
|
||||
}
|
||||
|
||||
|
||||
// Beware: System.TimeZone is what must be added to go to UTC
|
||||
// So if the shell command `date` displays "UTC+2", then that
|
||||
// function must return -7200!
|
||||
|
|
|
@ -54,7 +54,7 @@ typedef
|
|||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
enum {
|
||||
DP_MILLISECOND = 1,
|
||||
DP_SECOND = 2,
|
||||
|
@ -67,7 +67,7 @@ enum {
|
|||
DP_QUARTER = 9,
|
||||
DP_YEAR = 10,
|
||||
};
|
||||
|
||||
|
||||
#ifndef GBX_INFO
|
||||
|
||||
#define DATE_YEAR_MIN -4801
|
||||
|
@ -77,7 +77,9 @@ enum {
|
|||
|
||||
#define DATE_SERIAL_has_no_date(_date) ((_date)->year == 0)
|
||||
#define DATE_SERIAL_has_no_time(_date) ((_date)->hour == 0 && (_date)->min == 0 && (_date)->sec == 0 && (_date)->msec == 0)
|
||||
|
||||
|
||||
#define DATE_void_value(_value) ((_value)->type = T_DATE, (_value)->_date.time = (_value)->_date.date = 0)
|
||||
|
||||
void DATE_init(void);
|
||||
void DATE_init_local(void);
|
||||
int DATE_get_timezone(void);
|
||||
|
@ -94,8 +96,6 @@ int DATE_comp(DATE *date1, DATE *date2);
|
|||
double DATE_to_double(struct timeval *time, int from_start);
|
||||
bool DATE_timer(double *result, int from_start);
|
||||
|
||||
void DATE_void_value(VALUE *value);
|
||||
|
||||
void DATE_add(VALUE *date, int period, int val);
|
||||
int DATE_diff(VALUE *date1, VALUE *date2, int period);
|
||||
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
/***************************************************************************
|
||||
|
||||
gbx_subr_time.c
|
||||
gbx_subr_time.c
|
||||
|
||||
(c) 2000-2013 Benoît Minisini <gambas@users.sourceforge.net>
|
||||
(c) 2000-2013 Benoît Minisini <gambas@users.sourceforge.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301, USA.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301, USA.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
@ -35,252 +35,253 @@
|
|||
|
||||
void SUBR_timer(void)
|
||||
{
|
||||
double result = 0.0;
|
||||
double result = 0.0;
|
||||
|
||||
DATE_timer(&result, TRUE);
|
||||
DATE_timer(&result, TRUE);
|
||||
|
||||
SP->type = T_FLOAT;
|
||||
SP->_float.value = result;
|
||||
SP++;
|
||||
SP->type = T_FLOAT;
|
||||
SP->_float.value = result;
|
||||
SP++;
|
||||
}
|
||||
|
||||
|
||||
void SUBR_now(void)
|
||||
{
|
||||
DATE_now(SP);
|
||||
SP++;
|
||||
DATE_now(SP);
|
||||
SP++;
|
||||
}
|
||||
|
||||
|
||||
void SUBR_year(ushort code)
|
||||
{
|
||||
DATE_SERIAL *date;
|
||||
int val;
|
||||
DATE_SERIAL *date;
|
||||
int val;
|
||||
|
||||
SUBR_ENTER_PARAM(1);
|
||||
SUBR_ENTER_PARAM(1);
|
||||
|
||||
VALUE_conv(PARAM, T_DATE);
|
||||
VALUE_conv(PARAM, T_DATE);
|
||||
|
||||
date = DATE_split(PARAM);
|
||||
date = DATE_split(PARAM);
|
||||
|
||||
switch(code & 0xF)
|
||||
{
|
||||
case 1: val = date->year; break;
|
||||
case 2: val = date->month; break;
|
||||
case 3: val = date->day; break;
|
||||
case 4: val = date->hour; break;
|
||||
case 5: val = date->min; break;
|
||||
case 6: val = date->sec; break;
|
||||
case 7: val = date->weekday; break;
|
||||
case 8: val = date->msec; break;
|
||||
default: val = 0;
|
||||
}
|
||||
switch(code & 0xF)
|
||||
{
|
||||
case 1: val = date->year; break;
|
||||
case 2: val = date->month; break;
|
||||
case 3: val = date->day; break;
|
||||
case 4: val = date->hour; break;
|
||||
case 5: val = date->min; break;
|
||||
case 6: val = date->sec; break;
|
||||
case 7: val = date->weekday; break;
|
||||
case 8: val = date->msec; break;
|
||||
default: val = 0;
|
||||
}
|
||||
|
||||
PARAM->type = T_INTEGER;
|
||||
PARAM->_integer.value = val;
|
||||
|
||||
#if 0
|
||||
SUBR_LEAVE() /* Not necessary */
|
||||
#endif
|
||||
PARAM->type = T_INTEGER;
|
||||
PARAM->_integer.value = val;
|
||||
|
||||
#if 0
|
||||
SUBR_LEAVE() /* Not necessary */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void SUBR_date(ushort code)
|
||||
{
|
||||
DATE_SERIAL date;
|
||||
DATE_SERIAL date;
|
||||
|
||||
SUBR_ENTER();
|
||||
SUBR_ENTER();
|
||||
|
||||
if (NPARAM <= 1)
|
||||
{
|
||||
if (NPARAM == 0)
|
||||
DATE_now(PARAM);
|
||||
if (NPARAM <= 1)
|
||||
{
|
||||
if (NPARAM == 0)
|
||||
DATE_now(PARAM);
|
||||
else
|
||||
VALUE_conv(PARAM, T_DATE);
|
||||
|
||||
date = *DATE_split(PARAM);
|
||||
date.hour = 0;
|
||||
date.min = 0;
|
||||
date.sec = 0;
|
||||
date.msec = 0;
|
||||
}
|
||||
else if (NPARAM >= 3)
|
||||
{
|
||||
VALUE_conv_integer(PARAM);
|
||||
VALUE_conv_integer(&PARAM[1]);
|
||||
VALUE_conv_integer(&PARAM[2]);
|
||||
|
||||
CLEAR(&date);
|
||||
date.year = PARAM->_integer.value;
|
||||
date.month = PARAM[1]._integer.value;
|
||||
date.day = PARAM[2]._integer.value;
|
||||
|
||||
if (NPARAM >= 4)
|
||||
{
|
||||
VALUE_conv_integer(&PARAM[3]);
|
||||
date.hour = PARAM[3]._integer.value;
|
||||
}
|
||||
|
||||
if (NPARAM >= 5)
|
||||
{
|
||||
VALUE_conv_integer(&PARAM[4]);
|
||||
date.min = PARAM[4]._integer.value;
|
||||
}
|
||||
|
||||
if (NPARAM >= 6)
|
||||
{
|
||||
VALUE_conv_integer(&PARAM[5]);
|
||||
date.sec = PARAM[5]._integer.value;
|
||||
}
|
||||
|
||||
if (NPARAM >= 7)
|
||||
{
|
||||
VALUE_conv_integer(&PARAM[6]);
|
||||
date.msec = PARAM[6]._integer.value;
|
||||
}
|
||||
date = *DATE_split(PARAM);
|
||||
date.hour = 0;
|
||||
date.min = 0;
|
||||
date.sec = 0;
|
||||
date.msec = 0;
|
||||
}
|
||||
else
|
||||
else if (NPARAM >= 3)
|
||||
{
|
||||
VALUE_conv_integer(PARAM);
|
||||
VALUE_conv_integer(&PARAM[1]);
|
||||
VALUE_conv_integer(&PARAM[2]);
|
||||
|
||||
CLEAR(&date);
|
||||
date.year = PARAM->_integer.value;
|
||||
date.month = PARAM[1]._integer.value;
|
||||
date.day = PARAM[2]._integer.value;
|
||||
|
||||
if (NPARAM >= 4)
|
||||
{
|
||||
VALUE_conv_integer(&PARAM[3]);
|
||||
date.hour = PARAM[3]._integer.value;
|
||||
}
|
||||
|
||||
if (NPARAM >= 5)
|
||||
{
|
||||
VALUE_conv_integer(&PARAM[4]);
|
||||
date.min = PARAM[4]._integer.value;
|
||||
}
|
||||
|
||||
if (NPARAM >= 6)
|
||||
{
|
||||
VALUE_conv_integer(&PARAM[5]);
|
||||
date.sec = PARAM[5]._integer.value;
|
||||
}
|
||||
|
||||
if (NPARAM >= 7)
|
||||
{
|
||||
VALUE_conv_integer(&PARAM[6]);
|
||||
date.msec = PARAM[6]._integer.value;
|
||||
}
|
||||
}
|
||||
else
|
||||
THROW(E_NEPARAM);
|
||||
|
||||
if (DATE_make(&date, RETURN))
|
||||
THROW(E_DATE);
|
||||
|
||||
SUBR_LEAVE();
|
||||
if (DATE_make(&date, RETURN))
|
||||
THROW(E_DATE);
|
||||
|
||||
SUBR_LEAVE();
|
||||
}
|
||||
|
||||
|
||||
void SUBR_time(ushort code)
|
||||
{
|
||||
DATE_SERIAL date;
|
||||
DATE_SERIAL date;
|
||||
|
||||
SUBR_ENTER();
|
||||
SUBR_ENTER();
|
||||
|
||||
if (NPARAM <= 1)
|
||||
{
|
||||
if (NPARAM == 0)
|
||||
DATE_now(PARAM);
|
||||
if (NPARAM <= 1)
|
||||
{
|
||||
if (NPARAM == 0)
|
||||
DATE_now(PARAM);
|
||||
else
|
||||
VALUE_conv(PARAM, T_DATE);
|
||||
|
||||
date = *DATE_split(PARAM);
|
||||
date.year = 0;
|
||||
}
|
||||
else if (NPARAM >= 3)
|
||||
{
|
||||
VALUE_conv_integer(PARAM);
|
||||
VALUE_conv_integer(&PARAM[1]);
|
||||
VALUE_conv_integer(&PARAM[2]);
|
||||
date = *DATE_split(PARAM);
|
||||
date.year = 0;
|
||||
}
|
||||
else if (NPARAM >= 3)
|
||||
{
|
||||
VALUE_conv_integer(PARAM);
|
||||
VALUE_conv_integer(&PARAM[1]);
|
||||
VALUE_conv_integer(&PARAM[2]);
|
||||
|
||||
CLEAR(&date);
|
||||
date.hour = PARAM->_integer.value;
|
||||
date.min = PARAM[1]._integer.value;
|
||||
date.sec = PARAM[2]._integer.value;
|
||||
CLEAR(&date);
|
||||
date.hour = PARAM->_integer.value;
|
||||
date.min = PARAM[1]._integer.value;
|
||||
date.sec = PARAM[2]._integer.value;
|
||||
if (NPARAM == 4)
|
||||
{
|
||||
VALUE_conv_integer(&PARAM[3]);
|
||||
date.msec = PARAM[3]._integer.value;
|
||||
}
|
||||
}
|
||||
else
|
||||
THROW(E_NEPARAM);
|
||||
}
|
||||
else
|
||||
THROW(E_NEPARAM);
|
||||
|
||||
if (DATE_make(&date, RETURN))
|
||||
THROW(E_DATE);
|
||||
if (DATE_make(&date, RETURN))
|
||||
THROW(E_DATE);
|
||||
|
||||
SUBR_LEAVE();
|
||||
SUBR_LEAVE();
|
||||
}
|
||||
|
||||
|
||||
void SUBR_date_op(ushort code)
|
||||
{
|
||||
SUBR_ENTER_PARAM(3);
|
||||
SUBR_ENTER_PARAM(3);
|
||||
|
||||
switch (code & 0xF)
|
||||
{
|
||||
case 0: /* DateAdd */
|
||||
|
||||
VALUE_conv(PARAM, T_DATE);
|
||||
*RETURN = *PARAM;
|
||||
DATE_add(RETURN, SUBR_get_integer(&PARAM[1]), SUBR_get_integer(&PARAM[2]));
|
||||
|
||||
break;
|
||||
|
||||
case 1: /* DateDiff */
|
||||
|
||||
VALUE_conv(PARAM, T_DATE);
|
||||
VALUE_conv(&PARAM[1], T_DATE);
|
||||
|
||||
/* Dates are inverted! */
|
||||
RETURN->_integer.value = DATE_diff(&PARAM[1], PARAM, SUBR_get_integer(&PARAM[2]));
|
||||
RETURN->type = T_INTEGER;
|
||||
|
||||
break;
|
||||
}
|
||||
switch (code & 0xF)
|
||||
{
|
||||
case 0: /* DateAdd */
|
||||
|
||||
SUBR_LEAVE();
|
||||
VALUE_conv(PARAM, T_DATE);
|
||||
*RETURN = *PARAM;
|
||||
DATE_add(RETURN, SUBR_get_integer(&PARAM[1]), SUBR_get_integer(&PARAM[2]));
|
||||
|
||||
break;
|
||||
|
||||
case 1: /* DateDiff */
|
||||
|
||||
VALUE_conv(PARAM, T_DATE);
|
||||
VALUE_conv(&PARAM[1], T_DATE);
|
||||
|
||||
/* Dates are inverted! */
|
||||
RETURN->_integer.value = DATE_diff(&PARAM[1], PARAM, SUBR_get_integer(&PARAM[2]));
|
||||
RETURN->type = T_INTEGER;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
SUBR_LEAVE();
|
||||
}
|
||||
|
||||
|
||||
void SUBR_week(ushort code)
|
||||
{
|
||||
bool plain = FALSE;
|
||||
int start = LOCAL_get_first_day_of_week();
|
||||
DATE_SERIAL ds;
|
||||
VALUE date, first;
|
||||
int day, n;
|
||||
|
||||
SUBR_ENTER();
|
||||
|
||||
if (NPARAM >= 1)
|
||||
{
|
||||
VALUE_conv(PARAM, T_DATE);
|
||||
date = *PARAM;
|
||||
|
||||
if (NPARAM >= 2)
|
||||
{
|
||||
start = SUBR_get_integer(&PARAM[1]);
|
||||
if (start < 0 || start > 6)
|
||||
THROW(E_ARG);
|
||||
|
||||
if (NPARAM == 3)
|
||||
plain = SUBR_get_boolean(&PARAM[2]);
|
||||
}
|
||||
}
|
||||
else
|
||||
DATE_now(&date);
|
||||
|
||||
/* Split it */
|
||||
ds = *DATE_split(&date);
|
||||
/* Set to 1 Jan of the current year */
|
||||
ds.month = 1;
|
||||
ds.day = 1;
|
||||
ds.hour = 0;
|
||||
ds.min = 0;
|
||||
ds.sec = 0;
|
||||
/* Convert to date & time */
|
||||
DATE_make(&ds, &first);
|
||||
/* Get the weekday of this 1 Jan */
|
||||
day = DATE_split(&first)->weekday;
|
||||
|
||||
/* number of beginning days to ignore */
|
||||
|
||||
n = 0;
|
||||
while (day != start)
|
||||
{
|
||||
day++;
|
||||
if (day > 6)
|
||||
day = 0;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (!plain)
|
||||
{
|
||||
if (n >= 4)
|
||||
n -= 7;
|
||||
}
|
||||
|
||||
RETURN->type = T_INTEGER;
|
||||
RETURN->_integer.value = (date._date.date - first._date.date - n + 7) / 7;
|
||||
|
||||
SUBR_LEAVE();
|
||||
bool plain = FALSE;
|
||||
int start = LOCAL_get_first_day_of_week();
|
||||
DATE_SERIAL ds;
|
||||
VALUE date, first;
|
||||
int day, n;
|
||||
|
||||
SUBR_ENTER();
|
||||
|
||||
if (NPARAM >= 1)
|
||||
{
|
||||
VALUE_conv(PARAM, T_DATE);
|
||||
date = *PARAM;
|
||||
|
||||
if (NPARAM >= 2)
|
||||
{
|
||||
start = SUBR_get_integer(&PARAM[1]);
|
||||
if (start < 0 || start > 6)
|
||||
THROW(E_ARG);
|
||||
|
||||
if (NPARAM == 3)
|
||||
plain = SUBR_get_boolean(&PARAM[2]);
|
||||
}
|
||||
}
|
||||
else
|
||||
DATE_now(&date);
|
||||
|
||||
/* Split it */
|
||||
ds = *DATE_split(&date);
|
||||
/* Set to 1 Jan of the current year */
|
||||
ds.month = 1;
|
||||
ds.day = 1;
|
||||
ds.hour = 0;
|
||||
ds.min = 0;
|
||||
ds.sec = 0;
|
||||
/* Convert to date & time */
|
||||
DATE_make(&ds, &first);
|
||||
|
||||
/* Get the weekday of this 1 Jan */
|
||||
day = DATE_split(&first)->weekday;
|
||||
|
||||
/* number of beginning days to ignore */
|
||||
|
||||
n= 0;
|
||||
while (day != start)
|
||||
{
|
||||
day++;
|
||||
if (day > 6)
|
||||
day = 0;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (!plain)
|
||||
{
|
||||
if (n >= 4)
|
||||
n -= 7;
|
||||
}
|
||||
|
||||
RETURN->type = T_INTEGER;
|
||||
RETURN->_integer.value = (DATE_diff(&date, &first, DP_DAY) - n + 7) / 7;
|
||||
|
||||
SUBR_LEAVE();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue