Skip to content

Commit f2d250a

Browse files
author
Craig Cornelius
authored
Datetime fixes. Updating known issues in date time implementations (#512)
* Updating number format data generation and NodeJS number_fmt * Updated C++ number format, fixing errors and failing tests * Fix number format in ICU4J * Remove cout * Add halfOdd to possible test results * Add dateTimeFormatType to datagen, schema, and CPP version * Updating regex for unsupported test types. * Updates as suggested * Classify some datetime_fmt errors as known issues, fixing some ICU4C and ICU4J failures. * Handle Node known issue for timezone only format * Responding to suggestions * Remove unused variable * Remove extra line * Revise known issues for digit comparison * Mark timezone only as unsupported in NodeJS datetime_fmt * Simplified comparisons
1 parent bf4fd60 commit f2d250a

File tree

6 files changed

+109
-22
lines changed

6 files changed

+109
-22
lines changed

executors/cpp/datetime_fmt.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ auto TestDatetimeFmt(json_object *json_in) -> string {
129129
// skeleton or date_style.
130130
string default_skeleton_string = "M/d/yyyy";
131131

132+
// Indicates if the library outputs date and time with the "at", as in "July 1 at 10:00"
133+
bool supports_atTime = true;
134+
135+
string dateTimeFormatType_str = "";
136+
132137
if (options_obj != nullptr) {
133138
json_object* option_item = json_object_object_get(options_obj, "dateStyle");
134139
if (option_item != nullptr) {
@@ -141,6 +146,31 @@ auto TestDatetimeFmt(json_object *json_in) -> string {
141146
timeStyle_str = json_object_get_string(option_item);
142147
time_style = StringToEStyle(timeStyle_str);
143148
}
149+
150+
option_item = json_object_object_get(options_obj, "dateTimeFormatType");
151+
if (option_item != nullptr) {
152+
// What this data item expects.
153+
dateTimeFormatType_str = json_object_get_string(option_item);
154+
// Check if this is not supported?
155+
if ((dateTimeFormatType_str == "atTime" && !supports_atTime) ||
156+
(dateTimeFormatType_str != "atTime" && supports_atTime)) {
157+
// Inexact result is unsupported.
158+
json_object_object_add(
159+
return_json,
160+
"error_type",
161+
json_object_new_string("unsupported"));
162+
json_object_object_add(
163+
return_json,
164+
"unsupported",
165+
json_object_new_string("format type"));
166+
string detail_str = "formatType: " + dateTimeFormatType_str;
167+
json_object_object_add(
168+
return_json,
169+
"error_detail",
170+
json_object_new_string(detail_str.c_str()));
171+
return json_object_to_json_string(return_json);
172+
}
173+
}
144174
}
145175

146176
json_object *date_skeleton_item =

executors/node/datetime_fmt.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,16 @@ module.exports = {
169169
test_options['dateStyle'] = input_options['dateStyle'];
170170
}
171171

172+
if ('semanticSkeleton' in input_options) {
173+
// Check for known issue when format output should give only the time zone.
174+
if (input_options['semanticSkeleton'] == 'Z') {
175+
return_json['error'] = 'unsupported';
176+
return_json['error_detail'] = 'Requested timezone without date or time';
177+
return_json['unsupported'] = 'timezone only';
178+
return return_json;
179+
}
180+
}
181+
172182
let calendar;
173183
try {
174184
calendar = input_options['calendar'];

schema/datetime_fmt/result_schema.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
"and_more": {
3636
"description": "a placeholder for now",
3737
"type": "string"
38+
},
39+
"dateTimeFormatType": {
40+
"description": "Indicates if the 'at' should be used, e.g., 'July 1 at 10:00",
41+
"type": "string",
42+
"enum": ["standard", "atTime"]
3843
}
3944
}
4045
},

schema/datetime_fmt/test_schema.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,12 @@
141141
"semanticSkeletonLength": {
142142
"description": "Size of semantic skeleton for date/time format",
143143
"type": "string"
144-
}
144+
},
145+
"dateTimeFormatType": {
146+
"description": "Indicates if the 'at' should be used, e.g., 'July 1 at 10:00",
147+
"type": "string",
148+
"enum": ["standard", "atTime"]
149+
}
145150
}
146151
}
147152
},

