From 61064b6f6e0691a010943b85241e60f36ea0c880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Minisini?= Date: Thu, 25 Feb 2016 22:59:49 +0000 Subject: [PATCH] [INTERPRETER] * BUG: Week() now works correctly outside of UTC. git-svn-id: svn://localhost/gambas/trunk@7611 867c0c6c-44f3-4631-809d-bfa615b0a4ec --- main/gbx/gbx_date.c | 30 +-- main/gbx/gbx_date.h | 10 +- main/gbx/gbx_subr_time.c | 405 ++++++++++++++++++++------------------- 3 files changed, 224 insertions(+), 221 deletions(-) diff --git a/main/gbx/gbx_date.c b/main/gbx/gbx_date.c index 77454c7ff..cc2ec7272 100644 --- a/main/gbx/gbx_date.c +++ b/main/gbx/gbx_date.c @@ -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! diff --git a/main/gbx/gbx_date.h b/main/gbx/gbx_date.h index 02a3c1520..03672b4c8 100644 --- a/main/gbx/gbx_date.h +++ b/main/gbx/gbx_date.h @@ -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); diff --git a/main/gbx/gbx_subr_time.c b/main/gbx/gbx_subr_time.c index 3223f454a..d97e81d21 100644 --- a/main/gbx/gbx_subr_time.c +++ b/main/gbx/gbx_subr_time.c @@ -1,23 +1,23 @@ /*************************************************************************** - gbx_subr_time.c + gbx_subr_time.c - (c) 2000-2013 Benoît Minisini + (c) 2000-2013 Benoît Minisini - 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(); }