From e2f196be7bbfa806408b2ac77e23ba076cab29de Mon Sep 17 00:00:00 2001 From: guilherme Date: Sun, 15 Dec 2024 18:08:09 +1030 Subject: [PATCH 1/8] deps: bump constraint on intl --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 94f5fa7..67664fe 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,7 +8,7 @@ environment: sdk: '>=2.12.0 <4.0.0' dependencies: - intl: ">=0.18.1 <0.20.0" + intl: ">=0.18.1 <0.21.0" meta: ^1.0.0 dev_dependencies: From 9e9833a86267f80c58fd2ec7bf51716fe921714c Mon Sep 17 00:00:00 2001 From: guilherme Date: Sun, 15 Dec 2024 11:06:25 +1030 Subject: [PATCH 2/8] fix(ci): deactivate broken experimental lint --- analysis_options.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 8cccf3e..9f8939f 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -2,4 +2,8 @@ include: package:very_good_analysis/analysis_options.yaml analyzer: exclude: - - example/* \ No newline at end of file + - example/* + +linter: + rules: + use_late_for_private_fields_and_variables: false From 8d5df7a10824e252785a5b28e14adcddd608bde1 Mon Sep 17 00:00:00 2001 From: guilherme Date: Mon, 16 Dec 2024 21:22:29 +1030 Subject: [PATCH 3/8] started implementing support for intl 0.20 --- lib/src/param_cleanup_rules.dart | 13 ++++++++- test/failing_locales_test.dart | 48 ++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 test/failing_locales_test.dart diff --git a/lib/src/param_cleanup_rules.dart b/lib/src/param_cleanup_rules.dart index 9d52a48..d28cd42 100644 --- a/lib/src/param_cleanup_rules.dart +++ b/lib/src/param_cleanup_rules.dart @@ -84,7 +84,7 @@ const _knownSeparators = {..._usedSeparators, ..._specialSeparators}; /// these are the separators used by the default DateTime.parse String _replaceSeparators(String formattedString, Iterable separators) { - var result = formattedString; + var result = _replaceComma(formattedString); result = replaceUtc(result); final unknownSeparators = separators.toSet().difference(_knownSeparators); @@ -97,6 +97,17 @@ String _replaceSeparators(String formattedString, Iterable separators) { return _restoreMillisecons(result, separator).replaceAll(separator, '-'); } +String _replaceComma(String formattedString) { + final re1 = RegExp(r',\s+'); + final re2 = RegExp(r',\s+'); + final re3 = RegExp(r'\s+'); + + return formattedString + .replaceAll(re1, ' ') + .replaceAll(re2, ' ') + .replaceAll(re3, ' '); +} + String _restoreMillisecons(String formattedString, String separator) { // regex with T00:00:00-000 final r = RegExp( diff --git a/test/failing_locales_test.dart b/test/failing_locales_test.dart new file mode 100644 index 0000000..2484dda --- /dev/null +++ b/test/failing_locales_test.dart @@ -0,0 +1,48 @@ +// the following locales are failing: +// vi +// nyn +// ln +// zh-TW +// zh_HK +// zh_CN +// zh +// ko +// mn +// ja +import 'package:any_date/any_date.dart'; +import 'package:intl/intl.dart'; +import 'package:lean_extensions/lean_extensions.dart'; +import 'package:test/test.dart'; + +import 'test_values.dart'; + +const _failing = { + 'vi', + 'nyn', + 'ln', + 'zh_TW', + 'zh_HK', + 'zh_CN', + 'zh', + 'ko', + 'mn', + 'ja', +}; +Future main() async { + await initializeDateFormatting(); + + final date = DateTime.now().dateOnly; + group('ensure failing locales are working', () { + for (final l in _failing) { + final format = DateFormat.yMMMMd(l); + final formatted = format.format(date); + test('locale $l can parse $formatted text month', () { + final parser = AnyDate.fromLocale(l); + + final parsed = parser.tryParse(formatted); + + expect(parsed, equals(date)); + }); + } + }); +} From 4ade197d85d830c42176571aa10c1f1cb213e07a Mon Sep 17 00:00:00 2001 From: guilherme Date: Tue, 17 Dec 2024 21:50:14 +1030 Subject: [PATCH 4/8] test: added sanity check to failing locales --- test/failing_locales_test.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/failing_locales_test.dart b/test/failing_locales_test.dart index 2484dda..a94a914 100644 --- a/test/failing_locales_test.dart +++ b/test/failing_locales_test.dart @@ -43,6 +43,12 @@ Future main() async { expect(parsed, equals(date)); }); + + test('sanity check - locale $l can self-parse $formatted text month', () { + final parsed = format.tryParse(formatted); + + expect(parsed, equals(date)); + }); } }); } From d2816eaf21a807f9eb0be3599fbc800fdf248853 Mon Sep 17 00:00:00 2001 From: guilherme Date: Tue, 17 Dec 2024 21:52:37 +1030 Subject: [PATCH 5/8] fix: lookup expected months in sorted order --- lib/src/param_cleanup_rules.dart | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/src/param_cleanup_rules.dart b/lib/src/param_cleanup_rules.dart index d28cd42..15f4c17 100644 --- a/lib/src/param_cleanup_rules.dart +++ b/lib/src/param_cleanup_rules.dart @@ -122,9 +122,19 @@ String _restoreMillisecons(String formattedString, String separator) { ); } +// .reversed because it works for disambiguation +// (e.g., in vi locale try 'thang 12' before 'thang 1') +Iterable _sortMonths(Iterable months) { + final sorted = months.toList() + ..sort((a, b) => a.name.length.compareTo(b.name.length)) + ..sort((a, b) => a.number.compareTo(b.number)); + + return sorted.reversed; +} + Month? _expectMonth(DateParsingParameters parameters) { final timestamp = parameters.formattedString.toLowerCase(); - final month = parameters.parserInfo.months.where( + final month = _sortMonths(parameters.parserInfo.months).where( (element) => element.name.tryToInt() == null && timestamp.contains(element.name.toLowerCase()), @@ -136,12 +146,22 @@ Month? _expectMonth(DateParsingParameters parameters) { return month.firstOrNullExtension ?? english.firstOrNullExtension; } +// .reversed because it works for disambiguation +// (e.g., in vi locale try 'thang 12' before 'thang 1') +Iterable _sortWeekdays(Iterable weekdays) { + final sorted = weekdays.toList() + ..sort((a, b) => a.name.length.compareTo(b.name.length)) + ..sort((a, b) => a.number.compareTo(b.number)); + + return sorted.reversed; +} + Weekday? _expectWeekday(DateParsingParameters parameters) { // TODO(gbassisp): allow weekday in any part of the string // currently unsupported because some locales can have a conflict between // month and weekday (e.g., "Mar" in French for Mardi and Mars) final timestamp = parameters.formattedString.toLowerCase(); - var weekday = parameters.parserInfo.weekdays + var weekday = _sortWeekdays(parameters.parserInfo.weekdays) .where( (element) => timestamp.startsWith(element.name.toLowerCase()), // (element) => timestamp From 3c87587c51b6fbae04a3e35239b77ccb76f5925f Mon Sep 17 00:00:00 2001 From: guilherme Date: Wed, 18 Dec 2024 07:02:37 +1030 Subject: [PATCH 6/8] fix: use dateOnly from local extension --- lib/src/extensions.dart | 3 +++ test/failing_locales_test.dart | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/extensions.dart b/lib/src/extensions.dart index 3c589fa..ed5bd3d 100644 --- a/lib/src/extensions.dart +++ b/lib/src/extensions.dart @@ -2,6 +2,7 @@ import 'package:any_date/any_date.dart'; import 'package:meta/meta.dart'; /// a collection of extensions on [DateTime] +@internal extension DateTimeExtension on DateTime { /// returns a [DateTime] as UTC after applying the offset DateTime copyWithOffset(String offset) { @@ -111,6 +112,8 @@ extension DateTimeExtension on DateTime { allowRollover: true, ); } + + DateTime get dateOnly => DateTime(year, month, day); } const _parser = AnyDate(); diff --git a/test/failing_locales_test.dart b/test/failing_locales_test.dart index a94a914..79a989a 100644 --- a/test/failing_locales_test.dart +++ b/test/failing_locales_test.dart @@ -10,8 +10,8 @@ // mn // ja import 'package:any_date/any_date.dart'; +import 'package:any_date/src/extensions.dart'; import 'package:intl/intl.dart'; -import 'package:lean_extensions/lean_extensions.dart'; import 'package:test/test.dart'; import 'test_values.dart'; From d34e1414de068f62199707852e3f58b5d376ca05 Mon Sep 17 00:00:00 2001 From: guilherme Date: Wed, 18 Dec 2024 20:20:56 +1030 Subject: [PATCH 7/8] fix: remove usage of DateFormat.tryParse to be compatible with dart 2.12 --- test/failing_locales_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/failing_locales_test.dart b/test/failing_locales_test.dart index 79a989a..8b5241a 100644 --- a/test/failing_locales_test.dart +++ b/test/failing_locales_test.dart @@ -39,7 +39,7 @@ Future main() async { test('locale $l can parse $formatted text month', () { final parser = AnyDate.fromLocale(l); - final parsed = parser.tryParse(formatted); + final parsed = parser.parse(formatted); expect(parsed, equals(date)); }); From dcf37a5968c0d20796f8ee4d72a3a0de587b03ec Mon Sep 17 00:00:00 2001 From: guilherme Date: Wed, 18 Dec 2024 20:45:09 +1030 Subject: [PATCH 8/8] fix: remove correct failing tryParse --- test/failing_locales_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/failing_locales_test.dart b/test/failing_locales_test.dart index 8b5241a..49a78c8 100644 --- a/test/failing_locales_test.dart +++ b/test/failing_locales_test.dart @@ -39,13 +39,13 @@ Future main() async { test('locale $l can parse $formatted text month', () { final parser = AnyDate.fromLocale(l); - final parsed = parser.parse(formatted); + final parsed = parser.tryParse(formatted); expect(parsed, equals(date)); }); test('sanity check - locale $l can self-parse $formatted text month', () { - final parsed = format.tryParse(formatted); + final parsed = format.parse(formatted); expect(parsed, equals(date)); });