1 /*
   2  * Copyright (c) 2005, 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 /*
  25  * @test
  26  * @bug 4833268 6253991 8008577
  27  * @summary Test formatting and parsing with non-Gregorian calendars
  28  * @run main/othervm -Djava.locale.providers=COMPAT,SPI NonGregorianFormatTest
  29  */
  30 
  31 import java.util.*;
  32 import java.text.*;
  33 import static java.util.Calendar.*;
  34 
  35 public class NonGregorianFormatTest {
  36     static int errors;
  37 
  38     static final Object[][] JAPANESE_EN = {
  39         { "GGGG yyyy MMMM d", "Showa 1 December 31", new Date(1926-1900, DECEMBER, 31) },
  40         { "GGGG yyyy MMMM d", "Showa 64 January 6", new Date(1989-1900, JANUARY, 6) },
  41         { "GGGG yyyy MMMM d", "Heisei 1 August 9", new Date(1989-1900, AUGUST, 9) },
  42         { "GGGG yyyy MMMM d", "Heisei 17 June 10", new Date(2005-1900, JUNE, 10) },
  43         { "Gy.MM.dd", "S1.12.31", new Date(1926-1900, DECEMBER, 31) },
  44         { "Gy.MM.dd", "S64.01.06", new Date(1989-1900, JANUARY, 6) },
  45         { "Gyy.MM.dd", "H01.08.09", new Date(1989-1900, AUGUST, 9) },
  46         { "Gy.M.d", "H1.8.9", new Date(1989-1900, AUGUST, 9) },
  47         { "Gy.MM.dd", "H17.06.10", new Date(2005-1900, JUNE, 10) },
  48     };
  49 
  50     // Invalid dates for parse exception tests
  51     static final Object[][] EXCEPTION_JAPANESE_EN = {
  52         { "GGGG yyyy MMMM d", "Showa 1 December 10" },
  53         { "GGGG yyyy MMMM d", "Showa 64 January 16" },
  54         { "GGGG yyyy MMMM d", "Heisei 1 January 1" },
  55         { "Gy.MM.dd", "S1.12.10" },
  56         { "Gy.MM.dd", "S64.01.16" },
  57         { "Gyy.MM.dd", "H01.01.01" },
  58     };
  59 
  60     static final Object[][] BUDDHIST_EN = {
  61         { "GGGG yyyy MMMM d", "B.E. 2469 December 31", new Date(1926-1900, DECEMBER, 31) },
  62         { "GGGG yyyy MMMM d", "B.E. 2532 January 6", new Date(1989-1900, JANUARY, 6) },
  63         { "GGGG yyyy MMMM d", "B.E. 2532 August 8", new Date(1989-1900, AUGUST, 8) },
  64         { "GGGG yyyy MMMM d", "B.E. 2548 June 10", new Date(2005-1900, JUNE, 10) },
  65         { "Gyyyy/MM/dd", "B.E.2469/12/31", new Date(1926-1900, DECEMBER, 31) },
  66         { "Gyyyy/MM/dd", "B.E.2532/01/06", new Date(1989-1900, JANUARY, 6) },
  67         { "Gyyyy/MM/dd", "B.E.2532/08/09", new Date(1989-1900, AUGUST, 9) },
  68         { "Gyyyy/MM/dd", "B.E.2548/06/10", new Date(2005-1900, JUNE, 10) },
  69     };
  70 
  71     static final String FULL_DATE_FORMAT_JA = "GGGGyyyy'\u5e74'M'\u6708'd'\u65e5'";
  72 
  73     static final Object[][] JAPANESE_JA = {
  74         { FULL_DATE_FORMAT_JA, "\u662d\u548c\u5143\u5e7412\u670831\u65e5", new Date(1926-1900, DECEMBER, 31) },
  75         { FULL_DATE_FORMAT_JA, "\u662d\u548c64\u5e741\u67086\u65e5", new Date(1989-1900, JANUARY, 6) },
  76         { FULL_DATE_FORMAT_JA, "\u5e73\u6210\u5143\u5e748\u67089\u65e5", new Date(1989-1900, AUGUST, 9) },
  77         { FULL_DATE_FORMAT_JA, "\u5e73\u621017\u5e746\u670810\u65e5", new Date(2005-1900, JUNE, 10) },
  78         { "Gyy.MM.dd", "S01.12.31", new Date(1926-1900, DECEMBER, 31) },
  79         { "Gyy.MM.dd", "S64.01.06", new Date(1989-1900, JANUARY, 6) },
  80         { "Gyy.MM.dd", "H01.08.09", new Date(1989-1900, AUGUST, 9) },
  81         { "Gy.M.d", "H1.8.9", new Date(1989-1900, AUGUST, 9) },
  82         { "Gyy.MM.dd", "H17.06.10", new Date(2005-1900, JUNE, 10) },
  83     };
  84 
  85     // Invalid dates for parse exception tests
  86     static final Object[][] EXCEPTION_JAPANESE_JA = {
  87         { FULL_DATE_FORMAT_JA, "\u662d\u548c\u5143\u5e7412\u670810\u65e5" },
  88         { FULL_DATE_FORMAT_JA, "\u662d\u548c64\u5e741\u670816\u65e5" },
  89         { FULL_DATE_FORMAT_JA, "\u5e73\u6210\u5143\u5e741\u67081\u65e5" },
  90         { "Gyy.MM.dd", "S01.12.10" },
  91         { "Gyy.MM.dd", "S64.01.16" },
  92         { "Gyy.MM.dd", "H01.01.01" },
  93     };
  94 
  95     static final Object[][] BUDDHIST_JA = {
  96         { FULL_DATE_FORMAT_JA, "\u4ecf\u66a62469\u5e7412\u670831\u65e5", new Date(1926-1900, DECEMBER, 31) },
  97         { FULL_DATE_FORMAT_JA, "\u4ecf\u66a62532\u5e741\u67086\u65e5", new Date(1989-1900, JANUARY, 6) },
  98         { FULL_DATE_FORMAT_JA, "\u4ecf\u66a62532\u5e748\u67089\u65e5", new Date(1989-1900, AUGUST, 9) },
  99         { FULL_DATE_FORMAT_JA, "\u4ecf\u66a62548\u5e746\u670810\u65e5", new Date(2005-1900, JUNE, 10) },
 100         { "Gyyyy/MM/dd", "B.E.2469/12/31", new Date(1926-1900, DECEMBER, 31) },
 101         { "Gyyyy/MM/dd", "B.E.2532/01/06", new Date(1989-1900, JANUARY, 6) },
 102         { "Gyyyy/MM/dd", "B.E.2532/08/09", new Date(1989-1900, AUGUST, 9) },
 103         { "Gyyyy/MM/dd", "B.E.2548/06/10", new Date(2005-1900, JUNE, 10) },
 104     };
 105 
 106     public static void main(String[] args) throws ParseException {
 107         Locale defaultLocale = Locale.getDefault();
 108         Locale[] locales = { Locale.ENGLISH, Locale.JAPAN };
 109         try {
 110             for (Locale locale : locales) {
 111                 test(locale);
 112             }
 113         } finally {
 114             Locale.setDefault(defaultLocale);
 115         }
 116         if (errors > 0) {
 117             throw new RuntimeException("FAILED: " + errors + " error(s)");
 118         }
 119     }
 120 
 121     private static void test(Locale locale) {
 122         Locale.setDefault(locale);
 123 
 124         // Tests with the Japanese imperial calendar
 125         Locale calendarLocale = new Locale("ja", "JP", "JP");
 126         testRoundTrip(calendarLocale);
 127         testRoundTripSimple(calendarLocale,
 128                             locale == Locale.ENGLISH ? JAPANESE_EN : JAPANESE_JA);
 129         testParseExceptions(calendarLocale,
 130                             locale == Locale.ENGLISH ? EXCEPTION_JAPANESE_EN : EXCEPTION_JAPANESE_JA);
 131 
 132         // Tests with the Thai Buddhist calendar
 133         calendarLocale = new Locale("th", "TH");
 134         testRoundTrip(calendarLocale);
 135         testRoundTripSimple(calendarLocale,
 136                             locale == Locale.ENGLISH ? BUDDHIST_EN : BUDDHIST_JA);
 137     }
 138 
 139     private static void testRoundTrip(Locale calendarLocale) {
 140         DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL,
 141                                                        DateFormat.FULL,
 142                                                        calendarLocale);
 143 
 144         long t = System.currentTimeMillis();
 145         t = (t / 1000) * 1000; // discard milliseconds
 146         testRoundTrip(df, new Date(t));
 147 
 148         // H1.8.9
 149         testRoundTrip(df, new Date(1989-1900, AUGUST, 9));
 150 
 151         // H17.6.13
 152         testRoundTrip(df, new Date(2005-1900, JUNE, 13));
 153     }
 154 
 155     private static void testRoundTrip(DateFormat df, Date orig) {
 156         try {
 157             String s = df.format(orig);
 158             Date parsed = df.parse(s);
 159             if (!orig.equals(parsed)) {
 160                 error("testRoundTrip: bad date: origianl: '%s', parsed '%s'%n", orig, parsed);
 161             }
 162         } catch (Exception e) {
 163             error("Unexpected exception: %s%n", e);
 164         }
 165     }
 166 
 167     private static void testRoundTripSimple(Locale calendarLocale, Object[][] data) {
 168         try {
 169             for (Object[] item : data) {
 170                 String pattern = (String) item[0];
 171                 String str = (String) item[1];
 172                 Date date = (Date) item[2];
 173                 SimpleDateFormat sdf = new SimpleDateFormat(pattern);
 174                 Calendar cal = Calendar.getInstance(calendarLocale);
 175                 sdf.setCalendar(cal);
 176                 String s = sdf.format(date);
 177                 if (!s.equals(str)) {
 178                     error("testRoundTripSimple: Got '%s', expected '%s'%n", s, str);
 179                 }
 180                 Date d = sdf.parse(str);
 181                 if (!d.equals(date)) {
 182                     error("testRoundTripSimple: Got '%s', expected '%s'%n", d, date);
 183                 }
 184             }
 185         } catch (Exception e) {
 186             error("Unexpected exception: %s%n", e);
 187         }
 188     }
 189 
 190     private static void testParseExceptions(Locale calendarLocale, Object[][] data) {
 191         for (Object[] item : data) {
 192             String pattern = (String) item[0];
 193             String str = (String) item[1];
 194             SimpleDateFormat sdf = new SimpleDateFormat(pattern);
 195             Calendar cal = Calendar.getInstance(calendarLocale);
 196             sdf.setCalendar(cal);
 197             sdf.setLenient(false);
 198             try {
 199                 Date d = sdf.parse(str);
 200                 error("testParseExceptions: parsing '%s' doesn't throw a ParseException.%n", str);
 201             } catch (ParseException e) {
 202                 // OK
 203             }
 204         }
 205     }
 206 
 207     private static void error(String msg) {
 208         System.out.println(msg);
 209         errors++;
 210     }
 211 
 212     private static void error(String fmt, Object... args) {
 213         System.out.printf(fmt, args);
 214         errors++;
 215     }
 216 }