Skip to content

Commit

Permalink
ICU4J: adding datetime fmt (unicode-org#266)
Browse files Browse the repository at this point in the history
* Add plural rules to CPP

* Add the Rust datetime fmt code

* Rust datetime fmt and updates to ICU4C and NodeJS (unicode-org#240)

* Add plural rules to CPP

* Starting ICU4X datetime fmt

* DateTime format: Set default timezone explicitly

* Fix formatting

* Added ICU4X timezone computation - not working yet!

* DateTime generator updated to ISO formatted string

* DateTime updates for Node and ICU4C.

* Formatted src/datetimefmt.rs

* Updated using CustomTimeZone in ICU4X date time fmt

* Cargo clippified

* Remove unused function

* Update version to ~1.3

* ICU4J: adding date time format

* ICU4J DateTimeFormat tests starting to work

* Added two tests and reformatted some code

* Add Java date time formatter tests for ICU73 and ICU 75

* Removing unused code
  • Loading branch information
sven-oly authored Aug 8, 2024
1 parent 7db1d6a commit 6c137c5
Show file tree
Hide file tree
Showing 10 changed files with 471 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.unicode.conformance.testtype.ITestType;
import org.unicode.conformance.testtype.ITestTypeOutputJson;
import org.unicode.conformance.testtype.collator.CollatorTester;
import org.unicode.conformance.testtype.datetimeformatter.DateTimeFormatterTester;
import org.unicode.conformance.testtype.langnames.LangNamesTester;
import org.unicode.conformance.testtype.likelysubtags.LikelySubtagsTester;
import org.unicode.conformance.testtype.listformatter.ListFormatterTester;
Expand Down Expand Up @@ -118,6 +119,8 @@ public static String getTestCaseResponse(String inputLine) throws Exception {
ITestType testType;
if (testTypeStr.equals("collation_short")) {
testType = CollatorTester.INSTANCE;
} else if (testTypeStr.equals("datetime_fmt")) {
testType = DateTimeFormatterTester.INSTANCE;
} else if (testTypeStr.equals("lang_names")) {
testType = LangNamesTester.INSTANCE;
} else if (testTypeStr.equals("likely_subtags")) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.unicode.conformance.testtype.datetimeformatter;

public enum DateTimeFormatterDateStyle {
FULL,
LONG,
MEDIUM,
SHORT;

public static org.unicode.conformance.testtype.datetimeformatter.DateTimeFormatterDateStyle DEFAULT = MEDIUM;

public static org.unicode.conformance.testtype.datetimeformatter.DateTimeFormatterDateStyle getFromString(
String s) {
try {
return org.unicode.conformance.testtype.datetimeformatter.DateTimeFormatterDateStyle.valueOf(
s.toUpperCase());
} catch (Exception e) {
return DEFAULT;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.unicode.conformance.testtype.datetimeformatter;

import java.util.Date;
import com.ibm.icu.util.Calendar;

import org.unicode.conformance.testtype.ITestTypeInputJson;

public class DateTimeFormatterInputJson implements ITestTypeInputJson {

public String testType;

public String label;

public String locale;

// UTC formatted time
public String inputString;

public Date myDate;

public String skeleton;

public DateTimeFormatterDateStyle dateStyle;

public DateTimeFormatterTimeStyle timeStyle;

// TODO!!!
public String calendarString;
// Set calendar from calendarString!
public Calendar calendar;

public String numberingSystem;

public String timeZone;

public String timeZoneName;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.unicode.conformance.testtype.datetimeformatter;

import org.unicode.conformance.testtype.ITestTypeOutputJson;

public class DateTimeFormatterOutputJson implements ITestTypeOutputJson {

public String test_type;

public String label;

public String result;

public String error;

public String error_message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package org.unicode.conformance.testtype.datetimeformatter;

import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

import java.util.Date;

import com.ibm.icu.util.Calendar;
import com.ibm.icu.text.DateFormat;
import com.ibm.icu.util.ULocale;

import io.lacuna.bifurcan.IMap;
import io.lacuna.bifurcan.Map;


import org.unicode.conformance.ExecutorUtils;
import org.unicode.conformance.testtype.ITestType;
import org.unicode.conformance.testtype.ITestTypeInputJson;
import org.unicode.conformance.testtype.ITestTypeOutputJson;

public class DateTimeFormatterTester implements ITestType {

public static DateTimeFormatterTester INSTANCE = new DateTimeFormatterTester();

@Override
public ITestTypeInputJson inputMapToJson(Map<String, Object> inputMapData) {
DateTimeFormatterInputJson result = new DateTimeFormatterInputJson();

result.label = (String) inputMapData.get("label", null);
result.locale = (String) inputMapData.get("locale", null);
result.skeleton = (String) inputMapData.get("skeleton", null);

result.inputString = (String) inputMapData.get("input_string", null);

java.util.Map<String, Object> inputOptions =
(java.util.Map<String, Object>) inputMapData.get("options", null);

result.timeZone = (String) inputOptions.get("timeZone");
ZoneId thisZoneId;
if (result.timeZone == null) {
thisZoneId = ZoneId.systemDefault();
} else {
thisZoneId = ZoneId.of(result.timeZone);
}

// Extract ISO part of the input string to parse.
String inputStringDateTime = result.inputString.substring(0, 25);

// For parsing the input string and converting to java.util.date
LocalDateTime parsedLocalDateTime =
LocalDateTime.parse(inputStringDateTime, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
result.myDate =
java.util.Date.from(parsedLocalDateTime.atZone(thisZoneId)
.toInstant());

result.dateStyle = DateTimeFormatterDateStyle.getFromString(
"" + inputOptions.get("dateStyle")
);

result.timeStyle = DateTimeFormatterTimeStyle.getFromString(
"" + inputOptions.get("timeStyle")
);

result.calendarString = (String) inputOptions.get("calendar");

// TODO!!! Get calendar object. Depends on timezone and locale.
// Just a placeholder for now.
result.calendar = Calendar.getInstance();

result.numberingSystem = (String) inputOptions.get("numberingSystem");

result.timeZoneName = (String) inputOptions.get("timeZoneName");

return result;
}

public ITestTypeOutputJson execute(ITestTypeInputJson inputJson) {
DateTimeFormatterInputJson input = (DateTimeFormatterInputJson) inputJson;

// partially construct output
DateTimeFormatterOutputJson output = (DateTimeFormatterOutputJson) getDefaultOutputJson();
output.label = input.label;

try {
output.result = getDateTimeFormatterResultString(input);
} catch (Exception e) {
output.error = e.getMessage();
output.error_message = e.getMessage();
return output;
}

// If we get here, it's a pass/fail result (supported options and no runtime errors/exceptions)
return output;
}

@Override
public ITestTypeOutputJson getDefaultOutputJson() {
return new DateTimeFormatterOutputJson();
}

public IMap<String, Object> convertOutputToMap(ITestTypeOutputJson outputJson) {
DateTimeFormatterOutputJson output = (DateTimeFormatterOutputJson) outputJson;
return new io.lacuna.bifurcan.Map<String, Object>()
.put("label", output.label)
.put("result", output.result);
}

@Override
public String formatOutputJson(ITestTypeOutputJson outputJson) {
return ExecutorUtils.GSON.toJson((DateTimeFormatterOutputJson) outputJson);
}

public String getDateTimeFormatterResultString(DateTimeFormatterInputJson input) {

ULocale locale = ULocale.forLanguageTag(input.locale);

int dateStyle;
switch (input.dateStyle) {
case FULL:
dateStyle = DateFormat.FULL;
break;
case LONG:
dateStyle = DateFormat.LONG;
break;
default:
case MEDIUM:
dateStyle = DateFormat.MEDIUM;
break;
case SHORT:
dateStyle = DateFormat.SHORT;
break;
}

int timeStyle;
switch (input.timeStyle) {
case FULL:
timeStyle = DateFormat.FULL;
break;
case LONG:
timeStyle = DateFormat.LONG;
break;
default:
case MEDIUM:
timeStyle = DateFormat.MEDIUM;
break;
case SHORT:
timeStyle = DateFormat.SHORT;
break;

}

// Get calendar and timezone as needed.
Calendar cal = input.calendar;

DateFormat dtf;
if (input.skeleton != null) {
dtf = DateFormat.getInstanceForSkeleton(cal, input.skeleton, locale);
} else {
dtf = DateFormat.getDateTimeInstance(cal, dateStyle, timeStyle, locale);
}

return dtf.format(input.myDate);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.unicode.conformance.testtype.datetimeformatter;

public enum DateTimeFormatterTimeStyle {
FULL,
LONG,
MEDIUM,
SHORT;

public static org.unicode.conformance.testtype.datetimeformatter.DateTimeFormatterTimeStyle DEFAULT = MEDIUM;

public static org.unicode.conformance.testtype.datetimeformatter.DateTimeFormatterTimeStyle getFromString(
String s) {
try {
return org.unicode.conformance.testtype.datetimeformatter.DateTimeFormatterTimeStyle.valueOf(
s.toUpperCase());
} catch (Exception e) {
return DEFAULT;
}
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public ITestTypeInputJson inputMapToJson(Map<String, Object> inputMapData) {
result.label = (String) inputMapData.get("label", null);
result.locale = (String) inputMapData.get("locale", null);

java.util.Map<String,Object> inputOptions = (java.util.Map<String,Object>) inputMapData.get("options", null);
java.util.Map<String, Object> inputOptions = (java.util.Map<String, Object>) inputMapData.get(
"options", null);

result.listType = ListFormatterType.getFromString(
"" + inputOptions.get("list_type")
Expand Down Expand Up @@ -68,7 +69,7 @@ public ITestTypeOutputJson getDefaultOutputJson() {
@Override
public IMap<String, Object> convertOutputToMap(ITestTypeOutputJson outputJson) {
ListFormatterOutputJson output = (ListFormatterOutputJson) outputJson;
return new io.lacuna.bifurcan.Map<String,Object>()
return new io.lacuna.bifurcan.Map<String, Object>()
.put("label", output.label)
.put("result", output.result);
}
Expand All @@ -84,27 +85,33 @@ public String getListFormatResultString(ListFormatterInputJson input) {
ULocale locale = ULocale.forLanguageTag(input.locale);

switch (input.listType) {
case DISJUNCTION: listType = Type.OR;
case DISJUNCTION:
listType = Type.OR;
break;
case UNIT: listType = Type.UNITS;
case UNIT:
listType = Type.UNITS;
break;
default:
case CONJUNCTION: listType = Type.AND;
case CONJUNCTION:
listType = Type.AND;
break;
}

switch (input.style) {
case NARROW: listWidth = Width.NARROW;
case NARROW:
listWidth = Width.NARROW;
break;
case SHORT: listWidth = Width.SHORT;
case SHORT:
listWidth = Width.SHORT;
break;
default:
case LONG: listWidth = Width.WIDE;
case LONG:
listWidth = Width.WIDE;
break;
}

ListFormatter lf = ListFormatter.getInstance(locale, listType, listWidth);

return lf.format(input.inputList);
return lf.format(input.inputList);
}
}
Loading

0 comments on commit 6c137c5

Please sign in to comment.