Index: pkg/intl/date_format.dart |
=================================================================== |
--- pkg/intl/date_format.dart (revision 11110) |
+++ pkg/intl/date_format.dart (working copy) |
@@ -66,11 +66,13 @@ |
* |
* Examples Using the US Locale: |
* |
- * Pattern Result |
- * ---------------- ------- |
- * "yMd" -> 07/10/1996 |
- * "yMMMMd" -> July 10, 1996 |
- * "Hm" -> 12:08 PM |
+ * Pattern Result |
+ * ---------------- ------- |
+ * new DateFormat.yMd() -> 07/10/1996 |
+ * new DateFormat("yMd") -> 07/10/1996 |
+ * new DateFormat.yMMMMd("en_US") -> July 10, 1996 |
+ * new DateFormat("Hm", "en_US") -> 12:08 PM |
+ * new DateFormat.yMd().Hm() -> 07/10/1996 12:08 PM |
* |
* Explicit Pattern Syntax: Formats can also be specified with a pattern string. |
* The skeleton forms will resolve to explicit patterns of this form, but will |
@@ -150,17 +152,6 @@ |
* If the year pattern does not have exactly two 'y' characters, the year is |
* interpreted literally, regardless of the number of digits. So using the |
* pattern "MM/dd/yyyy", "01/11/12" parses to Jan 11, 12 A.D. |
- * |
- * When numeric fields abut one another directly, with no intervening |
- * delimiter characters, they constitute a run of abutting numeric fields. Such |
- * runs are parsed specially. For example, the format "HHmmss" parses the input |
- * text "123456" to 12:34:56, parses the input text "12345" to 1:23:45, and |
- * fails to parse "1234". In other words, the leftmost field of the run is |
- * flexible, while the others keep a fixed width. If the parse fails anywhere in |
- * the run, then the leftmost field is shortened by one character, and the |
- * entire run is parsed again. This is repeated until either the parse succeeds |
- * or the leftmost field is one character in length. If the parse still fails at |
- * that point, the parse of the run fails. |
*/ |
#library('date_format'); |
@@ -201,7 +192,7 @@ |
// TODO(alanknight): There will need to be at least setup type async |
// operations to avoid the need to bring along every locale in every program |
_locale = Intl.verifiedLocale(locale); |
- _setPattern(newPattern); |
+ addPattern(newPattern); |
} |
/** |
@@ -238,6 +229,8 @@ |
* format, treating it as being in the local timezone. |
*/ |
Date parse(String inputString, [utc = false]) { |
+ // TODO(alanknight): The Closure code refers to special parsing of numeric |
+ // values with no delimiters, which we currently don't do. Should we? |
var dateFields = new _DateBuilder(); |
if (utc) dateFields.utc=true; |
var stream = new _Stream(inputString); |
@@ -357,6 +350,55 @@ |
DateFormat.s([locale]) : this("s", locale); |
/** |
+ * Methods for appending a particular skeleton to the format, or setting |
+ * it as the only format if none was previously set. These are primarily |
+ * useful for creating compound formats. For example |
+ * new DateFormat.yMd().hms(); |
+ * would create a date format that prints both the date and the time. |
+ */ |
+ DateFormat d() => addPattern("d"); |
+ DateFormat E() => addPattern("E"); |
+ DateFormat EEEE() => addPattern("EEEE"); |
+ DateFormat LLL() => addPattern("LLL"); |
+ DateFormat LLLL() => addPattern("LLLL"); |
+ DateFormat M() => addPattern("M"); |
+ DateFormat Md() => addPattern("Md"); |
+ DateFormat MEd() => addPattern("MEd"); |
+ DateFormat MMM() => addPattern("MMM"); |
+ DateFormat MMMd() => addPattern("MMMd"); |
+ DateFormat MMMEd() => addPattern("MMMEd"); |
+ DateFormat MMMM() => addPattern("MMMM"); |
+ DateFormat MMMMd() => addPattern("MMMMd"); |
+ DateFormat MMMMEEEEd() => addPattern("MMMMEEEEd"); |
+ DateFormat QQQ() => addPattern("QQQ"); |
+ DateFormat QQQQ() => addPattern("QQQQ"); |
+ DateFormat y() => addPattern("y"); |
+ DateFormat yM() => addPattern("yM"); |
+ DateFormat yMd() => addPattern("yMd"); |
+ DateFormat yMEd() => addPattern("yMEd"); |
+ DateFormat yMMM() => addPattern("yMMM"); |
+ DateFormat yMMMd() => addPattern("yMMMd"); |
+ DateFormat yMMMEd() => addPattern("yMMMEd"); |
+ DateFormat yMMMM() => addPattern("yMMMM"); |
+ DateFormat yMMMMd() => addPattern("yMMMMd"); |
+ DateFormat yMMMMEEEEd() => addPattern("yMMMMEEEEd"); |
+ DateFormat yQQQ() => addPattern("yQQQ"); |
+ DateFormat yQQQQ() => addPattern("yQQQQ"); |
+ DateFormat H() => addPattern("H"); |
+ DateFormat Hm() => addPattern("Hm"); |
+ DateFormat Hms() => addPattern("Hms"); |
+ DateFormat j() => addPattern("j"); |
+ DateFormat jm() => addPattern("jm"); |
+ DateFormat jms() => addPattern("jms"); |
+ DateFormat jmv() => addPattern("jmv"); |
+ DateFormat jmz() => addPattern("jmz"); |
+ DateFormat jv() => addPattern("jv"); |
+ DateFormat jz() => addPattern("jz"); |
+ DateFormat m() => addPattern("m"); |
+ DateFormat ms() => addPattern("ms"); |
+ DateFormat s() => addPattern("s"); |
+ |
+ /** |
* ICU constants for format names, resolving to the corresponding skeletons. |
*/ |
static final String DAY = 'd'; |
@@ -412,12 +454,23 @@ |
String _pattern; |
/** |
- * We parse the format string into individual fields and store them here. |
- * This is what is actually used to do the formatting. |
+ * We parse the format string into individual [_DateFormatField] objects |
+ * that are used to do the actual formatting and parsing. Do not use |
+ * this variable directly, use the getter [_formatFields]. |
*/ |
- List<_DateFormatField> _formatFields; |
+ List<_DateFormatField> _formatFieldsPrivate; |
/** |
+ * Getter for [_formatFieldsPrivate] that lazily initializes it. |
+ */ |
+ get _formatFields() { |
+ if (_formatFieldsPrivate == null) { |
+ _formatFieldsPrivate = parsePattern(_pattern); |
+ } |
+ return _formatFieldsPrivate; |
+ } |
+ |
+ /** |
* A series of regular expressions used to parse a format string into its |
* component fields. |
*/ |
@@ -437,20 +490,36 @@ |
]; |
/** |
- * Given a format from the user look it up in our list of known skeletons. |
- * If it's there, then use the corresponding pattern for this locale. |
- * If it's not, then treat it as an explicit pattern. |
+ * Set our pattern, appending it to any existing patterns. Also adds a single |
+ * space to separate the two. |
*/ |
- _setPattern(String inputPattern) { |
+ _setPattern(String inputPattern, [String separator = ' ']) { |
+ if (_pattern == null) { |
+ _pattern = inputPattern; |
+ } else { |
+ _pattern = "$_pattern$separator$inputPattern"; |
+ } |
+ } |
+ |
+ /** |
+ * Add [inputPattern] to this instance as a pattern. If there was a previous |
+ * pattern, then this appends to it, separating the two by [separator]. |
+ * [inputPattern] is first looked up in our list of known skeletons. |
+ * If it's found there, then use the corresponding pattern for this locale. |
+ * If it's not, then treat [inputPattern] as an explicit pattern. |
+ */ |
+ DateFormat addPattern(String inputPattern, [String separator = ' ']) { |
// TODO(alanknight): This is an expensive operation. Caching recently used |
// formats, or possibly introducing an entire "locale" object that would |
// cache patterns for that locale could be a good optimization. |
if (!_availableSkeletons.containsKey(inputPattern)) { |
- _pattern = inputPattern; |
+ _setPattern(inputPattern, separator); |
} else { |
- _pattern = _availableSkeletons[inputPattern]; |
+ _setPattern(_availableSkeletons[inputPattern], separator); |
} |
- _formatFields = parsePattern(_pattern); |
+ // If we have already parsed the format fields, reset them. |
+ _formatFieldsPrivate = null; |
+ return this; |
} |
/** Return the pattern that we use to format dates.*/ |