Skip to content

Commit 9b74c3f

Browse files
committed
8176706: Additional Date-Time Formats
Reviewed-by: joehw, rriggs
1 parent 0f3d3ac commit 9b74c3f

File tree

12 files changed

+809
-96
lines changed

12 files changed

+809
-96
lines changed

make/jdk/src/classes/build/tools/cldrconverter/Bundle.java

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,9 @@
2525

2626
package build.tools.cldrconverter;
2727

28+
import java.io.IOException;
29+
import java.nio.file.Files;
30+
import java.nio.file.Path;
2831
import java.util.ArrayList;
2932
import java.util.Arrays;
3033
import java.util.EnumSet;
@@ -34,6 +37,7 @@
3437
import java.util.Map;
3538
import java.util.Objects;
3639
import java.util.Optional;
40+
import java.util.stream.Collectors;
3741
import java.util.stream.IntStream;
3842

3943
class Bundle {
@@ -47,21 +51,21 @@ static enum Type {
4751
FORMATDATA);
4852
}
4953

50-
private final static Map<String, Bundle> bundles = new HashMap<>();
54+
private static final Map<String, Bundle> bundles = new HashMap<>();
5155

52-
private final static String[] NUMBER_PATTERN_KEYS = {
56+
private static final String[] NUMBER_PATTERN_KEYS = {
5357
"NumberPatterns/decimal",
5458
"NumberPatterns/currency",
5559
"NumberPatterns/percent",
5660
"NumberPatterns/accounting"
5761
};
5862

59-
private final static String[] COMPACT_NUMBER_PATTERN_KEYS = {
60-
"short.CompactNumberPatterns",
61-
"long.CompactNumberPatterns"
63+
private static final String[] COMPACT_NUMBER_PATTERN_KEYS = {
64+
"short.CompactNumberPatterns",
65+
"long.CompactNumberPatterns"
6266
};
6367

64-
private final static String[] NUMBER_ELEMENT_KEYS = {
68+
private static final String[] NUMBER_ELEMENT_KEYS = {
6569
"NumberElements/decimal",
6670
"NumberElements/group",
6771
"NumberElements/list",
@@ -77,41 +81,45 @@ static enum Type {
7781
"NumberElements/currencyGroup",
7882
};
7983

80-
private final static String[] TIME_PATTERN_KEYS = {
84+
private static final String[] TIME_PATTERN_KEYS = {
8185
"DateTimePatterns/full-time",
8286
"DateTimePatterns/long-time",
8387
"DateTimePatterns/medium-time",
8488
"DateTimePatterns/short-time",
8589
};
8690

87-
private final static String[] DATE_PATTERN_KEYS = {
91+
private static final String[] DATE_PATTERN_KEYS = {
8892
"DateTimePatterns/full-date",
8993
"DateTimePatterns/long-date",
9094
"DateTimePatterns/medium-date",
9195
"DateTimePatterns/short-date",
9296
};
9397

94-
private final static String[] DATETIME_PATTERN_KEYS = {
98+
private static final String[] DATETIME_PATTERN_KEYS = {
9599
"DateTimePatterns/full-dateTime",
96100
"DateTimePatterns/long-dateTime",
97101
"DateTimePatterns/medium-dateTime",
98102
"DateTimePatterns/short-dateTime",
99103
};
100104

101-
private final static String[] ERA_KEYS = {
105+
private static final String[] ERA_KEYS = {
102106
"long.Eras",
103107
"Eras",
104108
"narrow.Eras"
105109
};
106110

111+
// DateFormatItem prefix
112+
static final String DATEFORMATITEM_KEY_PREFIX = "DateFormatItem.";
113+
static final String DATEFORMATITEM_INPUT_REGIONS_PREFIX = "DateFormatItemInputRegions.";
114+
107115
// Keys for individual time zone names
108-
private final static String TZ_GEN_LONG_KEY = "timezone.displayname.generic.long";
109-
private final static String TZ_GEN_SHORT_KEY = "timezone.displayname.generic.short";
110-
private final static String TZ_STD_LONG_KEY = "timezone.displayname.standard.long";
111-
private final static String TZ_STD_SHORT_KEY = "timezone.displayname.standard.short";
112-
private final static String TZ_DST_LONG_KEY = "timezone.displayname.daylight.long";
113-
private final static String TZ_DST_SHORT_KEY = "timezone.displayname.daylight.short";
114-
private final static String[] ZONE_NAME_KEYS = {
116+
private static final String TZ_GEN_LONG_KEY = "timezone.displayname.generic.long";
117+
private static final String TZ_GEN_SHORT_KEY = "timezone.displayname.generic.short";
118+
private static final String TZ_STD_LONG_KEY = "timezone.displayname.standard.long";
119+
private static final String TZ_STD_SHORT_KEY = "timezone.displayname.standard.short";
120+
private static final String TZ_DST_LONG_KEY = "timezone.displayname.daylight.long";
121+
private static final String TZ_DST_SHORT_KEY = "timezone.displayname.daylight.short";
122+
private static final String[] ZONE_NAME_KEYS = {
115123
TZ_STD_LONG_KEY,
116124
TZ_STD_SHORT_KEY,
117125
TZ_DST_LONG_KEY,
@@ -262,7 +270,7 @@ Map<String, Object> getTargetMap() throws Exception {
262270
CLDRConverter.handleAliases(myMap);
263271

264272
// another hack: parentsMap is not used for date-time resources.
265-
if ("root".equals(id)) {
273+
if (isRoot()) {
266274
parentsMap = null;
267275
}
268276

@@ -287,6 +295,14 @@ Map<String, Object> getTargetMap() throws Exception {
287295
handleDateTimeFormatPatterns(TIME_PATTERN_KEYS, myMap, parentsMap, calendarType, "TimePatterns");
288296
handleDateTimeFormatPatterns(DATE_PATTERN_KEYS, myMap, parentsMap, calendarType, "DatePatterns");
289297
handleDateTimeFormatPatterns(DATETIME_PATTERN_KEYS, myMap, parentsMap, calendarType, "DateTimePatterns");
298+
299+
// Skeleton
300+
handleSkeletonPatterns(myMap, calendarType);
301+
}
302+
303+
// Skeleton input regions
304+
if (isRoot()) {
305+
skeletonInputRegions(myMap);
290306
}
291307

292308
// First, weed out any empty timezone or metazone names from myMap.
@@ -647,8 +663,9 @@ private String toMetaZoneKey(String tzKey) {
647663
private void convertDateTimePatternLetter(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb) {
648664
switch (cldrLetter) {
649665
case 'u':
650-
// Change cldr letter 'u' to 'y', as 'u' is interpreted as
651-
// "Extended year (numeric)" in CLDR/LDML,
666+
case 'U':
667+
// Change cldr letter 'u'/'U' to 'y', as 'u' is interpreted as
668+
// "Extended year (numeric)", and 'U' as "Cyclic year" in CLDR/LDML,
652669
// which is not supported in SimpleDateFormat and
653670
// j.t.f.DateTimeFormatter, so it is replaced with 'y'
654671
// as the best approximation
@@ -742,6 +759,19 @@ private static boolean hasNulls(Object[] array) {
742759
return false;
743760
}
744761

762+
private void handleSkeletonPatterns(Map<String, Object> myMap, CalendarType calendarType) {
763+
String calendarPrefix = calendarType.keyElementName();
764+
myMap.putAll(myMap.entrySet().stream()
765+
.filter(e -> e.getKey().startsWith(Bundle.DATEFORMATITEM_KEY_PREFIX))
766+
.collect(Collectors.toMap(
767+
e -> calendarPrefix + e.getKey(),
768+
e -> translateDateFormatLetters(calendarType,
769+
(String)e.getValue(),
770+
this::convertDateTimePatternLetter)
771+
))
772+
);
773+
}
774+
745775
@FunctionalInterface
746776
private interface ConvertDateTimeLetters {
747777
void convert(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb);
@@ -790,4 +820,14 @@ private String[] createNumberArray(Map<String, Object> myMap, Map<String, Object
790820
}
791821
return numArray;
792822
}
823+
824+
private static void skeletonInputRegions(Map<String, Object> myMap) {
825+
myMap.putAll(myMap.entrySet().stream()
826+
.filter(e -> e.getKey().startsWith(Bundle.DATEFORMATITEM_INPUT_REGIONS_PREFIX))
827+
.collect(Collectors.toMap(
828+
e -> e.getKey(),
829+
e -> ((String)e.getValue()).trim()
830+
))
831+
);
832+
}
793833
}

make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -847,30 +847,26 @@ private static Map<String, Object> extractCalendarData(Map<String, Object> map,
847847
"DateTimePatternChars",
848848
"PluralRules",
849849
"DayPeriodRules",
850+
"DateFormatItem",
850851
};
851852

852853
private static Map<String, Object> extractFormatData(Map<String, Object> map, String id) {
853854
Map<String, Object> formatData = new LinkedHashMap<>();
854855
for (CalendarType calendarType : CalendarType.values()) {
855-
if (calendarType == CalendarType.GENERIC) {
856-
continue;
857-
}
858856
String prefix = calendarType.keyElementName();
859-
for (String element : FORMAT_DATA_ELEMENTS) {
860-
String key = prefix + element;
861-
copyIfPresent(map, "java.time." + key, formatData);
862-
copyIfPresent(map, key, formatData);
863-
}
857+
Arrays.stream(FORMAT_DATA_ELEMENTS)
858+
.flatMap(elem -> map.keySet().stream().filter(k -> k.startsWith(prefix + elem)))
859+
.forEach(key -> {
860+
copyIfPresent(map, "java.time." + key, formatData);
861+
copyIfPresent(map, key, formatData);
862+
});
864863
}
865864

866865
for (String key : map.keySet()) {
867866
// Copy available calendar names
868867
if (key.startsWith(CLDRConverter.LOCALE_TYPE_PREFIX_CA)) {
869868
String type = key.substring(CLDRConverter.LOCALE_TYPE_PREFIX_CA.length());
870869
for (CalendarType calendarType : CalendarType.values()) {
871-
if (calendarType == CalendarType.GENERIC) {
872-
continue;
873-
}
874870
if (type.equals(calendarType.lname())) {
875871
Object value = map.get(key);
876872
String dataKey = key.replace(LOCALE_TYPE_PREFIX_CA,

make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -756,6 +756,14 @@ public void startElement(String uri, String localName, String qName, Attributes
756756
pushStringEntry(qName, attributes, prefix + "DateTimePatterns/" + attributes.getValue("type") + "-dateTime");
757757
}
758758
break;
759+
case "dateFormatItem":
760+
{
761+
// for FormatData
762+
String prefix = (currentCalendarType == null) ? "" : currentCalendarType.keyElementName();
763+
pushStringEntry(qName, attributes,
764+
prefix + Bundle.DATEFORMATITEM_KEY_PREFIX + attributes.getValue("id"));
765+
}
766+
break;
759767
case "localizedPatternChars":
760768
{
761769
// for FormatData
@@ -1113,7 +1121,7 @@ private Object putIfEntry() {
11131121
if (id.equals("root") && key.startsWith("MonthNames")) {
11141122
value = new DateFormatSymbols(Locale.US).getShortMonths();
11151123
}
1116-
return put(entry.getKey(), value);
1124+
return put(key, value);
11171125
}
11181126
}
11191127
return null;

make/jdk/src/classes/build/tools/cldrconverter/SupplementDataParseHandler.java

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -27,8 +27,12 @@
2727

2828
import java.io.File;
2929
import java.io.IOException;
30+
import java.util.Arrays;
3031
import java.util.HashMap;
3132
import java.util.Map;
33+
import java.util.SortedSet;
34+
import java.util.TreeSet;
35+
import java.util.stream.Collectors;
3236
import org.xml.sax.Attributes;
3337
import org.xml.sax.InputSource;
3438
import org.xml.sax.SAXException;
@@ -62,10 +66,15 @@ class SupplementDataParseHandler extends AbstractLDMLHandler<Object> {
6266
// parentLocale.<parent_locale_id>=<child_locale_id>(" "<child_locale_id>)+
6367
private final Map<String, String> parentLocalesMap;
6468

69+
// Input Skeleton map for "preferred" and "allowed"
70+
// Map<"preferred"/"allowed", Map<"skeleton", SortedSet<"regions">>>
71+
private final Map<String, Map<String, SortedSet<String>>> inputSkeletonMap;
72+
6573
SupplementDataParseHandler() {
6674
firstDayMap = new HashMap<>();
6775
minDaysMap = new HashMap<>();
6876
parentLocalesMap = new HashMap<>();
77+
inputSkeletonMap = new HashMap<>();
6978
}
7079

7180
/**
@@ -76,22 +85,25 @@ class SupplementDataParseHandler extends AbstractLDMLHandler<Object> {
7685
* It returns null when there is no firstDay and minDays for the country
7786
* although this should not happen because supplementalData.xml includes
7887
* default value for the world ("001") for firstDay and minDays.
88+
*
89+
* This method also returns Maps for "preferred" and "allowed" skeletons,
90+
* which are grouped by regions. E.g, "h:XX YY ZZ;" which means 'h' pattern
91+
* is "preferred"/"allowed" in "XX", "YY", and "ZZ" regions.
7992
*/
8093
Map<String, Object> getData(String id) {
8194
Map<String, Object> values = new HashMap<>();
8295
if ("root".equals(id)) {
83-
parentLocalesMap.keySet().forEach(key -> {
84-
values.put(CLDRConverter.PARENT_LOCALE_PREFIX+key,
85-
parentLocalesMap.get(key));
86-
});
87-
firstDayMap.keySet().forEach(key -> {
88-
values.put(CLDRConverter.CALENDAR_FIRSTDAY_PREFIX+firstDayMap.get(key),
89-
key);
90-
});
91-
minDaysMap.keySet().forEach(key -> {
92-
values.put(CLDRConverter.CALENDAR_MINDAYS_PREFIX+minDaysMap.get(key),
93-
key);
94-
});
96+
parentLocalesMap.forEach((k, v) -> values.put(CLDRConverter.PARENT_LOCALE_PREFIX + k, v));
97+
firstDayMap.forEach((k, v) -> values.put(CLDRConverter.CALENDAR_FIRSTDAY_PREFIX + v, k));
98+
minDaysMap.forEach((k, v) -> values.put(CLDRConverter.CALENDAR_MINDAYS_PREFIX + v, k));
99+
inputSkeletonMap.get("preferred").forEach((k, v) ->
100+
values.merge(Bundle.DATEFORMATITEM_INPUT_REGIONS_PREFIX + "preferred",
101+
k + ":" + v.stream().collect(Collectors.joining(" ")) + ";",
102+
(old, newVal) -> old + (String)newVal));
103+
inputSkeletonMap.get("allowed").forEach((k, v) ->
104+
values.merge(Bundle.DATEFORMATITEM_INPUT_REGIONS_PREFIX + "allowed",
105+
k + ":" + v.stream().collect(Collectors.joining(" ")) + ";",
106+
(old, newVal) -> old + (String)newVal));
95107
}
96108
return values.isEmpty() ? null : values;
97109
}
@@ -158,11 +170,23 @@ public void startElement(String uri, String localName, String qName, Attributes
158170
attributes.getValue("locales").replaceAll("_", "-"));
159171
}
160172
break;
173+
case "hours":
174+
if (!isIgnored(attributes)) {
175+
var preferred = attributes.getValue("preferred");
176+
var allowed = attributes.getValue("allowed").replaceFirst(" .*", "").replaceFirst("b", "B"); // take only the first one, "b" -> "B"
177+
var regions = Arrays.stream(attributes.getValue("regions").split(" "))
178+
.map(r -> r.replaceAll("_", "-"))
179+
.collect(Collectors.toSet());
180+
var pmap = inputSkeletonMap.computeIfAbsent("preferred", k -> new HashMap<>());
181+
var amap = inputSkeletonMap.computeIfAbsent("allowed", k -> new HashMap<>());
182+
pmap.computeIfAbsent(preferred, k -> new TreeSet<>()).addAll(regions);
183+
amap.computeIfAbsent(allowed, k -> new TreeSet<>()).addAll(regions);
184+
}
185+
break;
161186
default:
162187
// treat anything else as a container
163188
pushContainer(qName, attributes);
164189
break;
165190
}
166191
}
167-
168192
}

0 commit comments

Comments
 (0)