Skip to content

Commit

Permalink
Almost complete strptime & strftime.
Browse files Browse the repository at this point in the history
  • Loading branch information
mbostock committed Nov 5, 2010
1 parent 8fb4ca4 commit 46b8056
Show file tree
Hide file tree
Showing 10 changed files with 563 additions and 29 deletions.
8 changes: 7 additions & 1 deletion Makefile
Expand Up @@ -12,7 +12,9 @@ all: \
d3.geo.js \
d3.geo.min.js \
d3.csv.js \
d3.csv.min.js
d3.csv.min.js \
d3.time.js \
d3.time.min.js

.INTERMEDIATE d3.js: \
d3.core.js \
Expand Down Expand Up @@ -68,6 +70,10 @@ d3.csv.js: \
src/csv/parse.js \
src/csv/format.js

d3.time.js: \
src/time/time.js \
src/time/format.js

%.min.js: %.js Makefile src/externs.js
@rm -f $@
$(JS_COMPILER) --js $< --js_output_file $@
Expand Down
4 changes: 2 additions & 2 deletions d3.js
@@ -1,4 +1,4 @@
d3 = {version: "0.12.1"}; // semver
d3 = {version: "0.13.0"}; // semver
if (!Date.now) Date.now = function() {
return +new Date();
};
Expand Down Expand Up @@ -204,7 +204,7 @@ var d3_ease_mode = {
"in": function(f) { return f; },
"out": d3_ease_reverse,
"in-out": d3_ease_reflect,
"out-int": function(f) { return d3_ease_reflect(d3_ease_reverse(f)); }
"out-in": function(f) { return d3_ease_reflect(d3_ease_reverse(f)); }
};

