1 /* 2 * Copyright (c) 2012, 2015, 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 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 printText(locale, zdt, TextStyle.FULL, tz, 88 tz.getDisplayName(isDST, TimeZone.LONG, locale)); 89 printText(locale, zdt, TextStyle.SHORT, tz, 90 tz.getDisplayName(isDST, TimeZone.SHORT, locale)); 91 } 92 } 93 } 94 } 95 96 private void printText(Locale locale, ZonedDateTime zdt, TextStyle style, TimeZone zone, String expected) { 97 String result = getFormatter(locale, style).format(zdt); 98 if (!result.equals(expected)) { 99 if (result.equals("FooLocation")) { // from rules provider test if same vm 100 return; 101 } 102 System.out.println("----------------"); 103 System.out.printf("tdz[%s]%n", zdt.toString()); 104 System.out.printf("[%-5s, %5s] :[%s]%n", locale.toString(), style.toString(),result); 105 System.out.printf(" %5s, %5s :[%s] %s%n", "", "", expected, zone); 106 } 107 assertEquals(result, expected); 108 } 109 110 public void test_ParseText() { 111 Locale[] locales = new Locale[] { Locale.ENGLISH, Locale.JAPANESE, Locale.FRENCH }; 112 Set<String> zids = ZoneRulesProvider.getAvailableZoneIds(); 113 for (Locale locale : locales) { 114 parseText(zids, locale, TextStyle.FULL, false); 115 parseText(zids, locale, TextStyle.FULL, true); 116 parseText(zids, locale, TextStyle.SHORT, false); 117 parseText(zids, locale, TextStyle.SHORT, true); 118 } 119 } 120 121 private static Set<ZoneId> preferred = new HashSet<>(Arrays.asList(new ZoneId[] { 122 ZoneId.of("EST", ZoneId.SHORT_IDS), 123 ZoneId.of("Asia/Taipei"), 124 ZoneId.of("Asia/Macau"), 125 ZoneId.of("CET"), 126 })); 127 128 private static Set<ZoneId> preferred_s = new HashSet<>(Arrays.asList(new ZoneId[] { 129 ZoneId.of("EST", ZoneId.SHORT_IDS), 130 ZoneId.of("CET"), 131 ZoneId.of("Australia/South"), 132 ZoneId.of("Australia/West"), 133 ZoneId.of("Asia/Shanghai"), 134 })); 135 136 private static Set<ZoneId> none = new HashSet<>(); 137 138 @DataProvider(name="preferredZones") 139 Object[][] data_preferredZones() { 140 return new Object[][] { 141 {"America/New_York", "Eastern Standard Time", none, Locale.ENGLISH, TextStyle.FULL}, 142 // {"EST", "Eastern Standard Time", preferred, Locale.ENGLISH, TextStyle.FULL}, 143 {"Europe/Paris", "Central European Time", none, Locale.ENGLISH, TextStyle.FULL}, 144 // {"CET", "Central European Time", preferred, Locale.ENGLISH, TextStyle.FULL}, no three-letter ID in CLDR 145 {"Asia/Shanghai", "China Standard Time", none, Locale.ENGLISH, TextStyle.FULL}, 146 {"Asia/Macau", "China Standard Time", preferred, Locale.ENGLISH, TextStyle.FULL}, 147 {"Asia/Taipei", "Taipei Standard Time", preferred, Locale.ENGLISH, TextStyle.FULL}, 148 {"America/Chicago", "CST", none, Locale.ENGLISH, TextStyle.SHORT}, 149 {"Asia/Taipei", "TST", preferred, Locale.ENGLISH, TextStyle.SHORT}, 150 {"Australia/South", "ACST", preferred_s, Locale.ENGLISH, TextStyle.SHORT}, 151 {"America/Chicago", "CDT", none, Locale.ENGLISH, TextStyle.SHORT}, 152 {"Asia/Shanghai", "CDT", preferred_s, Locale.ENGLISH, TextStyle.SHORT}, 153 }; 154 } 155 156 @Test(dataProvider="preferredZones") 157 public void test_ParseText(String expected, String text, Set<ZoneId> preferred, Locale locale, TextStyle style) { 158 DateTimeFormatter fmt = new DateTimeFormatterBuilder().appendZoneText(style, preferred) 159 .toFormatter(locale) 160 .withDecimalStyle(DecimalStyle.of(locale)); 161 162 String ret = fmt.parse(text, TemporalQueries.zone()).getId(); 163 164 System.out.printf("[%-5s %s] %24s -> %s(%s)%n", 165 locale.toString(), 166 style == TextStyle.FULL ? " full" :"short", 167 text, ret, expected); 168 169 assertEquals(ret, expected); 170 171 } 172 173 174 private void parseText(Set<String> zids, Locale locale, TextStyle style, boolean ci) { 175 System.out.println("---------------------------------------"); 176 DateTimeFormatter fmt = getFormatter(locale, style, ci); 177 for (String[] names : new DateFormatSymbols(locale).getZoneStrings()) { 178 if (!zids.contains(names[0])) { 179 continue; 180 } 181 String zid = names[0]; 182 String expected = ZoneName.toZid(zid, locale); 183 184 parse(fmt, zid, expected, zid, locale, style, ci); 185 int i = style == TextStyle.FULL ? 1 : 2; 186 for (; i < names.length; i += 2) { 187 parse(fmt, zid, expected, names[i], locale, style, ci); 188 } 189 } 190 } 191 192 private void parse(DateTimeFormatter fmt, 193 String zid, String expected, String text, 194 Locale locale, TextStyle style, boolean ci) { 195 if (ci) { 196 text = text.toUpperCase(); 197 } 198 String ret = fmt.parse(text, TemporalQueries.zone()).getId(); 199 // TBD: need an excluding list 200 // assertEquals(...); 201 if (ret.equals(expected) || 202 ret.equals(zid) || 203 ret.equals(ZoneName.toZid(zid)) || 204 ret.equals(expected.replace("UTC", "UCT"))) { 205 return; 206 } 207 System.out.printf("[%-5s %s %s %16s] %24s -> %s(%s)%n", 208 locale.toString(), 209 ci ? "ci" : " ", 210 style == TextStyle.FULL ? " full" :"short", 211 zid, text, ret, expected); 212 } 213 214 private DateTimeFormatter getFormatter(Locale locale, TextStyle style, boolean ci) { 215 DateTimeFormatterBuilder db = new DateTimeFormatterBuilder(); 216 if (ci) { 217 db = db.parseCaseInsensitive(); 218 } 219 return db.appendZoneText(style) 220 .toFormatter(locale) 221 .withDecimalStyle(DecimalStyle.of(locale)); 222 } 223 224 }