|
1 d3.time.format = function(template) { |
|
2 var n = template.length; |
|
3 |
|
4 function format(date) { |
|
5 var string = [], |
|
6 i = -1, |
|
7 j = 0, |
|
8 c, |
|
9 f; |
|
10 while (++i < n) { |
|
11 if (template.charCodeAt(i) == 37) { |
|
12 string.push( |
|
13 template.substring(j, i), |
|
14 (f = d3_time_formats[c = template.charAt(++i)]) |
|
15 ? f(date) : c); |
|
16 j = i + 1; |
|
17 } |
|
18 } |
|
19 string.push(template.substring(j, i)); |
|
20 return string.join(""); |
|
21 } |
|
22 |
|
23 format.parse = function(string) { |
|
24 var date = new d3_time(1900, 0, 1), |
|
25 i = d3_time_parse(date, template, string, 0); |
|
26 if (i != string.length) return null; |
|
27 if (date.hour12) { |
|
28 var hours = date.getHours() % 12; |
|
29 date.setHours(date.hour12pm ? hours + 12 : hours); |
|
30 } |
|
31 delete date.hour12; |
|
32 delete date.hour12pm; |
|
33 return date; |
|
34 }; |
|
35 |
|
36 format.toString = function() { |
|
37 return template; |
|
38 }; |
|
39 |
|
40 return format; |
|
41 }; |
|
42 |
|
43 function d3_time_parse(date, template, string, j) { |
|
44 var c, |
|
45 p, |
|
46 i = 0, |
|
47 n = template.length, |
|
48 m = string.length; |
|
49 while (i < n) { |
|
50 if (j >= m) return -1; |
|
51 c = template.charCodeAt(i++); |
|
52 if (c == 37) { |
|
53 p = d3_time_parsers[template.charAt(i++)]; |
|
54 if (!p || ((j = p(date, string, j)) < 0)) return -1; |
|
55 } else if (c != string.charCodeAt(j++)) { |
|
56 return -1; |
|
57 } |
|
58 } |
|
59 return j; |
|
60 } |
|
61 |
|
62 var d3_time_zfill2 = d3.format("02d"), |
|
63 d3_time_zfill3 = d3.format("03d"), |
|
64 d3_time_zfill4 = d3.format("04d"), |
|
65 d3_time_sfill2 = d3.format("2d"); |
|
66 |
|
67 var d3_time_formats = { |
|
68 a: function(d) { return d3_time_weekdays[d.getDay()].substring(0, 3); }, |
|
69 A: function(d) { return d3_time_weekdays[d.getDay()]; }, |
|
70 b: function(d) { return d3_time_months[d.getMonth()].substring(0, 3); }, |
|
71 B: function(d) { return d3_time_months[d.getMonth()]; }, |
|
72 c: d3.time.format("%a %b %e %H:%M:%S %Y"), |
|
73 d: function(d) { return d3_time_zfill2(d.getDate()); }, |
|
74 e: function(d) { return d3_time_sfill2(d.getDate()); }, |
|
75 H: function(d) { return d3_time_zfill2(d.getHours()); }, |
|
76 I: function(d) { return d3_time_zfill2(d.getHours() % 12 || 12); }, |
|
77 j: d3_time_dayOfYear, |
|
78 L: function(d) { return d3_time_zfill3(d.getMilliseconds()); }, |
|
79 m: function(d) { return d3_time_zfill2(d.getMonth() + 1); }, |
|
80 M: function(d) { return d3_time_zfill2(d.getMinutes()); }, |
|
81 p: function(d) { return d.getHours() >= 12 ? "PM" : "AM"; }, |
|
82 S: function(d) { return d3_time_zfill2(d.getSeconds()); }, |
|
83 U: d3_time_weekNumberSunday, |
|
84 w: function(d) { return d.getDay(); }, |
|
85 W: d3_time_weekNumberMonday, |
|
86 x: d3.time.format("%m/%d/%y"), |
|
87 X: d3.time.format("%H:%M:%S"), |
|
88 y: function(d) { return d3_time_zfill2(d.getFullYear() % 100); }, |
|
89 Y: function(d) { return d3_time_zfill4(d.getFullYear() % 10000); }, |
|
90 Z: d3_time_zone, |
|
91 "%": function(d) { return "%"; } |
|
92 }; |
|
93 |
|
94 var d3_time_parsers = { |
|
95 a: d3_time_parseWeekdayAbbrev, |
|
96 A: d3_time_parseWeekday, |
|
97 b: d3_time_parseMonthAbbrev, |
|
98 B: d3_time_parseMonth, |
|
99 c: d3_time_parseLocaleFull, |
|
100 d: d3_time_parseDay, |
|
101 e: d3_time_parseDay, |
|
102 H: d3_time_parseHour24, |
|
103 I: d3_time_parseHour12, |
|
104 // j: function(d, s, i) { /*TODO day of year [001,366] */ return i; }, |
|
105 L: d3_time_parseMilliseconds, |
|
106 m: d3_time_parseMonthNumber, |
|
107 M: d3_time_parseMinutes, |
|
108 p: d3_time_parseAmPm, |
|
109 S: d3_time_parseSeconds, |
|
110 // U: function(d, s, i) { /*TODO week number (sunday) [00,53] */ return i; }, |
|
111 // w: function(d, s, i) { /*TODO weekday [0,6] */ return i; }, |
|
112 // W: function(d, s, i) { /*TODO week number (monday) [00,53] */ return i; }, |
|
113 x: d3_time_parseLocaleDate, |
|
114 X: d3_time_parseLocaleTime, |
|
115 y: d3_time_parseYear, |
|
116 Y: d3_time_parseFullYear |
|
117 // , |
|
118 // Z: function(d, s, i) { /*TODO time zone */ return i; }, |
|
119 // "%": function(d, s, i) { /*TODO literal % */ return i; } |
|
120 }; |
|
121 |
|
122 // Note: weekday is validated, but does not set the date. |
|
123 function d3_time_parseWeekdayAbbrev(date, string, i) { |
|
124 return string.substring(i, i += 3).toLowerCase() in d3_time_weekdayAbbrevLookup ? i : -1; |
|
125 } |
|
126 |
|
127 var d3_time_weekdayAbbrevLookup = { |
|
128 sun: 3, |
|
129 mon: 3, |
|
130 tue: 3, |
|
131 wed: 3, |
|
132 thu: 3, |
|
133 fri: 3, |
|
134 sat: 3 |
|
135 }; |
|
136 |
|
137 // Note: weekday is validated, but does not set the date. |
|
138 function d3_time_parseWeekday(date, string, i) { |
|
139 d3_time_weekdayRe.lastIndex = 0; |
|
140 var n = d3_time_weekdayRe.exec(string.substring(i, i + 10)); |
|
141 return n ? i += n[0].length : -1; |
|
142 } |
|
143 |
|
144 var d3_time_weekdayRe = /^(?:Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)/ig; |
|
145 |
|
146 var d3_time_weekdays = [ |
|
147 "Sunday", |
|
148 "Monday", |
|
149 "Tuesday", |
|
150 "Wednesday", |
|
151 "Thursday", |
|
152 "Friday", |
|
153 "Saturday" |
|
154 ]; |
|
155 |
|
156 function d3_time_parseMonthAbbrev(date, string, i) { |
|
157 var n = d3_time_monthAbbrevLookup[string.substring(i, i += 3).toLowerCase()]; |
|
158 return n == null ? -1 : (date.setMonth(n), i); |
|
159 } |
|
160 |
|
161 var d3_time_monthAbbrevLookup = { |
|
162 jan: 0, |
|
163 feb: 1, |
|
164 mar: 2, |
|
165 apr: 3, |
|
166 may: 4, |
|
167 jun: 5, |
|
168 jul: 6, |
|
169 aug: 7, |
|
170 sep: 8, |
|
171 oct: 9, |
|
172 nov: 10, |
|
173 dec: 11 |
|
174 }; |
|
175 |
|
176 function d3_time_parseMonth(date, string, i) { |
|
177 d3_time_monthRe.lastIndex = 0; |
|
178 var n = d3_time_monthRe.exec(string.substring(i, i + 12)); |
|
179 return n ? (date.setMonth(d3_time_monthLookup[n[0].toLowerCase()]), i += n[0].length) : -1; |
|
180 } |
|
181 |
|
182 var d3_time_monthRe = /^(?:January|February|March|April|May|June|July|August|September|October|November|December)/ig; |
|
183 |
|
184 var d3_time_monthLookup = { |
|
185 january: 0, |
|
186 february: 1, |
|
187 march: 2, |
|
188 april: 3, |
|
189 may: 4, |
|
190 june: 5, |
|
191 july: 6, |
|
192 august: 7, |
|
193 september: 8, |
|
194 october: 9, |
|
195 november: 10, |
|
196 december: 11 |
|
197 }; |
|
198 |
|
199 var d3_time_months = [ |
|
200 "January", |
|
201 "February", |
|
202 "March", |
|
203 "April", |
|
204 "May", |
|
205 "June", |
|
206 "July", |
|
207 "August", |
|
208 "September", |
|
209 "October", |
|
210 "November", |
|
211 "December" |
|
212 ]; |
|
213 |
|
214 function d3_time_parseLocaleFull(date, string, i) { |
|
215 return d3_time_parse(date, d3_time_formats.c.toString(), string, i); |
|
216 } |
|
217 |
|
218 function d3_time_parseLocaleDate(date, string, i) { |
|
219 return d3_time_parse(date, d3_time_formats.x.toString(), string, i); |
|
220 } |
|
221 |
|
222 function d3_time_parseLocaleTime(date, string, i) { |
|
223 return d3_time_parse(date, d3_time_formats.X.toString(), string, i); |
|
224 } |
|
225 |
|
226 function d3_time_parseFullYear(date, string, i) { |
|
227 d3_time_numberRe.lastIndex = 0; |
|
228 var n = d3_time_numberRe.exec(string.substring(i, i + 4)); |
|
229 return n ? (date.setFullYear(n[0]), i += n[0].length) : -1; |
|
230 } |
|
231 |
|
232 function d3_time_parseYear(date, string, i) { |
|
233 d3_time_numberRe.lastIndex = 0; |
|
234 var n = d3_time_numberRe.exec(string.substring(i, i + 2)); |
|
235 return n ? (date.setFullYear(d3_time_century() + +n[0]), i += n[0].length) : -1; |
|
236 } |
|
237 |
|
238 function d3_time_century() { |
|
239 return ~~(new Date().getFullYear() / 1000) * 1000; |
|
240 } |
|
241 |
|
242 function d3_time_parseMonthNumber(date, string, i) { |
|
243 d3_time_numberRe.lastIndex = 0; |
|
244 var n = d3_time_numberRe.exec(string.substring(i, i + 2)); |
|
245 return n ? (date.setMonth(n[0] - 1), i += n[0].length) : -1; |
|
246 } |
|
247 |
|
248 function d3_time_parseDay(date, string, i) { |
|
249 d3_time_numberRe.lastIndex = 0; |
|
250 var n = d3_time_numberRe.exec(string.substring(i, i + 2)); |
|
251 return n ? (date.setDate(+n[0]), i += n[0].length) : -1; |
|
252 } |
|
253 |
|
254 // Note: we don't validate that the hour is in the range [0,23]. |
|
255 function d3_time_parseHour24(date, string, i) { |
|
256 d3_time_numberRe.lastIndex = 0; |
|
257 var n = d3_time_numberRe.exec(string.substring(i, i + 2)); |
|
258 return n ? (date.setHours(+n[0]), i += n[0].length) : -1; |
|
259 } |
|
260 |
|
261 // Note: we don't validate that the hour is in the range [1,12]. |
|
262 function d3_time_parseHour12(date, string, i) { |
|
263 date.hour12 = true; |
|
264 return d3_time_parseHour24(date, string, i); |
|
265 } |
|
266 |
|
267 function d3_time_parseMinutes(date, string, i) { |
|
268 d3_time_numberRe.lastIndex = 0; |
|
269 var n = d3_time_numberRe.exec(string.substring(i, i + 2)); |
|
270 return n ? (date.setMinutes(+n[0]), i += n[0].length) : -1; |
|
271 } |
|
272 |
|
273 function d3_time_parseSeconds(date, string, i) { |
|
274 d3_time_numberRe.lastIndex = 0; |
|
275 var n = d3_time_numberRe.exec(string.substring(i, i + 2)); |
|
276 return n ? (date.setSeconds(+n[0]), i += n[0].length) : -1; |
|
277 } |
|
278 |
|
279 function d3_time_parseMilliseconds(date, string, i) { |
|
280 d3_time_numberRe.lastIndex = 0; |
|
281 var n = d3_time_numberRe.exec(string.substring(i, i + 3)); |
|
282 return n ? (date.setMilliseconds(+n[0]), i += n[0].length) : -1; |
|
283 } |
|
284 |
|
285 // Note: we don't look at the next directive. |
|
286 var d3_time_numberRe = /\s*\d+/; |
|
287 |
|
288 function d3_time_parseAmPm(date, string, i) { |
|
289 var n = d3_time_amPmLookup[string.substring(i, i += 2).toLowerCase()]; |
|
290 return n == null ? -1 : (date.hour12pm = n, i); |
|
291 } |
|
292 |
|
293 var d3_time_amPmLookup = { |
|
294 am: 0, |
|
295 pm: 1 |
|
296 }; |
|
297 |
|
298 function d3_time_year(d) { |
|
299 return new d3_time(d.getFullYear(), 0, 1); |
|
300 } |
|
301 |
|
302 function d3_time_daysElapsed(d0, d1) { |
|
303 return ~~((d1 - d0) / 864e5 - (d1.getTimezoneOffset() - d0.getTimezoneOffset()) / 1440); |
|
304 } |
|
305 |
|
306 function d3_time_dayOfYear(d) { |
|
307 return d3_time_zfill3(1 + d3_time_daysElapsed(d3_time_year(d), d)); |
|
308 } |
|
309 |
|
310 function d3_time_weekNumberSunday(d) { |
|
311 var d0 = d3_time_year(d); |
|
312 return d3_time_zfill2(~~((d3_time_daysElapsed(d0, d) + d0.getDay()) / 7)); |
|
313 } |
|
314 |
|
315 function d3_time_weekNumberMonday(d) { |
|
316 var d0 = d3_time_year(d); |
|
317 return d3_time_zfill2(~~((d3_time_daysElapsed(d0, d) + (d0.getDay() + 6) % 7) / 7)); |
|
318 } |
|
319 |
|
320 // TODO table of time zone offset names? |
|
321 function d3_time_zone(d) { |
|
322 var z = d.getTimezoneOffset(), |
|
323 zs = z > 0 ? "-" : "+", |
|
324 zh = ~~(Math.abs(z) / 60), |
|
325 zm = Math.abs(z) % 60; |
|
326 return zs + d3_time_zfill2(zh) + d3_time_zfill2(zm); |
|
327 } |