1 /*
2  * Copyright (c) 2013, 2019, 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  *
26  * @test
27  * @bug 8206120
28  */
29 
30 package test.java.time.format;
31 
32 import static org.testng.Assert.assertEquals;
33 
34 import java.time.LocalDate;
35 import java.time.chrono.ChronoLocalDate;
36 import java.time.chrono.Chronology;
37 import java.time.chrono.HijrahChronology;
38 import java.time.chrono.IsoChronology;
39 import java.time.chrono.JapaneseChronology;
40 import java.time.chrono.MinguoChronology;
41 import java.time.chrono.ThaiBuddhistChronology;
42 import java.time.format.DecimalStyle;
43 import java.time.format.DateTimeFormatter;
44 import java.time.format.DateTimeFormatterBuilder;
45 import java.time.format.DateTimeParseException;
46 import java.time.format.FormatStyle;
47 import java.time.format.ResolverStyle;
48 import java.time.format.TextStyle;
49 import java.time.temporal.TemporalAccessor;
50 import java.time.temporal.TemporalQueries;
51 import java.util.Locale;
52 
53 import org.testng.annotations.BeforeMethod;
54 import org.testng.annotations.DataProvider;
55 import org.testng.annotations.Test;
56 
57 /**
58  * Test DateTimeFormatter with non-ISO chronology.
59  *
60  * Strings in test data are all dependent on CLDR data which may change
61  * in future CLDR releases.
62  */
63 @Test
64 public class TestNonIsoFormatter {
65     private static final Chronology ISO8601 = IsoChronology.INSTANCE;
66     private static final Chronology JAPANESE = JapaneseChronology.INSTANCE;
67     private static final Chronology HIJRAH = HijrahChronology.INSTANCE;
68     private static final Chronology MINGUO = MinguoChronology.INSTANCE;
69     private static final Chronology BUDDHIST = ThaiBuddhistChronology.INSTANCE;
70 
71     private static final LocalDate IsoDate = LocalDate.of(2013, 2, 11);
72 
73     private static final Locale ARABIC = new Locale("ar");
74     private static final Locale thTH = new Locale("th", "TH");
75     private static final Locale thTHTH = Locale.forLanguageTag("th-TH-u-nu-thai");
76     private static final Locale jaJPJP = Locale.forLanguageTag("ja-JP-u-ca-japanese");
77 
78     @BeforeMethod
setUp()79     public void setUp() {
80     }
81 
82     @DataProvider(name="format_data")
formatData()83     Object[][] formatData() {
84         return new Object[][] {
85             // Chronology, Format Locale, Numbering Locale, ChronoLocalDate, expected string
86             { JAPANESE, Locale.JAPANESE, Locale.JAPANESE, JAPANESE.date(IsoDate),
87               "\u5e73\u621025\u5e742\u670811\u65e5\u6708\u66dc\u65e5" }, // Japanese Heisei 25-02-11
88             // Android-changed: requesting arabic numbering actually produces arabic digits. Also
89             // new CLDR patterns include the era. Test Arabic locale with ASCII digits below.
90             { HIJRAH, ARABIC, ARABIC, HIJRAH.date(IsoDate),
91               "\u0627\u0644\u0627\u062b\u0646\u064a\u0646\u060c \u0661 \u0631\u0628\u064a\u0639 "
92               + "\u0627\u0644\u0622\u062e\u0631 \u0661\u0664\u0663\u0664 \u0647\u0640" }, // Hijrah AH 1434-04-01 (Mon)
93             { HIJRAH, ARABIC, Locale.ENGLISH, HIJRAH.date(IsoDate),
94               "\u0627\u0644\u0627\u062b\u0646\u064a\u0646\u060c 1 \u0631\u0628\u064a\u0639 "
95               + "\u0627\u0644\u0622\u062e\u0631 1434 \u0647\u0640" }, // Hijrah AH 1434-04-01 (Mon)
96             { MINGUO, Locale.TAIWAN, Locale.TAIWAN, MINGUO.date(IsoDate),
97               "\u6c11\u570b102\u5e742\u670811\u65e5 \u661f\u671f\u4e00" }, // Minguo ROC 102-02-11 (Mon)
98             { BUDDHIST, thTH, thTH, BUDDHIST.date(IsoDate),
99               "\u0e27\u0e31\u0e19\u0e08\u0e31\u0e19\u0e17\u0e23\u0e4c\u0e17\u0e35\u0e48 "
100               + "11 \u0e01\u0e38\u0e21\u0e20\u0e32\u0e1e\u0e31\u0e19\u0e18\u0e4c "
101               + "\u0e1e.\u0e28. 2556" }, // ThaiBuddhist BE 2556-02-11
102             { BUDDHIST, thTH, thTHTH, BUDDHIST.date(IsoDate),
103               "\u0e27\u0e31\u0e19\u0e08\u0e31\u0e19\u0e17\u0e23\u0e4c\u0e17\u0e35\u0e48 \u0e51\u0e51 "
104               + "\u0e01\u0e38\u0e21\u0e20\u0e32\u0e1e\u0e31\u0e19\u0e18\u0e4c "
105               + "\u0e1e.\u0e28. \u0e52\u0e55\u0e55\u0e56" }, // ThaiBuddhist BE 2556-02-11 (with Thai digits)
106         };
107     }
108 
109     @DataProvider(name="invalid_text")
invalidText()110     Object[][] invalidText() {
111         return new Object[][] {
112             // TODO: currently fixed Chronology and Locale.
113             // line commented out, as S64.01.09 seems like a reasonable thing to parse
114             // (era "S" ended on S64.01.07, but a little leniency is a good thing
115 //            { "\u662d\u548c64\u5e741\u67089\u65e5\u6708\u66dc\u65e5" }, // S64.01.09 (Mon)
116             { "\u662d\u548c65\u5e741\u67081\u65e5\u6708\u66dc\u65e5" }, // S65.01.01 (Mon)
117         };
118     }
119 
120     @DataProvider(name="chrono_names")
chronoNamesData()121     Object[][] chronoNamesData() {
122         return new Object[][] {
123             // Chronology, Locale, Chronology Name
124             // Android-changed: CLDR data has changed.
125             { ISO8601,  Locale.ENGLISH, "ISO-8601 Calendar" },
126             { BUDDHIST, Locale.ENGLISH, "Buddhist Calendar" },
127             { HIJRAH,   Locale.ENGLISH, "Islamic Calendar (Umm al-Qura)" },
128             { JAPANESE, Locale.ENGLISH, "Japanese Calendar" },
129             { MINGUO,   Locale.ENGLISH, "Minguo Calendar" },
130 
131             { ISO8601,  Locale.JAPANESE, "ISO-8601" },
132             { JAPANESE, Locale.JAPANESE, "\u548c\u66a6" },
133             { BUDDHIST, Locale.JAPANESE, "\u4ecf\u66a6" },
134 
135             { ISO8601,  thTH, "\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19 ISO-8601" },
136             { JAPANESE, thTH, "\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e0d\u0e35\u0e48\u0e1b\u0e38\u0e48\u0e19" },
137             { BUDDHIST, thTH, "\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e1e\u0e38\u0e17\u0e18" },
138 
139             { HIJRAH,   ARABIC, "\u0627\u0644\u062a\u0642\u0648\u064a\u0645 "
140                                 + "\u0627\u0644\u0625\u0633\u0644\u0627\u0645\u064a "
141                                 + "(\u0623\u0645 \u0627\u0644\u0642\u0631\u0649)" }, // JDK-8015986
142         };
143     }
144 
145     @DataProvider(name="lenient_eraYear")
lenientEraYear()146     Object[][] lenientEraYear() {
147         return new Object[][] {
148             // Chronology, lenient era/year, strict era/year
149             { JAPANESE, "Meiji 123", "Heisei 2" },
150             // Android-changed: Eras names have been changed in CLDR data.
151             // { JAPANESE, "Showa 65", "Heisei 2" }
152             { JAPANESE, "Shōwa 65", "Heisei 2" },
153             { JAPANESE, "Heisei 32", "Reiwa 2" },
154         };
155     }
156 
157     @Test(dataProvider="format_data")
test_formatLocalizedDate(Chronology chrono, Locale formatLocale, Locale numberingLocale, ChronoLocalDate date, String expected)158     public void test_formatLocalizedDate(Chronology chrono, Locale formatLocale, Locale numberingLocale,
159                                          ChronoLocalDate date, String expected) {
160         DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
161             .withChronology(chrono).withLocale(formatLocale)
162             .withDecimalStyle(DecimalStyle.of(numberingLocale));
163         String text = dtf.format(date);
164         assertEquals(text, expected);
165     }
166 
167     @Test(dataProvider="format_data")
test_parseLocalizedText(Chronology chrono, Locale formatLocale, Locale numberingLocale, ChronoLocalDate expected, String text)168     public void test_parseLocalizedText(Chronology chrono, Locale formatLocale, Locale numberingLocale,
169                                         ChronoLocalDate expected, String text) {
170         DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
171             .withChronology(chrono).withLocale(formatLocale)
172             .withDecimalStyle(DecimalStyle.of(numberingLocale));
173         TemporalAccessor temporal = dtf.parse(text);
174         ChronoLocalDate date = chrono.date(temporal);
175         assertEquals(date, expected);
176     }
177 
178     @Test(dataProvider="invalid_text", expectedExceptions=DateTimeParseException.class)
test_parseInvalidText(String text)179     public void test_parseInvalidText(String text) {
180         DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
181             .withChronology(JAPANESE).withLocale(Locale.JAPANESE);
182         dtf.parse(text);
183     }
184 
185     @Test(dataProvider="chrono_names")
test_chronoNames(Chronology chrono, Locale locale, String expected)186     public void test_chronoNames(Chronology chrono, Locale locale, String expected) {
187         DateTimeFormatter dtf = new DateTimeFormatterBuilder().appendChronologyText(TextStyle.SHORT)
188             .toFormatter(locale);
189         String text = dtf.format(chrono.dateNow());
190         assertEquals(text, expected);
191         TemporalAccessor ta = dtf.parse(text);
192         Chronology cal = ta.query(TemporalQueries.chronology());
193         assertEquals(cal, chrono);
194     }
195 
196     @Test(dataProvider="lenient_eraYear")
test_lenientEraYear(Chronology chrono, String lenient, String strict)197     public void test_lenientEraYear(Chronology chrono, String lenient, String strict) {
198         String mdStr = "-01-01";
199         DateTimeFormatter dtf = new DateTimeFormatterBuilder()
200             .appendPattern("GGGG y-M-d")
201             .toFormatter()
202             .withChronology(chrono);
203         DateTimeFormatter dtfLenient = dtf.withResolverStyle(ResolverStyle.LENIENT);
204         assertEquals(LocalDate.parse(lenient+mdStr, dtfLenient), LocalDate.parse(strict+mdStr, dtf));
205     }
206 }
207