1 /* 2 * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package test.java.time.format; 25 26 import static org.testng.Assert.assertEquals; 27 28 import java.text.DateFormatSymbols; 29 import java.time.ZoneId; 30 import java.time.ZonedDateTime; 31 import java.time.format.DecimalStyle; 32 import java.time.format.DateTimeFormatter; 33 import java.time.format.DateTimeFormatterBuilder; 34 import java.time.format.TextStyle; 35 import java.time.temporal.ChronoField; 36 import java.time.temporal.TemporalQueries; 37 import java.time.zone.ZoneRulesProvider; 38 import java.util.Arrays; 39 import java.util.Date; 40 import java.util.HashSet; 41 import java.util.Locale; 42 import java.util.Random; 43 import java.util.Set; 44 import java.util.TimeZone; 45 import jdk.testlibrary.RandomFactory; 46 47 import org.testng.annotations.DataProvider; 48 import org.testng.annotations.Test; 49 50 /* 51 * @test 52 * @bug 8081022 8151876 53 * @key randomness 54 */ 55 56 /** 57 * Test ZoneTextPrinterParser 58 */ 59 @Test 60 public class TestZoneTextPrinterParser extends AbstractTestPrinterParser { 61 62 protected static DateTimeFormatter getFormatter(Locale locale, TextStyle style) { 63 return new DateTimeFormatterBuilder().appendZoneText(style) 64 .toFormatter(locale) 65 .withDecimalStyle(DecimalStyle.of(locale)); 66 } 67 68 public void test_printText() { 69 Random r = RandomFactory.getRandom(); 70 int N = 8; 71 Locale[] locales = Locale.getAvailableLocales(); 72 Set<String> zids = ZoneRulesProvider.getAvailableZoneIds(); 73 ZonedDateTime zdt = ZonedDateTime.now(); 74 75 //System.out.printf("locale==%d, timezone=%d%n", locales.length, zids.size()); 76 while (N-- > 0) { 77 zdt = zdt.withDayOfYear(r.nextInt(365) + 1) 78 .with(ChronoField.SECOND_OF_DAY, r.nextInt(86400)); 79 for (String zid : zids) { 80 if (zid.equals("ROC") || zid.startsWith("Etc/GMT")) { 81 continue; // TBD: match jdk behavior? 82 } 83 zdt = zdt.withZoneSameLocal(ZoneId.of(zid)); 84 TimeZone tz = TimeZone.getTimeZone(zid); 85 boolean isDST = tz.inDaylightTime(new Date(zdt.toInstant().toEpochMilli())); 86 for (Locale locale : locales) { 87 String longDisplayName = tz.getDisplayName(isDST, TimeZone.LONG, locale); 88 String shortDisplayName = tz.getDisplayName(isDST, TimeZone.SHORT, locale); 89 if ((longDisplayName.startsWith("GMT+") && shortDisplayName.startsWith("GMT+")) 90 || (longDisplayName.startsWith("GMT-") && shortDisplayName.startsWith("GMT-"))) { 91 printText(locale, zdt, TextStyle.FULL, tz, tz.getID()); 92 printText(locale, zdt, TextStyle.SHORT, tz, tz.getID()); 93 continue; 94 } 95 printText(locale, zdt, TextStyle.FULL, tz, 96 tz.getDisplayName(isDST, TimeZone.LONG, locale)); 97 printText(locale, zdt, TextStyle.SHORT, tz, 98 tz.getDisplayName(isDST, TimeZone.SHORT, locale)); 99 } 100 } 101 } 102 } 103 104 private void printText(Locale locale, ZonedDateTime zdt, TextStyle style, TimeZone zone, String expected) { 105 String result = getFormatter(locale, style).format(zdt); 106 if (!result.equals(expected)) { 107 if (result.equals("FooLocation")) { // from rules provider test if same vm 108 return; 109 } 110 System.out.println("----------------"); 111 System.out.printf("tdz[%s]%n", zdt.toString()); 112 System.out.printf("[%-5s, %5s] :[%s]%n", locale.toString(), style.toString(),result); 113 System.out.printf(" %5s, %5s :[%s] %s%n", "", "", expected, zone); 114 } 115 assertEquals(result, expected); 116 } 117 118 public void test_ParseText() { 119 Locale[] locales = new Locale[] { Locale.ENGLISH, Locale.JAPANESE, Locale.FRENCH }; 120 Set<String> zids = ZoneRulesProvider.getAvailableZoneIds(); 121 for (Locale locale : locales) { 122 parseText(zids, locale, TextStyle.FULL, false); 123 parseText(zids, locale, TextStyle.FULL, true); 124 parseText(zids, locale, TextStyle.SHORT, false); 125 parseText(zids, locale, TextStyle.SHORT, true); 126 } 127 } 128 129 private static Set<ZoneId> preferred = new HashSet<>(Arrays.asList(new ZoneId[] { 130 ZoneId.of("EST", ZoneId.SHORT_IDS), 131 ZoneId.of("Asia/Taipei"), 132 ZoneId.of("Asia/Macau"), 133 ZoneId.of("CET"), 134 })); 135 136 private static Set<ZoneId> preferred_s = new HashSet<>(Arrays.asList(new ZoneId[] { 137 ZoneId.of("EST", ZoneId.SHORT_IDS), 138 ZoneId.of("CET"), 139 ZoneId.of("Australia/South"), 140 ZoneId.of("Australia/West"), 141 ZoneId.of("Asia/Shanghai"), 142 })); 143 144 private static Set<ZoneId> none = new HashSet<>(); 145 146 @DataProvider(name="preferredZones") 147 Object[][] data_preferredZones() { 148 return new Object[][] { 149 {"America/New_York", "Eastern Standard Time", none, Locale.ENGLISH, TextStyle.FULL}, 150 // {"EST", "Eastern Standard Time", preferred, Locale.ENGLISH, TextStyle.FULL}, 151 {"Europe/Paris", "Central European Time", none, Locale.ENGLISH, TextStyle.FULL}, 152 // {"CET", "Central European Time", preferred, Locale.ENGLISH, TextStyle.FULL}, no three-letter ID in CLDR 153 {"Asia/Shanghai", "China Standard Time", none, Locale.ENGLISH, TextStyle.FULL}, 154 {"Asia/Macau", "China Standard Time", preferred, Locale.ENGLISH, TextStyle.FULL}, 155 {"Asia/Taipei", "Taipei Standard Time", preferred, Locale.ENGLISH, TextStyle.FULL}, 156 {"America/Chicago", "CST", none, Locale.ENGLISH, TextStyle.SHORT}, 157 {"Asia/Taipei", "CST", preferred, Locale.ENGLISH, TextStyle.SHORT}, 158 {"Australia/South", "ACST", preferred_s, Locale.ENGLISH, TextStyle.SHORT}, 159 {"America/Chicago", "CDT", none, Locale.ENGLISH, TextStyle.SHORT}, 160 {"Asia/Shanghai", "CDT", preferred_s, Locale.ENGLISH, TextStyle.SHORT}, 161 }; 162 } 163 164 @Test(dataProvider="preferredZones") 165 public void test_ParseText(String expected, String text, Set<ZoneId> preferred, Locale locale, TextStyle style) { 166 DateTimeFormatter fmt = new DateTimeFormatterBuilder().appendZoneText(style, preferred) 167 .toFormatter(locale) 168 .withDecimalStyle(DecimalStyle.of(locale)); 169 170 String ret = fmt.parse(text, TemporalQueries.zone()).getId(); 171 172 System.out.printf("[%-5s %s] %24s -> %s(%s)%n", 173 locale.toString(), 174 style == TextStyle.FULL ? " full" :"short", 175 text, ret, expected); 176 177 assertEquals(ret, expected); 178 179 } 180 181 182 private void parseText(Set<String> zids, Locale locale, TextStyle style, boolean ci) { 183 System.out.println("---------------------------------------"); 184 DateTimeFormatter fmt = getFormatter(locale, style, ci); 185 for (String[] names : new DateFormatSymbols(locale).getZoneStrings()) { 186 if (!zids.contains(names[0])) { 187 continue; 188 } 189 String zid = names[0]; 190 String expected = ZoneName.toZid(zid, locale); 191 192 parse(fmt, zid, expected, zid, locale, style, ci); 193 int i = style == TextStyle.FULL ? 1 : 2; 194 for (; i < names.length; i += 2) { 195 parse(fmt, zid, expected, names[i], locale, style, ci); 196 } 197 } 198 } 199 200 private void parse(DateTimeFormatter fmt, 201 String zid, String expected, String text, 202 Locale locale, TextStyle style, boolean ci) { 203 if (ci) { 204 text = text.toUpperCase(); 205 } 206 String ret = fmt.parse(text, TemporalQueries.zone()).getId(); 207 // TBD: need an excluding list 208 // assertEquals(...); 209 if (ret.equals(expected) || 210 ret.equals(zid) || 211 ret.equals(ZoneName.toZid(zid)) || 212 ret.equals(expected.replace("UTC", "UCT"))) { 213 return; 214 } 215 System.out.printf("[%-5s %s %s %16s] %24s -> %s(%s)%n", 216 locale.toString(), 217 ci ? "ci" : " ", 218 style == TextStyle.FULL ? " full" :"short", 219 zid, text, ret, expected); 220 } 221 222 private DateTimeFormatter getFormatter(Locale locale, TextStyle style, boolean ci) { 223 DateTimeFormatterBuilder db = new DateTimeFormatterBuilder(); 224 if (ci) { 225 db = db.parseCaseInsensitive(); 226 } 227 return db.appendZoneText(style) 228 .toFormatter(locale) 229 .withDecimalStyle(DecimalStyle.of(locale)); 230 } 231 232 }