blob: 2175273ee0b09461517384ff910d97f10e7024d1 [file] [log] [blame]
Fredrik Roubert0596fae2017-04-18 21:34:02 +02001// © 2016 and later: Unicode, Inc. and others.
Fredrik Roubert64339d32016-10-21 19:43:16 +02002// License & terms of use: http://www.unicode.org/copyright.html
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -07003/***********************************************************************
4 * COPYRIGHT:
ccorneliusfceb3982014-04-16 12:27:14 -07005 * Copyright (c) 1997-2014, International Business Machines Corporation
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -07006 * and others. All Rights Reserved.
7 ***********************************************************************/
8
9/* Test Internationalized Calendars for C++ */
10
11#include "unicode/utypes.h"
Victor Chang978167a2021-01-18 17:56:33 +000012#include "cmemory.h"
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -070013#include "string.h"
14#include "unicode/locid.h"
15#include "japancal.h"
Nikita Iashchenkoda0990f2019-06-13 19:36:45 +010016#include "unicode/localpointer.h"
17#include "unicode/datefmt.h"
18#include "unicode/smpdtfmt.h"
19#include "unicode/dtptngen.h"
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -070020
21#if !UCONFIG_NO_FORMATTING
22
23#include <stdio.h>
24#include "caltest.h"
25
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +000026#define CHECK(status, msg) UPRV_BLOCK_MACRO_BEGIN { \
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -070027 if (U_FAILURE(status)) { \
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +000028 dataerrln((UnicodeString(u_errorName(status)) + UnicodeString(" : " ) )+ msg); \
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -070029 return; \
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +000030 } \
31} UPRV_BLOCK_MACRO_END
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -070032
33
34static UnicodeString escape( const UnicodeString&src)
35{
36 UnicodeString dst;
37 dst.remove();
38 for (int32_t i = 0; i < src.length(); ++i) {
39 UChar c = src[i];
40 if(c < 0x0080)
41 dst += c;
42 else {
43 dst += UnicodeString("[");
44 char buf [8];
45 sprintf(buf, "%#x", c);
46 dst += UnicodeString(buf);
47 dst += UnicodeString("]");
48 }
49 }
50
51 return dst;
52}
53
54
55#include "incaltst.h"
56#include "unicode/gregocal.h"
57#include "unicode/smpdtfmt.h"
58#include "unicode/simpletz.h"
59
60// *****************************************************************************
61// class IntlCalendarTest
62// *****************************************************************************
63//--- move to CalendarTest?
64
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -070065// Turn this on to dump the calendar fields
66#define U_DEBUG_DUMPCALS
67
68
69#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
70
71
72void IntlCalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
73{
74 if (exec) logln("TestSuite IntlCalendarTest");
Victor Chang978167a2021-01-18 17:56:33 +000075 TESTCASE_AUTO_BEGIN;
76 TESTCASE_AUTO(TestTypes);
77 TESTCASE_AUTO(TestGregorian);
78 TESTCASE_AUTO(TestBuddhist);
79 TESTCASE_AUTO(TestBug21043Indian);
80 TESTCASE_AUTO(TestBug21044Hebrew);
81 TESTCASE_AUTO(TestBug21045Islamic);
82 TESTCASE_AUTO(TestBug21046IslamicUmalqura);
83 TESTCASE_AUTO(TestJapanese);
84 TESTCASE_AUTO(TestBuddhistFormat);
85 TESTCASE_AUTO(TestJapaneseFormat);
86 TESTCASE_AUTO(TestJapanese3860);
87 TESTCASE_AUTO(TestForceGannenNumbering);
88 TESTCASE_AUTO(TestPersian);
89 TESTCASE_AUTO(TestPersianFormat);
90 TESTCASE_AUTO(TestTaiwan);
91 TESTCASE_AUTO(TestConsistencyGregorian);
92 TESTCASE_AUTO(TestConsistencyCoptic);
93 TESTCASE_AUTO(TestConsistencyEthiopic);
94 TESTCASE_AUTO(TestConsistencyROC);
95 TESTCASE_AUTO(TestConsistencyChinese);
96 TESTCASE_AUTO(TestConsistencyDangi);
97 TESTCASE_AUTO(TestConsistencyBuddhist);
98 TESTCASE_AUTO(TestConsistencyEthiopicAmeteAlem);
99 TESTCASE_AUTO(TestConsistencyHebrew);
100 TESTCASE_AUTO(TestConsistencyIndian);
101 TESTCASE_AUTO(TestConsistencyIslamic);
102 TESTCASE_AUTO(TestConsistencyIslamicCivil);
103 TESTCASE_AUTO(TestConsistencyIslamicRGSA);
104 TESTCASE_AUTO(TestConsistencyIslamicTBLA);
105 TESTCASE_AUTO(TestConsistencyIslamicUmalqura);
106 TESTCASE_AUTO(TestConsistencyPersian);
107 TESTCASE_AUTO(TestConsistencyJapanese);
108 TESTCASE_AUTO_END;
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700109}
110
111#undef CASE
112
113// ---------------------------------------------------------------------------------
114
115
116/**
117 * Test various API methods for API completeness.
118 */
119void
120IntlCalendarTest::TestTypes()
121{
122 Calendar *c = NULL;
123 UErrorCode status = U_ZERO_ERROR;
124 int j;
125 const char *locs [40] = { "en_US_VALLEYGIRL",
126 "en_US_VALLEYGIRL@collation=phonebook;calendar=japanese",
127 "en_US_VALLEYGIRL@collation=phonebook;calendar=gregorian",
128 "ja_JP@calendar=japanese",
129 "th_TH@calendar=buddhist",
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700130 "th_TH_TRADITIONAL",
131 "th_TH_TRADITIONAL@calendar=gregorian",
Jean-Baptiste Querub0ac9372009-07-20 15:09:32 -0700132 "en_US",
133 "th_TH", // Default calendar for th_TH is buddhist
134 "th", // th's default region is TH and buddhist is used as default for TH
135 "en_TH", // Default calendar for any locales with region TH is buddhist
claireho27f65472011-06-09 11:11:49 -0700136 "en-TH-u-ca-gregory",
Jean-Baptiste Querub0ac9372009-07-20 15:09:32 -0700137 NULL };
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700138 const char *types[40] = { "gregorian",
139 "japanese",
140 "gregorian",
141 "japanese",
Jean-Baptiste Querub0ac9372009-07-20 15:09:32 -0700142 "buddhist",
ccorneliusfceb3982014-04-16 12:27:14 -0700143 "buddhist",
ccorneliusf9878a22014-11-20 18:09:39 -0800144 "gregorian",
145 "gregorian",
Victor Chang18ad09d2021-01-19 10:17:23 +0000146 "gregorian", // android-changed. "buddhist",
147 "gregorian", // android-changed. "buddhist",
148 "gregorian", // android-changed. "buddhist",
claireho27f65472011-06-09 11:11:49 -0700149 "gregorian",
Jean-Baptiste Querub0ac9372009-07-20 15:09:32 -0700150 NULL };
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700151
152 for(j=0;locs[j];j++) {
153 logln(UnicodeString("Creating calendar of locale ") + locs[j]);
154 status = U_ZERO_ERROR;
155 c = Calendar::createInstance(locs[j], status);
156 CHECK(status, "creating '" + UnicodeString(locs[j]) + "' calendar");
157 if(U_SUCCESS(status)) {
158 logln(UnicodeString(" type is ") + c->getType());
159 if(strcmp(c->getType(), types[j])) {
Jean-Baptiste Queru6d5deb12009-07-20 15:14:11 -0700160 dataerrln(UnicodeString(locs[j]) + UnicodeString("Calendar type ") + c->getType() + " instead of " + types[j]);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700161 }
162 }
163 delete c;
164 }
165}
166
167
168
169/**
170 * Run a test of a quasi-Gregorian calendar. This is a calendar
171 * that behaves like a Gregorian but has different year/era mappings.
172 * The int[] data array should have the format:
173 *
174 * { era, year, gregorianYear, month, dayOfMonth, ... ... , -1 }
175 */
176void IntlCalendarTest::quasiGregorianTest(Calendar& cal, const Locale& gcl, const int32_t *data) {
177 UErrorCode status = U_ZERO_ERROR;
178 // As of JDK 1.4.1_01, using the Sun JDK GregorianCalendar as
179 // a reference throws us off by one hour. This is most likely
180 // due to the JDK 1.4 incorporation of historical time zones.
181 //java.util.Calendar grego = java.util.Calendar.getInstance();
182 Calendar *grego = Calendar::createInstance(gcl, status);
183 if (U_FAILURE(status)) {
184 dataerrln("Error calling Calendar::createInstance");
185 return;
186 }
187
188 int32_t tz1 = cal.get(UCAL_ZONE_OFFSET,status);
189 int32_t tz2 = grego -> get (UCAL_ZONE_OFFSET, status);
190 if(tz1 != tz2) {
191 errln((UnicodeString)"cal's tz " + tz1 + " != grego's tz " + tz2);
192 }
193
194 for (int32_t i=0; data[i]!=-1; ) {
195 int32_t era = data[i++];
196 int32_t year = data[i++];
197 int32_t gregorianYear = data[i++];
198 int32_t month = data[i++];
199 int32_t dayOfMonth = data[i++];
200
201 grego->clear();
202 grego->set(gregorianYear, month, dayOfMonth);
203 UDate D = grego->getTime(status);
204
205 cal.clear();
206 cal.set(UCAL_ERA, era);
207 cal.set(year, month, dayOfMonth);
208 UDate d = cal.getTime(status);
209#ifdef U_DEBUG_DUMPCALS
210 logln((UnicodeString)"cal : " + CalendarTest::calToStr(cal));
211 logln((UnicodeString)"grego: " + CalendarTest::calToStr(*grego));
212#endif
213 if (d == D) {
214 logln(UnicodeString("OK: ") + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth +
215 " => " + d + " (" + UnicodeString(cal.getType()) + ")");
216 } else {
217 errln(UnicodeString("Fail: (fields to millis)") + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth +
218 " => " + d + ", expected " + D + " (" + UnicodeString(cal.getType()) + "Off by: " + (d-D));
219 }
220
221 // Now, set the gregorian millis on the other calendar
222 cal.clear();
223 cal.setTime(D, status);
224 int e = cal.get(UCAL_ERA, status);
225 int y = cal.get(UCAL_YEAR, status);
226#ifdef U_DEBUG_DUMPCALS
227 logln((UnicodeString)"cal : " + CalendarTest::calToStr(cal));
228 logln((UnicodeString)"grego: " + CalendarTest::calToStr(*grego));
229#endif
230 if (y == year && e == era) {
231 logln((UnicodeString)"OK: " + D + " => " + cal.get(UCAL_ERA, status) + ":" +
232 cal.get(UCAL_YEAR, status) + "/" +
233 (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) + " (" + UnicodeString(cal.getType()) + ")");
234 } else {
235 errln((UnicodeString)"Fail: (millis to fields)" + D + " => " + cal.get(UCAL_ERA, status) + ":" +
236 cal.get(UCAL_YEAR, status) + "/" +
237 (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) +
238 ", expected " + era + ":" + year + "/" + (month+1) + "/" +
239 dayOfMonth + " (" + UnicodeString(cal.getType()));
240 }
241 }
242 delete grego;
243 CHECK(status, "err during quasiGregorianTest()");
244}
245
246// Verify that Gregorian works like Gregorian
247void IntlCalendarTest::TestGregorian() {
248 UDate timeA = Calendar::getNow();
249 int32_t data[] = {
250 GregorianCalendar::AD, 1868, 1868, UCAL_SEPTEMBER, 8,
251 GregorianCalendar::AD, 1868, 1868, UCAL_SEPTEMBER, 9,
252 GregorianCalendar::AD, 1869, 1869, UCAL_JUNE, 4,
253 GregorianCalendar::AD, 1912, 1912, UCAL_JULY, 29,
254 GregorianCalendar::AD, 1912, 1912, UCAL_JULY, 30,
255 GregorianCalendar::AD, 1912, 1912, UCAL_AUGUST, 1,
256 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
257 };
258
259 Calendar *cal;
260 UErrorCode status = U_ZERO_ERROR;
261 cal = Calendar::createInstance(/*"de_DE", */ status);
262 CHECK(status, UnicodeString("Creating de_CH calendar"));
263 // Sanity check the calendar
264 UDate timeB = Calendar::getNow();
265 UDate timeCal = cal->getTime(status);
266
267 if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
268 errln((UnicodeString)"Error: Calendar time " + timeCal +
269 " is not within sampled times [" + timeA + " to " + timeB + "]!");
270 }
271 // end sanity check
272
273 // Note, the following is a good way to test the sanity of the constructed calendars,
274 // using Collation as a delay-loop:
275 //
276 // $ intltest format/IntlCalendarTest collate/G7CollationTest format/IntlCalendarTest
277
278 quasiGregorianTest(*cal,Locale("fr_FR"),data);
279 delete cal;
280}
281
282/**
283 * Verify that BuddhistCalendar shifts years to Buddhist Era but otherwise
284 * behaves like GregorianCalendar.
285 */
286void IntlCalendarTest::TestBuddhist() {
287 // BE 2542 == 1999 CE
288 UDate timeA = Calendar::getNow();
289
290 int32_t data[] = {
291 0, // B. era [928479600000]
292 2542, // B. year
293 1999, // G. year
294 UCAL_JUNE, // month
295 4, // day
296
297 0, // B. era [-79204842000000]
298 3, // B. year
299 -540, // G. year
300 UCAL_FEBRUARY, // month
301 12, // day
302
303 0, // test month calculation: 4795 BE = 4252 AD is a leap year, but 4795 AD is not.
304 4795, // BE [72018057600000]
305 4252, // AD
306 UCAL_FEBRUARY,
307 29,
308
309 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
310 };
311 Calendar *cal;
312 UErrorCode status = U_ZERO_ERROR;
313 cal = Calendar::createInstance("th_TH@calendar=buddhist", status);
314 CHECK(status, UnicodeString("Creating th_TH@calendar=buddhist calendar"));
315
316 // Sanity check the calendar
317 UDate timeB = Calendar::getNow();
318 UDate timeCal = cal->getTime(status);
319
320 if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
321 errln((UnicodeString)"Error: Calendar time " + timeCal +
322 " is not within sampled times [" + timeA + " to " + timeB + "]!");
323 }
324 // end sanity check
325
326
327 quasiGregorianTest(*cal,Locale("th_TH@calendar=gregorian"),data);
328 delete cal;
329}
330
331
332/**
333 * Verify that TaiWanCalendar shifts years to Minguo Era but otherwise
334 * behaves like GregorianCalendar.
335 */
336void IntlCalendarTest::TestTaiwan() {
337 // MG 1 == 1912 AD
338 UDate timeA = Calendar::getNow();
339
340 // TODO port these to the data items
341 int32_t data[] = {
342 1, // B. era [928479600000]
343 1, // B. year
344 1912, // G. year
345 UCAL_JUNE, // month
346 4, // day
347
348 1, // B. era [-79204842000000]
349 3, // B. year
350 1914, // G. year
351 UCAL_FEBRUARY, // month
352 12, // day
353
354 1, // B. era [-79204842000000]
355 96, // B. year
356 2007, // G. year
357 UCAL_FEBRUARY, // month
358 12, // day
359
360 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
361 };
362 Calendar *cal;
363 UErrorCode status = U_ZERO_ERROR;
Jean-Baptiste Queruc69afce2009-07-20 15:02:39 -0700364 cal = Calendar::createInstance("en_US@calendar=roc", status);
365 CHECK(status, UnicodeString("Creating en_US@calendar=roc calendar"));
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700366
367 // Sanity check the calendar
368 UDate timeB = Calendar::getNow();
369 UDate timeCal = cal->getTime(status);
370
371 if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
372 errln((UnicodeString)"Error: Calendar time " + timeCal +
373 " is not within sampled times [" + timeA + " to " + timeB + "]!");
374 }
375 // end sanity check
376
377
378 quasiGregorianTest(*cal,Locale("en_US"),data);
379 delete cal;
380}
381
382
383
384/**
385 * Verify that JapaneseCalendar shifts years to Japanese Eras but otherwise
386 * behaves like GregorianCalendar.
387 */
388void IntlCalendarTest::TestJapanese() {
389 UDate timeA = Calendar::getNow();
390
391 /* Sorry.. japancal.h is private! */
392#define JapaneseCalendar_MEIJI 232
393#define JapaneseCalendar_TAISHO 233
394#define JapaneseCalendar_SHOWA 234
395#define JapaneseCalendar_HEISEI 235
396
397 // BE 2542 == 1999 CE
398 int32_t data[] = {
399 // Jera Jyr Gyear m d
400 JapaneseCalendar_MEIJI, 1, 1868, UCAL_SEPTEMBER, 8,
401 JapaneseCalendar_MEIJI, 1, 1868, UCAL_SEPTEMBER, 9,
402 JapaneseCalendar_MEIJI, 2, 1869, UCAL_JUNE, 4,
403 JapaneseCalendar_MEIJI, 45, 1912, UCAL_JULY, 29,
404 JapaneseCalendar_TAISHO, 1, 1912, UCAL_JULY, 30,
405 JapaneseCalendar_TAISHO, 1, 1912, UCAL_AUGUST, 1,
406
407 // new tests (not in java)
408 JapaneseCalendar_SHOWA, 64, 1989, UCAL_JANUARY, 7, // Test current era transition (different code path than others)
409 JapaneseCalendar_HEISEI, 1, 1989, UCAL_JANUARY, 8,
410 JapaneseCalendar_HEISEI, 1, 1989, UCAL_JANUARY, 9,
411 JapaneseCalendar_HEISEI, 1, 1989, UCAL_DECEMBER, 20,
412 JapaneseCalendar_HEISEI, 15, 2003, UCAL_MAY, 22,
413 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
414 };
415
416 Calendar *cal;
417 UErrorCode status = U_ZERO_ERROR;
418 cal = Calendar::createInstance("ja_JP@calendar=japanese", status);
419 CHECK(status, UnicodeString("Creating ja_JP@calendar=japanese calendar"));
420 // Sanity check the calendar
421 UDate timeB = Calendar::getNow();
422 UDate timeCal = cal->getTime(status);
423
424 if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
425 errln((UnicodeString)"Error: Calendar time " + timeCal +
426 " is not within sampled times [" + timeA + " to " + timeB + "]!");
427 }
428 // end sanity check
429 quasiGregorianTest(*cal,Locale("ja_JP"),data);
430 delete cal;
431}
432
433
434
435void IntlCalendarTest::TestBuddhistFormat() {
Victor Chang39491dd2021-01-19 10:18:27 +0000436 // Android patch: b/145129186 Disable failing tests
437 #ifndef ANDROID
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700438 UErrorCode status = U_ZERO_ERROR;
439
440 // Test simple parse/format with adopt
441
Fredrik Roubertdcdfae82017-12-19 22:28:32 +0100442 // First, a contrived English test..
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700443 UDate aDate = 999932400000.0;
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000444 SimpleDateFormat fmt(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=buddhist"), status);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700445 CHECK(status, "creating date format instance");
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000446 SimpleDateFormat fmt2(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700447 CHECK(status, "creating gregorian date format instance");
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000448 UnicodeString str;
449 fmt2.format(aDate, str);
450 logln(UnicodeString() + "Test Date: " + str);
451 str.remove();
452 fmt.format(aDate, str);
453 logln(UnicodeString() + "as Buddhist Calendar: " + escape(str));
454 UnicodeString expected("September 8, 2544 BE");
455 if(str != expected) {
456 errln("Expected " + escape(expected) + " but got " + escape(str));
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700457 }
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000458 UDate otherDate = fmt.parse(expected, status);
459 if(otherDate != aDate) {
460 UnicodeString str3;
461 fmt.format(otherDate, str3);
462 errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " + otherDate + ", " + escape(str3));
463 } else {
464 logln("Parsed OK: " + expected);
465 }
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700466
Fredrik Roubertdcdfae82017-12-19 22:28:32 +0100467 CHECK(status, "Error occurred testing Buddhist Calendar in English ");
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700468
469 status = U_ZERO_ERROR;
470 // Now, try in Thai
471 {
472 UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
473 " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e1e.\\u0e28. 2544");
474 UDate expectDate = 999932400000.0;
Victor Chang89ae8472021-03-16 18:05:01 +0000475 // Android-changed: Default calendar on Android is Gregorian.
476 // Locale loc("th_TH_TRADITIONAL"); // legacy
477 Locale loc("th_TH_TRADITIONAL@calendar=buddhist"); // legacy
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700478
479 simpleTest(loc, expect, expectDate, status);
480 }
481 status = U_ZERO_ERROR;
482 {
483 UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
484 " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e1e.\\u0e28. 2544");
485 UDate expectDate = 999932400000.0;
486 Locale loc("th_TH@calendar=buddhist");
487
488 simpleTest(loc, expect, expectDate, status);
489 }
490 status = U_ZERO_ERROR;
491 {
492 UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
493 " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e04.\\u0e28. 2001");
494 UDate expectDate = 999932400000.0;
495 Locale loc("th_TH@calendar=gregorian");
496
497 simpleTest(loc, expect, expectDate, status);
498 }
499 status = U_ZERO_ERROR;
500 {
501 UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
502 " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e04.\\u0e28. 2001");
503 UDate expectDate = 999932400000.0;
504 Locale loc("th_TH_TRADITIONAL@calendar=gregorian");
505
506 simpleTest(loc, expect, expectDate, status);
507 }
Victor Chang39491dd2021-01-19 10:18:27 +0000508 #endif /* ANDROID */
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700509}
510
511// TaiwanFormat has been moved to testdata/format.txt
512
513
514void IntlCalendarTest::TestJapaneseFormat() {
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000515 LocalPointer<Calendar> cal;
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700516 UErrorCode status = U_ZERO_ERROR;
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000517 cal.adoptInstead(Calendar::createInstance("ja_JP@calendar=japanese", status));
Nikita Iashchenkoda0990f2019-06-13 19:36:45 +0100518 CHECK(status, UnicodeString("Creating ja_JP@calendar=japanese calendar"));
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700519
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000520 LocalPointer<Calendar> cal2(cal->clone());
521 cal.adoptInstead(nullptr);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700522
523 // Test simple parse/format with adopt
524
525 UDate aDate = 999932400000.0;
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000526 SimpleDateFormat fmt(UnicodeString("MMMM d, yy G"), Locale("en_US@calendar=japanese"), status);
527 SimpleDateFormat fmt2(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700528 CHECK(status, "creating date format instance");
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000529 UnicodeString str;
530 fmt2.format(aDate, str);
531 logln(UnicodeString() + "Test Date: " + str);
532 str.remove();
533 fmt.format(aDate, str);
534 logln(UnicodeString() + "as Japanese Calendar: " + str);
535 UnicodeString expected("September 8, 13 Heisei");
536 if(str != expected) {
537 errln("Expected " + expected + " but got " + str);
538 }
539 UDate otherDate = fmt.parse(expected, status);
540 if(otherDate != aDate) {
541 UnicodeString str3;
542 ParsePosition pp;
543 fmt.parse(expected, *cal2, pp);
544 fmt.format(otherDate, str3);
545 errln("Parse incorrect of " + expected + " - wanted " + aDate + " but got " + " = " + otherDate + ", " + str3 + " = " + CalendarTest::calToStr(*cal2) );
546
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700547 } else {
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000548 logln("Parsed OK: " + expected);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700549 }
550
551 // Test parse with incomplete information
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000552 SimpleDateFormat fmti(UnicodeString("G y"), Locale("en_US@calendar=japanese"), status);
claireho50294ea2010-05-03 15:44:48 -0700553 aDate = -3197117222000.0;
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700554 CHECK(status, "creating date format instance");
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000555 str.remove();
556 fmt2.format(aDate, str);
557 logln(UnicodeString() + "Test Date: " + str);
558 str.remove();
559 fmti.format(aDate, str);
560 logln(UnicodeString() + "as Japanese Calendar: " + str);
561 expected = u"Meiji 1";
562 if(str != expected) {
563 errln("Expected " + expected + " but got " + str);
564 }
565 otherDate = fmti.parse(expected, status);
566 if(otherDate != aDate) {
567 UnicodeString str3;
568 ParsePosition pp;
569 fmti.parse(expected, *cal2, pp);
570 fmti.format(otherDate, str3);
571 errln("Parse incorrect of " + expected + " - wanted " + aDate + " but got " + " = " +
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700572 otherDate + ", " + str3 + " = " + CalendarTest::calToStr(*cal2) );
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000573 } else {
574 logln("Parsed OK: " + expected);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700575 }
576
Fredrik Roubertdcdfae82017-12-19 22:28:32 +0100577 CHECK(status, "Error occurred");
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700578
579 // Now, try in Japanese
580 {
581 UnicodeString expect = CharsToUnicodeString("\\u5e73\\u621013\\u5e749\\u67088\\u65e5\\u571f\\u66dc\\u65e5");
582 UDate expectDate = 999932400000.0; // Testing a recent date
583 Locale loc("ja_JP@calendar=japanese");
584
585 status = U_ZERO_ERROR;
586 simpleTest(loc, expect, expectDate, status);
587 }
588 {
589 UnicodeString expect = CharsToUnicodeString("\\u5e73\\u621013\\u5e749\\u67088\\u65e5\\u571f\\u66dc\\u65e5");
590 UDate expectDate = 999932400000.0; // Testing a recent date
Nikita Iashchenkoda0990f2019-06-13 19:36:45 +0100591 Locale loc("ja_JP@calendar=japanese");
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700592
593 status = U_ZERO_ERROR;
594 simpleTest(loc, expect, expectDate, status);
595 }
596 {
597 UnicodeString expect = CharsToUnicodeString("\\u5b89\\u6c385\\u5e747\\u67084\\u65e5\\u6728\\u66dc\\u65e5");
claireho50294ea2010-05-03 15:44:48 -0700598 UDate expectDate = -6106032422000.0; // 1776-07-04T00:00:00Z-075258
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700599 Locale loc("ja_JP@calendar=japanese");
600
601 status = U_ZERO_ERROR;
602 simpleTest(loc, expect, expectDate, status);
603
604 }
605 { // Jitterbug 1869 - this is an ambiguous era. (Showa 64 = Jan 6 1989, but Showa could be 2 other eras) )
606 UnicodeString expect = CharsToUnicodeString("\\u662d\\u548c64\\u5e741\\u67086\\u65e5\\u91d1\\u66dc\\u65e5");
607 UDate expectDate = 600076800000.0;
608 Locale loc("ja_JP@calendar=japanese");
609
610 status = U_ZERO_ERROR;
611 simpleTest(loc, expect, expectDate, status);
612
613 }
Nikita Iashchenkoda0990f2019-06-13 19:36:45 +0100614 { // 1989 Jan 9 Monday = Heisei 1; full is Gy年M月d日EEEE => 平成元年1月9日月曜日
615 UnicodeString expect = CharsToUnicodeString("\\u5E73\\u6210\\u5143\\u5E741\\u67089\\u65E5\\u6708\\u66DC\\u65E5");
616 UDate expectDate = 600336000000.0;
617 Locale loc("ja_JP@calendar=japanese");
618
619 status = U_ZERO_ERROR;
620 simpleTest(loc, expect, expectDate, status);
621
622 }
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700623 { // This Feb 29th falls on a leap year by gregorian year, but not by Japanese year.
624 UnicodeString expect = CharsToUnicodeString("\\u5EB7\\u6B632\\u5e742\\u670829\\u65e5\\u65e5\\u66dc\\u65e5");
claireho50294ea2010-05-03 15:44:48 -0700625 UDate expectDate = -16214400422000.0; // 1456-03-09T00:00Z-075258
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700626 Locale loc("ja_JP@calendar=japanese");
627
628 status = U_ZERO_ERROR;
629 simpleTest(loc, expect, expectDate, status);
630
631 }
632}
633
634void IntlCalendarTest::TestJapanese3860()
635{
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000636 LocalPointer<Calendar> cal;
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700637 UErrorCode status = U_ZERO_ERROR;
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000638 cal.adoptInstead(Calendar::createInstance("ja_JP@calendar=japanese", status));
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700639 CHECK(status, UnicodeString("Creating ja_JP@calendar=japanese calendar"));
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000640 LocalPointer<Calendar> cal2(cal->clone());
641 SimpleDateFormat fmt2(UnicodeString("HH:mm:ss.S MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700642 UnicodeString str;
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700643
644 {
645 // Test simple parse/format with adopt
646 UDate aDate = 0;
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000647
Nikita Iashchenkoda0990f2019-06-13 19:36:45 +0100648 // Test parse with missing era (should default to current era, heisei)
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700649 // Test parse with incomplete information
650 logln("Testing parse w/ missing era...");
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000651 SimpleDateFormat fmt(UnicodeString("y/M/d"), Locale("ja_JP@calendar=japanese"), status);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700652 CHECK(status, "creating date format instance");
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000653 UErrorCode s2 = U_ZERO_ERROR;
654 cal2->clear();
655 UnicodeString samplestr("1/5/9");
656 logln(UnicodeString() + "Test Year: " + samplestr);
657 aDate = fmt.parse(samplestr, s2);
658 ParsePosition pp=0;
659 fmt.parse(samplestr, *cal2, pp);
660 CHECK(s2, "parsing the 1/5/9 string");
661 logln("*cal2 after 159 parse:");
662 str.remove();
663 fmt2.format(aDate, str);
664 logln(UnicodeString() + "as Gregorian Calendar: " + str);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700665
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000666 cal2->setTime(aDate, s2);
667 int32_t gotYear = cal2->get(UCAL_YEAR, s2);
668 int32_t gotEra = cal2->get(UCAL_ERA, s2);
669 int32_t expectYear = 1;
670 int32_t expectEra = JapaneseCalendar::getCurrentEra();
671 if((gotYear!=1) || (gotEra != expectEra)) {
672 errln(UnicodeString("parse "+samplestr+" of 'y/M/d' as Japanese Calendar, expected year ") + expectYear +
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700673 UnicodeString(" and era ") + expectEra +", but got year " + gotYear + " and era " + gotEra + " (Gregorian:" + str +")");
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000674 } else {
675 logln(UnicodeString() + " year: " + gotYear + ", era: " + gotEra);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700676 }
677 }
678
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700679 {
680 // Test simple parse/format with adopt
681 UDate aDate = 0;
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000682
Nikita Iashchenkoda0990f2019-06-13 19:36:45 +0100683 // Test parse with missing era (should default to current era, heisei)
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700684 // Test parse with incomplete information
685 logln("Testing parse w/ just year...");
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000686 SimpleDateFormat fmt(UnicodeString("y"), Locale("ja_JP@calendar=japanese"), status);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700687 CHECK(status, "creating date format instance");
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000688 UErrorCode s2 = U_ZERO_ERROR;
689 cal2->clear();
690 UnicodeString samplestr("1");
691 logln(UnicodeString() + "Test Year: " + samplestr);
692 aDate = fmt.parse(samplestr, s2);
693 ParsePosition pp=0;
694 fmt.parse(samplestr, *cal2, pp);
695 CHECK(s2, "parsing the 1 string");
696 logln("*cal2 after 1 parse:");
697 str.remove();
698 fmt2.format(aDate, str);
699 logln(UnicodeString() + "as Gregorian Calendar: " + str);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700700
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000701 cal2->setTime(aDate, s2);
702 int32_t gotYear = cal2->get(UCAL_YEAR, s2);
703 int32_t gotEra = cal2->get(UCAL_ERA, s2);
704 int32_t expectYear = 1;
705 int32_t expectEra = JapaneseCalendar::getCurrentEra();
706 if((gotYear!=1) || (gotEra != expectEra)) {
707 errln(UnicodeString("parse "+samplestr+" of 'y' as Japanese Calendar, expected year ") + expectYear +
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700708 UnicodeString(" and era ") + expectEra +", but got year " + gotYear + " and era " + gotEra + " (Gregorian:" + str +")");
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000709 } else {
710 logln(UnicodeString() + " year: " + gotYear + ", era: " + gotEra);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700711 }
712 }
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700713}
714
Nikita Iashchenkoda0990f2019-06-13 19:36:45 +0100715void IntlCalendarTest::TestForceGannenNumbering()
716{
717 UErrorCode status;
718 const char* locID = "ja_JP@calendar=japanese";
719 Locale loc(locID);
720 UDate refDate = 600336000000.0; // 1989 Jan 9 Monday = Heisei 1
721 UnicodeString patText(u"Gy年M月d日",-1);
722 UnicodeString patNumr(u"GGGGGy/MM/dd",-1);
723 UnicodeString skelText(u"yMMMM",-1);
Nikita Iashchenkoac597cb2018-10-17 19:47:35 -0700724
Nikita Iashchenkoda0990f2019-06-13 19:36:45 +0100725 // Test Gannen year forcing
726 status = U_ZERO_ERROR;
727 LocalPointer<SimpleDateFormat> testFmt1(new SimpleDateFormat(patText, loc, status));
728 LocalPointer<SimpleDateFormat> testFmt2(new SimpleDateFormat(patNumr, loc, status));
729 if (U_FAILURE(status)) {
730 dataerrln("Fail in new SimpleDateFormat locale %s: %s", locID, u_errorName(status));
731 } else {
732 UnicodeString testString1, testString2;
733 testString1 = testFmt1->format(refDate, testString1);
734 if (testString1.length() < 3 || testString1.charAt(2) != 0x5143) {
735 errln(UnicodeString("Formatting year 1 in created text style, got " + testString1 + " but expected 3rd char to be 0x5143"));
Nikita Iashchenkoac597cb2018-10-17 19:47:35 -0700736 }
Nikita Iashchenkoda0990f2019-06-13 19:36:45 +0100737 testString2 = testFmt2->format(refDate, testString2);
738 if (testString2.length() < 2 || testString2.charAt(1) != 0x0031) {
739 errln(UnicodeString("Formatting year 1 in created numeric style, got " + testString2 + " but expected 2nd char to be 1"));
740 }
741 // Now switch the patterns and verify that Gannen use follows the pattern
742 testFmt1->applyPattern(patNumr);
743 testString1.remove();
744 testString1 = testFmt1->format(refDate, testString1);
745 if (testString1.length() < 2 || testString1.charAt(1) != 0x0031) {
746 errln(UnicodeString("Formatting year 1 in applied numeric style, got " + testString1 + " but expected 2nd char to be 1"));
747 }
748 testFmt2->applyPattern(patText);
749 testString2.remove();
750 testString2 = testFmt2->format(refDate, testString2);
751 if (testString2.length() < 3 || testString2.charAt(2) != 0x5143) {
752 errln(UnicodeString("Formatting year 1 in applied text style, got " + testString2 + " but expected 3rd char to be 0x5143"));
753 }
Nikita Iashchenkoac597cb2018-10-17 19:47:35 -0700754 }
Nikita Iashchenkoda0990f2019-06-13 19:36:45 +0100755
756 // Test disabling of Gannen year forcing
757 status = U_ZERO_ERROR;
758 LocalPointer<DateTimePatternGenerator> dtpgen(DateTimePatternGenerator::createInstance(loc, status));
759 if (U_FAILURE(status)) {
760 dataerrln("Fail in DateTimePatternGenerator::createInstance locale %s: %s", locID, u_errorName(status));
761 } else {
762 UnicodeString pattern = dtpgen->getBestPattern(skelText, status);
763 if (U_FAILURE(status)) {
764 dataerrln("Fail in DateTimePatternGenerator::getBestPattern locale %s: %s", locID, u_errorName(status));
765 } else {
766 // Use override string of ""
767 LocalPointer<SimpleDateFormat> testFmt3(new SimpleDateFormat(pattern, UnicodeString(""), loc, status));
768 if (U_FAILURE(status)) {
769 dataerrln("Fail in new SimpleDateFormat locale %s: %s", locID, u_errorName(status));
770 } else {
771 UnicodeString testString3;
772 testString3 = testFmt3->format(refDate, testString3);
773 if (testString3.length() < 3 || testString3.charAt(2) != 0x0031) {
774 errln(UnicodeString("Formatting year 1 with Gannen disabled, got " + testString3 + " but expected 3rd char to be 1"));
775 }
776 }
777 }
778 }
Nikita Iashchenkoac597cb2018-10-17 19:47:35 -0700779}
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700780
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700781/**
782 * Verify the Persian Calendar.
783 */
784void IntlCalendarTest::TestPersian() {
785 UDate timeA = Calendar::getNow();
786
787 Calendar *cal;
788 UErrorCode status = U_ZERO_ERROR;
789 cal = Calendar::createInstance("fa_IR@calendar=persian", status);
790 CHECK(status, UnicodeString("Creating fa_IR@calendar=persian calendar"));
791 // Sanity check the calendar
792 UDate timeB = Calendar::getNow();
793 UDate timeCal = cal->getTime(status);
794
795 if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
796 errln((UnicodeString)"Error: Calendar time " + timeCal +
797 " is not within sampled times [" + timeA + " to " + timeB + "]!");
798 }
799 // end sanity check
Craig Cornelius54dcd9b2013-02-15 14:03:14 -0800800
801 // Test various dates to be sure of validity
802 int32_t data[] = {
803 1925, 4, 24, 1304, 2, 4,
804 2011, 1, 11, 1389, 10, 21,
805 1986, 2, 25, 1364, 12, 6,
806 1934, 3, 14, 1312, 12, 23,
807
808 2090, 3, 19, 1468, 12, 29,
809 2007, 2, 22, 1385, 12, 3,
810 1969, 12, 31, 1348, 10, 10,
811 1945, 11, 12, 1324, 8, 21,
812 1925, 3, 31, 1304, 1, 11,
813
814 1996, 3, 19, 1374, 12, 29,
815 1996, 3, 20, 1375, 1, 1,
816 1997, 3, 20, 1375, 12, 30,
817 1997, 3, 21, 1376, 1, 1,
818
819 2008, 3, 19, 1386, 12, 29,
820 2008, 3, 20, 1387, 1, 1,
821 2004, 3, 19, 1382, 12, 29,
822 2004, 3, 20, 1383, 1, 1,
823
824 2006, 3, 20, 1384, 12, 29,
825 2006, 3, 21, 1385, 1, 1,
826
827 2005, 4, 20, 1384, 1, 31,
828 2005, 4, 21, 1384, 2, 1,
829 2005, 5, 21, 1384, 2, 31,
830 2005, 5, 22, 1384, 3, 1,
831 2005, 6, 21, 1384, 3, 31,
832 2005, 6, 22, 1384, 4, 1,
833 2005, 7, 22, 1384, 4, 31,
834 2005, 7, 23, 1384, 5, 1,
835 2005, 8, 22, 1384, 5, 31,
836 2005, 8, 23, 1384, 6, 1,
837 2005, 9, 22, 1384, 6, 31,
838 2005, 9, 23, 1384, 7, 1,
839 2005, 10, 22, 1384, 7, 30,
840 2005, 10, 23, 1384, 8, 1,
841 2005, 11, 21, 1384, 8, 30,
842 2005, 11, 22, 1384, 9, 1,
843 2005, 12, 21, 1384, 9, 30,
844 2005, 12, 22, 1384, 10, 1,
845 2006, 1, 20, 1384, 10, 30,
846 2006, 1, 21, 1384, 11, 1,
847 2006, 2, 19, 1384, 11, 30,
848 2006, 2, 20, 1384, 12, 1,
849 2006, 3, 20, 1384, 12, 29,
850 2006, 3, 21, 1385, 1, 1,
851
852 // The 2820-year cycle arithmetical algorithm would fail this one.
853 2025, 3, 21, 1404, 1, 1,
854
855 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
856 };
857
858 Calendar *grego = Calendar::createInstance("fa_IR@calendar=gregorian", status);
859 for (int32_t i=0; data[i]!=-1; ) {
860 int32_t gregYear = data[i++];
861 int32_t gregMonth = data[i++]-1;
862 int32_t gregDay = data[i++];
863 int32_t persYear = data[i++];
864 int32_t persMonth = data[i++]-1;
865 int32_t persDay = data[i++];
866
867 // Test conversion from Persian dates
868 grego->clear();
869 grego->set(gregYear, gregMonth, gregDay);
870
871 cal->clear();
872 cal->set(persYear, persMonth, persDay);
873
874 UDate persTime = cal->getTime(status);
875 UDate gregTime = grego->getTime(status);
876
877 if (persTime != gregTime) {
878 errln(UnicodeString("Expected ") + gregTime + " but got " + persTime);
879 }
880
881 // Test conversion to Persian dates
882 cal->clear();
883 cal->setTime(gregTime, status);
884
885 int32_t computedYear = cal->get(UCAL_YEAR, status);
886 int32_t computedMonth = cal->get(UCAL_MONTH, status);
887 int32_t computedDay = cal->get(UCAL_DATE, status);
888
889 if ((persYear != computedYear) ||
890 (persMonth != computedMonth) ||
891 (persDay != computedDay)) {
892 errln(UnicodeString("Expected ") + persYear + "/" + (persMonth+1) + "/" + persDay +
893 " but got " + computedYear + "/" + (computedMonth+1) + "/" + computedDay);
894 }
895
896 }
897
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700898 delete cal;
Craig Cornelius54dcd9b2013-02-15 14:03:14 -0800899 delete grego;
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700900}
901
902void IntlCalendarTest::TestPersianFormat() {
903 UErrorCode status = U_ZERO_ERROR;
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000904 SimpleDateFormat fmt(UnicodeString("MMMM d, yyyy G"), Locale(" en_US@calendar=persian"), status);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700905 CHECK(status, "creating date format instance");
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000906 SimpleDateFormat fmt2(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700907 CHECK(status, "creating gregorian date format instance");
908 UnicodeString gregorianDate("January 18, 2007 AD");
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000909 UDate aDate = fmt2.parse(gregorianDate, status);
910 UnicodeString str;
911 fmt.format(aDate, str);
912 logln(UnicodeString() + "as Persian Calendar: " + escape(str));
913 UnicodeString expected("Dey 28, 1385 AP");
914 if(str != expected) {
915 errln("Expected " + escape(expected) + " but got " + escape(str));
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700916 }
Nikita Iashchenko4c0e2862019-11-05 16:38:00 +0000917 UDate otherDate = fmt.parse(expected, status);
918 if(otherDate != aDate) {
919 UnicodeString str3;
920 fmt.format(otherDate, str3);
921 errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " + otherDate + ", " + escape(str3));
922 } else {
923 logln("Parsed OK: " + expected);
924 }
925 // Two digit year parsing problem #4732
926 fmt.applyPattern("yy-MM-dd");
927 str.remove();
928 fmt.format(aDate, str);
929 expected.setTo("85-10-28");
930 if(str != expected) {
931 errln("Expected " + escape(expected) + " but got " + escape(str));
932 }
933 otherDate = fmt.parse(expected, status);
934 if (otherDate != aDate) {
935 errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " + otherDate);
936 } else {
937 logln("Parsed OK: " + expected);
938 }
939
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -0700940 CHECK(status, "Error occured testing Persian Calendar in English ");
941}
942
Victor Chang978167a2021-01-18 17:56:33 +0000943void IntlCalendarTest::TestConsistencyGregorian() {
944 checkConsistency("en@calendar=gregorian");
945}
946void IntlCalendarTest::TestConsistencyIndian() {
947 checkConsistency("en@calendar=indian");
948}
949void IntlCalendarTest::TestConsistencyHebrew() {
950 checkConsistency("en@calendar=hebrew");
951}
952void IntlCalendarTest::TestConsistencyIslamic() {
953 checkConsistency("en@calendar=islamic");
954}
955void IntlCalendarTest::TestConsistencyIslamicRGSA() {
956 checkConsistency("en@calendar=islamic-rgsa");
957}
958void IntlCalendarTest::TestConsistencyIslamicTBLA() {
959 checkConsistency("en@calendar=islamic-tbla");
960}
961void IntlCalendarTest::TestConsistencyIslamicUmalqura() {
962 checkConsistency("en@calendar=islamic-umalqura");
963}
964void IntlCalendarTest::TestConsistencyIslamicCivil() {
965 checkConsistency("en@calendar=islamic-civil");
966}
967void IntlCalendarTest::TestConsistencyCoptic() {
968 checkConsistency("en@calendar=coptic");
969}
970void IntlCalendarTest::TestConsistencyEthiopic() {
971 checkConsistency("en@calendar=ethiopic");
972}
973void IntlCalendarTest::TestConsistencyROC() {
974 checkConsistency("en@calendar=roc");
975}
976void IntlCalendarTest::TestConsistencyChinese() {
977 checkConsistency("en@calendar=chinese");
978}
979void IntlCalendarTest::TestConsistencyDangi() {
980 checkConsistency("en@calendar=dangi");
981}
982void IntlCalendarTest::TestConsistencyPersian() {
983 checkConsistency("en@calendar=persian");
984}
985void IntlCalendarTest::TestConsistencyBuddhist() {
986 checkConsistency("en@calendar=buddhist");
987}
988void IntlCalendarTest::TestConsistencyJapanese() {
989 checkConsistency("en@calendar=japanese");
990}
991void IntlCalendarTest::TestConsistencyEthiopicAmeteAlem() {
992 checkConsistency("en@calendar=ethiopic-amete-alem");
993}
994void IntlCalendarTest::checkConsistency(const char* locale) {
995 // Check 2.5 years in quick mode and 8000 years in exhaustive mode.
996 int32_t numOfDaysToTest = (quick ? 2.5 : 8000) * 365;
997 constexpr int32_t msInADay = 1000*60*60*24;
998 std::string msg("TestConsistency");
999 IcuTestErrorCode status(*this, (msg + locale).c_str());
1000 // g is just for debugging messages.
1001 std::unique_ptr<Calendar> g(Calendar::createInstance("en", status));
1002 g->setTimeZone(*(TimeZone::getGMT()));
1003 std::unique_ptr<Calendar> base(Calendar::createInstance(locale, status));
1004 if (status.errIfFailureAndReset("Cannot create calendar %s", locale)) {
1005 return;
1006 }
1007 UDate test = Calendar::getNow();
1008 base->setTimeZone(*(TimeZone::getGMT()));
1009 int32_t j;
1010 int lastDay = 1;
1011 std::unique_ptr<Calendar> r(base->clone());
1012 for (j = 0; j < numOfDaysToTest; j++, test -= msInADay) {
1013 status.errIfFailureAndReset();
1014 g->setTime(test, status);
1015 if (status.errIfFailureAndReset("Cannot set time")) {
1016 return;
1017 }
1018 base->clear();
1019 base->setTime(test, status);
1020 if (status.errIfFailureAndReset("Cannot set time")) {
1021 return;
1022 }
1023 // First, we verify the date from base is decrease one day from the
1024 // last day unless the last day is 1.
1025 int32_t cday = base->get(UCAL_DATE, status);
1026 if (U_FAILURE(status)) {
1027 UErrorCode localStatus = U_ZERO_ERROR;
1028 if (status.errIfFailureAndReset(
1029 "Cannot get the %dth date for %f %d %d/%d/%d\n",
1030 j,
1031 test,
1032 g->get(UCAL_ERA, localStatus),
1033 g->get(UCAL_YEAR, localStatus),
1034 (g->get(UCAL_MONTH, localStatus) + 1),
1035 g->get(UCAL_DATE, localStatus))) {
1036 return;
1037 }
1038 }
1039 if (lastDay == 1) {
1040 lastDay = cday;
1041 } else {
1042 if (cday != lastDay-1) {
1043 // Ignore if it is the last day before Gregorian Calendar switch on
1044 // 1582 Oct 4
1045 if (g->get(UCAL_YEAR, status) == 1582 &&
1046 (g->get(UCAL_MONTH, status) + 1) == 10 &&
1047 g->get(UCAL_DATE, status) == 4) {
1048 lastDay = 5;
1049 } else {
1050 errln((UnicodeString)
1051 "Day is not one less from previous date for "
1052 "Gregorian(e=" + g->get(UCAL_ERA, status) + " " +
1053 g->get(UCAL_YEAR, status) + "/" +
1054 (g->get(UCAL_MONTH, status) + 1) + "/" +
1055 g->get(UCAL_DATE, status) + ") " + locale + "(" +
1056 base->get(UCAL_ERA, status) + " " +
1057 base->get(UCAL_YEAR, status) + "/" +
1058 (base->get(UCAL_MONTH, status) + 1 ) + "/" +
1059 base->get(UCAL_DATE, status) + ")");
1060 status.errIfFailureAndReset();
1061 return;
1062 }
1063 }
1064 lastDay--;
1065 }
1066 // Second, we verify the month is in reasonale range.
1067 int32_t cmonth = base->get(UCAL_MONTH, status);
1068 if (cmonth < 0 || cmonth > 13) {
1069 errln((UnicodeString)
1070 "Month is out of range Gregorian(e=" +
1071 g->get(UCAL_ERA, status) + " " +
1072 g->get(UCAL_YEAR, status) + "/" +
1073 (g->get(UCAL_MONTH, status) + 1) + "/" +
1074 g->get(UCAL_DATE, status) + ") " + locale + "(" +
1075 base->get(UCAL_ERA, status) + " " +
1076 base->get(UCAL_YEAR, status) + "/" +
1077 (base->get(UCAL_MONTH, status) + 1 ) + "/" +
1078 base->get(UCAL_DATE, status) + ")");
1079 status.errIfFailureAndReset();
1080 return;
1081 }
1082 // Third, we verify the set function can round trip the time back.
1083 r->clear();
1084 for (int32_t f = 0; f < UCAL_FIELD_COUNT; f++) {
1085 UCalendarDateFields ut = (UCalendarDateFields)f;
1086 r->set(ut, base->get(ut, status));
1087 }
1088 UDate result = r->getTime(status);
1089 if (status.errIfFailureAndReset("Cannot get time %s", locale)) {
1090 return;
1091 }
1092 if (test != result) {
1093 errln((UnicodeString)"Round trip conversion produces different "
1094 "time from " + test + " to " + result + " delta: " +
1095 (result - test) +
1096 " Gregorian(e=" + g->get(UCAL_ERA, status) + " " +
1097 g->get(UCAL_YEAR, status) + "/" +
1098 (g->get(UCAL_MONTH, status) + 1) + "/" +
1099 g->get(UCAL_DATE, status) + ") ");
1100 status.errIfFailureAndReset();
1101 return;
1102 }
1103 }
1104 status.errIfFailureAndReset();
1105}
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -07001106
1107void IntlCalendarTest::simpleTest(const Locale& loc, const UnicodeString& expect, UDate expectDate, UErrorCode& status)
1108{
1109 UnicodeString tmp;
1110 UDate d;
1111 DateFormat *fmt0 = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull);
1112
1113 logln("Try format/parse of " + (UnicodeString)loc.getName());
1114 DateFormat *fmt2 = DateFormat::createDateInstance(DateFormat::kFull, loc);
1115 if(fmt2) {
1116 fmt2->format(expectDate, tmp);
1117 logln(escape(tmp) + " ( in locale " + loc.getName() + ")");
1118 if(tmp != expect) {
1119 errln(UnicodeString("Failed to format " ) + loc.getName() + " expected " + escape(expect) + " got " + escape(tmp) );
1120 }
1121
1122 d = fmt2->parse(expect,status);
Fredrik Roubertdcdfae82017-12-19 22:28:32 +01001123 CHECK(status, "Error occurred parsing " + UnicodeString(loc.getName()));
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -07001124 if(d != expectDate) {
1125 fmt2->format(d,tmp);
1126 errln(UnicodeString("Failed to parse " ) + escape(expect) + ", " + loc.getName() + " expect " + (double)expectDate + " got " + (double)d + " " + escape(tmp));
1127 logln( "wanted " + escape(fmt0->format(expectDate,tmp.remove())) + " but got " + escape(fmt0->format(d,tmp.remove())));
1128 }
1129 delete fmt2;
1130 } else {
1131 errln((UnicodeString)"Can't create " + loc.getName() + " date instance");
1132 }
1133 delete fmt0;
1134}
1135
Victor Chang978167a2021-01-18 17:56:33 +00001136void IntlCalendarTest::TestBug21043Indian() {
1137 IcuTestErrorCode status(*this, "TestBug21043Indian");
1138 std::unique_ptr<Calendar> cal(
1139 Calendar::createInstance("en@calendar=indian", status));
1140 std::unique_ptr<Calendar> g(
1141 Calendar::createInstance("en@calendar=gregorian", status));
1142 // set to 10 BC
1143 g->set(UCAL_ERA, 0);
1144 g->set(UCAL_YEAR, 10);
1145 g->set(UCAL_MONTH, 1);
1146 g->set(UCAL_DATE, 1);
1147 cal->setTime(g->getTime(status), status);
1148 int32_t m = cal->get(UCAL_MONTH, status);
1149 if (m < 0 || m > 11) {
1150 errln(
1151 u"Month should be between 0 and 11 in India calendar");
1152 }
1153}
1154
1155void IntlCalendarTest::TestBug21044Hebrew() {
1156 IcuTestErrorCode status(*this, "TestBug21044Hebrew");
1157 std::unique_ptr<Calendar> cal(
1158 Calendar::createInstance("en@calendar=hebrew", status));
1159 std::unique_ptr<Calendar> g(
1160 Calendar::createInstance("en@calendar=gregorian", status));
1161 // set to 3771/10/27 BC which is before 3760 BC.
1162 g->set(UCAL_ERA, 0);
1163 g->set(UCAL_YEAR, 3771);
1164 g->set(UCAL_MONTH, 9);
1165 g->set(UCAL_DATE, 27);
1166 cal->setTime(g->getTime(status), status);
1167
1168 if (status.errIfFailureAndReset(
1169 "Cannot set date. Got error %s", u_errorName(status))) {
1170 return;
1171 }
1172 int32_t y = cal->get(UCAL_YEAR, status);
1173 int32_t m = cal->get(UCAL_MONTH, status);
1174 int32_t d = cal->get(UCAL_DATE, status);
1175 if (status.errIfFailureAndReset(
1176 "Cannot get date. Got error %s", u_errorName(status))) {
1177 return;
1178 }
1179 if (y > 0 || m < 0 || m > 12 || d < 0 || d > 32) {
1180 errln((UnicodeString)"Out of rage!\nYear " + y + " should be " +
1181 "negative number before 1AD.\nMonth " + m + " should " +
1182 "be between 0 and 12 in Hebrew calendar.\nDate " + d +
1183 " should be between 0 and 32 in Islamic calendar.");
1184 }
1185}
1186
1187void IntlCalendarTest::TestBug21045Islamic() {
1188 IcuTestErrorCode status(*this, "TestBug21045Islamic");
1189 std::unique_ptr<Calendar> cal(
1190 Calendar::createInstance("en@calendar=islamic", status));
1191 std::unique_ptr<Calendar> g(
1192 Calendar::createInstance("en@calendar=gregorian", status));
1193 // set to 500 AD before 622 AD.
1194 g->set(UCAL_ERA, 1);
1195 g->set(UCAL_YEAR, 500);
1196 g->set(UCAL_MONTH, 1);
1197 g->set(UCAL_DATE, 1);
1198 cal->setTime(g->getTime(status), status);
1199 int32_t m = cal->get(UCAL_MONTH, status);
1200 if (m < 0 || m > 11) {
1201 errln(u"Month should be between 1 and 12 in Islamic calendar");
1202 }
1203}
1204
1205void IntlCalendarTest::TestBug21046IslamicUmalqura() {
1206 IcuTestErrorCode status(*this, "TestBug21046IslamicUmalqura");
1207 std::unique_ptr<Calendar> cal(
1208 Calendar::createInstance("en@calendar=islamic-umalqura", status));
1209 std::unique_ptr<Calendar> g(
1210 Calendar::createInstance("en@calendar=gregorian", status));
1211 // set to 195366 BC
1212 g->set(UCAL_ERA, 0);
1213 g->set(UCAL_YEAR, 195366);
1214 g->set(UCAL_MONTH, 1);
1215 g->set(UCAL_DATE, 1);
1216 cal->setTime(g->getTime(status), status);
1217 int32_t y = cal->get(UCAL_YEAR, status);
1218 int32_t m = cal->get(UCAL_MONTH, status);
1219 int32_t d = cal->get(UCAL_DATE, status);
1220 if (y > 0 || m < 0 || m > 11 || d < 0 || d > 32) {
1221 errln((UnicodeString)"Out of rage!\nYear " + y + " should be " +
1222 "negative number before 1AD.\nMonth " + m + " should " +
1223 "be between 0 and 11 in Islamic calendar.\nDate " + d +
1224 " should be between 0 and 32 in Islamic calendar.");
1225 }
1226}
Jean-Baptiste Querub13da9d2009-07-17 17:53:22 -07001227#undef CHECK
1228
1229#endif /* #if !UCONFIG_NO_FORMATTING */
1230
1231//eof