8235238: Parsing a time string ignores any custom TimeZoneNameProvider
Reviewed-by: joehw, rriggs
This commit is contained in:
parent
57ece4c21a
commit
20b1410d0c
@ -4123,7 +4123,8 @@ public final class DateTimeFormatterBuilder {
|
|||||||
}
|
}
|
||||||
Locale locale = context.getLocale();
|
Locale locale = context.getLocale();
|
||||||
boolean isCaseSensitive = context.isCaseSensitive();
|
boolean isCaseSensitive = context.isCaseSensitive();
|
||||||
Set<String> regionIds = ZoneRulesProvider.getAvailableZoneIds();
|
Set<String> regionIds = new HashSet<>(ZoneRulesProvider.getAvailableZoneIds());
|
||||||
|
Set<String> nonRegionIds = new HashSet<>(64);
|
||||||
int regionIdsSize = regionIds.size();
|
int regionIdsSize = regionIds.size();
|
||||||
|
|
||||||
Map<Locale, Entry<Integer, SoftReference<PrefixTree>>> cached =
|
Map<Locale, Entry<Integer, SoftReference<PrefixTree>>> cached =
|
||||||
@ -4139,7 +4140,8 @@ public final class DateTimeFormatterBuilder {
|
|||||||
zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
|
zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
|
||||||
for (String[] names : zoneStrings) {
|
for (String[] names : zoneStrings) {
|
||||||
String zid = names[0];
|
String zid = names[0];
|
||||||
if (!regionIds.contains(zid)) {
|
if (!regionIds.remove(zid)) {
|
||||||
|
nonRegionIds.add(zid);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tree.add(zid, zid); // don't convert zid -> metazone
|
tree.add(zid, zid); // don't convert zid -> metazone
|
||||||
@ -4149,12 +4151,27 @@ public final class DateTimeFormatterBuilder {
|
|||||||
tree.add(names[i], zid);
|
tree.add(names[i], zid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add names for provider's custom ids
|
||||||
|
final PrefixTree t = tree;
|
||||||
|
regionIds.stream()
|
||||||
|
.filter(zid -> !zid.startsWith("Etc") && !zid.startsWith("GMT"))
|
||||||
|
.forEach(cid -> {
|
||||||
|
String[] cidNames = TimeZoneNameUtility.retrieveDisplayNames(cid, locale);
|
||||||
|
int i = textStyle == TextStyle.FULL ? 1 : 2;
|
||||||
|
for (; i < cidNames.length; i += 2) {
|
||||||
|
if (cidNames[i] != null && !cidNames[i].isEmpty()) {
|
||||||
|
t.add(cidNames[i], cid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// if we have a set of preferred zones, need a copy and
|
// if we have a set of preferred zones, need a copy and
|
||||||
// add the preferred zones again to overwrite
|
// add the preferred zones again to overwrite
|
||||||
if (preferredZones != null) {
|
if (preferredZones != null) {
|
||||||
for (String[] names : zoneStrings) {
|
for (String[] names : zoneStrings) {
|
||||||
String zid = names[0];
|
String zid = names[0];
|
||||||
if (!preferredZones.contains(zid) || !regionIds.contains(zid)) {
|
if (!preferredZones.contains(zid) || nonRegionIds.contains(zid)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int i = textStyle == TextStyle.FULL ? 1 : 2;
|
int i = textStyle == TextStyle.FULL ? 1 : 2;
|
||||||
|
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/* @test
|
||||||
|
* @bug 8235238
|
||||||
|
* @summary Checks whether custom zone names can be formatted/parsed correctly.
|
||||||
|
* @library zoneProvider
|
||||||
|
* @build custom.CustomZoneRulesProvider custom.CustomTimeZoneNameProvider
|
||||||
|
* @run main/othervm -Djava.locale.providers=SPI,CLDR CustomZoneNameTest
|
||||||
|
*/
|
||||||
|
public class CustomZoneNameTest {
|
||||||
|
|
||||||
|
private final static long now = 1575669972372L;
|
||||||
|
private final static Instant instant = Instant.ofEpochMilli(now);
|
||||||
|
private final static ZoneId customZone = ZoneId.of("Custom/Timezone");
|
||||||
|
|
||||||
|
// test data
|
||||||
|
private final static Map<String, String> formats = Map.of(
|
||||||
|
"yyyy-MM-dd HH:mm:ss.SSS VV", "2019-12-06 22:06:12.372 Custom/Timezone",
|
||||||
|
"yyyy-MM-dd HH:mm:ss.SSS z", "2019-12-06 22:06:12.372 CUST_WT",
|
||||||
|
"yyyy-MM-dd HH:mm:ss.SSS zzzz", "2019-12-06 22:06:12.372 Custom Winter Time",
|
||||||
|
"yyyy-MM-dd HH:mm:ss.SSS v", "2019-12-06 22:06:12.372 Custom Time",
|
||||||
|
"yyyy-MM-dd HH:mm:ss.SSS vvvv", "2019-12-06 22:06:12.372 Custom Timezone Time"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static void main(String... args) {
|
||||||
|
testFormatting();
|
||||||
|
testParsing();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testFormatting() {
|
||||||
|
var customZDT = ZonedDateTime.ofInstant(instant, customZone);
|
||||||
|
formats.entrySet().stream()
|
||||||
|
.filter(e -> {
|
||||||
|
var formatted = DateTimeFormatter.ofPattern(e.getKey()).format(customZDT);
|
||||||
|
var expected = e.getValue();
|
||||||
|
System.out.println("testFormatting. Pattern: " + e.getKey() +
|
||||||
|
", expected: " + expected +
|
||||||
|
", formatted: " + formatted);
|
||||||
|
return !formatted.equals(expected);
|
||||||
|
})
|
||||||
|
.findAny()
|
||||||
|
.ifPresent(e -> {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"Provider's custom name was not retrieved for the format " +
|
||||||
|
e.getKey());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void testParsing() {
|
||||||
|
formats.entrySet().stream()
|
||||||
|
.filter(e -> {
|
||||||
|
var fmt = DateTimeFormatter.ofPattern(e.getKey());
|
||||||
|
var input = e.getValue();
|
||||||
|
var parsedInstant = fmt.parse(input, Instant::from).toEpochMilli();
|
||||||
|
var parsedZone = fmt.parse(input, ZonedDateTime::from).getZone();
|
||||||
|
System.out.println("testParsing. Input: " + input +
|
||||||
|
", expected instant: " + now +
|
||||||
|
", expected zone: " + customZone +
|
||||||
|
", parsed instant: " + parsedInstant +
|
||||||
|
", parsed zone: " + parsedZone);
|
||||||
|
return parsedInstant != now ||
|
||||||
|
!parsedZone.equals(customZone);
|
||||||
|
})
|
||||||
|
.findAny()
|
||||||
|
.ifPresent(e -> {
|
||||||
|
throw new RuntimeException("Parsing failed for the format " +
|
||||||
|
e.getKey());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
custom.CustomZoneRulesProvider
|
@ -0,0 +1 @@
|
|||||||
|
custom.CustomTimeZoneNameProvider
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package custom;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
import java.util.spi.TimeZoneNameProvider;
|
||||||
|
|
||||||
|
public class CustomTimeZoneNameProvider extends TimeZoneNameProvider {
|
||||||
|
|
||||||
|
public static final String ZONE_ID = "Custom/Timezone";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayName(String ID, boolean daylight, int style, Locale locale) {
|
||||||
|
if (ZONE_ID.equals(ID)) {
|
||||||
|
switch (style) {
|
||||||
|
case TimeZone.SHORT:
|
||||||
|
if (daylight) {
|
||||||
|
return "CUST_ST";
|
||||||
|
} else {
|
||||||
|
return "CUST_WT";
|
||||||
|
}
|
||||||
|
case TimeZone.LONG:
|
||||||
|
if (daylight) {
|
||||||
|
return "Custom Summer Time";
|
||||||
|
} else {
|
||||||
|
return "Custom Winter Time";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getGenericDisplayName(String ID, int style, Locale locale) {
|
||||||
|
if (ZONE_ID.equals(ID)) {
|
||||||
|
switch (style) {
|
||||||
|
case TimeZone.SHORT:
|
||||||
|
return "Custom Time";
|
||||||
|
case TimeZone.LONG:
|
||||||
|
return "Custom Timezone Time";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSupportedLocale(Locale locale) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Locale[] getAvailableLocales() {
|
||||||
|
return new Locale[]{
|
||||||
|
Locale.getDefault()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package custom;
|
||||||
|
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.zone.ZoneRules;
|
||||||
|
import java.time.zone.ZoneRulesProvider;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.NavigableMap;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
public class CustomZoneRulesProvider extends ZoneRulesProvider {
|
||||||
|
@Override
|
||||||
|
protected Set<String> provideZoneIds() {
|
||||||
|
return Set.of("Custom/Timezone");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ZoneRules provideRules(String zoneId, boolean forCaching) {
|
||||||
|
return ZoneId.of("UTC").getRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
|
||||||
|
var map = new TreeMap<String, ZoneRules>();
|
||||||
|
map.put("bogusVersion", getRules(zoneId, false));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user