added test cases from #2560's thread; fixed more rounding edge cases

This commit is contained in:
scottysseus 2022-06-21 20:58:17 +00:00
parent c580ffcbc2
commit 456c403c09
5 changed files with 49 additions and 50 deletions

@ -55,7 +55,7 @@ function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:str
switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break;
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+(ss0 < 1 ? Math.round(val.S+val.u) : val.S); break;
default: throw 'bad abstime format: ' + fmt;
} outl = fmt.length === 3 ? 1 : 2; break;
case 101: /* 'e' era */

@ -99,23 +99,14 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
}
}
/* time rounding depends on presence of minute / second / usec fields */
switch(bt) {
case 0: break;
case 1:
/*::if(!dt) break;*/
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
break;
case 2:
/*::if(!dt) break;*/
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
break;
if (bt > 0 && bt < 3 && dt.u >= 0.5) {
round_up_date(dt, opts);
}
/* replace fields */
var {nstr,out} = replace_fields(out, dt, ss0, v, opts);
var replaced = replace_fields(out, dt, ss0, v, opts);
var nstr = replaced.nstr;
out = replaced.out;
var vv = "", myv, ostr;
if(nstr.length > 0) {
if(nstr.charCodeAt(0) == 40) /* '(' */ {
@ -183,7 +174,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
}
function replace_fields(fields, dt, ss0, v, opts) {
var out = [];
for (var i = 0; i < fields.length; i++) {out[i] = {t: fields[i].t, v: fields[i].v}}
for (var i = 0; i < fields.length; i++) {out[i] = {t: fields[i].t, v: fields[i].v};}
var nstr = "", jj;
for(i=0; i < out.length; ++i) {
switch(out[i].t) {

@ -335,7 +335,7 @@ function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:str
switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break;
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+(ss0 < 1 ? Math.round(val.S+val.u) : val.S); break;
default: throw 'bad abstime format: ' + fmt;
} outl = fmt.length === 3 ? 1 : 2; break;
case 101: /* 'e' era */
@ -793,23 +793,14 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
}
}
/* time rounding depends on presence of minute / second / usec fields */
switch(bt) {
case 0: break;
case 1:
/*::if(!dt) break;*/
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
break;
case 2:
/*::if(!dt) break;*/
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
break;
if (bt > 0 && bt < 3 && dt.u >= 0.5) {
round_up_date(dt, opts);
}
/* replace fields */
var {nstr,out} = replace_fields(out, dt, ss0, v, opts);
var replaced = replace_fields(out, dt, ss0, v, opts);
var nstr = replaced.nstr;
out = replaced.out;
var vv = "", myv, ostr;
if(nstr.length > 0) {
if(nstr.charCodeAt(0) == 40) /* '(' */ {
@ -877,7 +868,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
}
function replace_fields(fields, dt, ss0, v, opts) {
var out = [];
for (var i = 0; i < fields.length; i++) {out[i] = {t: fields[i].t, v: fields[i].v}}
for (var i = 0; i < fields.length; i++) {out[i] = {t: fields[i].t, v: fields[i].v};}
var nstr = "", jj;
for(i=0; i < out.length; ++i) {
switch(out[i].t) {

@ -330,7 +330,7 @@ if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break;
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+(ss0 < 1 ? Math.round(val.S+val.u) : val.S); break;
default: throw 'bad abstime format: ' + fmt;
} outl = fmt.length === 3 ? 1 : 2; break;
case 101: /* 'e' era */
@ -786,21 +786,14 @@ function eval_fmt(fmt, v, opts, flen) {
}
}
/* time rounding depends on presence of minute / second / usec fields */
switch(bt) {
case 0: break;
case 1:
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
break;
case 2:
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
break;
if (bt > 0 && bt < 3 && dt.u >= 0.5) {
round_up_date(dt, opts);
}
/* replace fields */
var {nstr,out} = replace_fields(out, dt, ss0, v, opts);
var replaced = replace_fields(out, dt, ss0, v, opts);
var nstr = replaced.nstr;
out = replaced.out;
var vv = "", myv, ostr;
if(nstr.length > 0) {
if(nstr.charCodeAt(0) == 40) /* '(' */ {
@ -868,7 +861,7 @@ if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
}
function replace_fields(fields, dt, ss0, v, opts) {
var out = [];
for (var i = 0; i < fields.length; i++) {out[i] = {t: fields[i].t, v: fields[i].v}}
for (var i = 0; i < fields.length; i++) {out[i] = {t: fields[i].t, v: fields[i].v};}
var nstr = "", jj;
for(i=0; i < out.length; ++i) {
switch(out[i].t) {

@ -49,10 +49,34 @@ describe('time format rounding', function() {
[{date1904: true}, {date1904: false}].forEach(opts => {
testCases.forEach(testCase => {
it(testCase.desc + ` (1904: ${opts.date1904})`,
() => testRow([testCase.value, testCase.date1904[`${opts.date1904}`]], headers, opts))
})
})
})
() => testRow([testCase.value, testCase.date1904[`${opts.date1904}`]], headers, opts));
});
});
});
describe('time format precision rounding', function() {
var value = "4018.99999998843";
var testCases = [
{desc: "end-of-year thousandths rounding", format: "mm/dd/yyyy hh:mm:ss.000", expected: "12/31/1910 23:59:59.999"},
{desc: "end-of-year hundredths round up", format: "mm/dd/yyyy hh:mm:ss.00", expected: "01/01/1911 00:00:00.00"},
{desc: "end-of-year minutes round up", format: "mm/dd/yyyy hh:mm", expected: "01/01/1911 00:00"},
{desc: "hour duration thousandths rounding", format: "[hh]:mm:ss.000", expected: "96455:59:59.999"},
{desc: "hour duration hundredths round up", format: "[hh]:mm:ss.00", expected: "96456:00:00.00"},
{desc: "hour duration minute round up (w/ ss)", format: "[hh]:mm:ss", expected: "96456:00:00"},
{desc: "hour duration minute round up", format: "[hh]:mm", expected: "96456:00"},
{desc: "hour duration round up", format: "[hh]", expected: "96456"},
{desc: "minute duration thousandths rounding", format: "[mm]:ss.000", expected: "5787359:59.999"},
{desc: "minute duration hundredths round up", format: "[mm]:ss.00", expected: "5787360:00.00"},
{desc: "minute duration round up", format: "[mm]:ss", expected: "5787360:00"},
{desc: "second duration thousandths rounding", format: "[ss].000", expected: "347241599.999"},
{desc: "second duration hundredths round up", format: "[ss].00", expected: "347241600.00"},
{desc: "second duration round up", format: "[ss]", expected: "347241600"},
];
testCases.forEach(testCase => {
var headers = ["value", testCase.format];
it(testCase.desc, () => {testRow([value, testCase.expected], headers, {})});
});
});
describe('date formats', function() {
doit(process.env.MINTEST ? dates.slice(0,4000) : dates);