Index: packages/intl/lib/src/intl/date_format_helpers.dart |
diff --git a/packages/intl/lib/src/intl/date_format_helpers.dart b/packages/intl/lib/src/intl/date_format_helpers.dart |
index 6a6e68c8f46d593a126ee0609672236d30479458..05a6a4927d4d72deb3d84f97993cdf79467bf0fa 100644 |
--- a/packages/intl/lib/src/intl/date_format_helpers.dart |
+++ b/packages/intl/lib/src/intl/date_format_helpers.dart |
@@ -4,10 +4,8 @@ |
part of intl; |
-/** |
- * A class for holding onto the data for a date so that it can be built |
- * up incrementally. |
- */ |
+/// A class for holding onto the data for a date so that it can be built |
+/// up incrementally. |
class _DateBuilder { |
// Default the date values to the EPOCH so that there's a valid date |
// in case the format doesn't set them. |
@@ -26,32 +24,36 @@ class _DateBuilder { |
void setYear(x) { |
year = x; |
} |
+ |
void setMonth(x) { |
month = x; |
} |
+ |
void setDay(x) { |
day = x; |
} |
+ |
void setHour(x) { |
hour = x; |
} |
+ |
void setMinute(x) { |
minute = x; |
} |
+ |
void setSecond(x) { |
second = x; |
} |
+ |
void setFractionalSecond(x) { |
fractionalSecond = x; |
} |
get hour24 => pm ? hour + 12 : hour; |
- /** |
- * Verify that we correspond to a valid date. This will reject out of |
- * range values, even if the DateTime constructor would accept them. An |
- * invalid message will result in throwing a [FormatException]. |
- */ |
+ /// Verify that we correspond to a valid date. This will reject out of |
+ /// range values, even if the DateTime constructor would accept them. An |
+ /// invalid message will result in throwing a [FormatException]. |
verify(String s) { |
_verify(month, 1, 12, "month", s); |
_verify(hour24, 0, 23, "hour", s); |
@@ -64,23 +66,24 @@ class _DateBuilder { |
// check the year, which we otherwise can't verify, and the hours, |
// which will catch cases like "14:00:00 PM". |
var date = asDate(); |
- _verify(hour24, date.hour, date.hour, "hour", s); |
- _verify(day, date.day, date.day, "day", s); |
- _verify(year, date.year, date.year, "year", s); |
+ _verify(hour24, date.hour, date.hour, "hour", s, date); |
+ _verify(day, date.day, date.day, "day", s, date); |
+ _verify(year, date.year, date.year, "year", s, date); |
} |
- _verify(int value, int min, int max, String desc, String originalInput) { |
+ _verify(int value, int min, int max, String desc, String originalInput, |
+ [DateTime parsed]) { |
if (value < min || value > max) { |
+ var parsedDescription = parsed == null ? "" : " Date parsed as $parsed."; |
throw new FormatException( |
- "Error parsing $originalInput, invalid $desc value: $value"); |
+ "Error parsing $originalInput, invalid $desc value: $value." |
+ " Expected value between $min and $max.$parsedDescription"); |
} |
} |
- /** |
- * Return a date built using our values. If no date portion is set, |
- * use the "Epoch" of January 1, 1970. |
- */ |
- DateTime asDate({retry: true}) { |
+ /// Return a date built using our values. If no date portion is set, |
+ /// use the "Epoch" of January 1, 1970. |
+ DateTime asDate({int retries: 10}) { |
// TODO(alanknight): Validate the date, especially for things which |
// can crash the VM, e.g. large month values. |
var result; |
@@ -90,22 +93,21 @@ class _DateBuilder { |
} else { |
result = new DateTime( |
year, month, day, hour24, minute, second, fractionalSecond); |
- // TODO(alanknight): Issue 15560 means non-UTC dates occasionally come |
- // out in UTC. If that happens, retry once. This will always happen if |
- // the local time zone is UTC, but that's ok. |
- if (result.toUtc() == result) { |
- result = asDate(retry: false); |
+ // TODO(alanknight): Issue 15560 means non-UTC dates occasionally come out |
+ // in UTC, or, alternatively, are constructed as if in UTC and then have |
+ // the offset subtracted. If that happens, retry, several times if |
+ // necessary. |
+ if (retries > 0 && (result.hour != hour24 || result.day != day)) { |
+ result = asDate(retries: retries - 1); |
} |
} |
return result; |
} |
} |
-/** |
- * A simple and not particularly general stream class to make parsing |
- * dates from strings simpler. It is general enough to operate on either |
- * lists or strings. |
- */ |
+/// A simple and not particularly general stream class to make parsing |
+/// dates from strings simpler. It is general enough to operate on either |
+/// lists or strings. |
// TODO(alanknight): With the improvements to the collection libraries |
// since this was written we might be able to get rid of it entirely |
// in favor of e.g. aString.split('') giving us an iterable of one-character |
@@ -121,33 +123,29 @@ class _Stream { |
next() => contents[index++]; |
- /** |
- * Return the next [howMany] items, or as many as there are remaining. |
- * Advance the stream by that many positions. |
- */ |
+ /// Return the next [howMany] items, or as many as there are remaining. |
+ /// Advance the stream by that many positions. |
read([int howMany = 1]) { |
var result = peek(howMany); |
index += howMany; |
return result; |
} |
- /** |
- * Does the input start with the given string, if we start from the |
- * current position. |
- */ |
+ /// Does the input start with the given string, if we start from the |
+ /// current position. |
bool startsWith(String pattern) { |
if (contents is String) return contents.startsWith(pattern, index); |
return pattern == peek(pattern.length); |
} |
- /** |
- * Return the next [howMany] items, or as many as there are remaining. |
- * Does not modify the stream position. |
- */ |
+ /// Return the next [howMany] items, or as many as there are remaining. |
+ /// Does not modify the stream position. |
peek([int howMany = 1]) { |
var result; |
if (contents is String) { |
- result = contents.substring(index, min(index + howMany, contents.length)); |
+ String stringContents = contents; |
+ result = stringContents.substring( |
+ index, min(index + howMany, stringContents.length)); |
} else { |
// Assume List |
result = contents.sublist(index, index + howMany); |
@@ -155,13 +153,11 @@ class _Stream { |
return result; |
} |
- /** Return the remaining contents of the stream */ |
+ /// Return the remaining contents of the stream |
rest() => peek(contents.length - index); |
- /** |
- * Find the index of the first element for which [f] returns true. |
- * Advances the stream to that position. |
- */ |
+ /// Find the index of the first element for which [f] returns true. |
+ /// Advances the stream to that position. |
int findIndex(Function f) { |
while (!atEnd()) { |
if (f(next())) return index - 1; |
@@ -169,10 +165,8 @@ class _Stream { |
return null; |
} |
- /** |
- * Find the indexes of all the elements for which [f] returns true. |
- * Leaves the stream positioned at the end. |
- */ |
+ /// Find the indexes of all the elements for which [f] returns true. |
+ /// Leaves the stream positioned at the end. |
List findIndexes(Function f) { |
var results = []; |
while (!atEnd()) { |
@@ -181,11 +175,9 @@ class _Stream { |
return results; |
} |
- /** |
- * Assuming that the contents are characters, read as many digits as we |
- * can see and then return the corresponding integer. Advance the stream. |
- */ |
- var digitMatcher = new RegExp(r'\d+'); |
+ /// Assuming that the contents are characters, read as many digits as we |
+ /// can see and then return the corresponding integer. Advance the stream. |
+ var digitMatcher = new RegExp(r'^\d+'); |
int nextInteger() { |
var string = digitMatcher.stringMatch(rest()); |
if (string == null || string.isEmpty) return null; |