| OLD | NEW |
| 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 /** | 7 /** |
| 8 * This is a private class internal to DateFormat which is used for formatting | 8 * This is a private class internal to DateFormat which is used for formatting |
| 9 * particular fields in a template. e.g. if the format is hh:mm:ss then the | 9 * particular fields in a template. e.g. if the format is hh:mm:ss then the |
| 10 * fields would be "hh", ":", "mm", ":", and "ss". Each type of field knows | 10 * fields would be "hh", ":", "mm", ":", and "ss". Each type of field knows |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 /** Format date according to our specification and return the result. */ | 32 /** Format date according to our specification and return the result. */ |
| 33 String format(DateTime date) { | 33 String format(DateTime date) { |
| 34 // Default implementation in the superclass, works for both types of | 34 // Default implementation in the superclass, works for both types of |
| 35 // literal patterns, and is overridden by _DateFormatPatternField. | 35 // literal patterns, and is overridden by _DateFormatPatternField. |
| 36 return pattern; | 36 return pattern; |
| 37 } | 37 } |
| 38 | 38 |
| 39 /** Abstract method for subclasses to implementing parsing for their format.*/ | 39 /** Abstract method for subclasses to implementing parsing for their format.*/ |
| 40 void parse(_Stream input, _DateBuilder dateFields); | 40 void parse(_Stream input, _DateBuilder dateFields); |
| 41 | 41 |
| 42 /** |
| 43 * Abstract method for subclasses to implementing 'loose' parsing for |
| 44 * their format, accepting input case-insensitively, and allowing some |
| 45 * delimiters to be skipped. |
| 46 */ |
| 47 void parseLoose(_Stream input, _DateBuilder dateFields); |
| 48 |
| 42 /** Parse a literal field. We just look for the exact input. */ | 49 /** Parse a literal field. We just look for the exact input. */ |
| 43 void parseLiteral(_Stream input) { | 50 void parseLiteral(_Stream input) { |
| 44 var found = input.read(width); | 51 var found = input.read(width); |
| 45 if (found != pattern) { | 52 if (found != pattern) { |
| 46 throwFormatException(input); | 53 throwFormatException(input); |
| 47 } | 54 } |
| 48 } | 55 } |
| 49 | 56 |
| 57 /** |
| 58 * Parse a literal field. We accept either an exact match, or an arbitrary |
| 59 * amount of whitespace. |
| 60 */ |
| 61 void parseLiteralLoose(_Stream input) { |
| 62 var found = input.peek(width); |
| 63 if (found == pattern) { |
| 64 input.read(width); |
| 65 } |
| 66 while (!input.atEnd() && input.peek().trim().isEmpty) { |
| 67 input.read(); |
| 68 } |
| 69 } |
| 70 |
| 50 /** Throw a format exception with an error message indicating the position.*/ | 71 /** Throw a format exception with an error message indicating the position.*/ |
| 51 void throwFormatException(_Stream stream) { | 72 void throwFormatException(_Stream stream) { |
| 52 throw new FormatException("Trying to read $this from ${stream.contents} " | 73 throw new FormatException("Trying to read $this from ${stream.contents} " |
| 53 "at position ${stream.index}"); | 74 "at position ${stream.index}"); |
| 54 } | 75 } |
| 55 } | 76 } |
| 56 | 77 |
| 57 /** | 78 /** |
| 58 * Represents a literal field - a sequence of characters that doesn't | 79 * Represents a literal field - a sequence of characters that doesn't |
| 59 * change according to the date's data. As such, the implementation | 80 * change according to the date's data. As such, the implementation |
| 60 * is extremely simple. | 81 * is extremely simple. |
| 61 */ | 82 */ |
| 62 class _DateFormatLiteralField extends _DateFormatField { | 83 class _DateFormatLiteralField extends _DateFormatField { |
| 63 | 84 |
| 64 _DateFormatLiteralField(pattern, parent): super(pattern, parent); | 85 _DateFormatLiteralField(pattern, parent): super(pattern, parent); |
| 65 | 86 |
| 66 parse(_Stream input, _DateBuilder dateFields) { | 87 parse(_Stream input, _DateBuilder dateFields) { |
| 67 return parseLiteral(input); | 88 parseLiteral(input); |
| 68 } | 89 } |
| 90 |
| 91 parseLoose(_Stream input, _DateBuilder dateFields) => |
| 92 parseLiteralLoose(input); |
| 69 } | 93 } |
| 70 | 94 |
| 71 /** | 95 /** |
| 72 * Represents a literal field with quoted characters in it. This is | 96 * Represents a literal field with quoted characters in it. This is |
| 73 * only slightly more complex than a _DateFormatLiteralField. | 97 * only slightly more complex than a _DateFormatLiteralField. |
| 74 */ | 98 */ |
| 75 class _DateFormatQuotedField extends _DateFormatField { | 99 class _DateFormatQuotedField extends _DateFormatField { |
| 76 | 100 |
| 77 String _fullPattern; | 101 String _fullPattern; |
| 78 | 102 |
| 79 String fullPattern() => _fullPattern; | 103 String fullPattern() => _fullPattern; |
| 80 | 104 |
| 81 _DateFormatQuotedField(pattern, parent): super(pattern, parent) { | 105 _DateFormatQuotedField(pattern, parent): super(pattern, parent) { |
| 82 _fullPattern = pattern; | 106 _fullPattern = pattern; |
| 83 patchQuotes(); | 107 patchQuotes(); |
| 84 } | 108 } |
| 85 | 109 |
| 86 parse(_Stream input, _DateBuilder dateFields) { | 110 parse(_Stream input, _DateBuilder dateFields) { |
| 87 return parseLiteral(input); | 111 parseLiteral(input); |
| 88 } | 112 } |
| 89 | 113 |
| 114 parseLoose(_Stream input, _DateBuilder dateFields) => |
| 115 parseLiteralLoose(input); |
| 116 |
| 90 void patchQuotes() { | 117 void patchQuotes() { |
| 91 if (pattern == "''") { | 118 if (pattern == "''") { |
| 92 pattern = "'"; | 119 pattern = "'"; |
| 93 } else { | 120 } else { |
| 94 pattern = pattern.substring(1, pattern.length - 1); | 121 pattern = pattern.substring(1, pattern.length - 1); |
| 95 var twoEscapedQuotes = new RegExp(r"''"); | 122 var twoEscapedQuotes = new RegExp(r"''"); |
| 96 pattern = pattern.replaceAll(twoEscapedQuotes, "'"); | 123 pattern = pattern.replaceAll(twoEscapedQuotes, "'"); |
| 97 } | 124 } |
| 98 } | 125 } |
| 99 } | 126 } |
| 100 | 127 |
| 128 /** |
| 129 * A field that parses "loosely", meaning that we'll accept input that is |
| 130 * missing delimiters, has upper/lower case mixed up, and might not strictly |
| 131 * conform to the pattern, e.g. the pattern calls for Sep we might accept |
| 132 * sep, september, sEPTember. Doesn't affect numeric fields. |
| 133 */ |
| 134 class _LoosePatternField extends _DateFormatPatternField { |
| 135 _LoosePatternField(String pattern, parent) : super(pattern, parent); |
| 136 |
| 137 /** |
| 138 * Parse from a list of possibilities, but case-insensitively. |
| 139 * Assumes that input is lower case. |
| 140 */ |
| 141 int parseEnumeratedString(_Stream input, List possibilities) { |
| 142 var lowercasePossibilities = possibilities |
| 143 .map((x) => x.toLowerCase()) |
| 144 .toList(); |
| 145 try { |
| 146 return super.parseEnumeratedString(input, lowercasePossibilities); |
| 147 } on FormatException { |
| 148 return -1; |
| 149 } |
| 150 } |
| 151 |
| 152 /** |
| 153 * Parse a month name, case-insensitively, and set it in [dateFields]. |
| 154 * Assumes that [input] is lower case. |
| 155 */ |
| 156 void parseMonth(input, dateFields) { |
| 157 if (width <= 2) { |
| 158 handleNumericField(input, dateFields.setMonth); |
| 159 return; |
| 160 } |
| 161 var possibilities = |
| 162 [symbols.MONTHS, symbols.SHORTMONTHS]; |
| 163 for (var monthNames in possibilities) { |
| 164 var month = parseEnumeratedString(input, monthNames); |
| 165 if (month != -1) { |
| 166 dateFields.month = month + 1; |
| 167 return; |
| 168 } |
| 169 } |
| 170 } |
| 171 |
| 172 /** |
| 173 * Parse a standalone day name, case-insensitively. |
| 174 * Assumes that input is lower case. Doesn't do anything |
| 175 */ |
| 176 void parseStandaloneDay(input) { |
| 177 // This is ignored, but we still have to skip over it the correct amount. |
| 178 if (width <= 2) { |
| 179 handleNumericField(input, (x) => x); |
| 180 return; |
| 181 } |
| 182 var possibilities = |
| 183 [symbols.STANDALONEWEEKDAYS, symbols.STANDALONESHORTWEEKDAYS]; |
| 184 for (var dayNames in possibilities) { |
| 185 var day = parseEnumeratedString(input, dayNames); |
| 186 if (day != -1) { |
| 187 return; |
| 188 } |
| 189 } |
| 190 } |
| 191 |
| 192 /** |
| 193 * Parse a standalone month name, case-insensitively. |
| 194 * Assumes that input is lower case. Doesn't do anything |
| 195 */ |
| 196 void parseStandaloneMonth(input, dateFields) { |
| 197 if (width <= 2) { |
| 198 handleNumericField(input, (x) => x); |
| 199 return; |
| 200 } |
| 201 var possibilities = |
| 202 [symbols.STANDALONEMONTHS, symbols.STANDALONESHORTMONTHS]; |
| 203 for (var monthNames in possibilities) { |
| 204 var month = parseEnumeratedString(input, monthNames); |
| 205 if (month != -1) { |
| 206 dateFields.month = month + 1; |
| 207 return; |
| 208 } |
| 209 } |
| 210 } |
| 211 |
| 212 /** |
| 213 * Parse a day of the week name, case-insensitively. |
| 214 * Assumes that input is lower case. Doesn't do anything |
| 215 */ |
| 216 void parseDayOfWeek(_Stream input) { |
| 217 // This is IGNORED, but we still have to skip over it the correct amount. |
| 218 if (width <= 2) { |
| 219 handleNumericField(input, (x) => x); |
| 220 return; |
| 221 } |
| 222 var possibilities = [symbols.WEEKDAYS, symbols.SHORTWEEKDAYS]; |
| 223 for (var dayNames in possibilities) { |
| 224 var day = parseEnumeratedString(input, dayNames); |
| 225 if (day != -1) { |
| 226 return; |
| 227 } |
| 228 } |
| 229 } |
| 230 } |
| 231 |
| 101 /* | 232 /* |
| 102 * Represents a field in the pattern that formats some aspect of the | 233 * Represents a field in the pattern that formats some aspect of the |
| 103 * date. Consists primarily of a switch on the particular pattern characters | 234 * date. Consists primarily of a switch on the particular pattern characters |
| 104 * to determine what to do. | 235 * to determine what to do. |
| 105 */ | 236 */ |
| 106 class _DateFormatPatternField extends _DateFormatField { | 237 class _DateFormatPatternField extends _DateFormatField { |
| 107 | 238 |
| 108 _DateFormatPatternField(pattern, parent): super(pattern, parent); | 239 _DateFormatPatternField(pattern, parent): super(pattern, parent); |
| 109 | 240 |
| 110 /** Format date according to our specification and return the result. */ | 241 /** Format date according to our specification and return the result. */ |
| 111 String format(DateTime date) { | 242 String format(DateTime date) { |
| 112 return formatField(date); | 243 return formatField(date); |
| 113 } | 244 } |
| 114 | 245 |
| 115 /** | 246 /** |
| 116 * Parse the date according to our specification and put the result | 247 * Parse the date according to our specification and put the result |
| 117 * into the correct place in dateFields. | 248 * into the correct place in dateFields. |
| 118 */ | 249 */ |
| 119 void parse(_Stream input, _DateBuilder dateFields) { | 250 void parse(_Stream input, _DateBuilder dateFields) { |
| 120 parseField(input, dateFields); | 251 parseField(input, dateFields); |
| 121 } | 252 } |
| 122 | 253 |
| 254 |
| 255 /** |
| 256 * Parse the date according to our specification and put the result |
| 257 * into the correct place in dateFields. Allow looser parsing, accepting |
| 258 * case-insensitive input and skipped delimiters. |
| 259 */ |
| 260 void parseLoose(_Stream input, _DateBuilder dateFields) { |
| 261 new _LoosePatternField(pattern, parent).parse(input, dateFields); |
| 262 } |
| 263 |
| 123 /** | 264 /** |
| 124 * Parse a field representing part of a date pattern. Note that we do not | 265 * Parse a field representing part of a date pattern. Note that we do not |
| 125 * return a value, but rather build up the result in [builder]. | 266 * return a value, but rather build up the result in [builder]. |
| 126 */ | 267 */ |
| 127 void parseField(_Stream input, _DateBuilder builder) { | 268 void parseField(_Stream input, _DateBuilder builder) { |
| 128 try { | 269 try { |
| 129 switch(pattern[0]) { | 270 switch(pattern[0]) { |
| 130 case 'a': parseAmPm(input, builder); break; | 271 case 'a': parseAmPm(input, builder); break; |
| 131 case 'c': parseStandaloneDay(input); break; | 272 case 'c': parseStandaloneDay(input); break; |
| 132 case 'd': handleNumericField(input, builder.setDay); break; // day | 273 case 'd': handleNumericField(input, builder.setDay); break; // day |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 var basicString = toBePrinted.toString(); | 567 var basicString = toBePrinted.toString(); |
| 427 if (basicString.length >= width) return basicString; | 568 if (basicString.length >= width) return basicString; |
| 428 var buffer = new StringBuffer(); | 569 var buffer = new StringBuffer(); |
| 429 for (var i = 0; i < width - basicString.length; i++) { | 570 for (var i = 0; i < width - basicString.length; i++) { |
| 430 buffer.write('0'); | 571 buffer.write('0'); |
| 431 } | 572 } |
| 432 buffer.write(basicString); | 573 buffer.write(basicString); |
| 433 return buffer.toString(); | 574 return buffer.toString(); |
| 434 } | 575 } |
| 435 } | 576 } |
| OLD | NEW |