DateFormat.parse fails to parse dates/times that look fine

141 views Asked by At

I'm getting the issue when converting string to TimeOfDay. It was working before but now I am getting the issue.

try {
    final format = DateFormat.jm(); //"6:00 AM"
    TimeOfDay day = TimeOfDay.fromDateTime(format.parse("6:00"));
} catch(ex) {
    PLPrint(name: "CheckTest",value: "${ex.toString()}");
}

I have tried the format for parsing string:

1: 6:00 - FormatException: Trying to read   from 6:00 at 5

2: 6:00 AM - FormatException: Trying to read   from 6:00 AM at 5

3: 6:00:00 - FormatException: Trying to read   from 6:00:00 at 5

4: 6:00:00 AM - FormatException: Trying to read   from 6:00:00 AM at 5

5: 16:00 - FormatException: Trying to read   from 16:00 at 6

6: 16:00:00 - FormatException: Trying to read   from 16:00:00 at 6

I have tried almost all the formats but still getting the Format issue.

1

There are 1 answers

0
jamesdlin On

The DateFormat jm skeleton uses a locale-dependent format and therefore can vary. In the default locale (which I think is default to U.S. English locale), that format includes an AM/PM marker, and as of 2023 that marker is now separated with a Unicode non-breaking space (specifically U+202F):

import 'package:intl/intl.dart';

void main() {
  var format = DateFormat.jm();
  var s1 = format.format(DateTime(2023, 1, 1, 6));
  var s2 = "6:00 AM";

  print(s1);       // Prints: 6:00 AM
  print(s1 == s2); // Prints: false

  print(s1.runes); // Prints: (54, 58, 48, 48, 8239, 65, 77)
  print(s2.runes); // Prints: (54, 58, 48, 48, 32, 65, 77)
}

If you want jm to accept other types of whitespace, use DateFormat.parseLoose instead of DateFormat.parse:

If inputString is accepted by parseStrict, just return the result. If not, attempt to parse it, but accepting either upper or lower case, allowing delimiters to be missing and replaced or supplemented with whitespace, and allowing arbitrary amounts of whitespace wherever whitespace is permitted. Note that this does not allow trailing characters, the way parse does.

import 'package:intl/intl.dart';

void main() {
  var format = DateFormat.jm();
  print(format.parseLoose("6:00 AM")); // Prints: 1970-01-01 06:00:00.000
}

From empirical testing, the change to use a non-breaking space seems to have been picked up by package:intl in 0.18.1, so you also could consider rolling back to 0.18.0 as another workaround.

Also see https://github.com/dart-lang/i18n/issues/743.