d3.ease = function(name) {
Expand Down
4 changes: 2 additions & 2 deletions d3.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

313 changes: 313 additions & 0 deletions d3.time.js
@@ -0,0 +1,313 @@
d3.time = {};
d3.time.format = function(template) {
var n = template.length;

function format(date) {
var string = [],
i = -1,
j = 0,
c,
f;
while (++i < n) {
if (template.charCodeAt(i) == 37) {
string.push(
template.substring(j, i),
(f = d3_time_formats[c = template.charAt(++i)])
? f(date) : c);
j = i + 1;
}
}
string.push(template.substring(j, i));
return string.join("");
}

format.parse = function(string) {
var date = new Date(1900, 0, 1),
i = d3_time_parse(date, template, string, 0);
if (i != string.length) return null;
if (date.hour12) {
var hours = date.getHours() % 12;
date.setHours(date.hour12pm ? hours + 12 : hours);
}
delete date.hour12;
delete date.hour12pm;
return date;
};

format.toString = function() {
return template;
};

return format;
};

function d3_time_parse(date, template, string, j) {
var c,
p,
i = 0,
n = template.length,
m = string.length;
while (i < n) {
if (j >= m) return -1;
c = template.charCodeAt(i++);
if (c == 37) {
p = d3_time_parsers[template.charAt(i++)];
if (!p || ((j = p(date, string, j)) < 0)) return -1;
} else if (c != string.charCodeAt(j++)) {
return -1;
}
}
return j;
}

var d3_time_zfill2 = d3.format("02d"),
d3_time_zfill3 = d3.format("03d"),
d3_time_zfill4 = d3.format("04d"),
d3_time_sfill2 = d3.format(" 2d");

var d3_time_formats = {
"a": function(d) { return d3_time_weekdays[d.getDay()].substring(0, 3); },
"A": function(d) { return d3_time_weekdays[d.getDay()]; },
"b": function(d) { return d3_time_months[d.getMonth()].substring(0, 3); },
"B": function(d) { return d3_time_months[d.getMonth()]; },
"c": d3.time.format("%a %b %e %H:%M:%S %Y"),
"d": function(d) { return d3_time_zfill2(d.getDate()); },
"e": function(d) { return d3_time_sfill2(d.getDate()); },
"H": function(d) { return d3_time_zfill2(d.getHours()); },
"I": function(d) { return d3_time_zfill2(d.getHours() % 12 || 12); },
"j": d3_time_dayOfYear,
"m": function(d) { return d3_time_zfill2(d.getMonth() + 1); },
"M": function(d) { return d3_time_zfill2(d.getMinutes()); },
"p": function(d) { return d.getHours() >= 12 ? "PM" : "AM"; },
"S": function(d) { return d3_time_zfill2(d.getSeconds()); },
"U": d3_time_weekNumberSunday,
"w": function(d) { return d.getDay(); },
"W": d3_time_weekNumberMonday,
"x": d3.time.format("%m/%d/%y"),
"X": d3.time.format("%H:%M:%S"),
"y": function(d) { return d3_time_zfill2(d.getYear() % 100); },
"Y": function(d) { return d3_time_zfill4(d.getFullYear() % 10000); },
"Z": d3_time_zone,
"%": function(d) { return "%"; }
};

var d3_time_parsers = {
"a": d3_time_parseWeekdayAbbrev,
"A": d3_time_parseWeekday,
"b": d3_time_parseMonthAbbrev,
"B": d3_time_parseMonth,
"c": d3_time_parseLocaleFull,
"d": d3_time_parseDay,
"e": d3_time_parseDay,
"H": d3_time_parseHour24,
"I": d3_time_parseHour12,
// "j": function(d, s, i) { /*TODO day of year [001,366] */ return i; },
"m": d3_time_parseMonthNumber,
"M": d3_time_parseMinutes,
"p": d3_time_parseAmPm,
"S": d3_time_parseSeconds,
// "U": function(d, s, i) { /*TODO week number (sunday) [00,53] */ return i; },
// "w": function(d, s, i) { /*TODO weekday [0,6] */ return i; },
// "W": function(d, s, i) { /*TODO week number (monday) [00,53] */ return i; },
"x": d3_time_parseLocaleDate,
"X": d3_time_parseLocaleTime,
"y": d3_time_parseYear,
"Y": d3_time_parseFullYear
// ,
// "Z": function(d, s, i) { /*TODO time zone */ return i; },
// "%": function(d, s, i) { /*TODO literal % */ return i; }
};

// Note: weekday is validated, but does not set the date.
function d3_time_parseWeekdayAbbrev(date, string, i) {
return string.substring(i, i += 3).toLowerCase() in d3_time_weekdayAbbrevLookup ? i : -1;
}

var d3_time_weekdayAbbrevLookup = {
"sun": 3,
"mon": 3,
"tue": 3,
"wed": 3,
"thu": 3,
"fri": 3,
"sat": 3
};

// Note: weekday is validated, but does not set the date.
function d3_time_parseWeekday(date, string, i) {
d3_time_weekdayRe.lastIndex = 0;
var n = d3_time_weekdayRe.exec(string.substring(i, i + 10));
return n ? i += n[0].length : -1;
}

var d3_time_weekdayRe = /^(?:Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)/ig;

var d3_time_weekdays = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
];

function d3_time_parseMonthAbbrev(date, string, i) {
var n = d3_time_monthAbbrevLookup[string.substring(i, i += 3).toLowerCase()];
return n == null ? -1 : (date.setMonth(n), i);
}

var d3_time_monthAbbrevLookup = {
"jan": 0,
"feb": 1,
"mar": 2,
"apr": 3,
"may": 4,
"jun": 5,
"jul": 6,
"aug": 7,
"sep": 8,
"oct": 9,
"nov": 10,
"dec": 11
};

function d3_time_parseMonth(date, string, i) {
d3_time_monthRe.lastIndex = 0;
var n = d3_time_monthRe.exec(string.substring(i, i + 12));
return n ? (date.setMonth(d3_time_monthLookup[n[0].toLowerCase()]), i += n[0].length) : -1;
}

var d3_time_monthRe = /^(?:January|February|March|April|May|June|July|August|September|October|November|December)/ig;

var d3_time_monthLookup = {
"january": 0,
"february": 1,
"march": 2,
"april": 3,
"may": 4,
"june": 5,
"july": 6,
"august": 7,
"september": 8,
"october": 9,
"november": 10,
"december": 11
};

var d3_time_months = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
];

