forked from sheetjs/sheetjs
		
	version bump 0.11.1
- support 上午/下午 (like AM/PM, supported in en-US and other locales) - `format(number)` guess format if table is missing value - removed entry 65535 from table
This commit is contained in:
		
							parent
							
								
									b00f11ce33
								
							
						
					
					
						commit
						885b27fda5
					
				| @ -1 +1 @@ | ||||
| SSF.version = '0.11.0'; | ||||
| SSF.version = '0.11.1'; | ||||
|  | ||||
| @ -28,7 +28,6 @@ function init_table(t/*:any*/) { | ||||
| 	t[48]= '##0.0E+0'; | ||||
| 	t[49]= '@'; | ||||
| 	t[56]= '"上午/下午 "hh"時"mm"分"ss"秒 "'; | ||||
| 	t[65535]= 'General'; | ||||
| } | ||||
| 
 | ||||
| var table_fmt = {}; | ||||
|  | ||||
							
								
								
									
										55
									
								
								bits/26_defaults.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										55
									
								
								bits/26_defaults.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | ||||
| /* Defaults determined by systematically testing in Excel 2019 */ | ||||
| 
 | ||||
| /* These formats appear to default to other formats in the table */ | ||||
| var default_map/*:Array<number>*/ = []; | ||||
| var defi = 0; | ||||
| 
 | ||||
| //  5 -> 37 ...  8 -> 40
 | ||||
| for(defi = 5; defi <= 8; ++defi) default_map[defi] = 32 + defi; | ||||
| 
 | ||||
| // 23 ->  0 ... 26 ->  0
 | ||||
| for(defi = 23; defi <= 26; ++defi) default_map[defi] = 0; | ||||
| 
 | ||||
| // 27 -> 14 ... 31 -> 14
 | ||||
| for(defi = 27; defi <= 31; ++defi) default_map[defi] = 14; | ||||
| // 50 -> 14 ... 58 -> 14
 | ||||
| for(defi = 50; defi <= 58; ++defi) default_map[defi] = 14; | ||||
| 
 | ||||
| // 59 ->  1 ... 62 ->  4
 | ||||
| for(defi = 59; defi <= 62; ++defi) default_map[defi] = defi - 58; | ||||
| // 67 ->  9 ... 68 -> 10
 | ||||
| for(defi = 67; defi <= 68; ++defi) default_map[defi] = defi - 58; | ||||
| // 72 -> 14 ... 75 -> 17
 | ||||
| for(defi = 72; defi <= 75; ++defi) default_map[defi] = defi - 58; | ||||
| 
 | ||||
| // 69 -> 12 ... 71 -> 14
 | ||||
| for(defi = 67; defi <= 68; ++defi) default_map[defi] = defi - 57; | ||||
| 
 | ||||
| // 76 -> 20 ... 78 -> 22
 | ||||
| for(defi = 76; defi <= 78; ++defi) default_map[defi] = defi - 56; | ||||
| 
 | ||||
| // 79 -> 45 ... 81 -> 47
 | ||||
| for(defi = 79; defi <= 81; ++defi) default_map[defi] = defi - 34; | ||||
| 
 | ||||
| // 82 ->  0 ... 65536 -> 0 (omitted)
 | ||||
| 
 | ||||
| /* These formats technically refer to Accounting formats with no equivalent */ | ||||
| var default_str/*:Array<string>*/ = []; | ||||
| 
 | ||||
| //  5 -- Currency,   0 decimal, black negative
 | ||||
| default_str[5] = default_str[63] = '"$"#,##0_);\\("$"#,##0\\)'; | ||||
| //  6 -- Currency,   0 decimal, red   negative
 | ||||
| default_str[6] = default_str[64] = '"$"#,##0_);[Red]\\("$"#,##0\\)'; | ||||
| //  7 -- Currency,   2 decimal, black negative
 | ||||
| default_str[7] = default_str[65] = '"$"#,##0.00_);\\("$"#,##0.00\\)'; | ||||
| //  8 -- Currency,   2 decimal, red   negative
 | ||||
| default_str[8] = default_str[66] = '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)'; | ||||
| 
 | ||||
| // 41 -- Accounting, 0 decimal, No Symbol
 | ||||
| default_str[41] = '_(* #,##0_);_(* \\(#,##0\\);_(* "-"_);_(@_)'; | ||||
| // 42 -- Accounting, 0 decimal, $  Symbol
 | ||||
