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

Side by Side Diff: pkg/intl/date_format.dart

Issue 10952004: Change intl to use new pub layout (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 3 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 | « pkg/intl/data/dates/symbols/zu.json ('k') | pkg/intl/date_symbol_data_file.dart » ('j') | no next file with comments »
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 * DateFormat is for formatting and parsing dates in a locale-sensitive
7 * manner.
8 * It allows the user to choose from a set of standard date time formats as well
9 * as specify a customized pattern under certain locales. Date elements that
10 * vary across locales include month name, week name, field order, etc.
11 * <!-- TODO(efortuna): Customized pattern system -- suggested by i18n needs
12 * feedback on appropriateness. -->
13 * We also allow the user to use any customized pattern to parse or format
14 * date-time strings under certain locales. Date elements that vary across
15 * locales include month name, weekname, field, order, etc.
16 *
17 * This library uses the ICU/JDK date/time pattern specification both for
18 * complete format specifications and also the abbreviated "skeleton" form
19 * which can also adapt to different locales and is preferred where available.
20 *
21 * Skeletons: These can be specified either as the ICU constant name or as the
22 * skeleton to which it resolves. The supported set of skeletons is as follows
23 * ICU Name Skeleton
24 * -------- --------
25 * DAY d
26 * ABBR_WEEKDAY E
27 * WEEKDAY EEEE
28 * ABBR_STANDALONE_MONTH LLL
29 * STANDALONE_MONTH LLLL
30 * NUM_MONTH M
31 * NUM_MONTH_DAY Md
32 * NUM_MONTH_WEEKDAY_DAY MEd
33 * ABBR_MONTH MMM
34 * ABBR_MONTH_DAY MMMd
35 * ABBR_MONTH_WEEKDAY_DAY MMMEd
36 * MONTH MMMM
37 * MONTH_DAY MMMMd
38 * MONTH_WEEKDAY_DAY MMMMEEEEd
39 * ABBR_QUARTER QQQ
40 * QUARTER QQQQ
41 * YEAR y
42 * YEAR_NUM_MONTH yM
43 * YEAR_NUM_MONTH_DAY yMd
44 * YEAR_NUM_MONTH_WEEKDAY_DAY yMEd
45 * YEAR_ABBR_MONTH yMMM
46 * YEAR_ABBR_MONTH_DAY yMMMd
47 * YEAR_ABBR_MONTH_WEEKDAY_DAY yMMMEd
48 * YEAR_MONTH yMMMM
49 * YEAR_MONTH_DAY yMMMMd
50 * YEAR_MONTH_WEEKDAY_DAY yMMMMEEEEd
51 * YEAR_ABBR_QUARTER yQQQ
52 * YEAR_QUARTER yQQQQ
53 * HOUR24 H
54 * HOUR24_MINUTE Hm
55 * HOUR24_MINUTE_SECOND Hms
56 * HOUR j
57 * HOUR_MINUTE jm
58 * HOUR_MINUTE_SECOND jms
59 * HOUR_MINUTE_GENERIC_TZ jmv
60 * HOUR_MINUTE_TZ jmz
61 * HOUR_GENERIC_TZ jv
62 * HOUR_TZ jz
63 * MINUTE m
64 * MINUTE_SECOND ms
65 * SECOND s
66 *
67 * Examples Using the US Locale:
68 *
69 * Pattern Result
70 * ---------------- -------
71 * new DateFormat.yMd() -> 07/10/1996
72 * new DateFormat("yMd") -> 07/10/1996
73 * new DateFormat.yMMMMd("en_US") -> July 10, 1996
74 * new DateFormat("Hm", "en_US") -> 12:08 PM
75 * new DateFormat.yMd().Hm() -> 07/10/1996 12:08 PM
76 *
77 * Explicit Pattern Syntax: Formats can also be specified with a pattern string.
78 * The skeleton forms will resolve to explicit patterns of this form, but will
79 * also adapt to different patterns in different locales.
80 * The following characters are reserved:
81 *
82 * Symbol Meaning Presentation Example
83 * ------ ------- ------------ -------
84 * G era designator (Text) AD
85 * y year (Number) 1996
86 * M month in year (Text & Number) July & 07
87 * L standalone month (Text & Number) July & 07
88 * d day in month (Number) 10
89 * c standalone day (Number) 10
90 * h hour in am/pm (1~12) (Number) 12
91 * H hour in day (0~23) (Number) 0
92 * m minute in hour (Number) 30
93 * s second in minute (Number) 55
94 * S fractional second (Number) 978
95 * E day of week (Text) Tuesday
96 * D day in year (Number) 189
97 * a am/pm marker (Text) PM
98 * k hour in day (1~24) (Number) 24
99 * K hour in am/pm (0~11) (Number) 0
100 * z time zone (Text) Pacific Standard Time
101 * Z time zone (RFC 822) (Number) -0800
102 * v time zone (generic) (Text) Pacific Time
103 * Q quarter (Text) Q3
104 * ' escape for text (Delimiter) 'Date='
105 * '' single quote (Literal) 'o''clock'
106 *
107 * The count of pattern letters determine the format.
108 * **Text**:
109 * * 5 pattern letters--use narrow form for standalone. Otherwise does not apply
110 * * 4 or more pattern letters--use full form,
111 * * 3 pattern letters--use short or abbreviated form if one exists
112 * * less than 3--use numeric form if one exists
113 *
114 * **Number**: the minimum number of digits. Shorter numbers are zero-padded to
115 * this amount (e.g. if "m" produces "6", "mm" produces "06"). Year is handled
116 * specially; that is, if the count of 'y' is 2, the Year will be truncated to
117 * 2 digits. (e.g., if "yyyy" produces "1997", "yy" produces "97".) Unlike other
118 * fields, fractional seconds are padded on the right with zero.
119 *
120 * (Text & Number): 3 or over, use text, otherwise use number.
121 *
122 * Any characters that not in the pattern will be treated as quoted text. For
123 * instance, characters like ':', '.', ' ', '#' and '@' will appear in the
124 * resulting time text even they are not embraced within single quotes. In our
125 * current pattern usage, we didn't use up all letters. But those unused
126 * letters are strongly discouraged to be used as quoted text without quote.
127 * That's because we may use other letter for pattern in future.
128 *
129 * Examples Using the US Locale:
130 *
131 * Format Pattern Result
132 * -------------- -------
133 * "yyyy.MM.dd G 'at' HH:mm:ss vvvv"->1996.07.10 AD at 15:08:56 Pacific Time
134 * "EEE, MMM d, ''yy" ->Wed, July 10, '96
135 * "h:mm a" ->12:08 PM
136 * "hh 'o''clock' a, zzzz" ->12 o'clock PM, Pacific Daylight Time
137 * "K:mm a, vvv" ->0:00 PM, PT
138 * "yyyyy.MMMMM.dd GGG hh:mm aaa" ->01996.July.10 AD 12:08 PM
139 *
140 * When parsing a date string using the abbreviated year pattern ("yy"),
141 * DateFormat must interpret the abbreviated year relative to some
142 * century. It does this by adjusting dates to be within 80 years before and 20
143 * years after the time the parse function is called. For example, using a
144 * pattern of "MM/dd/yy" and a DateTimeParse instance created on Jan 1, 1997,
145 * the string "01/11/12" would be interpreted as Jan 11, 2012 while the string
146 * "05/04/64" would be interpreted as May 4, 1964. During parsing, only
147 * strings consisting of exactly two digits, as defined by {@link
148 * java.lang.Character#isDigit(char)}, will be parsed into the default
149 * century. Any other numeric string, such as a one digit string, a three or
150 * more digit string will be interpreted as its face value.
151 *
152 * If the year pattern does not have exactly two 'y' characters, the year is
153 * interpreted literally, regardless of the number of digits. So using the
154 * pattern "MM/dd/yyyy", "01/11/12" parses to Jan 11, 12 A.D.
155 */
156
157 #library('date_format');
158
159 #import('dart:math');
160 #import('intl.dart');
161 #import('date_symbols.dart');
162 #import('lib/intl_helpers.dart');
163 #import('lib/date_format_internal.dart');
164
165 #source('lib/date_format_field.dart');
166 #source('lib/date_format_helpers.dart');
167
168 class DateFormat {
169
170 /**
171 * If [newPattern] matches one of the skeleton forms, it is looked up
172 * in [locale] or in the default if none is specified, and the corresponding
173 * full format string is used. If [newPattern] does not match one
174 * of the supported skeleton forms then it is used as a format directly.
175 *
176 * For example, in an en_US locale, specifying the skeleton
177 * `new DateFormat('yMEd');`
178 * or the explicit
179 * `new DateFormat('EEE, M/d/y');`
180 * would produce the same result, a date of the form
181 * `Wed, 6/27/2012`
182 * However, the skeleton version would also adapt to other locales.
183 *
184 * If [locale] does not exist in our set of supported locales then an
185 * [IllegalArgumentException] is thrown.
186 */
187 DateFormat([String newPattern, String locale]) {
188 // TODO(alanknight): It should be possible to specify multiple skeletons eg
189 // date, time, timezone all separately. Adding many or named parameters to
190 // the constructor seems awkward, especially with the possibility of
191 // confusion with the locale. A "fluent" interface with cascading on an
192 // instance might work better? A list of patterns is also possible.
193 // TODO(alanknight): There will need to be at least setup type async
194 // operations to avoid the need to bring along every locale in every program
195 _locale = Intl.verifiedLocale(locale);
196 addPattern(newPattern);
197 }
198
199 /**
200 * Return a string representing [date] formatted according to our locale
201 * and internal format.
202 */
203 String format(Date date) {
204 // TODO(efortuna): read optional TimeZone argument (or similar)?
205 var result = new StringBuffer();
206 _formatFields.forEach((field) => result.add(field.format(date)));
207 return result.toString();
208 }
209
210 /**
211 * Returns a date string indicating how long ago (3 hours, 2 minutes)
212 * something has happened or how long in the future something will happen
213 * given a [reference] Date relative to the current time.
214 */
215 String formatDuration(Date reference) {
216 return '';
217 }
218
219 /**
220 * Formats a string indicating how long ago (negative [duration]) or how far
221 * in the future (positive [duration]) some time is with respect to a
222 * reference [date].
223 */
224 String formatDurationFrom(Duration duration, Date date) {
225 return '';
226 }
227
228 /**
229 * Given user input, attempt to parse the [inputString] into the anticipated
230 * format, treating it as being in the local timezone.
231 */
232 Date parse(String inputString, [utc = false]) {
233 // TODO(alanknight): The Closure code refers to special parsing of numeric
234 // values with no delimiters, which we currently don't do. Should we?
235 var dateFields = new _DateBuilder();
236 if (utc) dateFields.utc=true;
237 var stream = new _Stream(inputString);
238 _formatFields.forEach(
239 (each) => each.parse(stream, dateFields));
240 return dateFields.asDate();
241 }
242
243 /**
244 * Given user input, attempt to parse the [inputString] into the anticipated
245 * format, treating it as being in UTC.
246 */
247 Date parseUTC(String inputString) {
248 return parse(inputString, true);
249 }
250
251 /**
252 * Return the locale code in which we operate, e.g. 'en_US' or 'pt'.
253 */
254 String get locale => _locale;
255
256 /**
257 * Returns a list of all locales for which we have date formatting
258 * information.
259 */
260 static List<String> allLocalesWithSymbols() => dateTimeSymbols.getKeys();
261
262 /**
263 * Constructors for a set of predefined "skeletons" for which the
264 * internationalized forms are known. These can also be chained
265 * together using the "add_" instance methods below.
266 */
267 DateFormat.d([locale]) : this("d", locale);
268 DateFormat.E([locale]) : this("E", locale);
269 DateFormat.EEEE([locale]) : this("EEEE", locale);
270 DateFormat.LLL([locale]) : this("LLL", locale);
271 DateFormat.LLLL([locale]) : this("LLLL", locale);
272 DateFormat.M([locale]) : this("M", locale);
273 DateFormat.Md([locale]) : this("Md", locale);
274 DateFormat.MEd([locale]) : this("MEd", locale);
275 DateFormat.MMM([locale]) : this("MMM", locale);
276 DateFormat.MMMd([locale]) : this("MMMd", locale);
277 DateFormat.MMMEd([locale]) : this("MMMEd", locale);
278 DateFormat.MMMM([locale]) : this("MMMM", locale);
279 DateFormat.MMMMd([locale]) : this("MMMMd", locale);
280 DateFormat.MMMMEEEEd([locale]) : this("MMMMEEEEd", locale);
281 DateFormat.QQQ([locale]) : this("QQQ", locale);
282 DateFormat.QQQQ([locale]) : this("QQQQ", locale);
283 DateFormat.y([locale]) : this("y", locale);
284 DateFormat.yM([locale]) : this("yM", locale);
285 DateFormat.yMd([locale]) : this("yMd", locale);
286 DateFormat.yMEd([locale]) : this("yMEd", locale);
287 DateFormat.yMMM([locale]) : this("yMMM", locale);
288 DateFormat.yMMMd([locale]) : this("yMMMd", locale);
289 DateFormat.yMMMEd([locale]) : this("yMMMEd", locale);
290 DateFormat.yMMMM([locale]) : this("yMMMM", locale);
291 DateFormat.yMMMMd([locale]) : this("yMMMMd", locale);
292 DateFormat.yMMMMEEEEd([locale]) : this("yMMMMEEEEd", locale);
293 DateFormat.yQQQ([locale]) : this("yQQQ", locale);
294 DateFormat.yQQQQ([locale]) : this("yQQQQ", locale);
295 DateFormat.H([locale]) : this("H", locale);
296 DateFormat.Hm([locale]) : this("Hm", locale);
297 DateFormat.Hms([locale]) : this("Hms", locale);
298 DateFormat.j([locale]) : this("j", locale);
299 DateFormat.jm([locale]) : this("jm", locale);
300 DateFormat.jms([locale]) : this("jms", locale);
301 DateFormat.jmv([locale]) : this("jmv", locale);
302 DateFormat.jmz([locale]) : this("jmz", locale);
303 DateFormat.jv([locale]) : this("jv", locale);
304 DateFormat.jz([locale]) : this("jz", locale);
305 DateFormat.m([locale]) : this("m", locale);
306 DateFormat.ms([locale]) : this("ms", locale);
307 DateFormat.s([locale]) : this("s", locale);
308
309 /**
310 * Methods for appending a particular skeleton to the format, or setting
311 * it as the only format if none was previously set. These are primarily
312 * useful for creating compound formats. For example
313 * new DateFormat.yMd().add_hms();
314 * would create a date format that prints both the date and the time.
315 */
316 DateFormat add_d() => addPattern("d");
317 DateFormat add_E() => addPattern("E");
318 DateFormat add_EEEE() => addPattern("EEEE");
319 DateFormat add_LLL() => addPattern("LLL");
320 DateFormat add_LLLL() => addPattern("LLLL");
321 DateFormat add_M() => addPattern("M");
322 DateFormat add_Md() => addPattern("Md");
323 DateFormat add_MEd() => addPattern("MEd");
324 DateFormat add_MMM() => addPattern("MMM");
325 DateFormat add_MMMd() => addPattern("MMMd");
326 DateFormat add_MMMEd() => addPattern("MMMEd");
327 DateFormat add_MMMM() => addPattern("MMMM");
328 DateFormat add_MMMMd() => addPattern("MMMMd");
329 DateFormat add_MMMMEEEEd() => addPattern("MMMMEEEEd");
330 DateFormat add_QQQ() => addPattern("QQQ");
331 DateFormat add_QQQQ() => addPattern("QQQQ");
332 DateFormat add_y() => addPattern("y");
333 DateFormat add_yM() => addPattern("yM");
334 DateFormat add_yMd() => addPattern("yMd");
335 DateFormat add_yMEd() => addPattern("yMEd");
336 DateFormat add_yMMM() => addPattern("yMMM");
337 DateFormat add_yMMMd() => addPattern("yMMMd");
338 DateFormat add_yMMMEd() => addPattern("yMMMEd");
339 DateFormat add_yMMMM() => addPattern("yMMMM");
340 DateFormat add_yMMMMd() => addPattern("yMMMMd");
341 DateFormat add_yMMMMEEEEd() => addPattern("yMMMMEEEEd");
342 DateFormat add_yQQQ() => addPattern("yQQQ");
343 DateFormat add_yQQQQ() => addPattern("yQQQQ");
344 DateFormat add_H() => addPattern("H");
345 DateFormat add_Hm() => addPattern("Hm");
346 DateFormat add_Hms() => addPattern("Hms");
347 DateFormat add_j() => addPattern("j");
348 DateFormat add_jm() => addPattern("jm");
349 DateFormat add_jms() => addPattern("jms");
350 DateFormat add_jmv() => addPattern("jmv");
351 DateFormat add_jmz() => addPattern("jmz");
352 DateFormat add_jv() => addPattern("jv");
353 DateFormat add_jz() => addPattern("jz");
354 DateFormat add_m() => addPattern("m");
355 DateFormat add_ms() => addPattern("ms");
356 DateFormat add_s() => addPattern("s");
357
358 /**
359 * ICU constants for format names, resolving to the corresponding skeletons.
360 */
361 static const String DAY = 'd';
362 static const String ABBR_WEEKDAY = 'E';
363 static const String WEEKDAY = 'EEEE';
364 static const String ABBR_STANDALONE_MONTH = 'LLL';
365 static const String STANDALONE_MONTH = 'LLLL';
366 static const String NUM_MONTH = 'M';
367 static const String NUM_MONTH_DAY = 'Md';
368 static const String NUM_MONTH_WEEKDAY_DAY = 'MEd';
369 static const String ABBR_MONTH = 'MMM';
370 static const String ABBR_MONTH_DAY = 'MMMd';
371 static const String ABBR_MONTH_WEEKDAY_DAY = 'MMMEd';
372 static const String MONTH = 'MMMM';
373 static const String MONTH_DAY = 'MMMMd';
374 static const String MONTH_WEEKDAY_DAY = 'MMMMEEEEd';
375 static const String ABBR_QUARTER = 'QQQ';
376 static const String QUARTER = 'QQQQ';
377 static const String YEAR = 'y';
378 static const String YEAR_NUM_MONTH = 'yM';
379 static const String YEAR_NUM_MONTH_DAY = 'yMd';
380 static const String YEAR_NUM_MONTH_WEEKDAY_DAY = 'yMEd';
381 static const String YEAR_ABBR_MONTH = 'yMMM';
382 static const String YEAR_ABBR_MONTH_DAY = 'yMMMd';
383 static const String YEAR_ABBR_MONTH_WEEKDAY_DAY = 'yMMMEd';
384 static const String YEAR_MONTH = 'yMMMM';
385 static const String YEAR_MONTH_DAY = 'yMMMMd';
386 static const String YEAR_MONTH_WEEKDAY_DAY = 'yMMMMEEEEd';
387 static const String YEAR_ABBR_QUARTER = 'yQQQ';
388 static const String YEAR_QUARTER = 'yQQQQ';
389 static const String HOUR24 = 'H';
390 static const String HOUR24_MINUTE = 'Hm';
391 static const String HOUR24_MINUTE_SECOND = 'Hms';
392 static const String HOUR = 'j';
393 static const String HOUR_MINUTE = 'jm';
394 static const String HOUR_MINUTE_SECOND = 'jms';
395 static const String HOUR_MINUTE_GENERIC_TZ = 'jmv';
396 static const String HOUR_MINUTE_TZ = 'jmz';
397 static const String HOUR_GENERIC_TZ = 'jv';
398 static const String HOUR_TZ = 'jz';
399 static const String MINUTE = 'm';
400 static const String MINUTE_SECOND = 'ms';
401 static const String SECOND = 's';
402
403 /** The locale in which we operate, e.g. 'en_US', or 'pt'. */
404 String _locale;
405
406 /**
407 * The full template string. This may have been specified directly, or
408 * it may have been derived from a skeleton and the locale information
409 * on how to interpret that skeleton.
410 */
411 String _pattern;
412
413 /**
414 * We parse the format string into individual [_DateFormatField] objects
415 * that are used to do the actual formatting and parsing. Do not use
416 * this variable directly, use the getter [_formatFields].
417 */
418 List<_DateFormatField> _formatFieldsPrivate;
419
420 /**
421 * Getter for [_formatFieldsPrivate] that lazily initializes it.
422 */
423 get _formatFields {
424 if (_formatFieldsPrivate == null) {
425 _formatFieldsPrivate = parsePattern(_pattern);
426 }
427 return _formatFieldsPrivate;
428 }
429
430 /**
431 * A series of regular expressions used to parse a format string into its
432 * component fields.
433 */
434 static var _matchers = const [
435 // Quoted String - anything between single quotes, with escaping
436 // of single quotes by doubling them.
437 // e.g. in the pattern "hh 'o''clock'" will match 'o''clock'
438 const RegExp("^\'(?:[^\']|\'\')*\'"),
439 // Fields - any sequence of 1 or more of the same field characters.
440 // e.g. in "hh:mm:ss" will match hh, mm, and ss. But in "hms" would
441 // match each letter individually.
442 const RegExp(
443 "^(?:G+|y+|M+|k+|S+|E+|a+|h+|K+|H+|c+|L+|Q+|d+|m+|s+|v+|z+|Z+)"),
444 // Everything else - A sequence that is not quotes or field characters.
445 // e.g. in "hh:mm:ss" will match the colons.
446 const RegExp("^[^\'GyMkSEahKHcLQdmsvzZ]+")
447 ];
448
449 /**
450 * Set our pattern, appending it to any existing patterns. Also adds a single
451 * space to separate the two.
452 */
453 _setPattern(String inputPattern, [String separator = ' ']) {
454 if (_pattern == null) {
455 _pattern = inputPattern;
456 } else {
457 _pattern = "$_pattern$separator$inputPattern";
458 }
459 }
460
461 /**
462 * Add [inputPattern] to this instance as a pattern. If there was a previous
463 * pattern, then this appends to it, separating the two by [separator].
464 * [inputPattern] is first looked up in our list of known skeletons.
465 * If it's found there, then use the corresponding pattern for this locale.
466 * If it's not, then treat [inputPattern] as an explicit pattern.
467 */
468 DateFormat addPattern(String inputPattern, [String separator = ' ']) {
469 // TODO(alanknight): This is an expensive operation. Caching recently used
470 // formats, or possibly introducing an entire "locale" object that would
471 // cache patterns for that locale could be a good optimization.
472 if (!_availableSkeletons.containsKey(inputPattern)) {
473 _setPattern(inputPattern, separator);
474 } else {
475 _setPattern(_availableSkeletons[inputPattern], separator);
476 }
477 // If we have already parsed the format fields, reset them.
478 _formatFieldsPrivate = null;
479 return this;
480 }
481
482 /** Return the pattern that we use to format dates.*/
483 get pattern => _pattern;
484
485 /** Return the skeletons for our current locale. */
486 Map get _availableSkeletons {
487 return dateTimePatterns[locale];
488 }
489
490 /**
491 * Set the locale. If the locale can't be found, we also look up
492 * based on alternative versions, e.g. if we have no 'en_CA' we will
493 * look for 'en' as a fallback. It will also translate en-ca into en_CA.
494 * Null is also considered a valid value for [newLocale], indicating
495 * to use the default.
496 */
497 _setLocale(String newLocale) {
498 _locale = Intl.verifiedLocale(newLocale);
499 }
500
501 /**
502 * Return true if the locale exists, or if it is null. The null case
503 * is interpreted to mean that we use the default locale.
504 */
505 static bool localeExists(localeName) {
506 if (localeName == null) return false;
507 return dateTimeSymbols.containsKey(localeName);
508 }
509
510 // TODO(alanknight): This can be a variable once that's permitted.
511 static List get _fieldConstructors => [
512 (pattern, parent) => new _DateFormatQuotedField(pattern, parent),
513 (pattern, parent) => new _DateFormatPatternField(pattern, parent),
514 (pattern, parent) => new _DateFormatLiteralField(pattern, parent)];
515
516 /** Parse the template pattern and return a list of field objects.*/
517 List parsePattern(String pattern) {
518 if (pattern == null) return null;
519 return _reverse(_parsePatternHelper(pattern));
520 }
521
522 /** Recursive helper for parsing the template pattern. */
523 List _parsePatternHelper(String pattern) {
524 if (pattern.isEmpty()) return [];
525
526 var matched = _match(pattern);
527 if (matched == null) return [];
528
529 var parsed = _parsePatternHelper(
530 pattern.substring(matched.fullPattern().length));
531 parsed.add(matched);
532 return parsed;
533 }
534
535 /** Find elements in a string that are patterns for specific fields.*/
536 _DateFormatField _match(String pattern) {
537 for (var i = 0; i < _matchers.length; i++) {
538 var regex = _matchers[i];
539 var match = regex.firstMatch(pattern);
540 if (match != null) {
541 return _fieldConstructors[i](match.group(0), this);
542 }
543 }
544 }
545
546 /** Polyfill for missing library function. */
547 List _reverse(List list) {
548 // TODO(alanknight): Use standardized list reverse when implemented.
549 // See Issue 2804.
550 var result = new List();
551 for (var i = list.length-1; i >= 0; i--) {
552 result.addLast(list[i]);
553 }
554 return result;
555 }
556 }
OLDNEW
« no previous file with comments | « pkg/intl/data/dates/symbols/zu.json ('k') | pkg/intl/date_symbol_data_file.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698