forked from sheetjs/sheetjs
		
	added test cases from #2560's thread; fixed more rounding edge cases
This commit is contained in:
		
							parent
							
								
									c580ffcbc2
								
							
						
					
					
						commit
						456c403c09
					
				| @ -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); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user