| default_str[42] = '_("$"* #,##0_);_("$"* \\(#,##0\\);_("$"* "-"_);_(@_)'; | ||||
| // 43 -- Accounting, 2 decimal, No Symbol
 | ||||
| default_str[43] = '_(* #,##0.00_);_(* \\(#,##0.00\\);_(* "-"??_);_(@_)'; | ||||
| // 44 -- Accounting, 2 decimal, $  Symbol
 | ||||
| default_str[44] = '_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)'; | ||||
| @ -1 +1,7 @@ | ||||
| function fix_hijri(/*::date, o*/) { return 0; } | ||||
| function fix_hijri(date/*:Date*/, o/*:[number, number, number]*/) { | ||||
|   /* TODO: properly adjust y/m/d and  */ | ||||
|   o[0] -= 581; | ||||
|   var dow = date.getDay(); | ||||
|   if(date < 60) dow = (dow + 6) % 7; | ||||
|   return dow; | ||||
| } | ||||
|  | ||||
							
								
								
									
										1
									
								
								bits/49_thaidigits.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								bits/49_thaidigits.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| var THAI_DIGITS = "\u0E50\u0E51\u0E52\u0E53\u0E54\u0E55\u0E56\u0E57\u0E58\u0E59".split(""); | ||||
| @ -64,4 +64,7 @@ function carry(val/*:number*/, d/*:number*/)/*:number*/ { | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| function flr(val/*:number*/)/*:string*/ { if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); return ""+Math.floor(val); } | ||||
| function flr(val/*:number*/)/*:string*/ { | ||||
| 	if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); | ||||
| 	return ""+Math.floor(val); | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| var abstime = /\[[HhMmSs]*\]/; | ||||
| var abstime = /\[[HhMmSs\u0E0A\u0E19\u0E17]*\]/; | ||||
| function fmt_is_date(fmt/*:string*/)/*:boolean*/ { | ||||
| 	var i = 0, /*cc = 0,*/ c = "", o = ""; | ||||
| 	while(i < fmt.length) { | ||||
| @ -14,9 +14,10 @@ function fmt_is_date(fmt/*:string*/)/*:boolean*/ { | ||||
| 			case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E': | ||||
| 				/* falls through */ | ||||
| 			case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': return true; | ||||
| 			case 'A': case 'a': | ||||
| 			case 'A': case 'a': case '上': | ||||
| 				if(fmt.substr(i, 3).toUpperCase() === "A/P") return true; | ||||
| 				if(fmt.substr(i, 5).toUpperCase() === "AM/PM") return true; | ||||
| 				if(fmt.substr(i, 5).toUpperCase() === "上午/下午") return true; | ||||
| 				++i; break; | ||||
| 			case '[': | ||||
| 				o = c; | ||||
|  | ||||
| @ -31,11 +31,12 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 				if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; | ||||
| 				if(c === 'h') c = hr; | ||||
| 				out[out.length] = {t:c, v:o}; lst = c; break; | ||||
| 			case 'A': case 'a': | ||||
| 			case 'A': case 'a': case '上': | ||||
| 				var q={t:c, v:c}; | ||||
| 				if(dt==null) dt=parse_date_code(v, opts); | ||||
| 				if(fmt.substr(i, 3).toUpperCase() === "A/P") { if(dt!=null) q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;} | ||||
| 				else if(fmt.substr(i,5).toUpperCase() === "AM/PM") { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; } | ||||
| 				else if(fmt.substr(i,5).toUpperCase() === "上午/下午") { if(dt!=null) q.v = dt.H >= 12 ? "下午" : "上午"; q.t = 'T'; i+=5; hr='h'; } | ||||
| 				else { q.t = "t"; ++i; } | ||||
| 				if(dt==null && q.t === 'T') return ""; | ||||
| 				out[out.length] = q; lst = c; break; | ||||
| @ -71,12 +72,14 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 				o = c; while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1) o+=fmt.charAt(i); | ||||
| 				out[out.length] = {t:'D', v:o}; break; | ||||
| 			case ' ': out[out.length] = {t:c, v:c}; ++i; break; | ||||
| 			case "$": out[out.length] = {t:'t', v:'$'}; ++i; break; | ||||
| 			case '$': out[out.length] = {t:'t', v:'$'}; ++i; break; | ||||
| 			default: | ||||
| 				if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxzP".indexOf(c) === -1) throw new Error('unrecognized character ' + c + ' in ' + fmt); | ||||
| 				out[out.length] = {t:'t', v:c}; ++i; break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* Scan for date/time parts */ | ||||
| 	var bt = 0, ss0 = 0, ssm; | ||||
| 	for(i=out.length-1, lst='t'; i >= 0; --i) { | ||||
| 		switch(out[i].t) { | ||||
| @ -95,6 +98,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 				if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3; | ||||
| 		} | ||||
| 	} | ||||
| 	/* time rounding depends on presence of minute / second / usec fields */ | ||||
| 	switch(bt) { | ||||
| 		case 0: break; | ||||
| 		case 1: | ||||
| @ -109,6 +113,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 			if(dt.S >=  60) { dt.S = 0; ++dt.M; } | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	/* replace fields */ | ||||
| 	var nstr = "", jj; | ||||
| 	for(i=0; i < out.length; ++i) { | ||||
|  | ||||
| @ -30,6 +30,8 @@ function format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) { | ||||
| 		case "number": | ||||
| 			if(fmt == 14 && o.dateNF) sfmt = o.dateNF; | ||||
| 			else sfmt = (o.table != null ? (o.table/*:any*/) : table_fmt)[fmt]; | ||||
| 			if(sfmt == null) sfmt = (o.table && o.table[default_map[fmt]]) || table_fmt[default_map[fmt]]; | ||||
| 			if(sfmt == null) sfmt = default_str[fmt] || "General"; | ||||
| 			break; | ||||
| 	} | ||||
| 	if(isgeneral(sfmt,0)) return general_fmt(v, o); | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| { | ||||
| 	"name": "ssf", | ||||
| 	"version": "0.11.0", | ||||
| 	"version": "0.11.1", | ||||
| 	"author": "sheetjs", | ||||
| 	"description": "Format data using ECMA-376 spreadsheet Format Codes", | ||||
| 	"keywords": [ | ||||
|  | ||||
							
								
								
									
										88
									
								
								ssf.flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										88
									
								
								ssf.flow.js
									
									
									
									
									
								
							| @ -4,7 +4,7 @@ | ||||
| /*:: declare var DO_NOT_EXPORT_SSF: any; */ | ||||
| var SSF/*:SSFModule*/ = ({}/*:any*/); | ||||
| var make_ssf = function make_ssf(SSF/*:SSFModule*/){ | ||||
| SSF.version = '0.11.0'; | ||||
| SSF.version = '0.11.1'; | ||||
| function _strrev(x/*:string*/)/*:string*/ { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; } | ||||
| function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; } | ||||
| function pad0(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;} | ||||
| @ -71,11 +71,65 @@ function init_table(t/*:any*/) { | ||||
| 	t[48]= '##0.0E+0'; | ||||
| 	t[49]= '@'; | ||||
| 	t[56]= '"上午/下午 "hh"時"mm"分"ss"秒 "'; | ||||
| 	t[65535]= 'General'; | ||||
| } | ||||
| 
 | ||||
| var table_fmt = {}; | ||||
| init_table(table_fmt); | ||||
| /* Defaults determined by systematically testing in Excel 2019 */ | ||||
| 
 | ||||
| /* These formats appear to default to other formats in the table */ | ||||
| var default_map/*:Array<number>*/ = []; | ||||
| var defi = 0; | ||||
| 
 | ||||
| //  5 -> 37 ...  8 -> 40
 | ||||
| for(defi = 5; defi <= 8; ++defi) default_map[defi] = 32 + defi; | ||||
| 
 | ||||
| // 23 ->  0 ... 26 ->  0
 | ||||
| for(defi = 23; defi <= 26; ++defi) default_map[defi] = 0; | ||||
| 
 | ||||
| // 27 -> 14 ... 31 -> 14
 | ||||
| for(defi = 27; defi <= 31; ++defi) default_map[defi] = 14; | ||||
| // 50 -> 14 ... 58 -> 14
 | ||||
| for(defi = 50; defi <= 58; ++defi) default_map[defi] = 14; | ||||
| 
 | ||||
| // 59 ->  1 ... 62 ->  4
 | ||||
| for(defi = 59; defi <= 62; ++defi) default_map[defi] = defi - 58; | ||||
| // 67 ->  9 ... 68 -> 10
 | ||||
| for(defi = 67; defi <= 68; ++defi) default_map[defi] = defi - 58; | ||||
| // 72 -> 14 ... 75 -> 17
 | ||||
| for(defi = 72; defi <= 75; ++defi) default_map[defi] = defi - 58; | ||||
| 
 | ||||
| // 69 -> 12 ... 71 -> 14
 | ||||
| for(defi = 67; defi <= 68; ++defi) default_map[defi] = defi - 57; | ||||
| 
 | ||||
| // 76 -> 20 ... 78 -> 22
 | ||||
| for(defi = 76; defi <= 78; ++defi) default_map[defi] = defi - 56; | ||||
| 
 | ||||
| // 79 -> 45 ... 81 -> 47
 | ||||
| for(defi = 79; defi <= 81; ++defi) default_map[defi] = defi - 34; | ||||
| 
 | ||||
| // 82 ->  0 ... 65536 -> 0 (omitted)
 | ||||
| 
 | ||||
| /* These formats technically refer to Accounting formats with no equivalent */ | ||||
| var default_str/*:Array<string>*/ = []; | ||||
| 
 | ||||
| //  5 -- Currency,   0 decimal, black negative
 | ||||
| default_str[5] = default_str[63] = '"$"#,##0_);\\("$"#,##0\\)'; | ||||
| //  6 -- Currency,   0 decimal, red   negative
 | ||||
| default_str[6] = default_str[64] = '"$"#,##0_);[Red]\\("$"#,##0\\)'; | ||||
| //  7 -- Currency,   2 decimal, black negative
 | ||||
| default_str[7] = default_str[65] = '"$"#,##0.00_);\\("$"#,##0.00\\)'; | ||||
| //  8 -- Currency,   2 decimal, red   negative
 | ||||
| default_str[8] = default_str[66] = '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)'; | ||||
| 
 | ||||
| // 41 -- Accounting, 0 decimal, No Symbol
 | ||||
| default_str[41] = '_(* #,##0_);_(* \\(#,##0\\);_(* "-"_);_(@_)'; | ||||
| // 42 -- Accounting, 0 decimal, $  Symbol
 | ||||
| default_str[42] = '_("$"* #,##0_);_("$"* \\(#,##0\\);_("$"* "-"_);_(@_)'; | ||||
| // 43 -- Accounting, 2 decimal, No Symbol
 | ||||
| default_str[43] = '_(* #,##0.00_);_(* \\(#,##0.00\\);_(* "-"??_);_(@_)'; | ||||
| // 44 -- Accounting, 2 decimal, $  Symbol
 | ||||
| default_str[44] = '_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)'; | ||||
| function frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array<number>*/ { | ||||
| 	var sgn = x < 0 ? -1 : 1; | ||||
| 	var B = x * sgn; | ||||
| @ -180,7 +234,14 @@ function general_fmt(v/*:any*/, opts/*:any*/) { | ||||
| 	throw new Error("unsupported value in General format: " + v); | ||||
| } | ||||
| SSF._general = general_fmt; | ||||
| function fix_hijri(/*::date, o*/) { return 0; } | ||||
| function fix_hijri(date/*:Date*/, o/*:[number, number, number]*/) { | ||||
|   /* TODO: properly adjust y/m/d and  */ | ||||
|   o[0] -= 581; | ||||
|   var dow = date.getDay(); | ||||
|   if(date < 60) dow = (dow + 6) % 7; | ||||
|   return dow; | ||||
| } | ||||
| var THAI_DIGITS = "\u0E50\u0E51\u0E52\u0E53\u0E54\u0E55\u0E56\u0E57\u0E58\u0E59".split(""); | ||||
| /*jshint -W086 */ | ||||
| function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:string*/ { | ||||
| 	var o="", ss=0, tt=0, y = val.y, out, outl = 0; | ||||
| @ -325,7 +386,10 @@ function carry(val/*:number*/, d/*:number*/)/*:number*/ { | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| function flr(val/*:number*/)/*:string*/ { if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); return ""+Math.floor(val); } | ||||
| function flr(val/*:number*/)/*:string*/ { | ||||
| 	if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); | ||||
| 	return ""+Math.floor(val); | ||||
| } | ||||
| function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/ { | ||||
| 	if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) { | ||||
| 		var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,""); | ||||
| @ -548,7 +612,7 @@ function split_fmt(fmt/*:string*/)/*:Array<string>*/ { | ||||
| 	return out; | ||||
| } | ||||
| SSF._split = split_fmt; | ||||
| var abstime = /\[[HhMmSs]*\]/; | ||||
| var abstime = /\[[HhMmSs\u0E0A\u0E19\u0E17]*\]/; | ||||
| function fmt_is_date(fmt/*:string*/)/*:boolean*/ { | ||||
| 	var i = 0, /*cc = 0,*/ c = "", o = ""; | ||||
| 	while(i < fmt.length) { | ||||
| @ -564,9 +628,10 @@ function fmt_is_date(fmt/*:string*/)/*:boolean*/ { | ||||
| 			case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E': | ||||
| 				/* falls through */ | ||||
| 			case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': return true; | ||||
| 			case 'A': case 'a': | ||||
| 			case 'A': case 'a': case '上': | ||||
| 				if(fmt.substr(i, 3).toUpperCase() === "A/P") return true; | ||||
| 				if(fmt.substr(i, 5).toUpperCase() === "AM/PM") return true; | ||||
| 				if(fmt.substr(i, 5).toUpperCase() === "上午/下午") return true; | ||||
| 				++i; break; | ||||
| 			case '[': | ||||
| 				o = c; | ||||
| @ -623,11 +688,12 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 				if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; | ||||
| 				if(c === 'h') c = hr; | ||||
| 				out[out.length] = {t:c, v:o}; lst = c; break; | ||||
| 			case 'A': case 'a': | ||||
| 			case 'A': case 'a': case '上': | ||||
| 				var q={t:c, v:c}; | ||||
| 				if(dt==null) dt=parse_date_code(v, opts); | ||||
| 				if(fmt.substr(i, 3).toUpperCase() === "A/P") { if(dt!=null) q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;} | ||||
| 				else if(fmt.substr(i,5).toUpperCase() === "AM/PM") { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; } | ||||
| 				else if(fmt.substr(i,5).toUpperCase() === "上午/下午") { if(dt!=null) q.v = dt.H >= 12 ? "下午" : "上午"; q.t = 'T'; i+=5; hr='h'; } | ||||
| 				else { q.t = "t"; ++i; } | ||||
| 				if(dt==null && q.t === 'T') return ""; | ||||
| 				out[out.length] = q; lst = c; break; | ||||
| @ -663,12 +729,14 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 				o = c; while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1) o+=fmt.charAt(i); | ||||
| 				out[out.length] = {t:'D', v:o}; break; | ||||
| 			case ' ': out[out.length] = {t:c, v:c}; ++i; break; | ||||
| 			case "$": out[out.length] = {t:'t', v:'$'}; ++i; break; | ||||
| 			case '$': out[out.length] = {t:'t', v:'$'}; ++i; break; | ||||
| 			default: | ||||
| 				if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxzP".indexOf(c) === -1) throw new Error('unrecognized character ' + c + ' in ' + fmt); | ||||
| 				out[out.length] = {t:'t', v:c}; ++i; break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* Scan for date/time parts */ | ||||
| 	var bt = 0, ss0 = 0, ssm; | ||||
| 	for(i=out.length-1, lst='t'; i >= 0; --i) { | ||||
| 		switch(out[i].t) { | ||||
| @ -687,6 +755,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 				if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3; | ||||
| 		} | ||||
| 	} | ||||
| 	/* time rounding depends on presence of minute / second / usec fields */ | ||||
| 	switch(bt) { | ||||
| 		case 0: break; | ||||
| 		case 1: | ||||
| @ -701,6 +770,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 			if(dt.S >=  60) { dt.S = 0; ++dt.M; } | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	/* replace fields */ | ||||
| 	var nstr = "", jj; | ||||
| 	for(i=0; i < out.length; ++i) { | ||||
| @ -840,6 +910,8 @@ function format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) { | ||||
| 		case "number": | ||||
| 			if(fmt == 14 && o.dateNF) sfmt = o.dateNF; | ||||
| 			else sfmt = (o.table != null ? (o.table/*:any*/) : table_fmt)[fmt]; | ||||
| 			if(sfmt == null) sfmt = (o.table && o.table[default_map[fmt]]) || table_fmt[default_map[fmt]]; | ||||
| 			if(sfmt == null) sfmt = default_str[fmt] || "General"; | ||||
| 			break; | ||||
| 	} | ||||
| 	if(isgeneral(sfmt,0)) return general_fmt(v, o); | ||||
|  | ||||
							
								
								
									
										88
									
								
								ssf.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										88
									
								
								ssf.js
									
									
									
									
									
								
							| @ -3,7 +3,7 @@ | ||||
| /*jshint -W041 */ | ||||
| var SSF = ({}); | ||||
| var make_ssf = function make_ssf(SSF){ | ||||
| SSF.version = '0.11.0'; | ||||
| SSF.version = '0.11.1'; | ||||
| function _strrev(x) { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; } | ||||
| function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; } | ||||
| function pad0(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;} | ||||
| @ -67,11 +67,65 @@ function init_table(t) { | ||||
| 	t[48]= '##0.0E+0'; | ||||
| 	t[49]= '@'; | ||||
| 	t[56]= '"上午/下午 "hh"時"mm"分"ss"秒 "'; | ||||
| 	t[65535]= 'General'; | ||||
| } | ||||
| 
 | ||||
| var table_fmt = {}; | ||||
| init_table(table_fmt); | ||||
| /* Defaults determined by systematically testing in Excel 2019 */ | ||||
| 
 | ||||
| /* These formats appear to default to other formats in the table */ | ||||
| var default_map = []; | ||||
| var defi = 0; | ||||
| 
 | ||||
| //  5 -> 37 ...  8 -> 40
 | ||||
| for(defi = 5; defi <= 8; ++defi) default_map[defi] = 32 + defi; | ||||
| 
 | ||||
| // 23 ->  0 ... 26 ->  0
 | ||||
| for(defi = 23; defi <= 26; ++defi) default_map[defi] = 0; | ||||
| 
 | ||||
| // 27 -> 14 ... 31 -> 14
 | ||||
| for(defi = 27; defi <= 31; ++defi) default_map[defi] = 14; | ||||
| // 50 -> 14 ... 58 -> 14
 | ||||
| for(defi = 50; defi <= 58; ++defi) default_map[defi] = 14; | ||||
| 
 | ||||
| // 59 ->  1 ... 62 ->  4
 | ||||
| for(defi = 59; defi <= 62; ++defi) default_map[defi] = defi - 58; | ||||
| // 67 ->  9 ... 68 -> 10
 | ||||
| for(defi = 67; defi <= 68; ++defi) default_map[defi] = defi - 58; | ||||
| // 72 -> 14 ... 75 -> 17
 | ||||
| for(defi = 72; defi <= 75; ++defi) default_map[defi] = defi - 58; | ||||
| 
 | ||||
| // 69 -> 12 ... 71 -> 14
 | ||||
| for(defi = 67; defi <= 68; ++defi) default_map[defi] = defi - 57; | ||||
| 
 | ||||
| // 76 -> 20 ... 78 -> 22
 | ||||
| for(defi = 76; defi <= 78; ++defi) default_map[defi] = defi - 56; | ||||
| 
 | ||||
| // 79 -> 45 ... 81 -> 47
 | ||||
| for(defi = 79; defi <= 81; ++defi) default_map[defi] = defi - 34; | ||||
| 
 | ||||
| // 82 ->  0 ... 65536 -> 0 (omitted)
 | ||||
| 
 | ||||
| /* These formats technically refer to Accounting formats with no equivalent */ | ||||
| var default_str = []; | ||||
| 
 | ||||
| //  5 -- Currency,   0 decimal, black negative
 | ||||
| default_str[5] = default_str[63] = '"$"#,##0_);\\("$"#,##0\\)'; | ||||
| //  6 -- Currency,   0 decimal, red   negative
 | ||||
| default_str[6] = default_str[64] = '"$"#,##0_);[Red]\\("$"#,##0\\)'; | ||||
| //  7 -- Currency,   2 decimal, black negative
 | ||||
| default_str[7] = default_str[65] = '"$"#,##0.00_);\\("$"#,##0.00\\)'; | ||||
| //  8 -- Currency,   2 decimal, red   negative
 | ||||
| default_str[8] = default_str[66] = '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)'; | ||||
| 
 | ||||
| // 41 -- Accounting, 0 decimal, No Symbol
 | ||||
| default_str[41] = '_(* #,##0_);_(* \\(#,##0\\);_(* "-"_);_(@_)'; | ||||
| // 42 -- Accounting, 0 decimal, $  Symbol
 | ||||
| default_str[42] = '_("$"* #,##0_);_("$"* \\(#,##0\\);_("$"* "-"_);_(@_)'; | ||||
| // 43 -- Accounting, 2 decimal, No Symbol
 | ||||
| default_str[43] = '_(* #,##0.00_);_(* \\(#,##0.00\\);_(* "-"??_);_(@_)'; | ||||
| // 44 -- Accounting, 2 decimal, $  Symbol
 | ||||
| default_str[44] = '_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)'; | ||||
| function frac(x, D, mixed) { | ||||
| 	var sgn = x < 0 ? -1 : 1; | ||||
| 	var B = x * sgn; | ||||
| @ -176,7 +230,14 @@ function general_fmt(v, opts) { | ||||
| 	throw new Error("unsupported value in General format: " + v); | ||||
| } | ||||
| SSF._general = general_fmt; | ||||
| function fix_hijri() { return 0; } | ||||
| function fix_hijri(date, o) { | ||||
|   /* TODO: properly adjust y/m/d and  */ | ||||
|   o[0] -= 581; | ||||
|   var dow = date.getDay(); | ||||
|   if(date < 60) dow = (dow + 6) % 7; | ||||
|   return dow; | ||||
| } | ||||
| var THAI_DIGITS = "\u0E50\u0E51\u0E52\u0E53\u0E54\u0E55\u0E56\u0E57\u0E58\u0E59".split(""); | ||||
| /*jshint -W086 */ | ||||
| function write_date(type, fmt, val, ss0) { | ||||
| 	var o="", ss=0, tt=0, y = val.y, out, outl = 0; | ||||
| @ -320,7 +381,10 @@ function carry(val, d) { | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| function flr(val) { if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); return ""+Math.floor(val); } | ||||
| function flr(val) { | ||||
| 	if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); | ||||
| 	return ""+Math.floor(val); | ||||
| } | ||||
| function write_num_flt(type, fmt, val) { | ||||
| 	if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) { | ||||
| 		var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,""); | ||||
| @ -541,7 +605,7 @@ function split_fmt(fmt) { | ||||
| 	return out; | ||||
| } | ||||
| SSF._split = split_fmt; | ||||
| var abstime = /\[[HhMmSs]*\]/; | ||||
| var abstime = /\[[HhMmSs\u0E0A\u0E19\u0E17]*\]/; | ||||
| function fmt_is_date(fmt) { | ||||
| 	var i = 0, /*cc = 0,*/ c = "", o = ""; | ||||
| 	while(i < fmt.length) { | ||||
| @ -557,9 +621,10 @@ function fmt_is_date(fmt) { | ||||
| 			case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E': | ||||
| 				/* falls through */ | ||||
| 			case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': return true; | ||||
| 			case 'A': case 'a': | ||||
| 			case 'A': case 'a': case '上': | ||||
| 				if(fmt.substr(i, 3).toUpperCase() === "A/P") return true; | ||||
| 				if(fmt.substr(i, 5).toUpperCase() === "AM/PM") return true; | ||||
| 				if(fmt.substr(i, 5).toUpperCase() === "上午/下午") return true; | ||||
| 				++i; break; | ||||
| 			case '[': | ||||
| 				o = c; | ||||
| @ -616,11 +681,12 @@ function eval_fmt(fmt, v, opts, flen) { | ||||
| 				if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; | ||||
| 				if(c === 'h') c = hr; | ||||
| 				out[out.length] = {t:c, v:o}; lst = c; break; | ||||
| 			case 'A': case 'a': | ||||
| 			case 'A': case 'a': case '上': | ||||
| 				var q={t:c, v:c}; | ||||
| 				if(dt==null) dt=parse_date_code(v, opts); | ||||
| 				if(fmt.substr(i, 3).toUpperCase() === "A/P") { if(dt!=null) q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;} | ||||
| 				else if(fmt.substr(i,5).toUpperCase() === "AM/PM") { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; } | ||||
| 				else if(fmt.substr(i,5).toUpperCase() === "上午/下午") { if(dt!=null) q.v = dt.H >= 12 ? "下午" : "上午"; q.t = 'T'; i+=5; hr='h'; } | ||||
| 				else { q.t = "t"; ++i; } | ||||
| 				if(dt==null && q.t === 'T') return ""; | ||||
| 				out[out.length] = q; lst = c; break; | ||||
| @ -656,12 +722,14 @@ function eval_fmt(fmt, v, opts, flen) { | ||||
| 				o = c; while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1) o+=fmt.charAt(i); | ||||
| 				out[out.length] = {t:'D', v:o}; break; | ||||
| 			case ' ': out[out.length] = {t:c, v:c}; ++i; break; | ||||
| 			case "$": out[out.length] = {t:'t', v:'$'}; ++i; break; | ||||
| 			case '$': out[out.length] = {t:'t', v:'$'}; ++i; break; | ||||
| 			default: | ||||
| 				if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxzP".indexOf(c) === -1) throw new Error('unrecognized character ' + c + ' in ' + fmt); | ||||
| 				out[out.length] = {t:'t', v:c}; ++i; break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* Scan for date/time parts */ | ||||
| 	var bt = 0, ss0 = 0, ssm; | ||||
| 	for(i=out.length-1, lst='t'; i >= 0; --i) { | ||||
| 		switch(out[i].t) { | ||||
| @ -680,6 +748,7 @@ function eval_fmt(fmt, v, opts, flen) { | ||||
| 				if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3; | ||||
| 		} | ||||
| 	} | ||||
| 	/* time rounding depends on presence of minute / second / usec fields */ | ||||
| 	switch(bt) { | ||||
| 		case 0: break; | ||||
| 		case 1: | ||||
| @ -692,6 +761,7 @@ if(dt.u >= 0.5) { dt.u = 0; ++dt.S; } | ||||
| 			if(dt.S >=  60) { dt.S = 0; ++dt.M; } | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	/* replace fields */ | ||||
| 	var nstr = "", jj; | ||||
| 	for(i=0; i < out.length; ++i) { | ||||
| @ -830,6 +900,8 @@ function format(fmt,v,o) { | ||||
| 		case "number": | ||||
| 			if(fmt == 14 && o.dateNF) sfmt = o.dateNF; | ||||
| 			else sfmt = (o.table != null ? (o.table) : table_fmt)[fmt]; | ||||
| 			if(sfmt == null) sfmt = (o.table && o.table[default_map[fmt]]) || table_fmt[default_map[fmt]]; | ||||
| 			if(sfmt == null) sfmt = default_str[fmt] || "General"; | ||||
| 			break; | ||||
| 	} | ||||
| 	if(isgeneral(sfmt,0)) return general_fmt(v, o); | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| /* vim: set ts=2: */ | ||||
| /*jshint loopfunc:true, mocha:true, node:true */ | ||||
| /*eslint-env mocha, node */ | ||||
| var SSF = require('../'); | ||||
| var assert = require('assert'); | ||||
| describe('dateNF override', function() { | ||||
| @ -14,3 +15,36 @@ describe('dateNF override', function() { | ||||
|     assert.equal(SSF.format('m/d/yy', 43880, {dateNF:"dd/mm/yyyy"}), "19/02/2020"); | ||||
|   }); | ||||
| }); | ||||
| describe('asian formats', function() { | ||||
| 	it('上午/下午 (AM/PM)', function() { | ||||
| 		assert.equal(SSF.format('上午/下午', 0),    '上午'); | ||||
| 		assert.equal(SSF.format('上午/下午', 0.25), '上午'); | ||||
| 		assert.equal(SSF.format('上午/下午', 0.49), '上午'); | ||||
| 		assert.equal(SSF.format('上午/下午', 0.5),  '下午'); | ||||
| 		assert.equal(SSF.format('上午/下午', 0.51), '下午'); | ||||
| 		assert.equal(SSF.format('上午/下午', 0.99), '下午'); | ||||
| 		assert.equal(SSF.format('上午/下午', 1),    '上午'); | ||||
| 	}); | ||||
| 	it('bb (buddhist)', function() { | ||||
| 		[ | ||||
| 			[12345, | ||||
| 				[ 'yyyy',   '1933'], | ||||
| 				[ 'eeee',   '1933'], | ||||
| 				[ 'bbbb',   '2476'], | ||||
| 				//[ 'ปปปป',   '๒๔๗๖'],
 | ||||
| 				[ 'b2yyyy', '1352'], | ||||
| 				[ 'b2eeee', '1352'], | ||||
| 				[ 'b2bbbb', '1895'], | ||||
| 				//[ 'b2ปปปป', '๑๘๙๕']
 | ||||
| 			] | ||||
| 		].forEach(function(row) { | ||||
| 			row.slice(1).forEach(function(fmt) { | ||||
| 				assert.equal(SSF.format(fmt[0], row[0]), fmt[1]); | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
| 	it.skip('thai fields', function() { | ||||
| 		SSF.format('\u0E27/\u0E14/\u0E1B\u0E1B\u0E1B\u0E1B \u0E0A\u0E0A:\u0E19\u0E19:\u0E17\u0E17', 12345.67); | ||||
| 		assert.equal(SSF.format('\u0E27/\u0E14/\u0E1B\u0E1B\u0E1B\u0E1B \u0E0A\u0E0A:\u0E19\u0E19:\u0E17\u0E17', 12345.67), "๑๘/๑๐/๒๔๗๖ ๑๖:๐๔:๔๘"); | ||||
| 	}); | ||||
| }); | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| /* vim: set ts=2: */ | ||||
| /*jshint loopfunc:true, mocha:true, node:true */ | ||||
| /*eslint-env mocha */ | ||||
| /*eslint-env mocha, node */ | ||||
| var SSF = require('../'); | ||||
| var assert = require('assert'); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user