Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Signed directives. #11

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ Returns a new [*format* function](#_format) for the given string *specifier*. Th

Directives marked with an asterisk (*) may be affected by the [locale definition](#localeFormat). For `%U`, all days in a new year preceding the first Sunday are considered to be in week 0. For `%W`, all days in a new year preceding the first Monday are considered to be in week 0. Week numbers are computed using [*interval*.count](https://github.com/d3/d3-time#interval_count).

The `%` sign indicating a directive may be immediately followed by a sign modifier, `+`. If no sign modifier is specified, the field will be displayed as unsigned. Otherwise, the field will be formatted with a plus sign (`+`) for positive or zero values and a minus sign (`-`) for negative values.

The `%` sign indicating a directive may be immediately followed by a padding modifier:

* `0` - zero-padding
Expand Down
170 changes: 104 additions & 66 deletions src/locale.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,24 @@ export default function(locale) {
while (++i < n) {
if (specifier.charCodeAt(i) === 37) {
string.push(specifier.slice(j, i));
if ((pad = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i);
else pad = c === "e" ? " " : "0";
if (format = formats[c]) c = format(date, pad);
switch (c = specifier.charAt(++i)) {
case "+": {
switch (c = specifier.charAt(++i)) {
case "-": pad = padNoneSigned; break;
case "_": pad = padSpaceSigned; break;
case "0": pad = padZeroSigned; break;
case "e": pad = padSpaceSigned; --i; break;
default: pad = padZeroSigned; --i; break;
}
break;
}
case "-": pad = padNone; break;
case "_": pad = padSpace; break;
case "0": pad = padZero; break;
case "e": pad = padSpace; --i; break;
default: pad = padZero; --i; break;
}
if (format = formats[c = specifier.charAt(++i)]) c = format(date, pad);
string.push(c);
j = i + 1;
}
Expand Down Expand Up @@ -199,8 +214,10 @@ export default function(locale) {
if (j >= m) return -1;
c = specifier.charCodeAt(i++);
if (c === 37) {
c = specifier.charAt(i++);
parse = parses[c in pads ? specifier.charAt(i++) : c];
switch (c = specifier.charAt(i++)) {
case "-": case "_": case "0": c = specifier.charAt(i++); break;
}
parse = parses[c];
if (!parse || ((j = parse(d, string, j)) < 0)) return -1;
} else if (c != string.charCodeAt(j++)) {
return -1;
Expand Down Expand Up @@ -303,16 +320,37 @@ export default function(locale) {
};
};

var pads = {"-": "", "_": " ", "0": "0"},
numberRe = /^\s*\d+/, // note: ignores next directive
var numberRe = /^\s*\d+/, // note: ignores next directive
// TODO signedNumberRe = /^\s*[+-]\d+/,
percentRe = /^%/,
requoteRe = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;

function pad(value, fill, width) {
var sign = value < 0 ? "-" : "",
string = (sign ? -value : value) + "",
length = string.length;
return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
function padNone(value) {
return Math.abs(value) + "";
}

function padZero(value, width) {
var length = (value = Math.abs(value) + "").length;
return length < width ? new Array(width - length + 1).join("0") + value : value;
}

function padSpace(value, width) {
var length = (value = Math.abs(value) + "").length;
return length < width ? new Array(width - length + 1).join(" ") + value : value;
}

function padNoneSigned(value) {
return (value < 0 ? "-" : "+") + Math.abs(value);
}

function padZeroSigned(value, width) {
var sign = value < 0 ? "-" : "+", length = (value = Math.abs(value) + "").length;
return sign + (length < width ? new Array(width - length + 1).join("0") + value : value);
}

function padSpaceSigned(value, width) {
var sign = value < 0 ? "-" : "+", length = (value = Math.abs(value) + "").length;
return (length < width ? new Array(width - length + 1).join(" ") + sign + value : sign + value);
}

function requote(s) {
Expand Down Expand Up @@ -399,115 +437,115 @@ function parseLiteralPercent(d, string, i) {
return n ? i + n[0].length : -1;
}

function formatDayOfMonth(d, p) {
return pad(d.getDate(), p, 2);
function formatDayOfMonth(d, pad) {
return pad(d.getDate(), 2);
}

function formatHour24(d, p) {
return pad(d.getHours(), p, 2);
function formatHour24(d, pad) {
return pad(d.getHours(), 2);
}

function formatHour12(d, p) {
return pad(d.getHours() % 12 || 12, p, 2);
function formatHour12(d, pad) {
return pad(d.getHours() % 12 || 12, 2);
}

function formatDayOfYear(d, p) {
return pad(1 + day.count(year(d), d), p, 3);
function formatDayOfYear(d, pad) {
return pad(1 + day.count(year(d), d), 3);
}

function formatMilliseconds(d, p) {
return pad(d.getMilliseconds(), p, 3);
function formatMilliseconds(d, pad) {
return pad(d.getMilliseconds(), 3);
}

function formatMonthNumber(d, p) {
return pad(d.getMonth() + 1, p, 2);
function formatMonthNumber(d, pad) {
return pad(d.getMonth() + 1, 2);
}

function formatMinutes(d, p) {
return pad(d.getMinutes(), p, 2);
function formatMinutes(d, pad) {
return pad(d.getMinutes(), 2);
}

function formatSeconds(d, p) {
return pad(d.getSeconds(), p, 2);
function formatSeconds(d, pad) {
return pad(d.getSeconds(), 2);
}

function formatWeekNumberSunday(d, p) {
return pad(sunday.count(year(d), d), p, 2);
function formatWeekNumberSunday(d, pad) {
return pad(sunday.count(year(d), d), 2);
}

function formatWeekdayNumber(d) {
return d.getDay();
function formatWeekdayNumber(d, pad) {
return pad(d.getDay(), 1);
}

function formatWeekNumberMonday(d, p) {
return pad(monday.count(year(d), d), p, 2);
function formatWeekNumberMonday(d, pad) {
return pad(monday.count(year(d), d), 2);
}

function formatYear(d, p) {
return pad(d.getFullYear() % 100, p, 2);
function formatYear(d, pad) {
return pad(d.getFullYear() % 100, 2);
}

function formatFullYear(d, p) {
return pad(d.getFullYear() % 10000, p, 4);
function formatFullYear(d, pad) {
return pad(d.getFullYear() % 10000, 4);
}

function formatZone(d) {
var z = d.getTimezoneOffset();
return (z > 0 ? "-" : (z *= -1, "+"))
+ pad(z / 60 | 0, "0", 2)
+ pad(z % 60, "0", 2);
+ padZero(z / 60 | 0, 2)
+ padZero(z % 60, 2);
}

function formatUTCDayOfMonth(d, p) {
return pad(d.getUTCDate(), p, 2);
function formatUTCDayOfMonth(d, pad) {
return pad(d.getUTCDate(), 2);
}

function formatUTCHour24(d, p) {
return pad(d.getUTCHours(), p, 2);
function formatUTCHour24(d, pad) {
return pad(d.getUTCHours(), 2);
}

function formatUTCHour12(d, p) {
return pad(d.getUTCHours() % 12 || 12, p, 2);
function formatUTCHour12(d, pad) {
return pad(d.getUTCHours() % 12 || 12, 2);
}

function formatUTCDayOfYear(d, p) {
return pad(1 + utcDay.count(utcYear(d), d), p, 3);
function formatUTCDayOfYear(d, pad) {
return pad(1 + utcDay.count(utcYear(d), d), 3);
}

function formatUTCMilliseconds(d, p) {
return pad(d.getUTCMilliseconds(), p, 3);
function formatUTCMilliseconds(d, pad) {
return pad(d.getUTCMilliseconds(), 3);
}

function formatUTCMonthNumber(d, p) {
return pad(d.getUTCMonth() + 1, p, 2);
function formatUTCMonthNumber(d, pad) {
return pad(d.getUTCMonth() + 1, 2);
}

function formatUTCMinutes(d, p) {
return pad(d.getUTCMinutes(), p, 2);
function formatUTCMinutes(d, pad) {
return pad(d.getUTCMinutes(), 2);
}

function formatUTCSeconds(d, p) {
return pad(d.getUTCSeconds(), p, 2);
function formatUTCSeconds(d, pad) {
return pad(d.getUTCSeconds(), 2);
}

function formatUTCWeekNumberSunday(d, p) {
return pad(utcSunday.count(utcYear(d), d), p, 2);
function formatUTCWeekNumberSunday(d, pad) {
return pad(utcSunday.count(utcYear(d), d), 2);
}

function formatUTCWeekdayNumber(d) {
return d.getUTCDay();
function formatUTCWeekdayNumber(d, pad) {
return pad(d.getUTCDay(), 1);
}

function formatUTCWeekNumberMonday(d, p) {
return pad(utcMonday.count(utcYear(d), d), p, 2);
function formatUTCWeekNumberMonday(d, pad) {
return pad(utcMonday.count(utcYear(d), d), 2);
}

function formatUTCYear(d, p) {
return pad(d.getUTCFullYear() % 100, p, 2);
function formatUTCYear(d, pad) {
return pad(d.getUTCFullYear() % 100, 2);
}

function formatUTCFullYear(d, p) {
return pad(d.getUTCFullYear() % 10000, p, 4);
function formatUTCFullYear(d, pad) {
return pad(d.getUTCFullYear() % 10000, 4);
}

function formatUTCZone() {
Expand Down
11 changes: 11 additions & 0 deletions test/format-parse-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,17 @@ tape("format(\"%m/%d/%y\").parse(date) parses month, date and two-digit year", f
test.end();
});

// TODO
// tape("format(\"%m/%d/%+y\").parse(date) parses month, date and signed two-digit year", function(test) {
// var p = timeFormat.format("%m/%d/%y").parse;
// test.deepEqual(p("02/03/+69"), date.local(1969, 1, 3));
// test.deepEqual(p("01/01/+90"), date.local(1990, 0, 1));
// test.deepEqual(p("02/03/+91"), date.local(1991, 1, 3));
// test.deepEqual(p("02/03/-68"), date.local(-68, 1, 3));
// test.equal(p("03/10/10"), null);
// test.end();
// });

tape("format(\"%x\").parse(date) parses locale date", function(test) {
var p = timeFormat.format("%x").parse;
test.deepEqual(p("01/01/1990"), date.local(1990, 0, 1));
Expand Down
38 changes: 37 additions & 1 deletion test/format-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ tape("format(\"%y\")(date) formats zero-padded two-digit years", function(test)
var f = timeFormat.format("%y");
test.equal(f(date.local(+1990, 0, 1)), "90");
test.equal(f(date.local(+2002, 0, 1)), "02");
test.equal(f(date.local(-0002, 0, 1)), "-02");
test.equal(f(date.local(-0002, 0, 1)), "02"); // unsigned year!
test.end();
});

Expand All @@ -220,10 +220,46 @@ tape("format(\"%Y\")(date) formats zero-padded four-digit years", function(test)
test.equal(f(date.local( 1990, 0, 1)), "1990");
test.equal(f(date.local( 2002, 0, 1)), "2002");
test.equal(f(date.local(10002, 0, 1)), "0002");
test.equal(f(date.local( -2, 0, 1)), "0002"); // unsigned year!
test.end();
});

tape("format(\"%+y\")(date) formats zero-padded signed two-digit years", function(test) {
var f = timeFormat.format("%+y");
test.equal(f(date.local(+1990, 0, 1)), "+90");
test.equal(f(date.local(+2002, 0, 1)), "+02");
test.equal(f(date.local(-0002, 0, 1)), "-02");
test.end();
});

tape("format(\"%+Y\")(date) formats zero-padded signed four-digit years", function(test) {
var f = timeFormat.format("%+Y");
test.equal(f(date.local( 123, 0, 1)), "+0123");
test.equal(f(date.local( 1990, 0, 1)), "+1990");
test.equal(f(date.local( 2002, 0, 1)), "+2002");
test.equal(f(date.local(10002, 0, 1)), "+0002");
test.equal(f(date.local( -2, 0, 1)), "-0002");
test.end();
});

tape("format(\"%+_y\")(date) formats space-padded signed two-digit years", function(test) {
var f = timeFormat.format("%+_y");
test.equal(f(date.local(+1990, 0, 1)), "+90");
test.equal(f(date.local(+2002, 0, 1)), " +2");
test.equal(f(date.local(-0002, 0, 1)), " -2");
test.end();
});

tape("format(\"%+_Y\")(date) formats space-padded signed four-digit years", function(test) {
var f = timeFormat.format("%+_Y");
test.equal(f(date.local( 123, 0, 1)), " +123");
test.equal(f(date.local( 1990, 0, 1)), "+1990");
test.equal(f(date.local( 2002, 0, 1)), "+2002");
test.equal(f(date.local(10002, 0, 1)), " +2");
test.equal(f(date.local( -2, 0, 1)), " -2");
test.end();
});

tape("format(\"%Z\")(date) formats time zones", function(test) {
var f = timeFormat.format("%Z");
test.equal(f(date.local(1990, 0, 1)), "-0800");
Expand Down
38 changes: 37 additions & 1 deletion test/utcFormat-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ tape("utcFormat(\"%y\")(date) formats zero-padded two-digit years", function(tes
var f = timeFormat.utcFormat("%y");
test.equal(f(date.utc(+1990, 0, 1)), "90");
test.equal(f(date.utc(+2002, 0, 1)), "02");
test.equal(f(date.utc(-0002, 0, 1)), "-02");
test.equal(f(date.utc(-0002, 0, 1)), "02"); // unsigned year!
test.end();
});

Expand All @@ -220,10 +220,46 @@ tape("utcFormat(\"%Y\")(date) formats zero-padded four-digit years", function(te
test.equal(f(date.utc( 1990, 0, 1)), "1990");
test.equal(f(date.utc( 2002, 0, 1)), "2002");
test.equal(f(date.utc(10002, 0, 1)), "0002");
test.equal(f(date.utc( -2, 0, 1)), "0002"); // unsigned year!
test.end();
});

tape("utcFormat(\"%+y\")(date) formats zero-padded signed two-digit years", function(test) {
var f = timeFormat.utcFormat("%+y");
test.equal(f(date.utc(+1990, 0, 1)), "+90");
test.equal(f(date.utc(+2002, 0, 1)), "+02");
test.equal(f(date.utc(-0002, 0, 1)), "-02");
test.end();
});

tape("utcFormat(\"%+Y\")(date) formats zero-padded signed four-digit years", function(test) {
var f = timeFormat.utcFormat("%+Y");
test.equal(f(date.utc( 123, 0, 1)), "+0123");
test.equal(f(date.utc( 1990, 0, 1)), "+1990");
test.equal(f(date.utc( 2002, 0, 1)), "+2002");
test.equal(f(date.utc(10002, 0, 1)), "+0002");
test.equal(f(date.utc( -2, 0, 1)), "-0002");
test.end();
});

tape("utcFormat(\"%+_y\")(date) formats space-padded signed two-digit years", function(test) {
var f = timeFormat.utcFormat("%+_y");
test.equal(f(date.utc(+1990, 0, 1)), "+90");
test.equal(f(date.utc(+2002, 0, 1)), " +2");
test.equal(f(date.utc(-0002, 0, 1)), " -2");
test.end();
});

tape("utcFormat(\"%+_Y\")(date) formats space-padded signed four-digit years", function(test) {
var f = timeFormat.utcFormat("%+_Y");
test.equal(f(date.utc( 123, 0, 1)), " +123");
test.equal(f(date.utc( 1990, 0, 1)), "+1990");
test.equal(f(date.utc( 2002, 0, 1)), "+2002");
test.equal(f(date.utc(10002, 0, 1)), " +2");
test.equal(f(date.utc( -2, 0, 1)), " -2");
test.end();
});

tape("utcFormat(\"%Z\")(date) formats time zones", function(test) {
var f = timeFormat.utcFormat("%Z");
test.equal(f(date.utc(1990, 0, 1)), "+0000");
Expand Down