[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:
Benoît Minisini 2016-02-25 22:59:49 +00:00
parent c1eb854159
commit 61064b6f6e
3 changed files with 224 additions and 221 deletions

View file

@ -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!

View file

@ -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);

View file

@ -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();
}