From a28bedf108ac36777fbd342c3c403ab7f788e642 Mon Sep 17 00:00:00 2001 From: Moritz Date: Mon, 18 Aug 2025 20:02:02 +0200 Subject: [PATCH 1/7] Start fixing dart --- executors/dart/bin/executor.dart | 2 +- executors/dart/lib/collator.dart | 37 ++++++++--- executors/dart/lib/datetime_format.dart | 82 ++++++++++++++++++++++--- executors/dart/lib/lang_names.dart | 9 ++- executors/dart/lib/numberformat.dart | 10 +-- executors/dart/lib/version.dart | 2 +- executors/dart/out/version.js | 2 +- executors/dart/pubspec.lock | 29 +++++---- executors/dart/pubspec.yaml | 5 ++ 9 files changed, 132 insertions(+), 46 deletions(-) diff --git a/executors/dart/bin/executor.dart b/executors/dart/bin/executor.dart index 478de2f6..bef1677a 100644 --- a/executors/dart/bin/executor.dart +++ b/executors/dart/bin/executor.dart @@ -82,7 +82,7 @@ void printVersion() { final dartVersion = version.substring(0, version.indexOf(' ')); final versionInfo = { 'platform': 'Dart Native', - 'icuVersion': '73', //TODO: get from ICU4X somehow + 'icuVersion': '77', //TODO: get from ICU4X somehow 'platformVersion': dartVersion, 'intlVersion': intl4xVersion, }; diff --git a/executors/dart/lib/collator.dart b/executors/dart/lib/collator.dart index 0d9a9f7c..84e87a57 100644 --- a/executors/dart/lib/collator.dart +++ b/executors/dart/lib/collator.dart @@ -6,16 +6,22 @@ import 'package:intl4x/collation.dart'; import 'package:intl4x/intl4x.dart'; String testCollation(String jsonEncoded) { - final json = - jsonDecode(jsonEncoded) - as Map< - String, - dynamic - >; // For the moment, use strings for easier interop + final json = jsonDecode(jsonEncoded) as Map; // Global default locale - final testLocale = json['locale'] as String? ?? 'en'; final outputLine = {'label': json['label']}; - + if (json.containsKey('rules')) { + outputLine['error_type'] = 'unsupported'; + outputLine['unsupported'] = 'unsupported_options'; + outputLine['error_message'] = 'Rules are not supported'; + return jsonEncode(outputLine); + } + final localeString = json['locale'] as String? ?? 'en'; + if (localeString == 'root') { + outputLine['error_type'] = 'unsupported'; + outputLine['unsupported'] = 'unsupported_options'; + outputLine['error_message'] = 'Locale `root` is unsupported'; + return jsonEncode(outputLine); + } // Set up collator object with optional locale and testOptions. final s1 = json['s1']; final s2 = json['s2']; @@ -36,6 +42,7 @@ String testCollation(String jsonEncoded) { .where((value) => value.jsName == json['case_first']) .firstOrNull ?? CaseFirst.localeDependent; + final compareType = json['compare_type'] as String?; if (s1 == null || s2 == null) { outputLine.addAll({ @@ -45,7 +52,7 @@ String testCollation(String jsonEncoded) { }); } else { try { - final coll = Intl(locale: Locale.parse(testLocale)); + final coll = Intl(locale: Locale.parse(localeString)); final collationOptions = CollationOptions( ignorePunctuation: ignorePunctuation, @@ -55,7 +62,17 @@ String testCollation(String jsonEncoded) { ); final compared = coll.collation(collationOptions).compare(s1, s2); - final result = compared <= 0; + + bool result; + if (compareType == '=') { + // Check for strict equality comparison + result = compared == 0; + } else if (compareType != null && compareType.startsWith('<')) { + // Check results with different compare types + result = compared < 0; + } else { + result = compared <= 0; + } outputLine['result'] = result; if (result != true) { diff --git a/executors/dart/lib/datetime_format.dart b/executors/dart/lib/datetime_format.dart index a32861ea..40013766 100644 --- a/executors/dart/lib/datetime_format.dart +++ b/executors/dart/lib/datetime_format.dart @@ -54,10 +54,20 @@ String testDateTimeFmt(String jsonEncoded) { // ignore: unused_local_variable - to be used with the timezoneformatter String? timezone; - if (testOptionsJson.containsKey('time_zone')) { + int? offset; + String? timeZoneStyle; + if (testOptionsJson.containsKey('time_zone') && + testOptionsJson.containsKey('tz_offset_secs') && + testOptionsJson.containsKey('timeStyle')) { timezone = testOptionsJson['time_zone'] as String; + offset = testOptionsJson['tz_offset_secs'] as int; + timeZoneStyle = testOptionsJson['timeStyle'] as String; } + final dateStyle = testOptionsJson['dateStyle'] as String?; + final timeStyle = testOptionsJson['timeStyle'] as String?; + final yearStyle = testOptionsJson['yearStyle'] as String?; + DateTime? testDate; if (json['input_string'] != null) { final isoDateString = json['input_string'] as String; @@ -87,19 +97,71 @@ String testDateTimeFmt(String jsonEncoded) { locale: locale, ).dateTimeFormat(dateTimeFormatOptions); - try {} catch (error) { - returnJson['error'] = 'DateTimeFormat Constructor: ${error.toString()}'; - returnJson['options'] = testOptionsJson; - return jsonEncode(returnJson); - } - try { - final formattedDt = dtFormatter.ymd(testDate); + final formatter = switch ((dateStyle, timeStyle, yearStyle)) { + ('medium', null, _) => dtFormatter.ymd(dateStyle: DateFormatStyle.medium), + (null, 'short', _) => dtFormatter.t(style: TimeFormatStyle.short), + ('full', 'short', null) => dtFormatter.ymdt( + dateStyle: DateFormatStyle.full, + timeStyle: TimeFormatStyle.short, + ), + ('short', 'full', null) => dtFormatter.ymdt( + dateStyle: DateFormatStyle.short, + timeStyle: TimeFormatStyle.full, + ), + (_, _, 'with_era') => dtFormatter.ymde(), + ('short', 'full', _) => dtFormatter.ymdet( + dateStyle: DateFormatStyle.short, + timeStyle: TimeFormatStyle.full, + ), + (_, _, _) => throw UnimplementedError( + 'Unknown combination of date style `$dateStyle`, time style `$timeStyle`, and year style `$yearStyle`', + ), + }; + String formattedDt; + if (timezone != null) { + final timeZone = TimeZone( + name: timezone, + offset: Duration(seconds: offset!), + ); + final zonedFormatter = switch (timeZoneStyle!) { + 'short' => formatter.withTimeZoneShort(timeZone), + 'long' => formatter.withTimeZoneLong(timeZone), + 'full' => formatter.withTimeZoneLongGeneric(timeZone), + String() => throw UnimplementedError( + 'Unknown time zone style `$timeZoneStyle`', + ), + }; + formattedDt = zonedFormatter.format(testDate); + } else { + formattedDt = formatter.format(testDate); + } returnJson['result'] = formattedDt; - returnJson['actual_options'] = dateTimeFormatOptions.toString(); + returnJson['actual_options'] = dateTimeFormatOptions.humanReadable; + returnJson['options'] = testOptionsJson; } catch (error) { - returnJson['unsupported'] = ': ${error.toString()}'; + returnJson['error'] = ': ${error.toString()}'; } return jsonEncode(returnJson); } + +extension on DateTimeFormatOptions { + String get humanReadable { + final fields = { + if (calendar != null) 'calendar': calendar, + if (dayPeriod != null) 'dayPeriod': dayPeriod, + if (numberingSystem != null) 'numberingSystem': numberingSystem, + if (clockstyle != null) 'clockstyle': clockstyle, + if (era != null) 'era': era, + if (timestyle != null) 'timestyle': timestyle, + if (fractionalSecondDigits != null) + 'fractionalSecondDigits': fractionalSecondDigits, + 'formatMatcher': formatMatcher, + }; + final entries = fields.entries + .map((e) => '${e.key}: ${e.value}') + .join(', '); + return 'DateTimeFormatOptions($entries)'; + } +} diff --git a/executors/dart/lib/lang_names.dart b/executors/dart/lib/lang_names.dart index 107fbfe6..f04c2e3b 100644 --- a/executors/dart/lib/lang_names.dart +++ b/executors/dart/lib/lang_names.dart @@ -26,6 +26,14 @@ String testLangNames(String jsonEncoded) { } final languageLabel = json['language_label'] as String; + if (languageLabel.contains('u-kr')) { + outputLine.addAll({ + 'unsupported': 'u-kr extension not supported', + 'error_retry': false, // Do not repeat + }); + return jsonEncode(outputLine); + } + Locale languageLabelLocale; try { languageLabelLocale = Locale.parse(languageLabel); @@ -49,7 +57,6 @@ String testLangNames(String jsonEncoded) { outputLine['result'] = resultLangName; } catch (error) { outputLine.addAll({ - 'error_type': 'unsupported', 'error_detail': error.toString(), 'actual_options': options.toJson(), 'error_retry': false, // Do not repeat diff --git a/executors/dart/lib/numberformat.dart b/executors/dart/lib/numberformat.dart index 7419b5cc..e2a8caf3 100644 --- a/executors/dart/lib/numberformat.dart +++ b/executors/dart/lib/numberformat.dart @@ -280,7 +280,8 @@ NumberFormatOptions _decimalPatternToOptions( ); return numberFormatOptions.copyWith(roundingMode: roundingMode); } else { - return numberFormatOptions; + //TODO: remove this halfEven default override, as soon as it is always passed in the numberformat args. + return numberFormatOptions.copyWith(roundingMode: RoundingMode.halfEven); } } @@ -324,9 +325,6 @@ NumberFormatOptions _fromJson(Map options) { final signDisplay = SignDisplay.values .where((element) => element.name == options['signDisplay']) .firstOrNull; - final localeMatcher = LocaleMatcher.values - .where((element) => element.jsName == options['localeMatcher']) - .firstOrNull; final useGrouping = Grouping.values .where((element) => element.jsName == options['useGrouping']) .firstOrNull; @@ -374,7 +372,6 @@ NumberFormatOptions _fromJson(Map options) { return NumberFormatOptions.custom().copyWith( style: style, currency: currency, - localeMatcher: localeMatcher, signDisplay: signDisplay, notation: notation, useGrouping: useGrouping, @@ -391,11 +388,10 @@ extension on NumberFormatOptions { return { 'style': style.name, 'currency': currency, - 'localeMatcher': localeMatcher.jsName, 'signDisplay': signDisplay.name, 'notation': notation.name, 'useGrouping': useGrouping.jsName, - 'numberingSystem': numberingSystem?.toString(), + 'numberingSystem': numberingSystem, 'roundingMode': roundingMode.name, 'trailingZeroDisplay': trailingZeroDisplay.name, 'minimumIntegerDigits': minimumIntegerDigits, diff --git a/executors/dart/lib/version.dart b/executors/dart/lib/version.dart index cdd58ea8..095c2994 100644 --- a/executors/dart/lib/version.dart +++ b/executors/dart/lib/version.dart @@ -1,2 +1,2 @@ /// This file is autogenerated by bin/set_version.dart, do not modify manually. -const intl4xVersion = '0.12.2'; +const intl4xVersion = '0.13.0-wip'; diff --git a/executors/dart/out/version.js b/executors/dart/out/version.js index 1cfd1d1a..d045e47d 100644 --- a/executors/dart/out/version.js +++ b/executors/dart/out/version.js @@ -1,2 +1,2 @@ -const dartVersion = "0.12.2"; +const dartVersion = "0.13.0-wip"; module.exports = { dartVersion }; diff --git a/executors/dart/pubspec.lock b/executors/dart/pubspec.lock index 1c22bf3d..1ea71011 100644 --- a/executors/dart/pubspec.lock +++ b/executors/dart/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: f7bac1065b51df46b2291296e1c1b3616a47aeb735aea46a8ca3dcb7bb700ee7 + sha256: f0bb5d1648339c8308cc0b9838d8456b3cfe5c91f9dc1a735b4d003269e5da9a url: "https://pub.dev" source: hosted - version: "86.0.0" + version: "88.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "4001e2de7c9d125af9504b4c4f64ebba507c9cb9c712caf02ac1d4c37824f58c" + sha256: "0b7b9c329d2879f8f05d6c05b32ee9ec025f39b077864bdb5ac9a7b63418a98f" url: "https://pub.dev" source: hosted - version: "8.0.0" + version: "8.1.1" args: dependency: transitive description: @@ -61,10 +61,10 @@ packages: dependency: transitive description: name: code_assets - sha256: dd7ed641b7f642092092969f2dcd5845ab31c9f3efead0c06ca437bf9ce8a8b2 + sha256: "7f42899e7b22f7810ea8c2b281c979add25555fbe391dde539621069e20b90b4" url: "https://pub.dev" source: hosted - version: "0.19.4" + version: "0.19.5" collection: dependency: "direct main" description: @@ -133,10 +133,10 @@ packages: dependency: transitive description: name: hooks - sha256: "75363eae6c0c2db051c4f6b3b1fcdea8a09c4a596cc83bfff847661da6e80dfc" + sha256: "2bd640e4625fdfe5788ef33d825a8639797d44bce05695ab13543cde0ff9a078" url: "https://pub.dev" source: hosted - version: "0.19.5" + version: "0.20.0" http_multi_server: dependency: transitive description: @@ -156,11 +156,10 @@ packages: intl4x: dependency: "direct main" description: - name: intl4x - sha256: "2684e98ae48b288e345bfc32356d9497d120fafc5a5bf8d840d1a6fd19f3a526" - url: "https://pub.dev" - source: hosted - version: "0.12.2" + path: "../../../i18n/pkgs/intl4x" + relative: true + source: path + version: "0.13.0-wip" io: dependency: transitive description: @@ -229,10 +228,10 @@ packages: dependency: transitive description: name: native_toolchain_c - sha256: "74a0c80d877c519bc6bde2c4e27b6b01c1f93c9b480f65ceae8bedd3aba3c086" + sha256: "7e8358a4f6ec69a4f2d366bb971af298aca50d6c2e8a07be7c12d7f6d40460aa" url: "https://pub.dev" source: hosted - version: "0.16.8" + version: "0.17.1" node_preamble: dependency: "direct main" description: diff --git a/executors/dart/pubspec.yaml b/executors/dart/pubspec.yaml index 25a564ff..b6942a80 100644 --- a/executors/dart/pubspec.yaml +++ b/executors/dart/pubspec.yaml @@ -19,3 +19,8 @@ dev_dependencies: hook: intl4x: buildMode: fetch + + +dependency_overrides: + intl4x: + path: ../../../i18n/pkgs/intl4x/ From a2ebca1f9cfd4e03be431515f1d68151e6884f5d Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 19 Aug 2025 14:28:16 +0200 Subject: [PATCH 2/7] datetime fixes --- executors/dart/lib/datetime_format.dart | 152 +++++++++++++++++------- generateDataAndRun.sh | 4 +- 2 files changed, 109 insertions(+), 47 deletions(-) diff --git a/executors/dart/lib/datetime_format.dart b/executors/dart/lib/datetime_format.dart index 40013766..7f4efe0a 100644 --- a/executors/dart/lib/datetime_format.dart +++ b/executors/dart/lib/datetime_format.dart @@ -1,4 +1,5 @@ import 'dart:convert'; + import 'package:collection/collection.dart'; import 'package:intl4x/datetime_format.dart'; import 'package:intl4x/intl4x.dart'; @@ -54,16 +55,17 @@ String testDateTimeFmt(String jsonEncoded) { // ignore: unused_local_variable - to be used with the timezoneformatter String? timezone; - int? offset; - String? timeZoneStyle; - if (testOptionsJson.containsKey('time_zone') && - testOptionsJson.containsKey('tz_offset_secs') && - testOptionsJson.containsKey('timeStyle')) { - timezone = testOptionsJson['time_zone'] as String; - offset = testOptionsJson['tz_offset_secs'] as int; - timeZoneStyle = testOptionsJson['timeStyle'] as String; + int? offsetSeconds; + if (testOptionsJson.containsKey('timeZone') && + json.containsKey('tz_offset_secs')) { + timezone = testOptionsJson['timeZone'] as String; + offsetSeconds = (json['tz_offset_secs'] as num).toInt(); } + final semanticSkeleton = testOptionsJson['semanticSkeleton'] as String?; + final semanticSkeletonLength = + testOptionsJson['semanticSkeletonLength'] as String?; + final dateStyle = testOptionsJson['dateStyle'] as String?; final timeStyle = testOptionsJson['timeStyle'] as String?; final yearStyle = testOptionsJson['yearStyle'] as String?; @@ -98,54 +100,114 @@ String testDateTimeFmt(String jsonEncoded) { ).dateTimeFormat(dateTimeFormatOptions); try { - final formatter = switch ((dateStyle, timeStyle, yearStyle)) { - ('medium', null, _) => dtFormatter.ymd(dateStyle: DateFormatStyle.medium), - (null, 'short', _) => dtFormatter.t(style: TimeFormatStyle.short), - ('full', 'short', null) => dtFormatter.ymdt( - dateStyle: DateFormatStyle.full, - timeStyle: TimeFormatStyle.short, - ), - ('short', 'full', null) => dtFormatter.ymdt( - dateStyle: DateFormatStyle.short, - timeStyle: TimeFormatStyle.full, - ), - (_, _, 'with_era') => dtFormatter.ymde(), - ('short', 'full', _) => dtFormatter.ymdet( - dateStyle: DateFormatStyle.short, - timeStyle: TimeFormatStyle.full, - ), - (_, _, _) => throw UnimplementedError( - 'Unknown combination of date style `$dateStyle`, time style `$timeStyle`, and year style `$yearStyle`', - ), - }; + final formatter = semanticSkeleton != null + ? getFormatterForSkeleton( + semanticSkeleton, + semanticSkeletonLength, + dtFormatter, + ) + : getFormatterForStyle(dateStyle, timeStyle, yearStyle, dtFormatter); String formattedDt; - if (timezone != null) { - final timeZone = TimeZone( - name: timezone, - offset: Duration(seconds: offset!), + if (timeStyle == 'full' && timezone != null) { + final offset = Duration(seconds: offsetSeconds!); + final timeZone = TimeZone(name: timezone, offset: offset); + final timeZoneStyle = 'long'; + final zonedFormatter = getZonedFormatter( + timeZoneStyle, + formatter, + timeZone, ); - final zonedFormatter = switch (timeZoneStyle!) { - 'short' => formatter.withTimeZoneShort(timeZone), - 'long' => formatter.withTimeZoneLong(timeZone), - 'full' => formatter.withTimeZoneLongGeneric(timeZone), - String() => throw UnimplementedError( - 'Unknown time zone style `$timeZoneStyle`', - ), - }; - formattedDt = zonedFormatter.format(testDate); + formattedDt = zonedFormatter.format(testDate.add(offset)); } else { formattedDt = formatter.format(testDate); } returnJson['result'] = formattedDt; - returnJson['actual_options'] = dateTimeFormatOptions.humanReadable; - returnJson['options'] = testOptionsJson; - } catch (error) { - returnJson['error'] = ': ${error.toString()}'; + } on Exception catch (e) { + returnJson['error_type'] = 'unsupported'; + returnJson['unsupported'] = ': ${e.toString()}'; } + returnJson['actual_options'] = dateTimeFormatOptions.humanReadable; + returnJson['options'] = testOptionsJson; return jsonEncode(returnJson); } +FormatterWithTimeZones getFormatterForSkeleton( + String semanticSkeleton, + String? semanticSkeletonLength, + DateTimeFormatBuilder dtFormatter, +) { + // The provided Rust code implies a more complex logic, but here we'll map the known skeletons. + // The Rust code's `None => None` and `None => Ok(...)` branches aren't directly translatable + // to a Dart function that must return a Formatter. We'll handle the valid cases and throw for others. + + final semanticDateStyle = switch (semanticSkeletonLength) { + 'short' => DateFormatStyle.short, + 'medium' => DateFormatStyle.medium, + 'long' => DateFormatStyle.long, + _ => throw Exception(), + }; + return switch (semanticSkeleton) { + 'D' || 'DT' || 'DTZ' => dtFormatter.d(), + 'MD' || 'MDT' || 'MDTZ' => dtFormatter.md(), + 'YMD' || 'YMDT' || 'YMDTZ' => dtFormatter.ymd(dateStyle: semanticDateStyle), + 'YMDE' || + 'YMDET' || + 'YMDETZ' => dtFormatter.ymde(dateStyle: semanticDateStyle), + 'M' => dtFormatter.m(), + 'Y' => dtFormatter.y(), + 'T' || 'Z' || 'TZ' => dtFormatter.t(), + _ => throw Exception('Unknown skeleton: $semanticSkeleton'), + }; +} + +ZonedFormatter getZonedFormatter( + String timeZoneStyle, + FormatterWithTimeZones formatter, + TimeZone timeZone, +) { + final zonedFormatter = switch (timeZoneStyle) { + 'short' => formatter.withTimeZoneShort(timeZone), + 'long' => formatter.withTimeZoneLong(timeZone), + 'full' => formatter.withTimeZoneLongGeneric(timeZone), + String() => throw Exception('Unknown time zone style `$timeZoneStyle`'), + }; + return zonedFormatter; +} + +FormatterWithTimeZones getFormatterForStyle( + String? dateStyle, + String? timeStyle, + String? yearStyle, + DateTimeFormatBuilder dtFormatter, +) { + final formatter = switch ((dateStyle, timeStyle, yearStyle)) { + ('medium', null, _) => dtFormatter.ymd(dateStyle: DateFormatStyle.medium), + (null, 'short', _) => dtFormatter.t(style: TimeFormatStyle.short), + ('full', 'short', null) => dtFormatter.ymdt( + dateStyle: DateFormatStyle.full, + timeStyle: TimeFormatStyle.short, + ), + ('full', 'full', null) => dtFormatter.ymdt( + dateStyle: DateFormatStyle.full, + timeStyle: TimeFormatStyle.full, + ), + ('short', 'full', null) => dtFormatter.ymdt( + dateStyle: DateFormatStyle.short, + timeStyle: TimeFormatStyle.full, + ), + ('short', 'full', 'with_era') => dtFormatter.ymdet( + dateStyle: DateFormatStyle.short, + timeStyle: TimeFormatStyle.full, + ), + (_, _, 'with_era') => dtFormatter.ymde(), + (_, _, _) => throw Exception( + 'Unknown combination of date style `$dateStyle`, time style `$timeStyle`, and year style `$yearStyle`', + ), + }; + return formatter; +} + extension on DateTimeFormatOptions { String get humanReadable { final fields = { diff --git a/generateDataAndRun.sh b/generateDataAndRun.sh index 672b3195..d812f093 100755 --- a/generateDataAndRun.sh +++ b/generateDataAndRun.sh @@ -48,8 +48,9 @@ mkdir -p $TEMP_DIR/testData # Generates all new test data source_file=${1:-'run_config.json'} pushd testgen +all_test_types=$(jq '.[].run.test_type' ../$source_file | jq -s '.' | jq 'add' | jq 'unique' | jq -r 'join(" ")') all_icu_versions=$(jq '.[].run.icu_version' ../$source_file | jq -s '.' | jq 'unique' | jq -r 'join(" ")') -python3 testdata_gen.py --icu_versions $all_icu_versions +python3 testdata_gen.py --icu_versions $all_icu_versions --test_types $all_test_types # And copy results to subdirectories. cp -r icu* ../$TEMP_DIR/testData popd @@ -145,7 +146,6 @@ popd mkdir -p $TEMP_DIR/testReports pushd verifier -all_test_types=$(jq '.[].run.test_type' ../$source_file | jq -s '.' | jq 'add' | jq 'unique' | jq -r 'join(" ")') all_execs=$(jq -r 'join(" ")' <<< $all_execs_json) # Specifies the arrangement of the columns in the summary dashboard From fd61c852804c3d63cdd91d72684dc1d8053849ac Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 19 Aug 2025 14:54:03 +0200 Subject: [PATCH 3/7] More --- executors/dart/lib/datetime_format.dart | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/executors/dart/lib/datetime_format.dart b/executors/dart/lib/datetime_format.dart index 7f4efe0a..1579f54e 100644 --- a/executors/dart/lib/datetime_format.dart +++ b/executors/dart/lib/datetime_format.dart @@ -17,6 +17,8 @@ String testDateTimeFmt(String jsonEncoded) { localeString = 'und'; // Default to 'und' if locale is null or empty } + final returnJson = {'label': label}; + // Parse Locale string Locale locale; try { @@ -34,6 +36,12 @@ String testDateTimeFmt(String jsonEncoded) { testOptionsJson = json['options'] as Map; } + if (testOptionsJson['dateTimeFormatType'] == 'atTime') { + returnJson['error_type'] = 'unsupported'; + returnJson['unsupported'] = '`at` not supported'; + return jsonEncode(returnJson); + } + // Initialize DateTimeFormatOptions var dateTimeFormatOptions = DateTimeFormatOptions(); @@ -94,7 +102,6 @@ String testDateTimeFmt(String jsonEncoded) { testDate = DateTime.now(); } - final returnJson = {'label': label}; final dtFormatter = Intl( locale: locale, ).dateTimeFormat(dateTimeFormatOptions); @@ -149,11 +156,11 @@ FormatterWithTimeZones getFormatterForSkeleton( }; return switch (semanticSkeleton) { 'D' || 'DT' || 'DTZ' => dtFormatter.d(), - 'MD' || 'MDT' || 'MDTZ' => dtFormatter.md(), + 'MD' => dtFormatter.md(), + 'MDT' || 'MDTZ' => dtFormatter.mdt(dateStyle: semanticDateStyle), 'YMD' || 'YMDT' || 'YMDTZ' => dtFormatter.ymd(dateStyle: semanticDateStyle), - 'YMDE' || - 'YMDET' || - 'YMDETZ' => dtFormatter.ymde(dateStyle: semanticDateStyle), + 'YMDE' => dtFormatter.ymde(dateStyle: semanticDateStyle), + 'YMDET' || 'YMDETZ' => dtFormatter.ymdet(dateStyle: semanticDateStyle), 'M' => dtFormatter.m(), 'Y' => dtFormatter.y(), 'T' || 'Z' || 'TZ' => dtFormatter.t(), @@ -184,11 +191,11 @@ FormatterWithTimeZones getFormatterForStyle( final formatter = switch ((dateStyle, timeStyle, yearStyle)) { ('medium', null, _) => dtFormatter.ymd(dateStyle: DateFormatStyle.medium), (null, 'short', _) => dtFormatter.t(style: TimeFormatStyle.short), - ('full', 'short', null) => dtFormatter.ymdt( + ('full', 'short', null) => dtFormatter.ymdet( dateStyle: DateFormatStyle.full, timeStyle: TimeFormatStyle.short, ), - ('full', 'full', null) => dtFormatter.ymdt( + ('full', 'full', null) => dtFormatter.ymdet( dateStyle: DateFormatStyle.full, timeStyle: TimeFormatStyle.full, ), From 0679e129e444c8d6702cb9955a7428929d93d8f2 Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 27 Aug 2025 15:35:46 +0200 Subject: [PATCH 4/7] Use published version --- executors/dart/lib/datetime_format.dart | 31 +++++++++++-------------- executors/dart/pubspec.lock | 21 ++++++++++++----- executors/dart/pubspec.yaml | 7 +----- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/executors/dart/lib/datetime_format.dart b/executors/dart/lib/datetime_format.dart index 1579f54e..951ffb01 100644 --- a/executors/dart/lib/datetime_format.dart +++ b/executors/dart/lib/datetime_format.dart @@ -62,11 +62,11 @@ String testDateTimeFmt(String jsonEncoded) { } // ignore: unused_local_variable - to be used with the timezoneformatter - String? timezone; + String? timeZoneName; int? offsetSeconds; if (testOptionsJson.containsKey('timeZone') && json.containsKey('tz_offset_secs')) { - timezone = testOptionsJson['timeZone'] as String; + timeZoneName = testOptionsJson['timeZone'] as String; offsetSeconds = (json['tz_offset_secs'] as num).toInt(); } @@ -115,16 +115,12 @@ String testDateTimeFmt(String jsonEncoded) { ) : getFormatterForStyle(dateStyle, timeStyle, yearStyle, dtFormatter); String formattedDt; - if (timeStyle == 'full' && timezone != null) { + if (timeStyle == 'full' && timeZoneName != null) { final offset = Duration(seconds: offsetSeconds!); - final timeZone = TimeZone(name: timezone, offset: offset); + final timeZone = TimeZone(name: timeZoneName, offset: offset); final timeZoneStyle = 'long'; - final zonedFormatter = getZonedFormatter( - timeZoneStyle, - formatter, - timeZone, - ); - formattedDt = zonedFormatter.format(testDate.add(offset)); + final zonedFormatter = getZonedFormatter(timeZoneStyle, formatter); + formattedDt = zonedFormatter.format(testDate.add(offset), timeZone); } else { formattedDt = formatter.format(testDate); } @@ -139,7 +135,7 @@ String testDateTimeFmt(String jsonEncoded) { return jsonEncode(returnJson); } -FormatterWithTimeZones getFormatterForSkeleton( +DateTimeFormatter getFormatterForSkeleton( String semanticSkeleton, String? semanticSkeletonLength, DateTimeFormatBuilder dtFormatter, @@ -168,21 +164,20 @@ FormatterWithTimeZones getFormatterForSkeleton( }; } -ZonedFormatter getZonedFormatter( +ZonedDateTimeFormatter getZonedFormatter( String timeZoneStyle, - FormatterWithTimeZones formatter, - TimeZone timeZone, + DateTimeFormatter formatter, ) { final zonedFormatter = switch (timeZoneStyle) { - 'short' => formatter.withTimeZoneShort(timeZone), - 'long' => formatter.withTimeZoneLong(timeZone), - 'full' => formatter.withTimeZoneLongGeneric(timeZone), + 'short' => formatter.withTimeZoneShort(), + 'long' => formatter.withTimeZoneLong(), + 'full' => formatter.withTimeZoneLongGeneric(), String() => throw Exception('Unknown time zone style `$timeZoneStyle`'), }; return zonedFormatter; } -FormatterWithTimeZones getFormatterForStyle( +DateTimeFormatter getFormatterForStyle( String? dateStyle, String? timeStyle, String? yearStyle, diff --git a/executors/dart/pubspec.lock b/executors/dart/pubspec.lock index 1ea71011..c2800c5c 100644 --- a/executors/dart/pubspec.lock +++ b/executors/dart/pubspec.lock @@ -153,13 +153,22 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.2" + icu4x: + dependency: transitive + description: + name: icu4x + sha256: "9e89a363c410608de336e1a15c599ecc49245cc6f9d7d719b4b1ced57151c92c" + url: "https://pub.dev" + source: hosted + version: "2.0.0-dev.0" intl4x: dependency: "direct main" description: - path: "../../../i18n/pkgs/intl4x" - relative: true - source: path - version: "0.13.0-wip" + name: intl4x + sha256: "17ca4511e95d036954897ca192d771598b3744c07bd43de72a35af795f244228" + url: "https://pub.dev" + source: hosted + version: "0.13.0" io: dependency: transitive description: @@ -420,10 +429,10 @@ packages: dependency: transitive description: name: watcher - sha256: "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a" + sha256: "5bf046f41320ac97a469d506261797f35254fa61c641741ef32dacda98b7d39c" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.3" web: dependency: transitive description: diff --git a/executors/dart/pubspec.yaml b/executors/dart/pubspec.yaml index b6942a80..6f18a0b3 100644 --- a/executors/dart/pubspec.yaml +++ b/executors/dart/pubspec.yaml @@ -6,7 +6,7 @@ environment: dependencies: collection: ^1.19.1 - intl4x: 0.12.2 + intl4x: 0.13.0 node_preamble: ^2.0.2 pubspec_lock_parse: ^2.2.0 @@ -19,8 +19,3 @@ dev_dependencies: hook: intl4x: buildMode: fetch - - -dependency_overrides: - intl4x: - path: ../../../i18n/pkgs/intl4x/ From c9150cce9ad1040b628fe6fb494d7d5808c2a469 Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 27 Aug 2025 15:37:00 +0200 Subject: [PATCH 5/7] Switch to icu77 --- run_config.json | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/run_config.json b/run_config.json index 8fb9330a..edca33a8 100644 --- a/run_config.json +++ b/run_config.json @@ -230,7 +230,7 @@ }, { "run": { - "icu_version": "icu74", + "icu_version": "icu77", "exec": "dart_native", "test_type": [ "collation", @@ -243,6 +243,26 @@ "per_execution": 10000 } }, + { + "prereq": { + "name": "nvm 24.0.0, icu77.1", + "version": "24.0.0", + "command": "nvm install 24.0.0;nvm use 24.0.0 --silent" + }, + "run": { + "icu_version": "icu76", + "exec": "dart_web", + "test_type": [ + "collation", + "datetime_fmt", + "number_fmt", + "lang_names", + "plural_rules", + "list_fmt" + ], + "per_execution": 10000 + } + }, { "prereq": { "name": "nvm", From cd85524d705a05ba238f82f685dd0767a1c659e5 Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 27 Aug 2025 15:39:25 +0200 Subject: [PATCH 6/7] set version --- executors/dart/lib/version.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/executors/dart/lib/version.dart b/executors/dart/lib/version.dart index 095c2994..d54983bd 100644 --- a/executors/dart/lib/version.dart +++ b/executors/dart/lib/version.dart @@ -1,2 +1,2 @@ /// This file is autogenerated by bin/set_version.dart, do not modify manually. -const intl4xVersion = '0.13.0-wip'; +const intl4xVersion = '0.13.0'; From 68d798257732c3d28fbde340448d26837f66ddff Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 27 Aug 2025 15:59:00 +0200 Subject: [PATCH 7/7] Regenerate --- executors/dart/out/version.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/executors/dart/out/version.js b/executors/dart/out/version.js index d045e47d..92fc0e76 100644 --- a/executors/dart/out/version.js +++ b/executors/dart/out/version.js @@ -1,2 +1,2 @@ -const dartVersion = "0.13.0-wip"; +const dartVersion = "0.13.0"; module.exports = { dartVersion };