1
forked from sheetjs/sheetjs

version bump 0.6.3: B2 stubs, b format

- B2 hijri stubs (TODO: find the algorithm)
- b* correspond to the equivalent year in buddhist calendar
This commit is contained in:
SheetJS 2014-04-02 11:47:03 -07:00
parent 95b338304b
commit be19bcd01e
6 changed files with 1048693 additions and 74 deletions

@ -1,6 +1,6 @@
{ {
"name": "ssf", "name": "ssf",
"version": "0.6.2", "version": "0.6.3",
"author": "SheetJS", "author": "SheetJS",
"description": "pure-JS library to format data using ECMA-376 spreadsheet Format Codes", "description": "pure-JS library to format data using ECMA-376 spreadsheet Format Codes",
"keywords": [ "format", "sprintf", "spreadsheet" ], "keywords": [ "format", "sprintf", "spreadsheet" ],

45
ssf.js

@ -5,14 +5,13 @@ var _strrev = function(x) { return String(x).split("").reverse().join("");};
function fill(c,l) { return new Array(l+1).join(c); } function fill(c,l) { return new Array(l+1).join(c); }
function pad(v,d,c){var t=String(v);return t.length>=d?t:(fill(c||0,d-t.length)+t);} function pad(v,d,c){var t=String(v);return t.length>=d?t:(fill(c||0,d-t.length)+t);}
function rpad(v,d,c){var t=String(v);return t.length>=d?t:(t+fill(c||0,d-t.length));} function rpad(v,d,c){var t=String(v);return t.length>=d?t:(t+fill(c||0,d-t.length));}
SSF.version = '0.6.2'; SSF.version = '0.6.3';
/* Options */ /* Options */
var opts_fmt = {}; var opts_fmt = {};
function fixopts(o){for(var y in opts_fmt) if(o[y]===undefined) o[y]=opts_fmt[y];} function fixopts(o){for(var y in opts_fmt) if(o[y]===undefined) o[y]=opts_fmt[y];}
SSF.opts = opts_fmt; SSF.opts = opts_fmt;
opts_fmt.date1904 = 0; opts_fmt.date1904 = 0;
opts_fmt.output = ""; opts_fmt.output = "";
opts_fmt.mode = "";
var table_fmt = { var table_fmt = {
0: 'General', 0: 'General',
1: '0', 1: '0',
@ -115,7 +114,8 @@ var general_fmt = function(v) {
throw new Error("unsupported value in General format: " + v); throw new Error("unsupported value in General format: " + v);
}; };
SSF._general = general_fmt; SSF._general = general_fmt;
var parse_date_code = function parse_date_code(v,opts) { function fix_hijri(date, o) { }
var parse_date_code = function parse_date_code(v,opts,b2) {
var date = Math.floor(v), time = Math.floor(86400 * (v - date)+1e-6), dow=0; var date = Math.floor(v), time = Math.floor(86400 * (v - date)+1e-6), dow=0;
var dout=[], out={D:date, T:time, u:86400*(v-date)-time}; fixopts(opts = (opts||{})); var dout=[], out={D:date, T:time, u:86400*(v-date)-time}; fixopts(opts = (opts||{}));
if(opts.date1904) date += 1462; if(opts.date1904) date += 1462;
@ -124,8 +124,8 @@ var parse_date_code = function parse_date_code(v,opts) {
out.u = 0; out.u = 0;
if(++time == 86400) { time = 0; ++date; } if(++time == 86400) { time = 0; ++date; }
} }
if(date === 60) {dout = [1900,2,29]; dow=3;} if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
else if(date === 0) {dout = [1900,1,0]; dow=6;} else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
else { else {
if(date > 60) --date; if(date > 60) --date;
/* 1 = Jan 1 1900 */ /* 1 = Jan 1 1900 */
@ -133,7 +133,8 @@ var parse_date_code = function parse_date_code(v,opts) {
d.setDate(d.getDate() + date - 1); d.setDate(d.getDate() + date - 1);
dout = [d.getFullYear(), d.getMonth()+1,d.getDate()]; dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
dow = d.getDay(); dow = d.getDay();
if(/* opts.mode === 'excel' && */ date < 60) dow = (dow + 6) % 7; if(date < 60) dow = (dow + 6) % 7;
if(b2) dow = fix_hijri(d, dout);
} }
out.y = dout[0]; out.m = dout[1]; out.d = dout[2]; out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
out.S = time % 60; time = Math.floor(time / 60); out.S = time % 60; time = Math.floor(time / 60);
@ -146,13 +147,15 @@ SSF.parse_date_code = parse_date_code;
/*jshint -W086 */ /*jshint -W086 */
var write_date = function(type, fmt, val) { var write_date = function(type, fmt, val) {
if(val < 0) return ""; if(val < 0) return "";
var o, ss; var o, ss, y = val.y;
switch(type) { switch(type) {
case 'y': switch(fmt) { /* year */ case 'b': y = val.y + 543;
case 'y': case 'yy': return pad(val.y % 100,2); /* falls through */
default: return pad(val.y % 10000,4); case 'y': switch(fmt.length) { /* year */
case 1: case 2: return pad(y % 100,2);
default: return pad(y % 10000,4);
} }
case 'm': switch(fmt) { /* month */ case 'm': switch(fmt) {
case 'm': return val.m; case 'm': return val.m;
case 'mm': return pad(val.m,2); case 'mm': return pad(val.m,2);
case 'mmm': return months[val.m-1][1]; case 'mmm': return months[val.m-1][1];
@ -317,7 +320,7 @@ function eval_fmt(fmt, v, opts, flen) {
while(i < fmt.length) { while(i < fmt.length) {
switch((c = fmt[i])) { switch((c = fmt[i])) {
case 'G': /* General */ case 'G': /* General */
if(fmt.substr(i, i+6).toLowerCase() !== "general") if(fmt.substr(i, 7).toLowerCase() !== "general")
throw new Error('unrecognized character ' + fmt[i] + ' in ' +fmt); throw new Error('unrecognized character ' + fmt[i] + ' in ' +fmt);
out.push({t:'G',v:'General'}); i+=7; break; out.push({t:'G',v:'General'}); i+=7; break;
case '"': /* Literal text */ case '"': /* Literal text */
@ -328,7 +331,12 @@ function eval_fmt(fmt, v, opts, flen) {
case '_': out.push({t:'t', v:" "}); i+=2; break; case '_': out.push({t:'t', v:" "}); i+=2; break;
case '@': /* Text Placeholder */ case '@': /* Text Placeholder */
out.push({t:'T', v:v}); ++i; break; out.push({t:'T', v:v}); ++i; break;
/* Dates */ case 'B': case 'b':
if(fmt[i+1] === "1" || fmt[i+1] === "2") {
if(!dt) dt = parse_date_code(v, opts, fmt[i+1] === "2");
q={t:'X', v:fmt.substr(i,2)}; out.push(q); lst = c; i+=2; break;
}
/* falls through */
case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E': case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
c = c.toLowerCase(); c = c.toLowerCase();
/* falls through */ /* falls through */
@ -350,7 +358,7 @@ function eval_fmt(fmt, v, opts, flen) {
else if(fmt.substr(i,5) === "AM/PM") { q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; } else if(fmt.substr(i,5) === "AM/PM") { q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; }
else { q.t = "t"; i++; } else { q.t = "t"; i++; }
out.push(q); lst = c; break; out.push(q); lst = c; break;
case '[': /* TODO: Fix this -- ignore all conditionals and formatting */ case '[':
o = c; o = c;
while(fmt[i++] !== ']' && i < fmt.length) o += fmt[i]; while(fmt[i++] !== ']' && i < fmt.length) o += fmt[i];
if(o.substr(-1) !== ']') throw 'unterminated "[" block: |' + o + '|'; if(o.substr(-1) !== ']') throw 'unterminated "[" block: |' + o + '|';
@ -374,7 +382,7 @@ function eval_fmt(fmt, v, opts, flen) {
out.push({t:'D', v:o}); break; out.push({t:'D', v:o}); break;
case ' ': out.push({t:c,v:c}); ++i; break; case ' ': out.push({t:c,v:c}); ++i; break;
default: default:
if(",$-+/():!^&'~{}<>=€".indexOf(c) === -1) if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxz".indexOf(c) === -1)
throw 'unrecognized character ' + fmt[i] + ' in ' + fmt; throw 'unrecognized character ' + fmt[i] + ' in ' + fmt;
out.push({t:'t', v:c}); ++i; break; out.push({t:'t', v:c}); ++i; break;
} }
@ -387,6 +395,8 @@ function eval_fmt(fmt, v, opts, flen) {
/* falls through */ /* falls through */
case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break; case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break; case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
case 'X': if(out[i].v === "B2");
break;
case 'Z': case 'Z':
if(bt < 1 && out[i].v.match(/[Hh]/)) bt = 1; if(bt < 1 && out[i].v.match(/[Hh]/)) bt = 1;
if(bt < 2 && out[i].v.match(/[Mm]/)) bt = 2; if(bt < 2 && out[i].v.match(/[Mm]/)) bt = 2;
@ -409,8 +419,9 @@ function eval_fmt(fmt, v, opts, flen) {
for(i=0; i < out.length; ++i) { for(i=0; i < out.length; ++i) {
switch(out[i].t) { switch(out[i].t) {
case 't': case 'T': case ' ': case 'D': break; case 't': case 'T': case ' ': case 'D': break;
case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'Z': case 'X': delete out[i]; break;
out[i].v = write_date(out[i].t, out[i].v, dt, bt); case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'b': case 'Z':
out[i].v = write_date(out[i].t, out[i].v, dt);
out[i].t = 't'; break; out[i].t = 't'; break;
case 'n': case '(': case '?': case 'n': case '(': case '?':
var jj = i+1; var jj = i+1;

88
ssf.md

@ -39,19 +39,6 @@ control the output, set the `output` variable:
opts_fmt.output = ""; opts_fmt.output = "";
``` ```
There are a few places where the specification is ambiguous or where Excel does
not follow the spec. They are noted in the document.
The `mode` option controls compatibility:
- `ssf`: options that the author believes makes the most sense (default)
- `ecma`: compatibility with ECMA-376
- `excel`: compatibility with MS-XLSX
```
opts_fmt.mode = "";
```
## Conditional Format Codes ## Conditional Format Codes
The specification is a bit unclear here. It initially claims in §18.3.1: The specification is a bit unclear here. It initially claims in §18.3.1:
@ -273,9 +260,10 @@ Most spreadsheet formats store dates and times as floating point numbers (where
the integer part is a day code based on a format and the fractional part is the the integer part is a day code based on a format and the fractional part is the
portion of a 24 hour day). portion of a 24 hour day).
Excel supports the alternative Hijri calendar (indicated with `b2`):
```js>tmp/50_date.js ```js>tmp/50_date.js
var parse_date_code = function parse_date_code(v,opts) { var parse_date_code = function parse_date_code(v,opts,b2) {
var date = Math.floor(v), time = Math.floor(86400 * (v - date)+1e-6), dow=0; var date = Math.floor(v), time = Math.floor(86400 * (v - date)+1e-6), dow=0;
var dout=[], out={D:date, T:time, u:86400*(v-date)-time}; fixopts(opts = (opts||{})); var dout=[], out={D:date, T:time, u:86400*(v-date)-time}; fixopts(opts = (opts||{}));
``` ```
@ -310,8 +298,8 @@ February 29, 1900 (date `60`) is recognized as a Wednesday. Date `0` is treated
as January 0, 1900 rather than December 31, 1899. as January 0, 1900 rather than December 31, 1899.
``` ```
if(date === 60) {dout = [1900,2,29]; dow=3;} if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
else if(date === 0) {dout = [1900,1,0]; dow=6;} else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
``` ```
For the other dates, using the JS date mechanism suffices. For the other dates, using the JS date mechanism suffices.
@ -333,7 +321,13 @@ Saturday. The "right" thing to do is to keep the DOW consistent and just break
the fact that there are two Wednesdays in that "week". the fact that there are two Wednesdays in that "week".
``` ```
if(/* opts.mode === 'excel' && */ date < 60) dow = (dow + 6) % 7; if(date < 60) dow = (dow + 6) % 7;
```
For the hijri calendar, the date needs to be fixed
```
if(b2) dow = fix_hijri(d, dout);
} }
``` ```
@ -350,6 +344,12 @@ Because JS dates cannot represent the bad leap day, this returns an object:
SSF.parse_date_code = parse_date_code; SSF.parse_date_code = parse_date_code;
``` ```
TODO: suitable hijri correction
```js>tmp/45_hijri.js
function fix_hijri(date, o) { }
```
## Evaluating Number Formats ## Evaluating Number Formats
```js>tmp/60_number.js ```js>tmp/60_number.js
@ -547,7 +547,7 @@ LO Formats sometimes leak "GENERAL" or "General" to stand for general format:
``` ```
case 'G': /* General */ case 'G': /* General */
if(fmt.substr(i, i+6).toLowerCase() !== "general") if(fmt.substr(i, 7).toLowerCase() !== "general")
throw new Error('unrecognized character ' + fmt[i] + ' in ' +fmt); throw new Error('unrecognized character ' + fmt[i] + ' in ' +fmt);
out.push({t:'G',v:'General'}); i+=7; break; out.push({t:'G',v:'General'}); i+=7; break;
``` ```
@ -583,11 +583,22 @@ mode but I'm not convinced that's the right approach)
out.push({t:'T', v:v}); ++i; break; out.push({t:'T', v:v}); ++i; break;
``` ```
`B1` and `B2` specify which calendar to use, while `b` is the buddhist year. It
acts just like `y` except the year is shifted:
```
case 'B': case 'b':
if(fmt[i+1] === "1" || fmt[i+1] === "2") {
if(!dt) dt = parse_date_code(v, opts, fmt[i+1] === "2");
q={t:'X', v:fmt.substr(i,2)}; out.push(q); lst = c; i+=2; break;
}
/* falls through */
```
The date codes `m,d,y,h,s` are standard. There are some special formats like The date codes `m,d,y,h,s` are standard. There are some special formats like
`e / g` (era year) that have different behaviors in Japanese/Chinese locales. `e / g` (era year) that have different behaviors in Japanese/Chinese locales.
``` ```
/* Dates */
case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E': case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
c = c.toLowerCase(); c = c.toLowerCase();
/* falls through */ /* falls through */
@ -646,7 +657,7 @@ Conditional and color blocks should be handled at one point (TODO). The
pseudo-type `Z` is used to capture absolute time blocks: pseudo-type `Z` is used to capture absolute time blocks:
``` ```
case '[': /* TODO: Fix this -- ignore all conditionals and formatting */ case '[':
o = c; o = c;
while(fmt[i++] !== ']' && i < fmt.length) o += fmt[i]; while(fmt[i++] !== ']' && i < fmt.length) o += fmt[i];
if(o.substr(-1) !== ']') throw 'unterminated "[" block: |' + o + '|'; if(o.substr(-1) !== ']') throw 'unterminated "[" block: |' + o + '|';
@ -701,11 +712,10 @@ The nonzero digits show up in fraction denominators:
The default magic characters are listed in subsubsections 18.8.30-31 of ECMA376: The default magic characters are listed in subsubsections 18.8.30-31 of ECMA376:
``` ```
case ' ': out.push({t:c,v:c}); ++i; break; case ' ': out.push({t:c,v:c}); ++i; break;
default: default:
if(",$-+/():!^&'~{}<>=€".indexOf(c) === -1) if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxz".indexOf(c) === -1)
throw 'unrecognized character ' + fmt[i] + ' in ' + fmt; throw 'unrecognized character ' + fmt[i] + ' in ' + fmt;
out.push({t:'t', v:c}); ++i; break; out.push({t:'t', v:c}); ++i; break;
} }
@ -726,6 +736,8 @@ identify the smallest time unit (0 = no time, 1 = hour, 2 = minute, 3 = second):
/* falls through */ /* falls through */
case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break; case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break; case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
case 'X': if(out[i].v === "B2");
break;
case 'Z': case 'Z':
if(bt < 1 && out[i].v.match(/[Hh]/)) bt = 1; if(bt < 1 && out[i].v.match(/[Hh]/)) bt = 1;
if(bt < 2 && out[i].v.match(/[Mm]/)) bt = 2; if(bt < 2 && out[i].v.match(/[Mm]/)) bt = 2;
@ -758,8 +770,9 @@ Finally, actually write the numbers:
for(i=0; i < out.length; ++i) { for(i=0; i < out.length; ++i) {
switch(out[i].t) { switch(out[i].t) {
case 't': case 'T': case ' ': case 'D': break; case 't': case 'T': case ' ': case 'D': break;
case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'Z': case 'X': delete out[i]; break;
out[i].v = write_date(out[i].t, out[i].v, dt, bt); case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'b': case 'Z':
out[i].v = write_date(out[i].t, out[i].v, dt);
out[i].t = 't'; break; out[i].t = 't'; break;
case 'n': case '(': case '?': case 'n': case '(': case '?':
var jj = i+1; var jj = i+1;
@ -801,18 +814,25 @@ display minutes instead of the month.
/*jshint -W086 */ /*jshint -W086 */
var write_date = function(type, fmt, val) { var write_date = function(type, fmt, val) {
if(val < 0) return ""; if(val < 0) return "";
var o, ss; var o, ss, y = val.y;
switch(type) { switch(type) {
case 'y': switch(fmt) { /* year */ ```
case 'y': case 'yy': return pad(val.y % 100,2);
`b` years are shifted by 543 (`y` 1900 == `b` 2443):
```
case 'b': y = val.y + 543;
/* falls through */
case 'y': switch(fmt.length) { /* year */
case 1: case 2: return pad(y % 100,2);
``` ```
Apparently, even `yyyyyyyyyyyyyyyyyyyy` is a 4 digit year Apparently, even `yyyyyyyyyyyyyyyyyyyy` is a 4 digit year
``` ```
default: return pad(val.y % 10000,4); default: return pad(y % 10000,4);
} }
case 'm': switch(fmt) { /* month */ case 'm': switch(fmt) {
case 'm': return val.m; case 'm': return val.m;
case 'mm': return pad(val.m,2); case 'mm': return pad(val.m,2);
case 'mmm': return months[val.m-1][1]; case 'mmm': return months[val.m-1][1];
@ -1119,7 +1139,7 @@ coveralls:
```json>package.json ```json>package.json
{ {
"name": "ssf", "name": "ssf",
"version": "0.6.2", "version": "0.6.3",
"author": "SheetJS", "author": "SheetJS",
"description": "pure-JS library to format data using ECMA-376 spreadsheet Format Codes", "description": "pure-JS library to format data using ECMA-376 spreadsheet Format Codes",
"keywords": [ "format", "sprintf", "spreadsheet" ], "keywords": [ "format", "sprintf", "spreadsheet" ],
@ -1237,6 +1257,7 @@ The dates test driver tests the date and time formats:
var SSF = require('../'); var SSF = require('../');
var fs = require('fs'), assert = require('assert'); var fs = require('fs'), assert = require('assert');
var dates = fs.readFileSync('./test/dates.tsv','utf8').split("\n"); var dates = fs.readFileSync('./test/dates.tsv','utf8').split("\n");
var date2 = fs.readFileSync('./test/cal.tsv', 'utf8').split("\n");
var times = fs.readFileSync('./test/times.tsv','utf8').split("\n"); var times = fs.readFileSync('./test/times.tsv','utf8').split("\n");
function doit(data) { function doit(data) {
@ -1255,9 +1276,12 @@ function doit(data) {
} }
}); });
} }
describe('time formats', function() { doit(process.env.MINTEST ? times.slice(0,4000) : times); }); describe('time formats', function() {
doit(process.env.MINTEST ? times.slice(0,4000) : times);
});
describe('date formats', function() { describe('date formats', function() {
doit(process.env.MINTEST ? dates.slice(0,1000) : dates); doit(process.env.MINTEST ? dates.slice(0,4000) : dates);
//doit(process.env.MINTEST ? date2.slice(0,1000) : date2);
it('should fail for bad formats', function() { it('should fail for bad formats', function() {
var bad = []; var bad = [];
var chk = function(fmt){ return function(){ SSF.format(fmt,0); }; }; var chk = function(fmt){ return function(){ SSF.format(fmt,0); }; };

1048576
test/cal.tsv Normal file

File diff suppressed because it is too large Load Diff

@ -3,6 +3,7 @@
var SSF = require('../'); var SSF = require('../');
var fs = require('fs'), assert = require('assert'); var fs = require('fs'), assert = require('assert');
var dates = fs.readFileSync('./test/dates.tsv','utf8').split("\n"); var dates = fs.readFileSync('./test/dates.tsv','utf8').split("\n");
var date2 = fs.readFileSync('./test/cal.tsv', 'utf8').split("\n");
var times = fs.readFileSync('./test/times.tsv','utf8').split("\n"); var times = fs.readFileSync('./test/times.tsv','utf8').split("\n");
function doit(data) { function doit(data) {
@ -21,9 +22,12 @@ function doit(data) {
} }
}); });
} }
describe('time formats', function() { doit(process.env.MINTEST ? times.slice(0,4000) : times); }); describe('time formats', function() {
doit(process.env.MINTEST ? times.slice(0,4000) : times);
});
describe('date formats', function() { describe('date formats', function() {
doit(process.env.MINTEST ? dates.slice(0,1000) : dates); doit(process.env.MINTEST ? dates.slice(0,4000) : dates);
//doit(process.env.MINTEST ? date2.slice(0,1000) : date2);
it('should fail for bad formats', function() { it('should fail for bad formats', function() {
var bad = []; var bad = [];
var chk = function(fmt){ return function(){ SSF.format(fmt,0); }; }; var chk = function(fmt){ return function(){ SSF.format(fmt,0); }; };

@ -15,7 +15,7 @@
["[Blue]General", [1, "1"], [-1, "-1"], [0, "0"], ["sheetjs", "sheetjs"]], ["[Blue]General", [1, "1"], [-1, "-1"], [0, "0"], ["sheetjs", "sheetjs"]],
["[Blue]G3neral", [1], [-1], [0], ["TODO","TODO"]], ["[Blue]G3neral", [1], [-1], [0], ["TODO","TODO"]],
["A\"TODO\"", [1, "ATODO"], [-1, "ATODO"], [0, "ATODO"], ["TODO","TODO"]], ["A\"TODO\"", [1, "ATODO"], [-1, "ATODO"], [0, "ATODO"], ["TODO","TODO"]],
["r", [1], [-1], [0], ["TODO","TODO"]], ["r", [1,"r"], [-1,"-r","#"], [0,"r"], ["sheetjs","sheetjs"]],
["((;@", [1,"(("], [0,"(("], ["foo","foo"]], ["((;@", [1,"(("], [0,"(("], ["foo","foo"]],
["\\r", [1, "r"], [-1, "r"], [0, "r"], ["TODO","TODO"]], ["\\r", [1, "r"], [-1, "r"], [0, "r"], ["TODO","TODO"]],
["_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(@_)", [1, " $1 "], [-1, " $(1)"], [0," $- "], ["TODO", " TODO "], ["",""]], ["_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(@_)", [1, " $1 "], [-1, " $(1)"], [0," $- "], ["TODO", " TODO "], ["",""]],
@ -48,27 +48,27 @@
["123", [0.7, "123"], [0, "123"], ["sheetjs", "sheetjs"]], ["123", [0.7, "123"], [0, "123"], ["sheetjs", "sheetjs"]],
["0.##", [1,"1."], [-1,"-1."], [0, "0."], [1.1, "1.1"], [-1.2, "-1.2"], [1000000000000.01, "1000000000000.01"], [-1000.01, "-1000.01"], [0.1, "0.1"], [1.007, "1.01"], [-1.008, "-1.01"]], ["0.##", [1,"1."], [-1,"-1."], [0, "0."], [1.1, "1.1"], [-1.2, "-1.2"], [1000000000000.01, "1000000000000.01"], [-1000.01, "-1000.01"], [0.1, "0.1"], [1.007, "1.01"], [-1.008, "-1.01"]],
["** #,###,#00,000.00,**", ["** #,###,#00,000.00,**",
[1.2345, " 00,000.00"], [1.2345, " 00,000.00"],
[12.345, " 00,000.01"], [12.345, " 00,000.01"],
[123.45, " 00,000.12"], [123.45, " 00,000.12"],
[1234.56, " 00,001.23"], [1234.56, " 00,001.23"],
[12345.67, " 00,012.35"], [12345.67, " 00,012.35"],
[123456.78, " 00,123.46"], [123456.78, " 00,123.46"],
[1234567.89, " 01,234.57"], [1234567.89, " 01,234.57"],
[12345681.9, " 12,345.68"], [12345681.9, " 12,345.68"],
[123456822, " 123,456.82"], [123456822, " 123,456.82"],
[1234568223, " 1,234,568.22"], [1234568223, " 1,234,568.22"],
[12345682233, " 12,345,682.23"], [12345682233, " 12,345,682.23"],
[123456822333, " 123,456,822.33"], [123456822333, " 123,456,822.33"],
[1234568223333, " 1,234,568,223.33"], [1234568223333, " 1,234,568,223.33"],
[12345682233333, " 12,345,682,233.33"], [12345682233333, " 12,345,682,233.33"],
[123456822333333, " 123,456,822,333.33"], [123456822333333, " 123,456,822,333.33"],
[1234568223333330, " 1,234,568,223,333.33"], [1234568223333330, " 1,234,568,223,333.33"],
[12345682233333300, " 12,345,682,233,333.30"], [12345682233333300, " 12,345,682,233,333.30"],
[123456822333333000, " 123,456,822,333,333.00", "#"], [123456822333333000, " 123,456,822,333,333.00", "#"],
[1234568223333330000, " 1,234,568,223,333,330.00"], [1234568223333330000, " 1,234,568,223,333,330.00"],
[12345682233333300000, " 12,345,682,233,333,300.00"], [12345682233333300000, " 12,345,682,233,333,300.00"],
[123456822333333000000, " 123,456,822,333,333,000.00"], [123456822333333000000, " 123,456,822,333,333,000.00"],
[1234568223333330000000, " 1,234,568,223,333,330,000.00"] [1234568223333330000000, " 1,234,568,223,333,330,000.00"]
], ],
["00000-0000", [941051630, "94105-1630"]], ["00000-0000", [941051630, "94105-1630"]],
@ -76,7 +76,11 @@
["[<=9999999]###-####;(###) ###-####", [8675309, "867-5309"],[2813308004, "(281) 330-8004"]], ["[<=9999999]###-####;(###) ###-####", [8675309, "867-5309"],[2813308004, "(281) 330-8004"]],
["[Red][<-25]General;[Blue][>25]General;[Green]General;[Yellow]General", [50, "50"],[26, "26"],[25,"25"],[1,"1"],[0,"0"],[-1,"-1"],[-25,"-25"],[-26,"26","#"],[-50,"50","#"], ["foo","foo"],["bar","bar"]], ["[Red][<-25]General;[Blue][>25]General;[Green]General;[Yellow]General", [50, "50"],[26, "26"],[25,"25"],[1,"1"],[0,"0"],[-1,"-1"],[-25,"-25"],[-26,"26","#"],[-50,"50","#"], ["foo","foo"],["bar","bar"]],
["[Red][<=-25]General;[Blue][>=25]General;[Green]General;[Yellow]General", [50, "50"],[26, "26"],[25,"25"],[1,"1"],[0,"0"],[-1,"-1"],[-25,"-25"],[-26,"26","#"],[-50,"50","#"], ["foo","foo"],["bar","bar"]], ["[Red][<=-25]General;[Blue][>=25]General;[Green]General;[Yellow]General", [50, "50"],[26, "26"],[25,"25"],[1,"1"],[0,"0"],[-1,"-1"],[-25,"-25"],[-26,"26","#"],[-50,"50","#"], ["foo","foo"],["bar","bar"]],
["[Red]General ;[Blue]General\\ ;[Green]Generalp;[Yellow]General'", [50, "50 "],[0,"0p"],[-25,"-25 "],["foo","foo'"]],
["[Red][=50]General;[Blue]000", [50, "50"], [51, "051"], [49, "049"]], ["[Red][=50]General;[Blue]000", [50, "50"], [51, "051"], [49, "049"]],
["[Red][<>50]General;[Blue]000", [50, "050"], [51, "51"], [49, "49"]], ["[Red][<>50]General;[Blue]000", [50, "050"], [51, "51"], [49, "49"]],
["b", [1,"43"], [1000,"45"], [10000,"70"]],
["B2yyyymmdd", [0,"13170829"], [1000,"13200624","#"], [10000,"13451117","#"]],
["☃", [0], [1], [-1]],
["\"foo\";\"bar\";\"baz\";\"qux\";\"foobar\"", [1], [0], [-1], ["sheetjs"]] ["\"foo\";\"bar\";\"baz\";\"qux\";\"foobar\"", [1], [0], [-1], ["sheetjs"]]
] ]