Skip to content

Commit

Permalink
CLDR-7401 Add examples for quarters and eras, updated tests, removed …
Browse files Browse the repository at this point in the history
…comments
  • Loading branch information
haytenf committed Aug 1, 2024
1 parent ed980db commit a9428b4
Show file tree
Hide file tree
Showing 2 changed files with 236 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ public class ExampleGenerator {
DATE_SAMPLE = calendar.getTime();
calendar.set(1999, 9, 27, 13, 25, 59); // 1999-10-27 13:25:59
DATE_SAMPLE2 = calendar.getTime();

calendar.set(1999, 8, 5, 7, 0, 0); // 1999-09-05 07:00:00
DATE_SAMPLE3 = calendar.getTime();
calendar.set(1999, 8, 5, 23, 0, 0); // 1999-09-05 23:00:00
Expand Down Expand Up @@ -274,6 +273,32 @@ public void setCachingEnabled(boolean enabled) {

HelpMessages helpMessages;

/* For each calendar type, maps the closest two eras to 2025
* defined in that calendar to their corresponding start/end date
* TODO: include methods for calendarData in supplementalDataInfo API
* to extract this data directly from supplementaldata.xml
*/
public static final Map<String, String> calendarEras = new HashMap<String, String>() {{
put("calendar[@type=\"gregorian\"]/eras/era[@type=\"0\"]", "end=\"0-12-31\"");
put("calendar[@type=\"gregorian\"]/eras/era[@type=\"1\"]", "start=\"1-01-01\"");
put("calendar[@type=\"japanese\"]/eras/era[@type=\"235\"]", "start=\"1989-1-8\"");
put("calendar[@type=\"japanese\"]/eras/era[@type=\"236\"]", "start=\"2019-5-1\"");
put("calendar[@type=\"islamic\"]/eras/era[@type=\"0\"]", "start=\"622-7-15\"");
put("calendar[@type=\"chinese\"]/eras/era[@type=\"0\"]", "start=\"-2636-01-01\"");
put("calendar[@type=\"hebrew\"]/eras/era[@type=\"0\"]", "start=\"-3760-10-7\"");
put("calendar[@type=\"buddhist\"]/eras/era[@type=\"0\"]", "start=\"-542-01-01\"");
put("calendar[@type=\"coptic\"]/eras/era[@type=\"0\"]", "end=\"284-08-28\"");
put("calendar[@type=\"coptic\"]/eras/era[@type=\"1\"]", "start=\"284-08-29\"");
put("calendar[@type=\"persian\"]/eras/era[@type=\"0\"]", "start=\"622-01-01\"");
put("calendar[@type=\"dangi\"]/eras/era[@type=\"0\"]", "start=\"-2332-01-01\"");
put("calendar[@type=\"ethiopic\"]/eras/era[@type=\"0\"]", "end=\"8-08-28\"");
put("calendar[@type=\"ethiopic\"]/eras/era[@type=\"1\"]", "start=\"8-08-29\"");
put("calendar[@type=\"ethiopic-amete-alem\"]/eras/era[@type=\"0\"]", "end=\"-5492-08-29\"");
put("calendar[@type=\"indian\"]/eras/era[@type=\"0\"]", "start=\"79-01-01\"");
put("calendar[@type=\"roc\"]/eras/era[@type=\"0\"]", "end=\"1911-12-31\"");
put("calendar[@type=\"roc\"]/eras/era[@type=\"1\"]", "start=\"1912-01-01\"");
}};

public CLDRFile getCldrFile() {
return cldrFile;
}
Expand Down Expand Up @@ -468,6 +493,10 @@ private String constructExampleHtml(String xpath, String value, boolean nonTrivi
result = handleDisplayNames(xpath, parts, value);
} else if (parts.contains("currency")) {
result = handleCurrency(xpath, parts, value);
} else if (parts.contains("eras")) {
result = handleEras(parts, value);
} else if (parts.contains("quarters")) {
result = handleQuarters(parts, value);
} else if (parts.contains("dayPeriods")) {
result = handleDayPeriod(parts, value);
} else if (parts.contains("monthContext")) {
Expand Down Expand Up @@ -2861,6 +2890,109 @@ private String handleDateRangePattern(String value) {
return result;
}

/**
* Extract the year, month, day for the given era start/end date
*
* @param eraInfo a value in the calendarEras map, formatted "start=\"year-month-day\"" or "end=\"year-month-day\""
* @return
*/
public int[] getEraDateParts(String eraInfo) {
String[] parts = eraInfo.split("\""); // ex. ["start=", "-3760-10-7"] or ["end=", "8-08-28"]
if (parts.length != 2) {
throw new IllegalArgumentException("Values in calendarEras map must be formatted: end=\"year-month-day\" or start=\"year-month-day\"");
}
String eraDate = parts[1];
int firstSeparator = eraDate.indexOf("-", 1); // start from index=1 in case negative year
int secondSeparator = eraDate.indexOf("-", firstSeparator + 1);
if (firstSeparator == -1 || secondSeparator == -1) {
throw new IllegalArgumentException("Dates in calendarEras map must be formatted: \"year-month-day\"");
}
int year = Integer.parseInt(eraDate.substring(0, firstSeparator));
int month = Integer.parseInt(eraDate.substring(firstSeparator + 1, secondSeparator));
int date = Integer.parseInt(eraDate.substring(secondSeparator + 1));
int[] dateParts = new int[]{year, month, date};
return dateParts;
}

/**
* Add examples for eras. First checks if there is info for this
* calendar type and this era type in the calendarEras map, then
* generates a sample date based on this info and formats it
*/
private String handleEras(XPathParts parts, String value) {
String calendarId = parts.getAttributeValue(3, "type");
String type = parts.getAttributeValue(-1, "type");
String id = (calendarId.contains("islamic")) ? "islamic" : calendarId; // map all islamic variations to same entry
String curCalendar = "calendar[@type=\"" + id + "\"]/eras/era[@type=\"" + type + "\"]";
if (!calendarEras.containsKey(curCalendar)) {
return null;
}
String eraInfo = calendarEras.get(curCalendar);
int[] dateParts = getEraDateParts(eraInfo);
calendar.set(dateParts[0], dateParts[1] - 1, dateParts[2], 0, 0, 0); // calendar.set month is 0 based
Date sample = calendar.getTime();
String skeleton = "Gy";
String checkPath =
"//ldml/dates/calendars/calendar[@type=\""
+ calendarId
+ "\"]/dateTimeFormats/availableFormats/dateFormatItem[@id=\""
+ skeleton
+ "\"]";
String dateFormat = cldrFile.getWinningValue(checkPath);
SimpleDateFormat sdf =
icuServiceBuilder.getDateFormat(calendarId, dateFormat);
DateFormatSymbols dfs = sdf.getDateFormatSymbols();
String[] eraNames = dfs.getEras();
int eraIndex = Integer.parseInt(type);
eraNames[eraIndex] = value; // overwrite era to curr value
dfs.setEras(eraNames);
sdf.setDateFormatSymbols(dfs);
return sdf.format(sample);
}

/**
* Add examples for quarters for the gregorian calendar,
* matching each quarter type (1, 2, 3, 4) to a corresponding
* sample month and formatting an example with that date
*/
private String handleQuarters(XPathParts parts, String value) {
String calendarId = parts.getAttributeValue(3, "type");
if (!calendarId.equals("gregorian")) {
return null;
}
String width = parts.findAttributeValue("quarterWidth", "type");
if (width.equals("narrow")) {
return null;
}
String context = parts.findAttributeValue("quarterContext", "type");
String type = parts.getAttributeValue(-1, "type"); // 1-indexed
int quarterIndex = Integer.parseInt(type) - 1;
String skeleton = (width.equals("wide")) ? "yQQQQ" : "yQQQ";
String checkPath =
"//ldml/dates/calendars/calendar[@type=\""
+ calendarId
+ "\"]/dateTimeFormats/availableFormats/dateFormatItem[@id=\""
+ skeleton
+ "\"]";
String dateFormat = cldrFile.getWinningValue(checkPath);
SimpleDateFormat sdf =
icuServiceBuilder.getDateFormat(calendarId, dateFormat);

DateFormatSymbols dfs = sdf.getDateFormatSymbols();
int widthVal = width.equals("abbreviated") ? 0 : 1;
String[] quarterNames = dfs.getQuarters(0, widthVal); // 0 for formatting
quarterNames[quarterIndex] = value;
dfs.setQuarters(quarterNames, 0, widthVal);
sdf.setDateFormatSymbols(dfs);
sdf.setTimeZone(ZONE_SAMPLE);

final int[] monthSamples = new int[]{1, 4, 7, 10}; // {feb, may, oct, nov}
int month = monthSamples[quarterIndex];
calendar.set(1999, month, 5, 13, 25, 59);
Date sample = calendar.getTime();
return sdf.format(sample);
}

/**
* @param elementToOverride the element that is to be overridden
* @param element the overriding element
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.unicode.cldr.util.SupplementalDataInfo.PluralType;
import org.unicode.cldr.util.UnitPathType;
import org.unicode.cldr.util.With;
import com.ibm.icu.impl.Relation;

public class TestExampleGenerator extends TestFmwk {

Expand Down Expand Up @@ -118,7 +119,7 @@ public void testCurrency() {
"//ldml/characters/parseLenients.*",
"//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/months/monthContext[@type=\"([^\"]*+)\"]/monthWidth[@type=\"([^\"]*+)\"]/month[@type=\"([^\"]*+)\"]",
"//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/days/dayContext[@type=\"([^\"]*+)\"]/dayWidth[@type=\"([^\"]*+)\"]/day[@type=\"([^\"]*+)\"]",
"//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/quarters/quarterContext[@type=\"([^\"]*+)\"]/quarterWidth[@type=\"([^\"]*+)\"]/quarter[@type=\"([^\"]*+)\"]",
"//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/quarters/quarterContext[@type=\"([^\"]*+)\"]/quarterWidth[@type=\"([^\"]*+)\"]/quarter[@type=\"([^\"]*+)\"]", // examples only for gregorian
"//ldml/dates/fields/field[@type=\"([^\"]*+)\"]/displayName",
"//ldml/dates/fields/field[@type=\"([^\"]*+)\"]/relative[@type=\"([^\"]*+)\"]",
"//ldml/dates/fields/field[@type=\"([^\"]*+)\"]/relativeTime[@type=\"([^\"]*+)\"]/relativeTimePattern[@count=\"([^\"]*+)\"]",
Expand Down Expand Up @@ -165,7 +166,7 @@ public void testCurrency() {
"//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/dateTimeFormats/appendItems/appendItem[@request=\"([^\"]*+)\"]",
"//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/dateTimeFormats/intervalFormats/intervalFormatFallback",
"//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/dateTimeFormats/intervalFormats/intervalFormatItem[@id=\"([^\"]*+)\"]/greatestDifference[@id=\"([^\"]*+)\"]",
"//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/eras/eraNames/era[@type=\"([^\"]*+)\"][@alt=\"([^\"]*+)\"]",
"//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/eras/eraNames/era[@type=\"([^\"]*+)\"][@alt=\"([^\"]*+)\"]", // examples only for two closest eras to 2025
"//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/eras/eraAbbr/era[@type=\"([^\"]*+)\"][@alt=\"([^\"]*+)\"]",
"//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/eras/eraNarrow/era[@type=\"([^\"]*+)\"][@alt=\"([^\"]*+)\"]",
"//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/months/monthContext[@type=\"([^\"]*+)\"]/monthWidth[@type=\"([^\"]*+)\"]/month[@type=\"([^\"]*+)\"][@yeartype=\"([^\"]*+)\"]",
Expand Down Expand Up @@ -1645,4 +1646,104 @@ public void TestUnicodeSetExamples() {
assertEquals(locale + path + "=" + value, expected, actual);
}
}

public void TestEraDateParser() {
ExampleGenerator exampleGenerator = getExampleGenerator("en");
int[] result = new int[]{-4321, 10, 15};
assertTrue("Parse end=\"-4321-10-15\" into array with year, month, date numeric entries",
Arrays.equals(exampleGenerator.getEraDateParts("end=\"-4321-10-15\""), result));
int[] result2 = new int[]{645, 6, 19};
assertTrue("Parse start=\"645-6-19\" into array with year, month, date numeric entries",
Arrays.equals(exampleGenerator.getEraDateParts("start=\"645-6-19\""), result2));
}

public void TestEraMap() {
ExampleGenerator exampleGenerator = getExampleGenerator("en");
Relation<String, String> keyToSubtypes = SupplementalDataInfo.getInstance().getBcp47Keys();
Set<String> calendars = keyToSubtypes.get("ca"); // gets calendar codes
Map<String, String> codeToType = new HashMap<String, String>() {{ // only calendars where their code != type
put("gregory", "gregorian");
put("ethioaa", "ethiopic-amete-alem");
put("islamic-civil", "islamic");
put("islamic-rgsa", "islamic");
put("islamic-tbla", "islamic");
put("islamic-umalqura", "islamic");
put("islamicc", "islamic");
}};
for (String id : calendars) {
if (id.equals("iso8601")) { // generic
continue;
}
if (codeToType.containsKey(id)) {
id = codeToType.get(id);
}
String type = (id.equals("japanese")) ? "235" : "0"; // japanese only has last 2 eras (235, 236)
String curCalendar = "calendar[@type=\"" + id + "\"]/eras/era[@type=\"" + type + "\"]";
Map<String, String> calendarMap = exampleGenerator.calendarEras;
assertTrue("calendarEras map contains calendar type \"" + id + "\"", calendarMap.containsKey(curCalendar));
}
}

public void TestEraFormats() {
String[][] tests = {
{
"ja",
"//ldml/dates/calendars/calendar[@type=\"japanese\"]/eras/eraAbbr/era[@type=\"235\"]",
"japanese type=235 abbreviated",
"〖平成1年〗"
},
{
"es",
"//ldml/dates/calendars/calendar[@type=\"gregorian\"]/eras/eraNames/era[@type=\"0\"]",
"gregorian type=0 wide",
"〖1 antes de Cristo〗"
},
{
"es",
"//ldml/dates/calendars/calendar[@type=\"gregorian\"]/eras/eraNames/era[@type=\"0\"][@alt=\"variant\"]",
"gregorian type=0-variant wide",
"〖1 antes de la era común〗"
},
{
"zh",
"//ldml/dates/calendars/calendar[@type=\"roc\"]/eras/eraAbbr/era[@type=\"1\"]",
"roc type=1 abbreviated",
"〖民国1年〗"
},
};
for (String[] test : tests) {
final String locale = test[0];
final String path = test[1];
final String message = test[2];
final String expected = test[3];
ExampleGenerator exampleGenerator = getExampleGenerator(locale);
checkValue(message, expected, exampleGenerator, path);
}
}

public void TestQuarterFormats() {
ExampleGenerator exampleGenerator = getExampleGenerator("ti");
checkValue(
"ti Q2 format wide",
"〖2ይ ርብዒ 1999〗",
exampleGenerator,
"//ldml/dates/calendars/calendar[@type=\"gregorian\"]/quarters/quarterContext[@type=\"format\"]/quarterWidth[@type=\"wide\"]/quarter[@type=\"2\"]");
checkValue(
"ti Q2 format abbreviated",
"〖ር2 1999〗",
exampleGenerator,
"//ldml/dates/calendars/calendar[@type=\"gregorian\"]/quarters/quarterContext[@type=\"format\"]/quarterWidth[@type=\"abbreviated\"]/quarter[@type=\"2\"]");
checkValue(
"ti Q4 stand-alone wide",
"〖4ይ ርብዒ 1999〗",
exampleGenerator,
"//ldml/dates/calendars/calendar[@type=\"gregorian\"]/quarters/quarterContext[@type=\"stand-alone\"]/quarterWidth[@type=\"wide\"]/quarter[@type=\"4\"]");
checkValue(
"ti Q4 stand-alone abbreviated",
"〖ር4 1999〗",
exampleGenerator,
"//ldml/dates/calendars/calendar[@type=\"gregorian\"]/quarters/quarterContext[@type=\"stand-alone\"]/quarterWidth[@type=\"abbreviated\"]/quarter[@type=\"4\"]");
}
}


0 comments on commit a9428b4

Please sign in to comment.