Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(182)

Side by Side Diff: lib/i18n/_date_format_field.dart

Issue 10807096: Add date formatting and parsing code. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | lib/i18n/_date_format_helpers.dart » ('j') | lib/i18n/_date_format_helpers.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * This is a private class internal to DateFormat which is used for formatting
7 * particular fields in a template. e.g. if the format is hh:mm:ss then the
8 * fields would be "hh", ":", "mm", ":", and "ss". Each type of field knows
9 * how to format that portion of a date.
10 */
11 class _DateFormatField{
Emily Fortuna 2012/08/06 22:43:00 space between _DateFormatField and {
Alan Knight 2012/08/08 00:47:44 Done.
12 /** The format string that defines us, e.g. "hh" */
13 String pattern;
14
15 /** The DateFormat that we are part of.*/
16 DateFormat parent;
17
18 _DateFormatField(this.pattern, this.parent);
19
20 /**
21 * Return the width of [pattern]. Different widths represent different
22 * formatting options. See the comment for DateFormat for details.
23 */
24 int get width() => pattern.length;
25
26 String fullPattern() => pattern;
27
28 String toString() => pattern;
29
30 /** Format date according to our specification and return the result. */
31 String format(Date date) {
Emily Fortuna 2012/08/06 22:43:00 String format(Date date) => pattern; (?) seems lik
Alan Knight 2012/08/08 00:47:44 It's a default implementation in the superclass th
32 return pattern;
33 }
34
35 abstract void parse(_Stream input, _DateBuilder dateFields);
36
37 /** Parse a literal field. We just look for the exact input. */
38 void parseLiteral(_Stream input) {
39 var found = input.read(width);
40 if (found != pattern) throw
Emily Fortuna 2012/08/06 22:43:00 if your "if" statement is going to span more than
Alan Knight 2012/08/08 00:47:44 Done.
41 new FormatException(input, this);
42 }
43 }
44
45 /**
46 * Represents a literal field - a sequence of characters that doesn't
47 * change according to the date's data. As such, the implementation
48 * is extremely simple.
49 */
50 class _DateFormatLiteralField extends _DateFormatField{
Emily Fortuna 2012/08/06 22:43:00 space before { and elsewhere
Alan Knight 2012/08/08 00:47:44 Done.
51
52 _DateFormatLiteralField(pattern,parent): super(pattern,parent);
Emily Fortuna 2012/08/06 22:43:00 give these variables some space to breathe! space
Alan Knight 2012/08/08 00:47:44 Done.
53
54 parse(_Stream input, _DateBuilder dateFields) {
55 return parseLiteral(input);
56 }
57 }
58
59 /**
60 * Represents a literal field with quoted characters in it. This is
61 * only slightly more complex than a _DateFormatLiteralField.
62 */
63 class _DateFormatQuotedField extends _DateFormatField{
64
65 String _fullPattern;
66
67 String fullPattern() => _fullPattern;
68
69 _DateFormatQuotedField(pattern,parent): super(pattern,parent) {
70 _fullPattern = pattern;
71 patchQuotes();
72 }
73
74 parse(_Stream input, _DateBuilder dateFields) {
75 return parseLiteral(input);
76 }
77
78 void patchQuotes() {
79 if (pattern == "''") {
80 pattern = "'";
81 } else {
82 pattern = pattern.substring(1,pattern.length - 1);
83 var twoEscapedQuotes = new RegExp("\'\'");
Emily Fortuna 2012/08/06 22:43:00 nit: could also be written as new RegExp(@"''");
Alan Knight 2012/08/08 00:47:44 Done.
84 pattern = pattern.replaceAll(twoEscapedQuotes, "'");
85 }
86 }
87 }
88
89 /*
90 * Represents a field in the pattern that formats some aspect of the
91 * date. Consists primarily of a switch on the particular pattern characters
92 * to determine what to do.
93 */
94 class _DateFormatPatternField extends _DateFormatField {
95
96 _DateFormatPatternField(pattern,parent): super(pattern,parent);
Emily Fortuna 2012/08/06 22:43:00 space between parameters: "pattern, parent"
Alan Knight 2012/08/08 00:47:44 Done.
97
98 /** Format date according to our specification and return the result. */
99 String format(Date date) {
100 return formatField(date);
101 }
102
103 /**
104 * Parse the date according to our specification and put the result
105 * into the correct place in dateFields.
106 */
107 void parse(_Stream input, _DateBuilder dateFields) {
108 parseField(input,dateFields);
109 }
110
111 /**
112 * Parse a field representing part of a date pattern. Note that we do not
113 * return a value, but rather build up the result in [builder].
114 */
115 void parseField(_Stream input, _DateBuilder builder) {
116 try {
117 switch(pattern[0]) {
118 case 'a': parseAmPm(input,builder); break;
119 case 'c': parseStandaloneDay(input); break;
120 case 'd': handleNumericField(input,builder.setDay); break; // day
121 case 'E': parseDayOfWeek(input); break;
122 case 'G': break; // era
123 case 'h': parse1To12Hours(input,builder); break;
124 case 'H': handleNumericField(input,builder.setHour); break; // hour 0-23
125 case 'K': handleNumericField(input,builder.setHour); break; //hour 0-11
126 case 'k': handleNumericField(input,builder.setHour,-1); break; //hr 1-24
127 case 'L': parseStandaloneMonth(input,builder); break;
128 case 'M': parseMonth(input,builder); break;
129 case 'm': handleNumericField(input,builder.setMinute); break; // minutes
130 case 'Q': break; // quarter
131 case 'S': handleNumericField(input,builder.setFractionalSecond); break;
132 case 's': handleNumericField(input,builder.setSecond); break;
133 case 'v': break; // time zone id
134 case 'y': handleNumericField(input,builder.setYear); break;
135 case 'z': break; // time zone
136 case 'Z': break; // time zone RFC
137 default: return;
138 }
139 } catch (var e) {throw new FormatException(input,this);}
140 }
141
142 /** Formatting logic if we are of type FIELD */
143 String formatField(Date date) {
144 switch (pattern[0]) {
145 case 'a': return formatAmPm(date);
146 case 'c': return formatStandaloneDay(date);
147 case 'd': return formatDayOfMonth(date);
148 case 'E': return formatDayOfWeek(date);
149 case 'G': return formatEra(date);
150 case 'h': return format1To12Hours(date);
151 case 'H': return format0To23Hours(date);
152 case 'K': return format0To11Hours(date);
153 case 'k': return format24Hours(date);
154 case 'L': return formatStandaloneMonth(date);
155 case 'M': return formatMonth(date);
156 case 'm': return formatMinutes(date);
157 case 'Q': return formatQuarter(date);
158 case 'S': return formatFractionalSeconds(date);
159 case 's': return formatSeconds(date);
160 case 'v': return formatTimeZoneId(date);
161 case 'y': return formatYear(date);
162 case 'z': return formatTimeZone(date);
163 case 'Z': return formatTimeZoneRFC(date);
164 default: return '';
165 }
166 }
167
168 /** Return the symbols for our current locale. */
169 DateSymbols get symbols() => dateTimeSymbols[parent.locale];
170
171 formatEra(Date date) {
172 var era = date.year > 0 ? 1 : 0;
173 return width >= 4 ? symbols.ERANAMES[era] :
174 symbols.ERAS[era];
175 }
176
177 formatYear(Date date) {
178 // TODO(alanknight): Proper handling of years <= 0
179 var year = date.year;
180 if (year < 0) {
181 year = -year;
182 }
183 return width == 2 ? padTo(2, year % 100) : year.toString();
184 }
185
186 /**
187 * We are given [input] as a stream from which we want to read a date. We
188 * can't dynamically build up a date, so we are given a list [dateFields] of
189 * the constructor arguments and an [position] at which to set it
190 * (year,month,day,hour,minute,second,fractionalSecond)
191 * then after all parsing is done we construct a date from the arguments.
192 * This method handles reading any of the numeric fields. The [offset]
193 * argument allows us to compensate for zero-based versus one-based values.
194 */
195 void handleNumericField(
196 _Stream input,
Emily Fortuna 2012/08/06 22:43:00 curious indentation
Alan Knight 2012/08/08 00:47:44 Done. It fits into 80 characters now, so no need t
197 Function setter,
198 [int offset = 0]) {
199 var result = input.nextInteger();
200 setter(result + offset);
201 }
202
203 /**
204 * We are given [input] as a stream from which we want to read a date. We
205 * can't dynamically build up a date, so we are given a list [dateFields] of
206 * the constructor arguments and an [position] at which to set it
207 * (year,month,day,hour,minute,second,fractionalSecond)
208 * then after all parsing is done we construct a date from the arguments.
209 * This method handles reading any of string fields from an enumerated set.
210 */
211 int parseEnumeratedString(_Stream input, List possibilities) {
212 var results = new _Stream(possibilities).findIndexes(
213 (each) => input.peek(each.length) == each);
214 if (results.isEmpty()) throw new FormatException(input,this);
215 results.sort(
216 (a, b) => possibilities[a].length.compareTo(possibilities[b].length));
217 var longestResult = results.last();
218 input.read(possibilities[longestResult].length);
219 return longestResult;
220 }
221
222 String formatMonth(Date date) {
223 switch (width) {
224 case 5: return symbols.NARROWMONTHS[date.month-1];
225 case 4: return symbols.MONTHS[date.month-1];
226 case 3: return symbols.SHORTMONTHS[date.month-1];
227 default:
228 return padTo(width, date.month);
229 }
230 }
231
232 void parseMonth(input,dateFields) {
233 var possibilities;
234 switch(width) {
235 case 5: possibilities = symbols.NARROWMONTHS; break;
236 case 4: possibilities = symbols.MONTHS; break;
237 case 3: possibilities = symbols.SHORTMONTHS; break;
238 default: return handleNumericField(input,dateFields.setMonth);
239 }
240 dateFields.month = parseEnumeratedString(input,possibilities) + 1;
241 }
242
243 String format24Hours(Date date) {
244 return padTo(width, date.hour);
245 }
246
247 String formatFractionalSeconds(Date date) {
248 // Always print at least 3 digits. If the width is greater, append 0s
249 var basic = padTo(3,date.millisecond);
250 if (width - 3 > 0) {
251 var extra = padTo(width - 3, 0);
252 return basic.concat(extra);
253 } else {
254 return basic;
255 }
256 }
257
258 String formatAmPm(Date date) {
259 var hours = date.hour;
260 var index = (date.hour >= 12) && (date.hour < 24) ? 1 : 0;
261 var ampm = symbols.AMPMS;
262 return ampm[index];
263 }
264
265 void parseAmPm(input,dateFields) {
266 // If we see a "PM" note it in an extra field.
267 var ampm = parseEnumeratedString(input,symbols.AMPMS);
268 if (ampm == 1) dateFields.pm = true;
269 }
270
271 String format1To12Hours(Date date) {
272 var hours = date.hour;
273 if (date.hour > 12) hours = hours - 12;
274 if (hours == 0) hours = 12;
275 return padTo(width,hours);
276 }
277
278 void parse1To12Hours(_Stream input, _DateBuilder dateFields) {
279 handleNumericField(input,dateFields.setHour);
280 if (dateFields.hour == 12) dateFields.hour = 0;
281 }
282
283 String format0To11Hours(Date date) {
284 return padTo(width,date.hour % 12);
285 }
286
287 String format0To23Hours(Date date) {
288 return padTo(width,date.hour);
289 }
290
291 String formatStandaloneDay(Date date) {
292 switch (width) {
293 case 5: return symbols.STANDALONENARROWWEEKDAYS[date.weekday % 7];
294 case 4: return symbols.STANDALONEWEEKDAYS[date.weekday % 7];
295 case 3: return symbols.STANDALONESHORTWEEKDAYS[date.weekday % 7];
296 default:
297 return padTo(1, date.day);
298 }
299 }
300
301 void parseStandaloneDay(_Stream input) {
302 // This is ignored, but we still have to skip over it the correct amount.
303 var possibilities;
304 switch(width) {
305 case 5: possibilities = symbols.STANDALONENARROWWEEKDAYS; break;
306 case 4: possibilities = symbols.STANDALONEWEEKDAYS; break;
307 case 3: possibilities = symbols.STANDALONESHORTWEEKDAYS; break;
308 default: return handleNumericField(input,(x)=>x);
309 }
310 parseEnumeratedString(input,possibilities);
311 }
312
313 String formatStandaloneMonth(Date date) {
314 switch (width) {
315 case 5:
316 return symbols.STANDALONENARROWMONTHS[date.month-1];
317 case 4:
318 return symbols.STANDALONEMONTHS[date.month-1];
319 case 3:
320 return symbols.STANDALONESHORTMONTHS[date.month-1];
321 default:
322 return padTo(width, date.month);
323 }
324 }
325
326 void parseStandaloneMonth(input,dateFields) {
327 var possibilities;
328 switch(width) {
329 case 5: possibilities = symbols.STANDALONENARROWMONTHS; break;
330 case 4: possibilities = symbols.STANDALONEMONTHS; break;
331 case 3: possibilities = symbols.STANDALONESHORTMONTHS; break;
332 default: return handleNumericField(input,dateFields.setMonth);
333 }
334 dateFields.month = parseEnumeratedString(input,possibilities) + 1;
335 }
336
337 String formatQuarter(Date date) {
338 var quarter = (date.month / 3).truncate().toInt();
339 if (width < 4) {
340 return symbols.SHORTQUARTERS[quarter];
341 } else {
342 return symbols.QUARTERS[quarter];
343 }
344 }
345 String formatDayOfMonth(Date date) {
346 return padTo(width,date.day);
347 }
348
349 String formatDayOfWeek(Date date) {
350 // Note that Dart's weekday returns 1 for Monday and 7 for Sunday.
351 return (width >= 4 ? symbols.WEEKDAYS :
352 symbols.SHORTWEEKDAYS)[(date.weekday) % 7];
353 }
354
355 void parseDayOfWeek(_Stream input) {
356 // This is IGNORED, but we still have to skip over it the correct amount.
357 var possibilities = width >= 4 ? symbols.WEEKDAYS : symbols.SHORTWEEKDAYS;
358 parseEnumeratedString(input,possibilities);
359 }
360
361 String formatMinutes(Date date) {
362 return padTo(width,date.minute);
363 }
364
365 String formatSeconds(Date date) {
366 return padTo(width,date.second);
367 }
368
369 String formatTimeZoneId(Date date) {
370 // TODO(alanknight): implement time zone support
371 throw new NotImplementedException();
372 }
373
374 String formatTimeZone(Date date) {
375 throw new NotImplementedException();
376 }
377
378 String formatTimeZoneRFC(Date date) {
379 throw new NotImplementedException();
380 }
381
382 /**
383 * Return a string representation of the object padded to the left with
384 * zeros. Primarily useful for numbers.
385 */
386 String padTo(int width, Object toBePrinted) {
387 var basicString = toBePrinted.toString();
388 if (basicString.length >= width) return basicString;
389 var buffer = new StringBuffer();
390 for (var i = 0; i < width - basicString.length; i++) {
391 buffer.add('0');
392 }
393 buffer.add(basicString);
394 return buffer.toString();
395 }
396 }
OLDNEW
« no previous file with comments | « no previous file | lib/i18n/_date_format_helpers.dart » ('j') | lib/i18n/_date_format_helpers.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698