Skip to content

Commit

Permalink
Merge pull request #2459 from deirdreobyrne/date_limit
Browse files Browse the repository at this point in the history
Bugfix for #2456 (PR #2230) - Date library bug fixes
  • Loading branch information
gfwilliams authored Jan 29, 2024
2 parents 812addd + 38a5b0c commit fcd68f6
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 25 deletions.
1 change: 1 addition & 0 deletions boards/PICO_R1_3.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
'DEFINES+=-DUSE_USB_OTG_FS=1 -DPICO -DPICO_1V3',
'DEFINES+=-DPIN_NAMES_DIRECT=1', # Package skips out some pins, so we can't assume each port starts from 0
'DEFINES += -DESPR_USE_STEPPER_TIMER=1', # Build in the code for stepping using the timer
'DEFINES += -DESPR_LIMIT_DATE_RANGE', # not enough code memory left for the full range of Date()
'STLIB=STM32F401xE',
'PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f4/lib/startup_stm32f401xx.o'
]
Expand Down
2 changes: 1 addition & 1 deletion libs/filesystem/jswrap_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ JsVar *jswrap_fs_stat(JsVar *path) {
date.month = (int)(((info.fdate>>5)&15)-1); // TomWS: Month is 0 based.
date.day = (int)((info.fdate)&31);
TimeInDay td;
td.daysSinceEpoch = fromCalenderDate(&date);
td.daysSinceEpoch = fromCalendarDate(&date);
td.hour = (int)((info.ftime>>11)&31);
td.min = (int)((info.ftime>>5)&63);
td.sec = (int)((info.ftime)&63);
Expand Down
2 changes: 1 addition & 1 deletion libs/misc/nmea.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ JsVar *nmea_to_jsVar(NMEAFixInfo *gpsFix) {
date.month = gpsFix->month-1; // 1 based to 0 based
date.year = 2000+gpsFix->year;
TimeInDay td;
td.daysSinceEpoch = fromCalenderDate(&date);
td.daysSinceEpoch = fromCalendarDate(&date);
td.hour = gpsFix->hour;
td.min = gpsFix->min;
td.sec = gpsFix->sec;
Expand Down
69 changes: 50 additions & 19 deletions src/jswrap_date.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,52 @@ const int BASE_DOW = 4;
const char *MONTHNAMES = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec";
const char *DAYNAMES = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat";

#ifdef ESPR_LIMIT_DATE_RANGE
// This rounds towards zero - which is not what the algorithm needs. Hence the range for Date() is further limited when ESPR_LIMIT_DATE_RANGE is set
#define INTEGER_DIVIDE_FLOOR(a,b) ((a)/(b))
#else
// This rounds down, which is what the algorithm needs
int integerDivideFloor(int a, int b) {
return (a < 0 ? a-b+1 : a)/b;
}
#define INTEGER_DIVIDE_FLOOR(a,b) integerDivideFloor((a),(b))
#endif


// Convert y,m,d into a number of days since 1970, where 0<=m<=11
// https://github.com/deirdreobyrne/CalendarAndDST
int getDayNumberFromDate(int y, int m, int d) {
int ans;

if (m < 2) {

#ifdef ESPR_LIMIT_DATE_RANGE
if (y < 1500 || y >= 1250000) { // Should actually work down to 1101, but since the Gregorian calendar started in 1582 . . .
#else
if (y < -1250000 || y >= 1250000) {
#endif
jsExceptionHere(JSET_ERROR, "Date out of bounds");
return 0; // Need to head off any overflow error
}
while (m < 2) {
y--;
m+=12;
}
ans = (y/100);
return 365*y + (y>>2) - ans + (ans>>2) + 30*m + ((3*m+6)/5) + d - 719531;
// #2456 was created by integer division rounding towards zero, rather than the FLOOR-behaviour required by the algorithm.
ans = INTEGER_DIVIDE_FLOOR(y,100);
return 365*y + INTEGER_DIVIDE_FLOOR(y,4) - ans + INTEGER_DIVIDE_FLOOR(ans,4) + 30*m + ((3*m+6)/5) + d - 719531;
}

// Convert a number of days since 1970 into y,m,d. 0<=m<=11
// https://github.com/deirdreobyrne/CalendarAndDST
void getDateFromDayNumber(int day, int *y, int *m, int *date) {
int a = day + 135081;
int b,c,d;
a = (a-(a/146097)+146095)/36524;
a = day + a - (a>>2);
b = ((a<<2)+2877911)/1461;
c = a + 719600 - 365*b - (b>>2);
d = (5*c-1)/153;

// Bug #2456 fixed here too
a = INTEGER_DIVIDE_FLOOR(a - INTEGER_DIVIDE_FLOOR(a,146097) + 146095,36524);
a = day + a - INTEGER_DIVIDE_FLOOR(a,4);
b = INTEGER_DIVIDE_FLOOR((a<<2)+2877911,1461);
c = a + 719600 - 365*b - INTEGER_DIVIDE_FLOOR(b,4);
d = (5*c-1)/153; // Floor behaviour not needed, as c is always positive
if (date) *date=c-30*d-((3*d)/5);
if (m) {
if (d<14)
Expand Down Expand Up @@ -178,7 +201,7 @@ CalendarDate getCalendarDate(int d) {
return date;
};

int fromCalenderDate(CalendarDate *date) {
int fromCalendarDate(CalendarDate *date) {
while (date->month < 0) {
date->year--;
date->month += 12;
Expand Down Expand Up @@ -298,7 +321,7 @@ JsVar *jswrap_date_constructor(JsVar *args) {
date.month = (int)(jsvGetIntegerAndUnLock(jsvGetArrayItem(args, 1)));
date.day = (int)(jsvGetIntegerAndUnLock(jsvGetArrayItem(args, 2)));
TimeInDay td;
td.daysSinceEpoch = fromCalenderDate(&date);
td.daysSinceEpoch = fromCalendarDate(&date);
td.hour = (int)(jsvGetIntegerAndUnLock(jsvGetArrayItem(args, 3)));
td.min = (int)(jsvGetIntegerAndUnLock(jsvGetArrayItem(args, 4)));
td.sec = (int)(jsvGetIntegerAndUnLock(jsvGetArrayItem(args, 5)));
Expand Down Expand Up @@ -376,6 +399,14 @@ JsVarFloat jswrap_date_getTime(JsVar *date) {
Set the time/date of this Date class
*/
JsVarFloat jswrap_date_setTime(JsVar *date, JsVarFloat timeValue) {
#ifdef ESPR_LIMIT_DATE_RANGE
if (timeValue < -1.48317696e13 || timeValue >= 3.93840543168E+016) { // This should actually work down to 1101AD . . .
#else
if (timeValue < -3.95083256832E+016 || timeValue >= 3.93840543168E+016) {
#endif
jsExceptionHere(JSET_ERROR, "Date out of bounds");
return 0.0;
}
if (date)
jsvObjectSetChildAndUnLock(date, "ms", jsvNewFromFloat(timeValue));
return timeValue;
Expand Down Expand Up @@ -607,7 +638,7 @@ JsVarFloat jswrap_date_setDate(JsVar *parent, int dayValue) {
TimeInDay td = getTimeFromDateVar(parent, false/*system timezone*/);
CalendarDate d = getCalendarDate(td.daysSinceEpoch);
d.day = dayValue;
td.daysSinceEpoch = fromCalenderDate(&d);
td.daysSinceEpoch = fromCalendarDate(&d);
setCorrectTimeZone(&td);
return jswrap_date_setTime(parent, fromTimeInDay(&td));
}
Expand All @@ -620,11 +651,11 @@ JsVarFloat jswrap_date_setDate(JsVar *parent, int dayValue) {
"name" : "setMonth",
"generate" : "jswrap_date_setMonth",
"params" : [
["yearValue","int","The month, between 0 and 11"],
["monthValue","int","The month, between 0 and 11"],
["dayValue","JsVar","[optional] the day, between 0 and 31"]
],
"return" : ["float","The number of milliseconds since 1970"],
"typescript" : "setMonth(yearValue: number, dayValue?: number): number;"
"typescript" : "setMonth(monthValue: number, dayValue?: number): number;"
}
Month of the year 0..11
*/
Expand All @@ -634,7 +665,7 @@ JsVarFloat jswrap_date_setMonth(JsVar *parent, int monthValue, JsVar *dayValue)
d.month = monthValue;
if (jsvIsNumeric(dayValue))
d.day = jsvGetInteger(dayValue);
td.daysSinceEpoch = fromCalenderDate(&d);
td.daysSinceEpoch = fromCalendarDate(&d);
setCorrectTimeZone(&td);
return jswrap_date_setTime(parent, fromTimeInDay(&td));
}
Expand Down Expand Up @@ -662,7 +693,7 @@ JsVarFloat jswrap_date_setFullYear(JsVar *parent, int yearValue, JsVar *monthVal
d.month = jsvGetInteger(monthValue);
if (jsvIsNumeric(dayValue))
d.day = jsvGetInteger(dayValue);
td.daysSinceEpoch = fromCalenderDate(&d);
td.daysSinceEpoch = fromCalendarDate(&d);
setCorrectTimeZone(&td);
return jswrap_date_setTime(parent, fromTimeInDay(&td));
}
Expand Down Expand Up @@ -874,7 +905,7 @@ JsVarFloat jswrap_date_parse(JsVar *str) {
jslGetNextToken();
if (lex.tk == LEX_INT) {
date.year = _parse_int();
time.daysSinceEpoch = fromCalenderDate(&date);
time.daysSinceEpoch = fromCalendarDate(&date);
jslGetNextToken();
if (lex.tk == LEX_INT) {
_parse_time(&time, 0);
Expand All @@ -897,7 +928,7 @@ JsVarFloat jswrap_date_parse(JsVar *str) {
jslGetNextToken();
if (lex.tk == LEX_INT) {
date.year = _parse_int();
time.daysSinceEpoch = fromCalenderDate(&date);
time.daysSinceEpoch = fromCalendarDate(&date);
jslGetNextToken();
if (lex.tk == LEX_INT) {
_parse_time(&time, 0);
Expand All @@ -924,7 +955,7 @@ JsVarFloat jswrap_date_parse(JsVar *str) {
jslGetNextToken();
if (lex.tk == LEX_INT) {
date.day = _parse_int();
time.daysSinceEpoch = fromCalenderDate(&date);
time.daysSinceEpoch = fromCalendarDate(&date);
jslGetNextToken();
if (lex.tk == LEX_ID && jslGetTokenValueAsString()[0]=='T') {
_parse_time(&time, 1);
Expand Down
2 changes: 1 addition & 1 deletion src/jswrap_date.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ void setCorrectTimeZone(TimeInDay *td);
TimeInDay getTimeFromMilliSeconds(JsVarFloat ms_in, bool forceGMT);
JsVarFloat fromTimeInDay(TimeInDay *td);
CalendarDate getCalendarDate(int d);
int fromCalenderDate(CalendarDate *date);
int fromCalendarDate(CalendarDate *date);

JsVarFloat jswrap_date_now();
JsVar *jswrap_date_from_milliseconds(JsVarFloat time);
Expand Down
2 changes: 1 addition & 1 deletion targets/nrf5x/bluetooth_ancs.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ void ble_cts_handle_time(BLEPending blep, char *buffer, size_t bufferLen) {
date.month = time.month-1; // JS months are 0-11, but CTS uses 1-12
date.day = time.day;
TimeInDay td;
td.daysSinceEpoch = fromCalenderDate(&date);
td.daysSinceEpoch = fromCalendarDate(&date);
td.hour = time.hours;
td.min = time.minutes;
td.sec = time.seconds;
Expand Down
2 changes: 1 addition & 1 deletion targets/stm32/jshardware.c
Original file line number Diff line number Diff line change
Expand Up @@ -1536,7 +1536,7 @@ JsSysTime jshGetRTCSystemTime() {
cdate.month = date.RTC_Month-1; // 1..12 -> 0..11
cdate.year = 2000+date.RTC_Year; // 0..99 -> 2000..2099
cdate.dow = date.RTC_WeekDay%7; // 1(monday)..7 -> 0(sunday)..6
ctime.daysSinceEpoch = fromCalenderDate(&cdate);
ctime.daysSinceEpoch = fromCalendarDate(&cdate);
ctime.zone = 0;
ctime.ms = 0;
ctime.sec = time.RTC_Seconds;
Expand Down
12 changes: 11 additions & 1 deletion tests/test_date.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
pass=0;

try { new Date(4.1e16); pass--; } catch(e) { };
try { new Date(-4.1e16); pass--; } catch(e) { };
try { new Date(2000000,0); pass--; } catch(e) { };
try { new Date(-2000000,0); pass--; } catch(e) { };
// This next Date() constructor use to give a segfault. However it is now out of range for the PICO_R1_3
try { a = new Date(-12,8).toString(); if (!(a== "Wed Aug 31 -12 00:00:00 GMT+0000")) pass--; } catch (e) { };

var gmt = [
[ Date.parse("2011-10-20") , 1319068800000.0 ],
[ Date.parse("2011-10-20T14:48:12.345") , 1319122092345.0 ],
Expand All @@ -11,7 +18,10 @@ var gmt = [
[ new Date(807926400000.0).toString() , "Wed Aug 9 1995 00:00:00 GMT+0000" ],
[ new Date("Fri, 20 Jun 2014 15:27:22 GMT").toString(), "Fri Jun 20 2014 15:27:22 GMT+0000"],
[ new Date("Fri, 20 Jun 2014 15:27:22 GMT").toISOString(), "2014-06-20T15:27:22.000Z"],
[ new Date("Fri, 20 Jun 2014 17:27:22 GMT+0200").toISOString(), "2014-06-20T15:27:22.000Z"]
[ new Date("Fri, 20 Jun 2014 17:27:22 GMT+0200").toISOString(), "2014-06-20T15:27:22.000Z"],
[ new Date("5000-1-1").toString(), "Wed Jan 1 5000 00:00:00 GMT+0000"],
[ new Date(1500,0,1).toString(), "Mon Jan 1 1500 00:00:00 GMT+0000"],
[ new Date(1500,0,1).getTime(), -14831769600000]
];

gmt.forEach(function(n) { if (n[0]==n[1]) pass++; });
Expand Down

0 comments on commit fcd68f6

Please sign in to comment.