--- /dev/null 2019-01-03 08:03:45.787020613 -0800 +++ new/test/jdk/java/text/Format/DateFormat/SDFTCKZoneNamesTest.java 2019-03-05 13:59:00.684308732 -0800 @@ -0,0 +1,368 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8218948 + * @summary TCK tests that check the time zone names between DFS.getZoneStrings() + * and SDF.format("z*") + * @run main SDFTCKZoneNamesTest + */ +import java.text.*; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.TimeZone; + +public class SDFTCKZoneNamesTest { + + StringBuffer myFormat(Date date, SimpleDateFormat sdf) { + String pattern = sdf.toPattern(); + StringBuffer toAppendTo = new StringBuffer(""); + boolean inQuote = false; + char prevCh = 0; + char ch; + int count = 0; + for (int i = 0; i < pattern.length(); i++) { + ch = pattern.charAt(i); + if (inQuote) { + if (ch == '\'') { + inQuote = false; + if (count == 0) toAppendTo.append(ch); + else count = 0; + } else { + toAppendTo.append(ch); + count++; + } + } else { // not inQuote + if (ch == '\'') { + inQuote = true; + if (count > 0) { + toAppendTo.append(subFormat(prevCh, count, date, sdf)); + count = 0; + prevCh = 0; + } + } else if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') { + if (ch != prevCh && count > 0) { + toAppendTo.append(subFormat(prevCh, count, date, sdf)); + prevCh = ch; + count = 1; + } else { + if (ch != prevCh) prevCh = ch; + count++; + } + } else if (count > 0) { + toAppendTo.append(subFormat(prevCh, count, date, sdf)); + toAppendTo.append(ch); + prevCh = 0; + count = 0; + } else toAppendTo.append(ch); + } + } + if (count > 0) { + toAppendTo.append(subFormat(prevCh, count, date, sdf)); + } + return toAppendTo; + } + + private String subFormat(char ch, int count, Date date, SimpleDateFormat sdf) + throws IllegalArgumentException { + int value = 0; + int patternCharIndex = -1; + int maxIntCount = 10; + String current = ""; + DateFormatSymbols formatData = sdf.getDateFormatSymbols(); + Calendar calendar = sdf.getCalendar(); + calendar.setTime(date); + NumberFormat nf = sdf.getNumberFormat(); + nf.setGroupingUsed(false); + + if ((patternCharIndex = "GyMdkHmsSEDFwWahKz".indexOf(ch)) == -1) + throw new IllegalArgumentException("Illegal pattern character " + + "'" + ch + "'"); + switch (patternCharIndex) { + case 0: // 'G' - ERA + value = calendar.get(Calendar.ERA); + current = formatData.getEras()[value]; + break; + case 1: // 'y' - YEAR + value = calendar.get(Calendar.YEAR); + + if (count == 2) { + // For formatting, if the number of pattern letters is 2, + // the year is truncated to 2 digits; + current = zeroPaddingNumber(value, 2, 2, nf); + } else { + // otherwise it is interpreted as a number. + current = zeroPaddingNumber(value, count, maxIntCount, nf); + } + + break; + case 2: // 'M' - MONTH + value = calendar.get(Calendar.MONTH); + if (count >= 4) + // DateFormatSymbols::getMonths spec: "If the language requires different forms for formatting + // and stand-alone usages, this method returns month names in the formatting form." + // Because of that only formatting cases patterns may be tested. Like, "MMMM yyyy". Wrong + // pattern: "MMMM". + current = formatData.getMonths()[value]; + else if (count == 3) + // DateFormatSymbols::getShortMonths spec: "If the language requires different forms for formatting + // and stand-alone usages, This method returns short month names in the formatting form." + // Because of that only formatting cases patterns may be tested. Like, "MMM yyyy". Wrong pattern: + // "MMM". + current = formatData.getShortMonths()[value]; + else + current = zeroPaddingNumber(value + 1, count, maxIntCount, nf); + break; + case 3: // 'd' - DATE + value = calendar.get(Calendar.DATE); + current = zeroPaddingNumber(value, count, maxIntCount, nf); + break; + case 4: // 'k' - HOUR_OF_DAY: 1-based. eg, 23:59 + 1 hour =>> 24:59 + if ((value = calendar.get(Calendar.HOUR_OF_DAY)) == 0) + current = zeroPaddingNumber( + calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1, + count, maxIntCount, nf); + else + current = zeroPaddingNumber(value, count, maxIntCount, nf); + break; + case 5: // 'H' - HOUR_OF_DAY:0-based. eg, 23:59 + 1 hour =>> 00:59 + value = calendar.get(Calendar.HOUR_OF_DAY); + current = zeroPaddingNumber(value, count, maxIntCount, nf); + break; + case 6: // 'm' - MINUTE + value = calendar.get(Calendar.MINUTE); + current = zeroPaddingNumber(value, count, maxIntCount, nf); + break; + case 7: // 's' - SECOND + value = calendar.get(Calendar.SECOND); + current = zeroPaddingNumber(value, count, maxIntCount, nf); + break; + case 8: // 'S' - MILLISECOND + value = calendar.get(Calendar.MILLISECOND); + /* + if (count > 3) + value = value * (int) Math.pow(10, count - 3); + else if (count == 2) + value = (value + 5) / 10; + else if (count == 1) + value = (value + 50) / 100; + */ + current = zeroPaddingNumber(value, count, maxIntCount, nf); + break; + case 9: // 'E' - DAY_OF_WEEK + value = calendar.get(Calendar.DAY_OF_WEEK); + if (count >= 4) + current = formatData.getWeekdays()[value]; + else // count < 4, use abbreviated form if exists + current = formatData.getShortWeekdays()[value]; + break; + case 10: // 'D' - DAY_OF_YEAR + value = calendar.get(Calendar.DAY_OF_YEAR); + current = zeroPaddingNumber(value, count, maxIntCount, nf); + break; + case 11: // 'F' - DAY_OF_WEEK_IN_MONTH + value = calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH); + current = zeroPaddingNumber(value, count, maxIntCount, nf); + break; + case 12: // 'w' - WEEK_OF_YEAR + value = calendar.get(Calendar.WEEK_OF_YEAR); + current = zeroPaddingNumber(value, count, maxIntCount, nf); + break; + case 13: // 'W' - WEEK_OF_MONTH + value = calendar.get(Calendar.WEEK_OF_MONTH); + current = zeroPaddingNumber(value, count, maxIntCount, nf); + break; + case 14: // 'a' - AM_PM + value = calendar.get(Calendar.AM_PM); + current = formatData.getAmPmStrings()[value]; + break; + case 15: // 'h' - HOUR:1-based. eg, 11PM + 1 hour =>> 12 AM + if ((value = calendar.get(Calendar.HOUR)) == 0) + current = zeroPaddingNumber( + calendar.getLeastMaximum(Calendar.HOUR) + 1, + count, maxIntCount, nf); + else + current = zeroPaddingNumber(value, count, maxIntCount, nf); + break; + case 16: // 'K' - HOUR: 0-based. eg, 11PM + 1 hour =>> 0 AM + value = calendar.get(Calendar.HOUR); + current = zeroPaddingNumber(value, count, maxIntCount, nf); + break; + case 17: // 'z' - ZONE_OFFSET + int zoneIndex = getZoneIndex(calendar.getTimeZone().getID(), formatData); + if (zoneIndex == -1) { + StringBuffer zoneString = new StringBuffer(); + value = calendar.get(Calendar.ZONE_OFFSET) + + calendar.get(Calendar.DST_OFFSET); + if (value < 0) { + zoneString.append("GMT-"); + value = -value; // suppress the '-' sign for text display. + } else + zoneString.append("GMT+"); + zoneString.append( + zeroPaddingNumber((int) (value / (60 * 60 * 1000)), 2, 2, nf)); + zoneString.append(':'); + zoneString.append( + zeroPaddingNumber( + (int) ((value % (60 * 60 * 1000)) / (60 * 1000)), 2, 2, nf)); + current = zoneString.toString(); + } else if (calendar.get(Calendar.DST_OFFSET) != 0) { + if (count >= 4) + current = formatData.getZoneStrings()[zoneIndex][3]; + else + // count < 4, use abbreviated form if exists + current = formatData.getZoneStrings()[zoneIndex][4]; + } else { + if (count >= 4) + current = formatData.getZoneStrings()[zoneIndex][1]; + else + current = formatData.getZoneStrings()[zoneIndex][2]; + } + break; + } + + return current; + } + + + String zeroPaddingNumber(long value, int minDigits, int maxDigits, + NumberFormat nf) { + nf.setMinimumIntegerDigits(minDigits); + nf.setMaximumIntegerDigits(maxDigits); + return nf.format(value); + } + + + int getZoneIndex(String ID, DateFormatSymbols dfs) { + String[][] zoneStrings = dfs.getZoneStrings(); + + for (int index = 0; index < zoneStrings.length; index++) { + if (ID.equalsIgnoreCase(zoneStrings[index][0])) return index; + } + return -1; + } + + + final int second = 1000; + final int minute = 60 * second; + final int hour = 60 * minute; + final int day = 24 * hour; + final int month = 30 * day; + final int year = 365 * day; + final int someday = 30 * year + 3 * month + 19 * day + 5 * hour; + + + /* standalone interface */ + public static void main(String argv[]) { + Locale defaultLocale = Locale.getDefault(); + SDFTCKZoneNamesTest test = new SDFTCKZoneNamesTest(); + + try { + List.of(Locale.ROOT, + Locale.CHINA, + Locale.forLanguageTag("es-419"), + Locale.GERMANY, + Locale.forLanguageTag("hi-IN"), + Locale.JAPAN, + Locale.TAIWAN, + Locale.UK, + Locale.US, + Locale.forLanguageTag("uz-Cyrl-UZ"), + Locale.forLanguageTag("zh-SG"), + Locale.forLanguageTag("zh-HK"), + Locale.forLanguageTag("zh-MO")).stream() + .forEach(l -> { + System.out.printf("Testing locale: %s%n", l); + Locale.setDefault(l); + test.SimpleDateFormat0062(); + }); + } finally { + Locale.setDefault(defaultLocale); + } + } + + + /** + * Equivalence class partitioning + * with state, input and output values orientation + * for public StringBuffer format(Date date, StringBuffer result, FieldPosition fp), + *
pre-conditions: patterns: { "'s0mething'z mm::hh,yyyy zz", + * "zzzz", + * "z"} (each pattern contains letter for TIMEZONE_FIELD), + *
date: a Date object + *
result: a string + *
fp: a FieldPosition object with TIMEZONE_FIELD field + *
output: formatted date as expected. + */ + public void SimpleDateFormat0062() { + boolean passed = true; + String patterns[] = {"'s0mething'z mm::hh,yyyy zz", + "zzzz", + "z"}; + SimpleDateFormat sdf = new SimpleDateFormat(); + Date date = new Date(1234567890); + for (String[] tz : sdf.getDateFormatSymbols().getZoneStrings()) { + sdf.setTimeZone(TimeZone.getTimeZone(tz[0])); + for (int i = 0; i < patterns.length && passed; i++) { + StringBuffer result = new StringBuffer("qwerty"); + FieldPosition fp = new FieldPosition(DateFormat.TIMEZONE_FIELD); + sdf.applyPattern(patterns[i]); + String expected = new + StringBuffer("qwerty").append(myFormat(date, + sdf)).toString(); + String formatted = sdf.format(date, result, fp).toString(); + + if (!expected.equals(formatted)) { + System.out.println( + "method format(date, StringBuffer, FieldPosition) formats wrong"); + System.out.println(" pattern: " + patterns[i]); + System.out.println(" time zone ID: " + tz[0]); + System.out.println(" expected result: " + expected); + System.out.println(" formatted result: " + formatted); + passed = false; + } + + if (passed && !expected.equals(result.toString())) { + System.out.println( + "method format(Date date, StringBuffer toAppendTo, FieldPosition fp) toAppendTo is not " + + "equal to output"); + System.out.println(" pattern: " + patterns[i]); + System.out.println(" time zone ID: " + tz[0]); + System.out.println(" toAppendTo : " + result); + System.out.println(" formatted date: " + formatted); + passed = false; + } + } + } + if(passed) + { + System.out.println("PASSED : OKAY"); + }else + { + throw new RuntimeException("FAILED"); + } + } +}