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