testgen/generators/datetime_fmt.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ def generate_datetime_data_from_cldr(self, dt_json_path, run_limit=-1):
7676
options['dateStyle'] = test_item['dateLength']
7777
if 'timeLength' in test_item:
7878
options['timeStyle'] = test_item['timeLength']
79+
# Specifies if the expected output includes "at"
80+
if 'dateTimeFormatType' in test_item:
81+
options['dateTimeFormatType'] = test_item['dateTimeFormatType']
7982

8083
if 'calendar' in test_item:
8184
options['calendar'] = test_item['calendar']
@@ -92,8 +95,6 @@ def generate_datetime_data_from_cldr(self, dt_json_path, run_limit=-1):
9295
input_string = u_time.isoformat().replace('+00:00', 'Z')
9396
tz_offset_secs = raw_time.utcoffset().total_seconds()
9497

95-
if 'dateTimeFormatType' in test_item:
96-
options['dateTimeFormatType'] = test_item['dateTimeFormatType']
9798
if 'classicalSkeleton' in test_item:
9899
options['skeleton'] = test_item['classicalSkeleton']
99100
if 'semanticSkeleton' in test_item:

verifier/check_known_issues.py

Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,12 @@
4545
# Global KnownIssue Info types and strings
4646
class knownIssueType(Enum):
4747
known_issue_nbsp_sp = 'ASCII Space instead of NBSP'
48+
known_issue_sp_nbsp = 'NBSP instead of ASCII Space'
49+
4850
known_issue_replaced_numerals = 'Not creating non-ASCII numerals'
4951

52+
known_issue_different_number_system = 'Different number systems'
53+
5054
# Relative Date Time Format
5155
known_issue_unsupported_unit = 'Unsupported unit' # https://github.com/unicode-org/conformance/issues/274
5256

@@ -55,6 +59,9 @@ class knownIssueType(Enum):
5559
datetime_fmt_arabic_comma = 'Arabic comma vs. ASCII comma'
5660
datetime_unexpected_comma = 'Unexpected comma'
5761

62+
datetime_semantic_Z = 'NodeJS always includes date or time'
63+
64+
5865
# Likely Subtags
5966
likely_subtags_sr_latn = "sr_latin becoming en"
6067

@@ -93,6 +100,19 @@ def diff_nbsp_vs_ascii_space(actual, expected_value):
93100
else:
94101
return None
95102

103+
def diff_ascii_space_vs_nbsp(actual, expected_value):
104+
# Returns the ID of this if the only difference in the two strings
105+
# is Narrow Non-breaking Space (NBSP) in expected vs. ASCII space in the actual result.
106+
# Found in datetime testing.
107+
if not expected_value or not actual:
108+
return None
109+
110+
# If replacing all the NBSP characdters in expected gives the actual result,
111+
# then the only differences were with this type of space in formatted output.
112+
if expected_value.replace(SP, NBSP) == actual:
113+
return knownIssueType.known_issue_sp_nbsp
114+
else:
115+
return None
96116

97117
def numerals_replaced_by_another_numbering_system(expected, actual):
98118
# If the only difference are one type of digit
@@ -114,28 +134,24 @@ def numerals_replaced_by_another_numbering_system(expected, actual):
114134
# Tag indicates the type of change.
115135
# i1:i2 is the range of the substring in expected
116136
# j1:j2 is the range of the substring in actual
137+
different_number_systems = False
138+
different_digit = False
139+
117140