function d3_time_parseLocaleFull(date, string, i) {
return d3_time_parse(date, d3_time_formats.c.toString(), string, i);
}

function d3_time_parseLocaleDate(date, string, i) {
return d3_time_parse(date, d3_time_formats.x.toString(), string, i);
}

function d3_time_parseLocaleTime(date, string, i) {
return d3_time_parse(date, d3_time_formats.X.toString(), string, i);
}

function d3_time_parseFullYear(date, string, i) {
d3_time_number4Re.lastIndex = 0;
var n = d3_time_number4Re.exec(string.substring(i, i + 4));
return n ? (date.setFullYear(n[0]), i += n[0].length) : -1;
}

function d3_time_parseYear(date, string, i) {
d3_time_number2Re.lastIndex = 0;
var n = d3_time_number2Re.exec(string.substring(i, i + 2));
return n ? (date.setFullYear(d3_time_century() + +n[0]), i += n[0].length) : -1;
}

function d3_time_century() {
return ~~(new Date().getFullYear() / 1000) * 1000;
}

function d3_time_parseMonthNumber(date, string, i) {
d3_time_number2Re.lastIndex = 0;
var n = d3_time_number2Re.exec(string.substring(i, i + 2));
return n ? (date.setMonth(n[0] - 1), i += n[0].length) : -1;
}

function d3_time_parseDay(date, string, i) {
d3_time_number2Re.lastIndex = 0;
var n = d3_time_number2Re.exec(string.substring(i, i + 2));
return n ? (date.setDate(+n[0]), i += n[0].length) : -1;
}

// Note: we don't validate that the hour is in the range [0,23].
function d3_time_parseHour24(date, string, i) {
d3_time_number2Re.lastIndex = 0;
var n = d3_time_number2Re.exec(string.substring(i, i + 2));
return n ? (date.setHours(+n[0]), i += n[0].length) : -1;
}

// Note: we don't validate that the hour is in the range [1,12].
function d3_time_parseHour12(date, string, i) {
date.hour12 = true;
return d3_time_parseHour24(date, string, i);
}

function d3_time_parseMinutes(date, string, i) {
d3_time_number2Re.lastIndex = 0;
var n = d3_time_number2Re.exec(string.substring(i, i + 2));
return n ? (date.setMinutes(+n[0]), i += n[0].length) : -1;
}

function d3_time_parseSeconds(date, string, i) {
d3_time_number2Re.lastIndex = 0;
var n = d3_time_number2Re.exec(string.substring(i, i + 2));
return n ? (date.setSeconds(+n[0]), i += n[0].length) : -1;
}

// Note: we don't look at the next directive.
var d3_time_number2Re = /[\s\d]{1,2}/,
d3_time_number4Re = /[\s\d]{1,4}/;

function d3_time_parseAmPm(date, string, i) {
var n = d3_time_amPmLookup[string.substring(i, i += 2).toLowerCase()];
return n == null ? -1 : (date.hour12pm = n, i);
}

var d3_time_amPmLookup = {
"am": 0,
"pm": 1
};

function d3_time_dayOfYear(d) {
return d3_time_zfill3(1 + ~~((d - new Date(d.getFullYear(), 0, 1)) / 864e5));
}

function d3_time_weekNumberSunday(d) {
var d0 = new Date(d.getFullYear(), 0, 1);
return d3_time_zfill2(~~(((d - d0) / 864e5 + d0.getDay()) / 7));
}

function d3_time_weekNumberMonday(d) {
var d0 = new Date(d.getFullYear(), 0, 1);
return d3_time_zfill2(~~(((d - d0) / 864e5 + (d0.getDay() + 6) % 7) / 7));
}

// TODO table of time zone offset names?
function d3_time_zone(d) {
var z = d.getTimezoneOffset(),
zs = z > 0 ? "-" : "+",
zh = ~~(Math.abs(z) / 60),
zm = Math.abs(z) % 60;
return zs + d3_time_zfill2(zh) + d3_time_zfill2(zm);
}
10 changes: 10 additions & 0 deletions d3.time.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 46b8056

Please sign in to comment.