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

Side by Side Diff: packages/intl/lib/src/intl/date_format.dart

Issue 2989763002: Update charted to 0.4.8 and roll (Closed)
Patch Set: Removed Cutch from list of reviewers Created 3 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
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of intl; 5 part of intl;
6 6
7 // TODO(efortuna): Customized pattern system -- suggested by i18n needs 7 // TODO(efortuna): Customized pattern system -- suggested by i18n needs
8 // feedback on appropriateness. 8 // feedback on appropriateness.
9 /** 9 /// DateFormat is for formatting and parsing dates in a locale-sensitive
10 * DateFormat is for formatting and parsing dates in a locale-sensitive 10 /// manner.
11 * manner. 11 ///
12 * 12 /// It allows the user to choose from a set of standard date time formats as
13 * It allows the user to choose from a set of standard date time formats as well 13 /// well as specify a customized pattern under certain locales. Date elements
14 * as specify a customized pattern under certain locales. Date elements that 14 /// that vary across locales include month name, week name, field order, etc.
15 * vary across locales include month name, week name, field order, etc. 15 /// We also allow the user to use any customized pattern to parse or format
16 * We also allow the user to use any customized pattern to parse or format 16 /// date-time strings under certain locales. Date elements that vary across
17 * date-time strings under certain locales. Date elements that vary across 17 /// locales include month name, weekname, field, order, etc.
18 * locales include month name, weekname, field, order, etc. 18 ///
19 * 19 /// Formatting dates in the default "en_US" format does not require any
20 * Formatting dates in the default "en_US" format does not require any 20 /// initialization. e.g.
21 * initialization. e.g. 21 /// print(new DateFormat.yMMMd().format(new DateTime.now()));
22 * print(new DateFormat.yMMMd().format(new Date.now())); 22 ///
23 * 23 /// But for other locales, the formatting data for the locale must be
24 * But for other locales, the formatting data for the locale must be 24 /// obtained. This can currently be done in one of three ways, determined by
25 * obtained. This can currently be done 25 /// which library you import. In all cases, the "initializeDateFormatting"
26 * in one of three ways, determined by which library you import. In all cases, 26 /// method must be called and will return a future that is complete once the
27 * the "initializeDateFormatting" method must be called and will return a future 27 /// locale data is available. The result of the future isn't important, but the
28 * that is complete once the locale data is available. The result of the future 28 /// data for that locale is available to the date formatting and parsing once it
29 * isn't important, but the data for that locale is available to the date 29 /// completes.
30 * formatting and parsing once it completes. 30 ///
31 * 31 /// The easiest option is that the data may be available locally, imported in a
32 * The easiest option is that the data may be available locally, imported in a 32 /// library that contains data for all the locales.
33 * library that contains data for all the locales. 33 /// import 'package:intl/date_symbol_data_local.dart';
34 * import 'package:intl/date_symbol_data_local.dart'; 34 /// initializeDateFormatting("fr_FR", null).then((_) => runMyCode());
35 * initializeDateFormatting("fr_FR", null).then((_) => runMyCode()); 35 ///
36 * 36 /// If we are running outside of a browser, we may want to read the data
37 * If we are running outside of a browser, we may want to read the data 37 /// from files in the file system.
38 * from files in the file system. 38 /// import 'package:intl/date_symbol_data_file.dart';
39 * import 'package:intl/date_symbol_data_file.dart'; 39 /// initializeDateFormatting("de_DE", null).then((_) => runMyCode());
40 * initializeDateFormatting("de_DE", null).then((_) => runMyCode()); 40 ///
41 * 41 /// If we are running in a browser, we may want to read the data from the
42 * If we are running in a browser, we may want to read the data from the 42 /// server using the XmlHttpRequest mechanism.
43 * server using the XmlHttpRequest mechanism. 43 /// import 'package:intl/date_symbol_data_http_request.dart';
44 * import 'package:intl/date_symbol_data_http_request.dart'; 44 /// initializeDateFormatting("pt_BR", null).then((_) => runMyCode());
45 * initializeDateFormatting("pt_BR", null).then((_) => runMyCode()); 45 ///
46 * 46 /// The code in example/basic/basic_example.dart shows a full example of
47 * The code in example/basic/basic_example.dart shows a full example of 47 /// using this mechanism.
48 * using this mechanism. 48 ///
49 * 49 /// Once we have the locale data, we need to specify the particular format.
50 * Once we have the locale data, we need to specify the particular format. 50 /// This library uses the ICU/JDK date/time pattern specification both for
51 * This library uses the ICU/JDK date/time pattern specification both for 51 /// complete format specifications and also the abbreviated "skeleton" form
52 * complete format specifications and also the abbreviated "skeleton" form 52 /// which can also adapt to different locales and is preferred where available.
53 * which can also adapt to different locales and is preferred where available. 53 ///
54 * 54 /// Skeletons: These can be specified either as the ICU constant name or as the
55 * Skeletons: These can be specified either as the ICU constant name or as the 55 /// skeleton to which it resolves. The supported set of skeletons is as follows.
56 * skeleton to which it resolves. The supported set of skeletons is as follows. 56 /// For each skeleton there is a named constructor that can be used to create
57 * For each skeleton there is a named constructor that can be used to create it. 57 /// it. It's also possible to pass the skeleton as a string, but the
58 * It's also possible to pass the skeleton as a string, but the constructor 58 /// constructor is preferred.
59 * is preferred. 59 ///
60 * 60 /// ICU Name Skeleton
61 * ICU Name Skeleton 61 /// -------- --------
62 * -------- -------- 62 /// DAY d
63 * DAY d 63 /// ABBR_WEEKDAY E
64 * ABBR_WEEKDAY E 64 /// WEEKDAY EEEE
65 * WEEKDAY EEEE 65 /// ABBR_STANDALONE_MONTH LLL
66 * ABBR_STANDALONE_MONTH LLL 66 /// STANDALONE_MONTH LLLL
67 * STANDALONE_MONTH LLLL 67 /// NUM_MONTH M
68 * NUM_MONTH M 68 /// NUM_MONTH_DAY Md
69 * NUM_MONTH_DAY Md 69 /// NUM_MONTH_WEEKDAY_DAY MEd
70 * NUM_MONTH_WEEKDAY_DAY MEd 70 /// ABBR_MONTH MMM
71 * ABBR_MONTH MMM 71 /// ABBR_MONTH_DAY MMMd
72 * ABBR_MONTH_DAY MMMd 72 /// ABBR_MONTH_WEEKDAY_DAY MMMEd
73 * ABBR_MONTH_WEEKDAY_DAY MMMEd 73 /// MONTH MMMM
74 * MONTH MMMM 74 /// MONTH_DAY MMMMd
75 * MONTH_DAY MMMMd 75 /// MONTH_WEEKDAY_DAY MMMMEEEEd
76 * MONTH_WEEKDAY_DAY MMMMEEEEd 76 /// ABBR_QUARTER QQQ
77 * ABBR_QUARTER QQQ 77 /// QUARTER QQQQ
78 * QUARTER QQQQ 78 /// YEAR y
79 * YEAR y 79 /// YEAR_NUM_MONTH yM
80 * YEAR_NUM_MONTH yM 80 /// YEAR_NUM_MONTH_DAY yMd
81 * YEAR_NUM_MONTH_DAY yMd 81 /// YEAR_NUM_MONTH_WEEKDAY_DAY yMEd
82 * YEAR_NUM_MONTH_WEEKDAY_DAY yMEd 82 /// YEAR_ABBR_MONTH yMMM
83 * YEAR_ABBR_MONTH yMMM 83 /// YEAR_ABBR_MONTH_DAY yMMMd
84 * YEAR_ABBR_MONTH_DAY yMMMd 84 /// YEAR_ABBR_MONTH_WEEKDAY_DAY yMMMEd
85 * YEAR_ABBR_MONTH_WEEKDAY_DAY yMMMEd 85 /// YEAR_MONTH yMMMM
86 * YEAR_MONTH yMMMM 86 /// YEAR_MONTH_DAY yMMMMd
87 * YEAR_MONTH_DAY yMMMMd 87 /// YEAR_MONTH_WEEKDAY_DAY yMMMMEEEEd
88 * YEAR_MONTH_WEEKDAY_DAY yMMMMEEEEd 88 /// YEAR_ABBR_QUARTER yQQQ
89 * YEAR_ABBR_QUARTER yQQQ 89 /// YEAR_QUARTER yQQQQ
90 * YEAR_QUARTER yQQQQ 90 /// HOUR24 H
91 * HOUR24 H 91 /// HOUR24_MINUTE Hm
92 * HOUR24_MINUTE Hm 92 /// HOUR24_MINUTE_SECOND Hms
93 * HOUR24_MINUTE_SECOND Hms 93 /// HOUR j
94 * HOUR j 94 /// HOUR_MINUTE jm
95 * HOUR_MINUTE jm 95 /// HOUR_MINUTE_SECOND jms
96 * HOUR_MINUTE_SECOND jms 96 /// HOUR_MINUTE_GENERIC_TZ jmv
97 * HOUR_MINUTE_GENERIC_TZ jmv 97 /// HOUR_MINUTE_TZ jmz
98 * HOUR_MINUTE_TZ jmz 98 /// HOUR_GENERIC_TZ jv
99 * HOUR_GENERIC_TZ jv 99 /// HOUR_TZ jz
100 * HOUR_TZ jz 100 /// MINUTE m
101 * MINUTE m 101 /// MINUTE_SECOND ms
102 * MINUTE_SECOND ms 102 /// SECOND s
103 * SECOND s 103 ///
104 * 104 /// Examples Using the US Locale:
105 * Examples Using the US Locale: 105 ///
106 * 106 /// Pattern Result
107 * Pattern Result 107 /// ---------------- -------
108 * ---------------- ------- 108 /// new DateFormat.yMd() -> 7/10/1996
109 * new DateFormat.yMd() -> 7/10/1996 109 /// new DateFormat("yMd") -> 7/10/1996
110 * new DateFormat("yMd") -> 7/10/1996 110 /// new DateFormat.yMMMMd("en_US") -> July 10, 1996
111 * new DateFormat.yMMMMd("en_US") -> July 10, 1996 111 /// new DateFormat.jm() -> 5:08 PM
112 * new DateFormat.jm() -> 5:08 PM 112 /// new DateFormat.yMd().add_jm() -> 7/10/1996 5:08 PM
113 * new DateFormat.yMd().add_jm() -> 7/10/1996 5:08 PM 113 /// new DateFormat.Hm() -> 17:08 // force 24 hour time
114 * new DateFormat.Hm() -> 17:08 // force 24 hour time 114 ///
115 * 115 /// Explicit Pattern Syntax: Formats can also be specified with a pattern
116 * Explicit Pattern Syntax: Formats can also be specified with a pattern string. 116 /// string. This can be used for formats that don't have a skeleton available,
117 * This can be used for formats that don't have a skeleton available, but these 117 /// but these will not adapt to different locales. For example, in an explicit
118 * will not adapt to different locales. For example, in an explicit pattern the 118 /// pattern the letters "H" and "h" are available for 24 hour and 12 hour time
119 * letters "H" and "h" are available for 24 hour and 12 hour time formats 119 /// formats respectively. But there isn't a way in an explicit pattern to get
120 * respectively. But there isn't a way in an explicit pattern to get the 120 /// the behaviour of the "j" skeleton, which prints 24 hour or 12 hour time
121 * behaviour of the "j" skeleton, which prints 24 hour or 12 hour time according 121 /// according to the conventions of the locale, and also includes am/pm markers
122 * to the conventions of the locale, and also includes am/pm markers where 122 /// where appropriate. So it is preferable to use the skeletons.
123 * appropriate. So it is preferable to use the skeletons. 123 ///
124 * 124 /// The following characters are available in explicit patterns:
125 * The following characters are available in explicit patterns: 125 ///
126 * 126 /// Symbol Meaning Presentation Example
127 * Symbol Meaning Presentation Example 127 /// ------ ------- ------------ -------
128 * ------ ------- ------------ ------- 128 /// G era designator (Text) AD
129 * G era designator (Text) AD 129 /// y year (Number) 1996
130 * y year (Number) 1996 130 /// M month in year (Text & Number) July & 07
131 * M month in year (Text & Number) July & 07 131 /// L standalone month (Text & Number) July & 07
132 * L standalone month (Text & Number) July & 07 132 /// d day in month (Number) 10
133 * d day in month (Number) 10 133 /// c standalone day (Number) 10
134 * c standalone day (Number) 10 134 /// h hour in am/pm (1~12) (Number) 12
135 * h hour in am/pm (1~12) (Number) 12 135 /// H hour in day (0~23) (Number) 0
136 * H hour in day (0~23) (Number) 0 136 /// m minute in hour (Number) 30
137 * m minute in hour (Number) 30 137 /// s second in minute (Number) 55
138 * s second in minute (Number) 55 138 /// S fractional second (Number) 978
139 * S fractional second (Number) 978 139 /// E day of week (Text) Tuesday
140 * E day of week (Text) Tuesday 140 /// D day in year (Number) 189
141 * D day in year (Number) 189 141 /// a am/pm marker (Text) PM
142 * a am/pm marker (Text) PM 142 /// k hour in day (1~24) (Number) 24
143 * k hour in day (1~24) (Number) 24 143 /// K hour in am/pm (0~11) (Number) 0
144 * K hour in am/pm (0~11) (Number) 0 144 /// z time zone (Text) Pacific Standard Time
145 * z time zone (Text) Pacific Standard Time 145 /// Z time zone (RFC 822) (Number) -0800
146 * Z time zone (RFC 822) (Number) -0800 146 /// v time zone (generic) (Text) Pacific Time
147 * v time zone (generic) (Text) Pacific Time 147 /// Q quarter (Text) Q3
148 * Q quarter (Text) Q3 148 /// ' escape for text (Delimiter) 'Date='
149 * ' escape for text (Delimiter) 'Date=' 149 /// '' single quote (Literal) 'o''clock'
150 * '' single quote (Literal) 'o''clock' 150 ///
151 * 151 /// The count of pattern letters determine the format.
152 * The count of pattern letters determine the format. 152 ///
153 * 153 /// **Text**:
154 * **Text**: 154 /// * 5 pattern letters--use narrow form for standalone. Otherwise not used.
155 * * 5 pattern letters--use narrow form for standalone. Otherwise does not apply 155 /// * 4 or more pattern letters--use full form,
156 * * 4 or more pattern letters--use full form, 156 /// * 3 pattern letters--use short or abbreviated form if one exists
157 * * 3 pattern letters--use short or abbreviated form if one exists 157 /// * less than 3--use numeric form if one exists
158 * * less than 3--use numeric form if one exists 158 ///
159 * 159 /// **Number**: the minimum number of digits. Shorter numbers are zero-padded to
160 * **Number**: the minimum number of digits. Shorter numbers are zero-padded to 160 /// this amount (e.g. if "m" produces "6", "mm" produces "06"). Year is handled
161 * this amount (e.g. if "m" produces "6", "mm" produces "06"). Year is handled 161 /// specially; that is, if the count of 'y' is 2, the Year will be truncated to
162 * specially; that is, if the count of 'y' is 2, the Year will be truncated to 162 /// 2 digits. (e.g., if "yyyy" produces "1997", "yy" produces "97".) Unlike
163 * 2 digits. (e.g., if "yyyy" produces "1997", "yy" produces "97".) Unlike other 163 /// other fields, fractional seconds are padded on the right with zero.
164 * fields, fractional seconds are padded on the right with zero. 164 ///
165 * 165 /// **(Text & Number)**: 3 or over, use text, otherwise use number.
166 * **(Text & Number)**: 3 or over, use text, otherwise use number. 166 ///
167 * 167 /// Any characters not in the pattern will be treated as quoted text. For
168 * Any characters not in the pattern will be treated as quoted text. For 168 /// instance, characters like ':', '.', ' ', '#' and '@' will appear in the
169 * instance, characters like ':', '.', ' ', '#' and '@' will appear in the 169 /// resulting text even though they are not enclosed in single quotes. In our
170 * resulting text even though they are not enclosed in single quotes. In our 170 /// current pattern usage, not all letters have meanings. But those unused
171 * current pattern usage, not all letters have meanings. But those unused 171 /// letters are strongly discouraged to be used as quoted text without quotes,
172 * letters are strongly discouraged to be used as quoted text without quotes, 172 /// because we may use other letters as pattern characters in the future.
173 * because we may use other letters as pattern characters in the future. 173 ///
174 * 174 /// Examples Using the US Locale:
175 * Examples Using the US Locale: 175 ///
176 * 176 /// Format Pattern Result
177 * Format Pattern Result 177 /// -------------- -------
178 * -------------- ------- 178 /// "yyyy.MM.dd G 'at' HH:mm:ss vvvv" 1996.07.10 AD at 15:08:56 Pacific Time
179 * "yyyy.MM.dd G 'at' HH:mm:ss vvvv" 1996.07.10 AD at 15:08:56 Pacific Time 179 /// "EEE, MMM d, ''yy" Wed, July 10, '96
180 * "EEE, MMM d, ''yy" Wed, July 10, '96 180 /// "h:mm a" 12:08 PM
181 * "h:mm a" 12:08 PM 181 /// "hh 'o''clock' a, zzzz" 12 o'clock PM, Pacific Daylight Time
182 * "hh 'o''clock' a, zzzz" 12 o'clock PM, Pacific Daylight Time 182 /// "K:mm a, vvv" 0:00 PM, PT
183 * "K:mm a, vvv" 0:00 PM, PT 183 /// "yyyyy.MMMMM.dd GGG hh:mm aaa" 01996.July.10 AD 12:08 PM
184 * "yyyyy.MMMMM.dd GGG hh:mm aaa" 01996.July.10 AD 12:08 PM 184 ///
185 * 185 /// When parsing a date string using the abbreviated year pattern ("yy"),
186 * When parsing a date string using the abbreviated year pattern ("yy"), 186 /// DateFormat must interpret the abbreviated year relative to some
187 * DateFormat must interpret the abbreviated year relative to some 187 /// century. It does this by adjusting dates to be within 80 years before and 20
188 * century. It does this by adjusting dates to be within 80 years before and 20 188 /// years after the time the parse function is called. For example, using a
189 * years after the time the parse function is called. For example, using a 189 /// pattern of "MM/dd/yy" and a DateParse instance created on Jan 1, 1997,
190 * pattern of "MM/dd/yy" and a DateParse instance created on Jan 1, 1997, 190 /// the string "01/11/12" would be interpreted as Jan 11, 2012 while the string
191 * the string "01/11/12" would be interpreted as Jan 11, 2012 while the string 191 /// "05/04/64" would be interpreted as May 4, 1964. During parsing, only
192 * "05/04/64" would be interpreted as May 4, 1964. During parsing, only 192 /// strings consisting of exactly two digits, as defined by {@link
193 * strings consisting of exactly two digits, as defined by {@link 193 /// java.lang.Character#isDigit(char)}, will be parsed into the default
194 * java.lang.Character#isDigit(char)}, will be parsed into the default 194 /// century. Any other numeric string, such as a one digit string, a three or
195 * century. Any other numeric string, such as a one digit string, a three or 195 /// more digit string will be interpreted as its face value.
196 * more digit string will be interpreted as its face value. 196 ///
197 * 197 /// If the year pattern does not have exactly two 'y' characters, the year is
198 * If the year pattern does not have exactly two 'y' characters, the year is 198 /// interpreted literally, regardless of the number of digits. So using the
199 * interpreted literally, regardless of the number of digits. So using the 199 /// pattern "MM/dd/yyyy", "01/11/12" parses to Jan 11, 12 A.D.
200 * pattern "MM/dd/yyyy", "01/11/12" parses to Jan 11, 12 A.D.
201 */
202 200
203 class DateFormat { 201 class DateFormat {
204 202 /// Creates a new DateFormat, using the format specified by [newPattern]. For
205 /** 203 /// forms that match one of our predefined skeletons, we look up the
206 * Creates a new DateFormat, using the format specified by [newPattern]. For 204 /// corresponding pattern in [locale] (or in the default locale if none is
207 * forms that match one of our predefined skeletons, we look up the 205 /// specified) and use the resulting full format string. This is the
208 * corresponding pattern in [locale] (or in the default locale if none is 206 /// preferred usage, but if [newPattern] does not match one of the skeletons,
209 * specified) and use the resulting full format string. This is the 207 /// then it is used as a format directly, but will not be adapted to suit
210 * preferred usage, but if [newPattern] does not match one of the skeletons, 208 /// the locale.
211 * then it is used as a format directly, but will not be adapted to suit 209 ///
212 * the locale. 210 /// For example, in an en_US locale, specifying the skeleton
213 * 211 /// new DateFormat.yMEd();
214 * For example, in an en_US locale, specifying the skeleton 212 /// or the explicit
215 * new DateFormat.yMEd(); 213 /// new DateFormat('EEE, M/d/y');
216 * or the explicit 214 /// would produce the same result, a date of the form
217 * new DateFormat('EEE, M/d/y'); 215 /// Wed, 6/27/2012
218 * would produce the same result, a date of the form 216 /// The first version would produce a different format string if used in
219 * Wed, 6/27/2012 217 /// another locale, but the second format would always be the same.
220 * The first version would produce a different format string if used in 218 ///
221 * another locale, but the second format would always be the same. 219 /// If [locale] does not exist in our set of supported locales then an
222 * 220 /// [ArgumentError] is thrown.
223 * If [locale] does not exist in our set of supported locales then an
224 * [ArgumentError] is thrown.
225 */
226 DateFormat([String newPattern, String locale]) { 221 DateFormat([String newPattern, String locale]) {
227 // TODO(alanknight): It should be possible to specify multiple skeletons eg 222 // TODO(alanknight): It should be possible to specify multiple skeletons eg
228 // date, time, timezone all separately. Adding many or named parameters to 223 // date, time, timezone all separately. Adding many or named parameters to
229 // the constructor seems awkward, especially with the possibility of 224 // the constructor seems awkward, especially with the possibility of
230 // confusion with the locale. A "fluent" interface with cascading on an 225 // confusion with the locale. A "fluent" interface with cascading on an
231 // instance might work better? A list of patterns is also possible. 226 // instance might work better? A list of patterns is also possible.
232 _locale = Intl.verifiedLocale(locale, localeExists); 227 _locale = Intl.verifiedLocale(locale, localeExists);
233 addPattern(newPattern); 228 addPattern(newPattern);
234 } 229 }
235 230
236 /** 231 /// Return a string representing [date] formatted according to our locale
237 * Return a string representing [date] formatted according to our locale 232 /// and internal format.
238 * and internal format.
239 */
240 String format(DateTime date) { 233 String format(DateTime date) {
241 // TODO(efortuna): read optional TimeZone argument (or similar)? 234 // TODO(efortuna): read optional TimeZone argument (or similar)?
242 var result = new StringBuffer(); 235 var result = new StringBuffer();
243 _formatFields.forEach((field) => result.write(field.format(date))); 236 _formatFields.forEach((field) => result.write(field.format(date)));
244 return result.toString(); 237 return result.toString();
245 } 238 }
246 239
247 /** 240 /// NOT YET IMPLEMENTED.
248 * NOT YET IMPLEMENTED. 241 ///
249 * 242 /// Returns a date string indicating how long ago (3 hours, 2 minutes)
250 * Returns a date string indicating how long ago (3 hours, 2 minutes) 243 /// something has happened or how long in the future something will happen
251 * something has happened or how long in the future something will happen 244 /// given a [reference] DateTime relative to the current time.
252 * given a [reference] DateTime relative to the current time.
253 */
254 String formatDuration(DateTime reference) => ''; 245 String formatDuration(DateTime reference) => '';
255 246
256 /** 247 /// NOT YET IMPLEMENTED.
257 * NOT YET IMPLEMENTED. 248 ///
258 * 249 /// Formats a string indicating how long ago (negative [duration]) or how far
259 * Formats a string indicating how long ago (negative [duration]) or how far 250 /// in the future (positive [duration]) some time is with respect to a
260 * in the future (positive [duration]) some time is with respect to a 251 /// reference [date].
261 * reference [date].
262 */
263 String formatDurationFrom(Duration duration, DateTime date) => ''; 252 String formatDurationFrom(Duration duration, DateTime date) => '';
264 253
265 /** 254 /// Given user input, attempt to parse the [inputString] into the anticipated
266 * Given user input, attempt to parse the [inputString] into the anticipated 255 /// format, treating it as being in the local timezone. If [inputString] does
267 * format, treating it as being in the local timezone. If [inputString] does 256 /// not match our format, throws a [FormatException]. This will accept dates
268 * not match our format, throws a [FormatException]. This will accept dates 257 /// whose values are not strictly valid, or strings with additional characters
269 * whose values are not strictly valid, or strings with additional characters 258 /// (including whitespace) after a valid date. For stricter parsing, use
270 * (including whitespace) after a valid date. For stricter parsing, use 259 /// [parseStrict].
271 * [parseStrict].
272 */
273 DateTime parse(String inputString, [utc = false]) => 260 DateTime parse(String inputString, [utc = false]) =>
274 _parse(inputString, utc: utc, strict: false); 261 _parse(inputString, utc: utc, strict: false);
275 262
276 /** 263 /// Given user input, attempt to parse the [inputString] "loosely" into the
277 * Given user input, attempt to parse the [inputString] "loosely" into the 264 /// anticipated format, accepting some variations from the strict format.
278 * anticipated format, accepting some variations from the strict format. 265 ///
279 * 266 /// If [inputString]
280 * If [inputString] 267 /// is accepted by [parseStrict], just return the result. If not, attempt to
281 * is accepted by [parseStrict], just return the result. If not, attempt to 268 /// parse it, but accepting either upper or
282 * parse it, but accepting either upper or 269 /// lower case, allowing delimiters to be missing and replaced or
283 * lower case, allowing delimiters to be missing and replaced or 270 /// supplemented with whitespace,
284 * supplemented with whitespace, 271 /// and allowing arbitrary amounts of whitespace wherever whitespace is
285 * and allowing arbitrary amounts of whitespace wherever whitespace is 272 /// permitted. Note that this does not allow trailing characters, the way
286 * permitted. Note that this does not allow trailing characters, the way 273 /// [parse] does.
287 * [parse] does. It also does not allow leading whitespace on delimiters, 274 /// It also does not allow alternative names for months or weekdays other than
288 * and does not allow alternative names for months or weekdays other than 275 /// those the format knows about. The restrictions are quite arbitrary and
289 * those the format knows about. The restrictions are quite arbitrary and 276 /// it's not known how well they'll work for locales that aren't English-like.
290 * it's not known how well they'll work for locales that aren't English-like. 277 ///
291 * 278 /// If [inputString] does not parse, this throws a
292 * If [inputString] does not parse, this throws a 279 /// [FormatException].
293 * [FormatException]. 280 ///
294 * 281 /// For example, this will accept
295 * For example, this will accept 282 ///
296 * 283 /// new DateFormat.yMMMd("en_US").parseLoose("SEp 3 2014");
297 * new DateFormat.yMMMd("en_US").parseLoose("SEp 3 2014"); 284 /// new DateFormat.yMd("en_US").parseLoose("09 03/2014");
298 * new DateFormat.yMd("en_US").parseLoose("09 03/2014"); 285 /// new DateFormat.yMd("en_US").parseLoose("09 / 03 / 2014");
299 * 286 ///
300 * It will NOT accept 287 /// It will NOT accept
301 * 288 ///
302 * // "Sept" is not a valid month name. 289 /// // "Sept" is not a valid month name.
303 * new DateFormat.yMMMd("en_US").parseLoose("Sept 3, 2014"); 290 /// new DateFormat.yMMMd("en_US").parseLoose("Sept 3, 2014");
304 * // Delimiters can't have leading whitespace.
305 * new DateFormat.yMd("en_US").parseLoose("09 / 03 / 2014");
306 */
307 DateTime parseLoose(String inputString, [utc = false]) { 291 DateTime parseLoose(String inputString, [utc = false]) {
308 try { 292 try {
309 return _parse(inputString, utc: utc, strict: true); 293 return _parse(inputString, utc: utc, strict: true);
310 } on FormatException { 294 } on FormatException {
311 return _parseLoose(inputString.toLowerCase(), utc); 295 return _parseLoose(inputString.toLowerCase(), utc);
312 } 296 }
313 } 297 }
314 298
315 _parseLoose(String inputString, bool utc) { 299 _parseLoose(String inputString, bool utc) {
316 var dateFields = new _DateBuilder(); 300 var dateFields = new _DateBuilder();
317 if (utc) dateFields.utc = true; 301 if (utc) dateFields.utc = true;
318 var stream = new _Stream(inputString); 302 var stream = new _Stream(inputString);
319 _formatFields.forEach((f) => f.parseLoose(stream, dateFields)); 303 _formatFields.forEach((f) => f.parseLoose(stream, dateFields));
320 if (!stream.atEnd()) { 304 if (!stream.atEnd()) {
321 throw new FormatException( 305 throw new FormatException(
322 "Characters remaining after date parsing in $inputString"); 306 "Characters remaining after date parsing in $inputString");
323 } 307 }
324 dateFields.verify(inputString); 308 dateFields.verify(inputString);
325 return dateFields.asDate(); 309 return dateFields.asDate();
326 } 310 }
327 311
328 /** 312 /// Given user input, attempt to parse the [inputString] into the anticipated
329 * Given user input, attempt to parse the [inputString] into the anticipated 313 /// format, treating it as being in the local timezone. If [inputString] does
330 * format, treating it as being in the local timezone. If [inputString] does 314 /// not match our format, throws a [FormatException]. This will reject dates
331 * not match our format, throws a [FormatException]. This will reject dates 315 /// whose values are not strictly valid, even if the
332 * whose values are not strictly valid, even if the 316 /// DateTime constructor will accept them. It will also rejct strings with
333 * DateTime constructor will accept them. It will also rejct strings with 317 /// additional characters (including whitespace) after a valid date. For
334 * additional characters (including whitespace) after a valid date. For 318 /// looser parsing, use [parse].
335 * looser parsing, use [parse].
336 */
337 DateTime parseStrict(String inputString, [utc = false]) => 319 DateTime parseStrict(String inputString, [utc = false]) =>
338 _parse(inputString, utc: utc, strict: true); 320 _parse(inputString, utc: utc, strict: true);
339 321
340 DateTime _parse(String inputString, {utc: false, strict: false}) { 322 DateTime _parse(String inputString, {utc: false, strict: false}) {
341 // TODO(alanknight): The Closure code refers to special parsing of numeric 323 // TODO(alanknight): The Closure code refers to special parsing of numeric
342 // values with no delimiters, which we currently don't do. Should we? 324 // values with no delimiters, which we currently don't do. Should we?
343 var dateFields = new _DateBuilder(); 325 var dateFields = new _DateBuilder();
344 if (utc) dateFields.utc = true; 326 if (utc) dateFields.utc = true;
345 var stream = new _Stream(inputString); 327 var stream = new _Stream(inputString);
346 _formatFields.forEach((f) => f.parse(stream, dateFields)); 328 _formatFields.forEach((f) => f.parse(stream, dateFields));
347 if (strict && !stream.atEnd()) { 329 if (strict && !stream.atEnd()) {
348 throw new FormatException( 330 throw new FormatException(
349 "Characters remaining after date parsing in $inputString"); 331 "Characters remaining after date parsing in $inputString");
350 } 332 }
351 if (strict) dateFields.verify(inputString); 333 if (strict) dateFields.verify(inputString);
352 return dateFields.asDate(); 334 return dateFields.asDate();
353 } 335 }
354 336
355 /** 337 /// Given user input, attempt to parse the [inputString] into the anticipated
356 * Given user input, attempt to parse the [inputString] into the anticipated 338 /// format, treating it as being in UTC.
357 * format, treating it as being in UTC. 339 ///
358 * 340 /// The canonical Dart style name
359 * The canonical Dart style name 341 /// is [parseUtc], but [parseUTC] is retained
360 * is [parseUtc], but [parseUTC] is retained 342 /// for backward-compatibility.
361 * for backward-compatibility.
362 */
363 DateTime parseUTC(String inputString) => parse(inputString, true); 343 DateTime parseUTC(String inputString) => parse(inputString, true);
364 344
365 /** 345 /// Given user input, attempt to parse the [inputString] into the anticipated
366 * Given user input, attempt to parse the [inputString] into the anticipated 346 /// format, treating it as being in UTC.
367 * format, treating it as being in UTC. 347 ///
368 * 348 /// The canonical Dart style name
369 * The canonical Dart style name 349 /// is [parseUtc], but [parseUTC] is retained
370 * is [parseUtc], but [parseUTC] is retained 350 /// for backward-compatibility.
371 * for backward-compatibility.
372 */
373 DateTime parseUtc(String inputString) => parse(inputString, true); 351 DateTime parseUtc(String inputString) => parse(inputString, true);
374 352
375 /** 353 /// Return the locale code in which we operate, e.g. 'en_US' or 'pt'.
376 * Return the locale code in which we operate, e.g. 'en_US' or 'pt'.
377 */
378 String get locale => _locale; 354 String get locale => _locale;
379 355
380 /** 356 /// Returns a list of all locales for which we have date formatting
381 * Returns a list of all locales for which we have date formatting 357 /// information.
382 * information. 358 static List<String> allLocalesWithSymbols() =>
383 */ 359 new List<String>.from(dateTimeSymbols.keys);
384 static List<String> allLocalesWithSymbols() => dateTimeSymbols.keys.toList();
385 360
386 /** 361 /// The named constructors for this class are all conveniences for creating
387 * The named constructors for this class are all conveniences for creating 362 /// instances using one of the known "skeleton" formats, and having code
388 * instances using one of the known "skeleton" formats, and having code 363 /// completion support for discovering those formats.
389 * completion support for discovering those formats. 364 /// So,
390 * So, 365 /// new DateFormat.yMd("en_US")
391 * new DateFormat.yMd("en_US") 366 /// is equivalent to
392 * is equivalent to 367 /// new DateFormat("yMd", "en_US")
393 * new DateFormat("yMd", "en_US") 368 /// To create a compound format you can use these constructors in combination
394 * To create a compound format you can use these constructors in combination 369 /// with the add_ methods below. e.g.
395 * with the add_ methods below. e.g. 370 /// new DateFormat.yMd().add_Hms();
396 * new DateFormat.yMd().add_Hms(); 371 /// If the optional [locale] is omitted, the format will be created using the
397 * If the optional [locale] is omitted, the format will be created using the 372 /// default locale in [Intl.systemLocale].
398 * default locale in [Intl.systemLocale].
399 */
400 DateFormat.d([locale]) : this("d", locale); 373 DateFormat.d([locale]) : this("d", locale);
401 DateFormat.E([locale]) : this("E", locale); 374 DateFormat.E([locale]) : this("E", locale);
402 DateFormat.EEEE([locale]) : this("EEEE", locale); 375 DateFormat.EEEE([locale]) : this("EEEE", locale);
403 DateFormat.LLL([locale]) : this("LLL", locale); 376 DateFormat.LLL([locale]) : this("LLL", locale);
404 DateFormat.LLLL([locale]) : this("LLLL", locale); 377 DateFormat.LLLL([locale]) : this("LLLL", locale);
405 DateFormat.M([locale]) : this("M", locale); 378 DateFormat.M([locale]) : this("M", locale);
406 DateFormat.Md([locale]) : this("Md", locale); 379 DateFormat.Md([locale]) : this("Md", locale);
407 DateFormat.MEd([locale]) : this("MEd", locale); 380 DateFormat.MEd([locale]) : this("MEd", locale);
408 DateFormat.MMM([locale]) : this("MMM", locale); 381 DateFormat.MMM([locale]) : this("MMM", locale);
409 DateFormat.MMMd([locale]) : this("MMMd", locale); 382 DateFormat.MMMd([locale]) : this("MMMd", locale);
(...skipping 22 matching lines...) Expand all
432 DateFormat.jm([locale]) : this("jm", locale); 405 DateFormat.jm([locale]) : this("jm", locale);
433 DateFormat.jms([locale]) : this("jms", locale); 406 DateFormat.jms([locale]) : this("jms", locale);
434 DateFormat.jmv([locale]) : this("jmv", locale); 407 DateFormat.jmv([locale]) : this("jmv", locale);
435 DateFormat.jmz([locale]) : this("jmz", locale); 408 DateFormat.jmz([locale]) : this("jmz", locale);
436 DateFormat.jv([locale]) : this("jv", locale); 409 DateFormat.jv([locale]) : this("jv", locale);
437 DateFormat.jz([locale]) : this("jz", locale); 410 DateFormat.jz([locale]) : this("jz", locale);
438 DateFormat.m([locale]) : this("m", locale); 411 DateFormat.m([locale]) : this("m", locale);
439 DateFormat.ms([locale]) : this("ms", locale); 412 DateFormat.ms([locale]) : this("ms", locale);
440 DateFormat.s([locale]) : this("s", locale); 413 DateFormat.s([locale]) : this("s", locale);
441 414
442 /** 415 /// The "add_*" methods append a particular skeleton to the format, or set
443 * The "add_*" methods append a particular skeleton to the format, or set 416 /// it as the only format if none was previously set. These are primarily
444 * it as the only format if none was previously set. These are primarily 417 /// useful for creating compound formats. For example
445 * useful for creating compound formats. For example 418 /// new DateFormat.yMd().add_Hms();
446 * new DateFormat.yMd().add_Hms(); 419 /// would create a date format that prints both the date and the time.
447 * would create a date format that prints both the date and the time.
448 */
449 DateFormat add_d() => addPattern("d"); 420 DateFormat add_d() => addPattern("d");
450 DateFormat add_E() => addPattern("E"); 421 DateFormat add_E() => addPattern("E");
451 DateFormat add_EEEE() => addPattern("EEEE"); 422 DateFormat add_EEEE() => addPattern("EEEE");
452 DateFormat add_LLL() => addPattern("LLL"); 423 DateFormat add_LLL() => addPattern("LLL");
453 DateFormat add_LLLL() => addPattern("LLLL"); 424 DateFormat add_LLLL() => addPattern("LLLL");
454 DateFormat add_M() => addPattern("M"); 425 DateFormat add_M() => addPattern("M");
455 DateFormat add_Md() => addPattern("Md"); 426 DateFormat add_Md() => addPattern("Md");
456 DateFormat add_MEd() => addPattern("MEd"); 427 DateFormat add_MEd() => addPattern("MEd");
457 DateFormat add_MMM() => addPattern("MMM"); 428 DateFormat add_MMM() => addPattern("MMM");
458 DateFormat add_MMMd() => addPattern("MMMd"); 429 DateFormat add_MMMd() => addPattern("MMMd");
(...skipping 22 matching lines...) Expand all
481 DateFormat add_jm() => addPattern("jm"); 452 DateFormat add_jm() => addPattern("jm");
482 DateFormat add_jms() => addPattern("jms"); 453 DateFormat add_jms() => addPattern("jms");
483 DateFormat add_jmv() => addPattern("jmv"); 454 DateFormat add_jmv() => addPattern("jmv");
484 DateFormat add_jmz() => addPattern("jmz"); 455 DateFormat add_jmz() => addPattern("jmz");
485 DateFormat add_jv() => addPattern("jv"); 456 DateFormat add_jv() => addPattern("jv");
486 DateFormat add_jz() => addPattern("jz"); 457 DateFormat add_jz() => addPattern("jz");
487 DateFormat add_m() => addPattern("m"); 458 DateFormat add_m() => addPattern("m");
488 DateFormat add_ms() => addPattern("ms"); 459 DateFormat add_ms() => addPattern("ms");
489 DateFormat add_s() => addPattern("s"); 460 DateFormat add_s() => addPattern("s");
490 461
491 /** 462 /// For each of the skeleton formats we also allow the use of the
492 * For each of the skeleton formats we also allow the use of the corresponding 463 /// corresponding ICU constant names.
493 * ICU constant names.
494 */
495 static const String ABBR_MONTH = 'MMM'; 464 static const String ABBR_MONTH = 'MMM';
496 static const String DAY = 'd'; 465 static const String DAY = 'd';
497 static const String ABBR_WEEKDAY = 'E'; 466 static const String ABBR_WEEKDAY = 'E';
498 static const String WEEKDAY = 'EEEE'; 467 static const String WEEKDAY = 'EEEE';
499 static const String ABBR_STANDALONE_MONTH = 'LLL'; 468 static const String ABBR_STANDALONE_MONTH = 'LLL';
500 static const String STANDALONE_MONTH = 'LLLL'; 469 static const String STANDALONE_MONTH = 'LLLL';
501 static const String NUM_MONTH = 'M'; 470 static const String NUM_MONTH = 'M';
502 static const String NUM_MONTH_DAY = 'Md'; 471 static const String NUM_MONTH_DAY = 'Md';
503 static const String NUM_MONTH_WEEKDAY_DAY = 'MEd'; 472 static const String NUM_MONTH_WEEKDAY_DAY = 'MEd';
504 static const String ABBR_MONTH_DAY = 'MMMd'; 473 static const String ABBR_MONTH_DAY = 'MMMd';
(...skipping 22 matching lines...) Expand all
527 static const String HOUR_MINUTE = 'jm'; 496 static const String HOUR_MINUTE = 'jm';
528 static const String HOUR_MINUTE_SECOND = 'jms'; 497 static const String HOUR_MINUTE_SECOND = 'jms';
529 static const String HOUR_MINUTE_GENERIC_TZ = 'jmv'; 498 static const String HOUR_MINUTE_GENERIC_TZ = 'jmv';
530 static const String HOUR_MINUTE_TZ = 'jmz'; 499 static const String HOUR_MINUTE_TZ = 'jmz';
531 static const String HOUR_GENERIC_TZ = 'jv'; 500 static const String HOUR_GENERIC_TZ = 'jv';
532 static const String HOUR_TZ = 'jz'; 501 static const String HOUR_TZ = 'jz';
533 static const String MINUTE = 'm'; 502 static const String MINUTE = 'm';
534 static const String MINUTE_SECOND = 'ms'; 503 static const String MINUTE_SECOND = 'ms';
535 static const String SECOND = 's'; 504 static const String SECOND = 's';
536 505
537 /** The locale in which we operate, e.g. 'en_US', or 'pt'. */ 506 /// The locale in which we operate, e.g. 'en_US', or 'pt'.
538 String _locale; 507 String _locale;
539 508
540 /** 509 /// The full template string. This may have been specified directly, or
541 * The full template string. This may have been specified directly, or 510 /// it may have been derived from a skeleton and the locale information
542 * it may have been derived from a skeleton and the locale information 511 /// on how to interpret that skeleton.
543 * on how to interpret that skeleton.
544 */
545 String _pattern; 512 String _pattern;
546 513
547 /** 514 /// We parse the format string into individual [_DateFormatField] objects
548 * We parse the format string into individual [_DateFormatField] objects 515 /// that are used to do the actual formatting and parsing. Do not use
549 * that are used to do the actual formatting and parsing. Do not use 516 /// this variable directly, use the getter [_formatFields].
550 * this variable directly, use the getter [_formatFields].
551 */
552 List<_DateFormatField> _formatFieldsPrivate; 517 List<_DateFormatField> _formatFieldsPrivate;
553 518
554 /** 519 /// Getter for [_formatFieldsPrivate] that lazily initializes it.
555 * Getter for [_formatFieldsPrivate] that lazily initializes it. 520 List<_DateFormatField> get _formatFields {
556 */
557 get _formatFields {
558 if (_formatFieldsPrivate == null) { 521 if (_formatFieldsPrivate == null) {
559 if (_pattern == null) _useDefaultPattern(); 522 if (_pattern == null) _useDefaultPattern();
560 _formatFieldsPrivate = parsePattern(_pattern); 523 _formatFieldsPrivate = parsePattern(_pattern);
561 } 524 }
562 return _formatFieldsPrivate; 525 return _formatFieldsPrivate;
563 } 526 }
564 527
565 /** 528 /// We are being asked to do formatting without having set any pattern.
566 * We are being asked to do formatting without having set any pattern. 529 /// Use a default.
567 * Use a default.
568 */
569 _useDefaultPattern() { 530 _useDefaultPattern() {
570 add_yMMMMd(); 531 add_yMMMMd();
571 add_jms(); 532 add_jms();
572 } 533 }
573 534
574 /** 535 /// A series of regular expressions used to parse a format string into its
575 * A series of regular expressions used to parse a format string into its 536 /// component fields.
576 * component fields.
577 */
578 static List<RegExp> _matchers = [ 537 static List<RegExp> _matchers = [
579 // Quoted String - anything between single quotes, with escaping 538 // Quoted String - anything between single quotes, with escaping
580 // of single quotes by doubling them. 539 // of single quotes by doubling them.
581 // e.g. in the pattern "hh 'o''clock'" will match 'o''clock' 540 // e.g. in the pattern "hh 'o''clock'" will match 'o''clock'
582 new RegExp("^\'(?:[^\']|\'\')*\'"), 541 new RegExp("^\'(?:[^\']|\'\')*\'"),
583 // Fields - any sequence of 1 or more of the same field characters. 542 // Fields - any sequence of 1 or more of the same field characters.
584 // e.g. in "hh:mm:ss" will match hh, mm, and ss. But in "hms" would 543 // e.g. in "hh:mm:ss" will match hh, mm, and ss. But in "hms" would
585 // match each letter individually. 544 // match each letter individually.
586 new RegExp( 545 new RegExp(
587 "^(?:G+|y+|M+|k+|S+|E+|a+|h+|K+|H+|c+|L+|Q+|d+|D+|m+|s+|v+|z+|Z+)"), 546 "^(?:G+|y+|M+|k+|S+|E+|a+|h+|K+|H+|c+|L+|Q+|d+|D+|m+|s+|v+|z+|Z+)"),
588 // Everything else - A sequence that is not quotes or field characters. 547 // Everything else - A sequence that is not quotes or field characters.
589 // e.g. in "hh:mm:ss" will match the colons. 548 // e.g. in "hh:mm:ss" will match the colons.
590 new RegExp("^[^\'GyMkSEahKHcLQdDmsvzZ]+") 549 new RegExp("^[^\'GyMkSEahKHcLQdDmsvzZ]+")
591 ]; 550 ];
592 551
593 /** 552 /// Set our pattern, appending it to any existing patterns. Also adds a single
594 * Set our pattern, appending it to any existing patterns. Also adds a single 553 /// space to separate the two.
595 * space to separate the two.
596 */
597 _appendPattern(String inputPattern, [String separator = ' ']) { 554 _appendPattern(String inputPattern, [String separator = ' ']) {
598 _pattern = 555 _pattern =
599 _pattern == null ? inputPattern : "$_pattern$separator$inputPattern"; 556 _pattern == null ? inputPattern : "$_pattern$separator$inputPattern";
600 } 557 }
601 558
602 /** 559 /// Add [inputPattern] to this instance as a pattern. If there was a previous
603 * Add [inputPattern] to this instance as a pattern. If there was a previous 560 /// pattern, then this appends to it, separating the two by [separator].
604 * pattern, then this appends to it, separating the two by [separator]. 561 /// [inputPattern] is first looked up in our list of known skeletons.
605 * [inputPattern] is first looked up in our list of known skeletons. 562 /// If it's found there, then use the corresponding pattern for this locale.
606 * If it's found there, then use the corresponding pattern for this locale. 563 /// If it's not, then treat [inputPattern] as an explicit pattern.
607 * If it's not, then treat [inputPattern] as an explicit pattern.
608 */
609 DateFormat addPattern(String inputPattern, [String separator = ' ']) { 564 DateFormat addPattern(String inputPattern, [String separator = ' ']) {
610 // TODO(alanknight): This is an expensive operation. Caching recently used 565 // TODO(alanknight): This is an expensive operation. Caching recently used
611 // formats, or possibly introducing an entire "locale" object that would 566 // formats, or possibly introducing an entire "locale" object that would
612 // cache patterns for that locale could be a good optimization. 567 // cache patterns for that locale could be a good optimization.
613 // If we have already parsed the format fields, reset them. 568 // If we have already parsed the format fields, reset them.
614 _formatFieldsPrivate = null; 569 _formatFieldsPrivate = null;
615 if (inputPattern == null) return this; 570 if (inputPattern == null) return this;
616 if (!_availableSkeletons.containsKey(inputPattern)) { 571 if (!_availableSkeletons.containsKey(inputPattern)) {
617 _appendPattern(inputPattern, separator); 572 _appendPattern(inputPattern, separator);
618 } else { 573 } else {
619 _appendPattern(_availableSkeletons[inputPattern], separator); 574 _appendPattern(_availableSkeletons[inputPattern], separator);
620 } 575 }
621 return this; 576 return this;
622 } 577 }
623 578
624 /** Return the pattern that we use to format dates.*/ 579 /// Return the pattern that we use to format dates.
625 get pattern => _pattern; 580 get pattern => _pattern;
626 581
627 /** Return the skeletons for our current locale. */ 582 /// Return the skeletons for our current locale.
628 Map get _availableSkeletons => dateTimePatterns[locale]; 583 Map get _availableSkeletons => dateTimePatterns[locale];
629 584
630 /** 585 /// Return the [DateSymbol] information for the locale. This can be useful
631 * Return the [DateSymbol] information for the locale. This can be useful 586 /// to find lists like the names of weekdays or months in a locale, but
632 * to find lists like the names of weekdays or months in a locale, but 587 /// the structure of this data may change, and it's generally better to go
633 * the structure of this data may change, and it's generally better to go 588 /// through the [format] and [parse] APIs. If the locale isn't present, or
634 * through the [format] and [parse] APIs. If the locale isn't present, or 589 /// is uninitialized, returns null;
635 * is uninitialized, returns null; 590 DateSymbols get dateSymbols {
636 */ 591 if (_locale != lastDateSymbolLocale) {
637 DateSymbols get dateSymbols => dateTimeSymbols[_locale]; 592 lastDateSymbolLocale = _locale;
638 593 cachedDateSymbols = dateTimeSymbols[_locale];
639 /** 594 }
640 * Set the locale. If the locale can't be found, we also look up 595 return cachedDateSymbols;
641 * based on alternative versions, e.g. if we have no 'en_CA' we will
642 * look for 'en' as a fallback. It will also translate en-ca into en_CA.
643 * Null is also considered a valid value for [newLocale], indicating
644 * to use the default.
645 */
646 _setLocale(String newLocale) {
647 _locale = Intl.verifiedLocale(newLocale, localeExists);
648 } 596 }
649 597
650 /** 598 /// Return true if the locale exists, or if it is null. The null case
651 * Return true if the locale exists, or if it is null. The null case 599 /// is interpreted to mean that we use the default locale.
652 * is interpreted to mean that we use the default locale.
653 */
654 static bool localeExists(localeName) { 600 static bool localeExists(localeName) {
655 if (localeName == null) return false; 601 if (localeName == null) return false;
656 return dateTimeSymbols.containsKey(localeName); 602 return dateTimeSymbols.containsKey(localeName);
657 } 603 }
658 604
659 static List get _fieldConstructors => [ 605 static List get _fieldConstructors => [
660 (pattern, parent) => new _DateFormatQuotedField(pattern, parent), 606 (pattern, parent) => new _DateFormatQuotedField(pattern, parent),
661 (pattern, parent) => new _DateFormatPatternField(pattern, parent), 607 (pattern, parent) => new _DateFormatPatternField(pattern, parent),
662 (pattern, parent) => new _DateFormatLiteralField(pattern, parent) 608 (pattern, parent) => new _DateFormatLiteralField(pattern, parent)
663 ]; 609 ];
664 610
665 /** Parse the template pattern and return a list of field objects.*/ 611 /// Parse the template pattern and return a list of field objects.
666 List parsePattern(String pattern) { 612 List<_DateFormatField> parsePattern(String pattern) {
667 if (pattern == null) return null; 613 if (pattern == null) return null;
668 return _parsePatternHelper(pattern).reversed.toList(); 614 return _parsePatternHelper(pattern).reversed.toList();
669 } 615 }
670 616
671 /** Recursive helper for parsing the template pattern. */ 617 /// Recursive helper for parsing the template pattern.
672 List _parsePatternHelper(String pattern) { 618 List<_DateFormatField> _parsePatternHelper(String pattern) {
673 if (pattern.isEmpty) return []; 619 if (pattern.isEmpty) return [];
674 620
675 var matched = _match(pattern); 621 var matched = _match(pattern);
676 if (matched == null) return []; 622 if (matched == null) return [];
677 623
678 var parsed = 624 var parsed =
679 _parsePatternHelper(pattern.substring(matched.fullPattern().length)); 625 _parsePatternHelper(pattern.substring(matched.fullPattern().length));
680 parsed.add(matched); 626 parsed.add(matched);
681 return parsed; 627 return parsed;
682 } 628 }
683 629
684 /** Find elements in a string that are patterns for specific fields.*/ 630 /// Find elements in a string that are patterns for specific fields.
685 _DateFormatField _match(String pattern) { 631 _DateFormatField _match(String pattern) {
686 for (var i = 0; i < _matchers.length; i++) { 632 for (var i = 0; i < _matchers.length; i++) {
687 var regex = _matchers[i]; 633 var regex = _matchers[i];
688 var match = regex.firstMatch(pattern); 634 var match = regex.firstMatch(pattern);
689 if (match != null) { 635 if (match != null) {
690 return _fieldConstructors[i](match.group(0), this); 636 return _fieldConstructors[i](match.group(0), this);
691 } 637 }
692 } 638 }
639 return null;
693 } 640 }
694 } 641 }
OLDNEW
« no previous file with comments | « packages/intl/lib/src/intl/compact_number_format.dart ('k') | packages/intl/lib/src/intl/date_format_field.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698