118141
for diff in sm_opcodes:
119142
tag = diff[0] # 'replace', 'delete', 'insert', or 'equal'
120143
old_val = expected[diff[1]:diff[2]]
121144
new_val = actual[diff[3]:diff[4]]
122145
if tag == 'replace':
123146
# expected[i1:i2] was replaced by actual[j1:j2]
124-
if old_val.isdigit() and new_val.isdigit():
125-
# TODO!! : check the value of the numeral
147+
if old_val.isdigit() and new_val.isdigit() and len(old_val) == len(new_val):
126148
# If the same value, then its a numbering system difference
127-
if unicodedata.numeric(old_val) == unicodedata.numeric(new_val):
128-
digit_replace = True
129-
else:
130-
# Both were digits but different numeric values
131-
non_digit_replacement = True
132-
else:
133-
# a digit was replaced with a non-digit
134-
non_digit_replacement = True
135-
136-
# Only true if the only changes were replacing digits
137-
if digit_replace and not non_digit_replace:
138-
return knownIssueType.known_issue_replaced_numerals
149+
for digit_old, digit_new in zip(old_val, new_val):
150+
if unicodedata.numeric(digit_old) == unicodedata.numeric(digit_new):
151+
different_number_systems = True
152+
153+
if different_number_systems:
154+
return knownIssueType.known_issue_different_number_system
139155
else:
140156
return None
141157

@@ -153,14 +169,20 @@ def dt_check_for_alternate_long_form(test, actual, expected):
153169
return None
154170
if actual.replace(' at', ',') == expected:
155171
return knownIssueType.datetime_fmt_at_inserted
172+
# Thai language difference with "time" inserted
173+
if actual.replace(' เวลา', '') == expected:
174+
return knownIssueType.datetime_fmt_at_inserted
175+
# Arabic
176+
if actual.replace(' في', '،') == expected:
177+
return knownIssueType.datetime_fmt_at_inserted
178+
156179
return None
157180

158181

159182
def dt_check_arabic_comma(test, actual, expected):
160183
if expected.replace('\u002c', '\u060c') == actual:
161184
return knownIssueType.datetime_fmt_arabic_comma
162-
else:
163-
return None
185+
return None
164186

165187

166188
def dt_unexpected_comma(test, actual, expected):
@@ -177,15 +199,23 @@ def check_datetime_known_issues(test):
177199
try:
178200
result = test['result']
179201
expected = test['expected']
202+
input_data = test.get('input_data')
203+
180204
is_ki = diff_nbsp_vs_ascii_space(result, expected)
181205
if is_ki:
182206
# Mark the test with this issue
183-
test['known_issue'] = knownIssueType.known_issue_nbsp_sp.value
207+
test['known_issue'] = is_ki.value
208+
remove_this_one = True
209+
210+
is_ki = diff_ascii_space_vs_nbsp(result, expected)
211+
if is_ki:
212+
# Mark the test with this issue
213+
test['known_issue'] = is_ki.value
184214
remove_this_one = True
185215

186216
is_ki = numerals_replaced_by_another_numbering_system(result, expected)
187217
if is_ki:
188-
test['known_issue_id'] = knownIssueType.known_issue_replaced_numerals.value
218+
test['known_issue_id'] = is_ki.value
189219
remove_this_one = True
190220

191221
is_ki = dt_check_for_alternate_long_form(test, result, expected)
@@ -198,11 +228,17 @@ def check_datetime_known_issues(test):
198228
test['known_issue_id'] = is_ki.value
199229
remove_this_one = True
200230

201-
is_ki = dt_unexpectedcomma(test, result, expected)
231+
is_ki = dt_unexpected_comma(test, result, expected)
202232
if is_ki:
203233
test['known_issue_id'] = is_ki.value
204234
remove_this_one = True
205235

236+
# Check if the semantic skeleton has "Z"
237+
if input_data and 'semanticSkeleton' in input_data['options'] and \
238+
input_data['options']['semanticSkeleton'] == 'Z':
239+
test['known_issud_id'] = knownIssueType.datetime_semantic_Z.value
240+
remove_this_one = True
241+
206242
except BaseException as err:
207243
# Can't get the info
208244
pass

0 commit comments

Comments
 (0)