Skip to content

Commit

Permalink
Fix #44 - more concise date formatting.
Browse files Browse the repository at this point in the history
  • Loading branch information
mbostock committed Feb 8, 2019
1 parent 609717b commit c0ccf01
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 3 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ If *columns* is not specified, the list of column names that forms the header ro
var string = d3.csvFormat(data, ["year", "make", "model", "length"]);
```

All fields on each row object will be coerced to strings. If the field value is null or undefined, the empty string is used. If the field value is a Date, the ISO 8601 date format is used per [*date*.toISOString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString). For more control over which and how fields are formatted, first map *rows* to an array of array of string, and then use [*dsv*.formatRows](#dsv_formatRows).
All fields on each row object will be coerced to strings. If the field value is null or undefined, the empty string is used. If the field value is a Date, the [ECMAScript date-time string format](https://www.ecma-international.org/ecma-262/9.0/index.html#sec-date-time-string-format) (a subset of ISO 8601) is used: for examples, dates at UTC midnight are formatted as `YYYY-MM-DD`. For more control over which and how fields are formatted, first map *rows* to an array of array of string, and then use [*dsv*.formatRows](#dsv_formatRows).

<a name="dsv_formatBody" href="#dsv_formatBody">#</a> <i>dsv</i>.<b>formatBody</b>(<i>rows</i>[, <i>columns</i>]) [<>](https://github.com/d3/d3-dsv/blob/master/src/dsv.js "Source")

Expand Down
37 changes: 36 additions & 1 deletion src/dsv.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,41 @@ function inferColumns(rows) {
return columns;
}

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

function formatYear(year) {
return year < 0 ? "-" + pad(-year, 6)
: year > 9999 ? "+" + pad(year, 6)
: pad(year, 4);
}

function formatDate(date) {
var hours = date.getUTCHours(),
minutes = date.getUTCMinutes(),
seconds = date.getUTCSeconds(),
milliseconds = date.getUTCMilliseconds();
return isNaN(date) ? "Invalid Date"
: formatYear(date.getUTCFullYear(), 4) + "-"
+ pad(date.getUTCMonth() + 1, 2) + "-"
+ pad(date.getUTCDate(), 2)
+ (milliseconds ? "T"
+ pad(hours, 2) + ":"
+ pad(minutes, 2) + ":"
+ pad(seconds, 2) + "."
+ pad(milliseconds, 3) + "Z"
: seconds ? "T"
+ pad(hours, 2) + ":"
+ pad(minutes, 2) + ":"
+ pad(seconds, 2) + "Z"
: minutes || hours ? "T"
+ pad(hours, 2) + ":"
+ pad(minutes, 2) + "Z"
: "");
}

export default function(delimiter) {
var reFormat = new RegExp("[\"" + delimiter + "\n\r]"),
DELIMITER = delimiter.charCodeAt(0);
Expand Down Expand Up @@ -123,7 +158,7 @@ export default function(delimiter) {

function formatValue(value) {
return value == null ? ""
: value instanceof Date ? value.toISOString()
: value instanceof Date ? formatDate(value)
: reFormat.test(value += "") ? "\"" + value.replace(/"/g, "\"\"") + "\""
: value;
}
Expand Down
3 changes: 2 additions & 1 deletion test/csv-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,8 @@ tape("csvFormatRows(array) separates lines using Unix newline", function(test) {
});

tape("csvFormatRows(array) converts dates to ISO 8601", function(test) {
test.deepEqual(dsv.csvFormatRows([[new Date(Date.UTC(2018, 0, 1))]]), "2018-01-01T00:00:00.000Z");
test.deepEqual(dsv.csvFormatRows([[new Date(Date.UTC(2018, 0, 1))]]), "2018-01-01");
test.deepEqual(dsv.csvFormatRows([[new Date(2018, 0, 1)]]), "2018-01-01T08:00Z");
test.end();
});

Expand Down

0 comments on commit c0ccf01

Please sign in to comment.