Add more information to the error when a DateTime fails verification.
Tracking down some erratic errors where dates seem to be off by an integer number of hours, which might be a time zone offset.
PiperOrigin-RevId: 273811213
diff --git a/lib/src/intl/date_format.dart b/lib/src/intl/date_format.dart
index 5625802..2046035 100644
--- a/lib/src/intl/date_format.dart
+++ b/lib/src/intl/date_format.dart
@@ -319,7 +319,7 @@
}
DateTime _parseLoose(String inputString, bool utc) {
- var dateFields = _DateBuilder();
+ var dateFields = _DateBuilder(locale ?? Intl.defaultLocale);
if (utc) dateFields.utc = true;
var stream = _Stream(inputString);
for (var field in _formatFields) {
@@ -347,7 +347,7 @@
DateTime _parse(String inputString, {bool utc = false, bool strict = 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 = _DateBuilder();
+ var dateFields = _DateBuilder(locale ?? Intl.defaultLocale);
if (utc) dateFields.utc = true;
dateFields._dateOnly = dateOnly;
var stream = _Stream(inputString);
diff --git a/lib/src/intl/date_format_helpers.dart b/lib/src/intl/date_format_helpers.dart
index 8193a47..acfe003 100644
--- a/lib/src/intl/date_format_helpers.dart
+++ b/lib/src/intl/date_format_helpers.dart
@@ -44,6 +44,18 @@
bool pm = false;
bool utc = false;
+ /// The locale, kept for logging purposes when there's an error.
+ final String _locale;
+
+ /// The date result produced from [asDate].
+ ///
+ /// Kept as a field to cache the result and to reduce the possibility of error
+ /// after we've verified.
+ DateTime _date;
+
+ /// The number of times we've retried, for error reporting.
+ int _retried = 0;
+
/// Is this constructing a pure date.
///
/// This is important because some locales change times at midnight,
@@ -59,6 +71,8 @@
// ignore: prefer_final_fields
var _dateOnly = false;
+ _DateBuilder(this._locale);
+
// Functions that exist just to be closurized so we can pass them to a general
// method.
void setYear(x) {
@@ -130,9 +144,15 @@
[DateTime parsed]) {
if (value < min || value > max) {
var parsedDescription = parsed == null ? '' : ' Date parsed as $parsed.';
- throw FormatException(
- 'Error parsing $originalInput, invalid $desc value: $value.'
- ' Expected value between $min and $max.$parsedDescription');
+ var errorDescription =
+ 'Error parsing $originalInput, invalid $desc value: $value'
+ ' in $_locale'
+ ' with time zone offset ${parsed?.timeZoneOffset ?? 'unknown'}.'
+ ' Expected value between $min and $max.$parsedDescription.';
+ if (_retried > 0) {
+ errorDescription += ' Failed after $_retried retries.';
+ }
+ throw FormatException(errorDescription);
}
}
@@ -141,15 +161,17 @@
DateTime asDate({int retries = 3}) {
// TODO(alanknight): Validate the date, especially for things which
// can crash the VM, e.g. large month values.
+ if (_date != null) return _date;
if (utc) {
- return DateTime.utc(
+ _date = DateTime.utc(
year, month, day, hour24, minute, second, fractionalSecond);
} else {
var preliminaryResult =
DateTime(year, month, day, hour24, minute, second, fractionalSecond);
- return _correctForErrors(preliminaryResult, retries);
+ _date = _correctForErrors(preliminaryResult, retries);
}
+ return _date;
}
/// Given a local DateTime, check for errors and try to compensate for them if
@@ -193,6 +215,7 @@
!DateTime.now().isUtc)) {
// This may be a UTC failure. Retry and if the result doesn't look
// like it's in the UTC time zone, use that instead.
+ _retried++;
return asDate(retries: retries - 1);
}
if (_dateOnly && day != correspondingDay) {