Skip to content
Permalink
Browse files

8235238: Parsing a time string ignores any custom TimeZoneNameProvider

Reviewed-by: joehw, rriggs
  • Loading branch information
Naoto Sato
Naoto Sato committed Dec 13, 2019
1 parent 57ece4c commit 20b1410d0c890385467c6ac1c5dedbcc7c955a2c
@@ -4123,7 +4123,8 @@ protected PrefixTree getTree(DateTimeParseContext context) {
}
Locale locale = context.getLocale();
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();

Map<Locale, Entry<Integer, SoftReference<PrefixTree>>> cached =
@@ -4139,7 +4140,8 @@ protected PrefixTree getTree(DateTimeParseContext context) {
zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
for (String[] names : zoneStrings) {
String zid = names[0];
if (!regionIds.contains(zid)) {
if (!regionIds.remove(zid)) {
nonRegionIds.add(zid);
continue;
}
tree.add(zid, zid); // don't convert zid -> metazone
@@ -4149,12 +4151,27 @@ protected PrefixTree getTree(DateTimeParseContext context) {
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
// add the preferred zones again to overwrite
if (preferredZones != null) {
for (String[] names : zoneStrings) {
String zid = names[0];
if (!preferredZones.contains(zid) || !regionIds.contains(zid)) {
if (!preferredZones.contains(zid) || nonRegionIds.contains(zid)) {
continue;
}
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;
}
}

0 comments on commit 20b1410

Please sign in to comment.
You can’t perform that action at this time.