1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4 * COPYRIGHT:
5 * Copyright (c) 1997-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************/
8
9 #include "unicode/utypes.h"
10
11 #if !UCONFIG_NO_FORMATTING
12
13
14 //TODO: define it in compiler flag
15 //#define DTIFMTTS_DEBUG 1
16
17
18 #ifdef DTIFMTTS_DEBUG
19 #include <iostream>
20 #endif
21
22 #include "dtifmtts.h"
23
24 #include "cmemory.h"
25 #include "cstr.h"
26 #include "cstring.h"
27 #include "simplethread.h"
28 #include "japancal.h"
29 #include "unicode/gregocal.h"
30 #include "unicode/dtintrv.h"
31 #include "unicode/dtitvinf.h"
32 #include "unicode/dtitvfmt.h"
33 #include "unicode/localpointer.h"
34 #include "unicode/timezone.h"
35
36
37
38 #ifdef DTIFMTTS_DEBUG
39 //#define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
40 #define PRINTMESG(msg) { std::cout << msg; }
41 #endif
42
43 #include <stdio.h>
44
45
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)46 void DateIntervalFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) {
47 if (exec) logln("TestSuite DateIntervalFormat");
48 TESTCASE_AUTO_BEGIN;
49 TESTCASE_AUTO(testAPI);
50 TESTCASE_AUTO(testFormat);
51 TESTCASE_AUTO(testFormatUserDII);
52 TESTCASE_AUTO(testSetIntervalPatternNoSideEffect);
53 TESTCASE_AUTO(testYearFormats);
54 TESTCASE_AUTO(testStress);
55 TESTCASE_AUTO(testTicket11583_2);
56 TESTCASE_AUTO(testTicket11985);
57 TESTCASE_AUTO(testTicket11669);
58 TESTCASE_AUTO(testTicket12065);
59 TESTCASE_AUTO(testFormattedDateInterval);
60 TESTCASE_AUTO(testCreateInstanceForAllLocales);
61 TESTCASE_AUTO(testTicket20707);
62 TESTCASE_AUTO(testFormatMillisecond);
63 TESTCASE_AUTO(testHourMetacharacters);
64 TESTCASE_AUTO(testContext);
65 TESTCASE_AUTO(testTicket21222GregorianEraDiff);
66 TESTCASE_AUTO(testTicket21222ROCEraDiff);
67 TESTCASE_AUTO(testTicket21222JapaneseEraDiff);
68 TESTCASE_AUTO_END;
69 }
70
71 /**
72 * Test various generic API methods of DateIntervalFormat for API coverage.
73 */
testAPI()74 void DateIntervalFormatTest::testAPI() {
75
76 /* ====== Test create interval instance with default locale and skeleton
77 */
78 UErrorCode status = U_ZERO_ERROR;
79 logln("Testing DateIntervalFormat create instance with default locale and skeleton");
80
81 DateIntervalFormat* dtitvfmt = DateIntervalFormat::createInstance(UDAT_YEAR_MONTH_DAY, status);
82 if(U_FAILURE(status)) {
83 dataerrln("ERROR: Could not create DateIntervalFormat (skeleton + default locale) - exiting");
84 return;
85 } else {
86 delete dtitvfmt;
87 }
88
89
90 /* ====== Test create interval instance with given locale and skeleton
91 */
92 status = U_ZERO_ERROR;
93 logln("Testing DateIntervalFormat create instance with given locale and skeleton");
94
95 dtitvfmt = DateIntervalFormat::createInstance(UDAT_YEAR_MONTH_DAY, Locale::getJapanese(), status);
96 if(U_FAILURE(status)) {
97 dataerrln("ERROR: Could not create DateIntervalFormat (skeleton + locale) - exiting");
98 return;
99 } else {
100 delete dtitvfmt;
101 }
102
103
104 /* ====== Test create interval instance with dateIntervalInfo and skeleton
105 */
106 status = U_ZERO_ERROR;
107 logln("Testing DateIntervalFormat create instance with dateIntervalInfo and skeleton");
108
109 DateIntervalInfo* dtitvinf = new DateIntervalInfo(Locale::getSimplifiedChinese(), status);
110
111 dtitvfmt = DateIntervalFormat::createInstance("EEEdMMMyhms", *dtitvinf, status);
112 delete dtitvinf;
113
114 if(U_FAILURE(status)) {
115 dataerrln("ERROR: Could not create DateIntervalFormat (skeleton + DateIntervalInfo + default locale) - exiting");
116 return;
117 } else {
118 delete dtitvfmt;
119 }
120
121
122 /* ====== Test create interval instance with dateIntervalInfo and skeleton
123 */
124 status = U_ZERO_ERROR;
125 logln("Testing DateIntervalFormat create instance with dateIntervalInfo and skeleton");
126
127 dtitvinf = new DateIntervalInfo(Locale::getSimplifiedChinese(), status);
128
129 dtitvfmt = DateIntervalFormat::createInstance("EEEdMMMyhms", Locale::getSimplifiedChinese(), *dtitvinf, status);
130 delete dtitvinf;
131 if(U_FAILURE(status)) {
132 dataerrln("ERROR: Could not create DateIntervalFormat (skeleton + DateIntervalInfo + locale) - exiting");
133 return;
134 }
135 // not deleted, test clone
136
137
138 // ====== Test clone()
139 status = U_ZERO_ERROR;
140 logln("Testing DateIntervalFormat clone");
141
142 DateIntervalFormat* another = dtitvfmt->clone();
143 if ( (*another) != (*dtitvfmt) ) {
144 dataerrln("%s:%d ERROR: clone failed", __FILE__, __LINE__);
145 }
146
147
148 // ====== Test getDateIntervalInfo, setDateIntervalInfo, adoptDateIntervalInfo
149 status = U_ZERO_ERROR;
150 logln("Testing DateIntervalFormat getDateIntervalInfo");
151 const DateIntervalInfo* inf = another->getDateIntervalInfo();
152 dtitvfmt->setDateIntervalInfo(*inf, status);
153 const DateIntervalInfo* anotherInf = dtitvfmt->getDateIntervalInfo();
154 if ( (*inf) != (*anotherInf) || U_FAILURE(status) ) {
155 dataerrln("ERROR: getDateIntervalInfo/setDateIntervalInfo failed");
156 }
157
158 {
159 // We make sure that setDateIntervalInfo does not corrupt the cache. See ticket 9919.
160 status = U_ZERO_ERROR;
161 logln("Testing DateIntervalFormat setDateIntervalInfo");
162 const Locale &enLocale = Locale::getEnglish();
163 LocalPointer<DateIntervalFormat> dif(DateIntervalFormat::createInstance("yMd", enLocale, status));
164 if (U_FAILURE(status)) {
165 errln("Failure encountered: %s", u_errorName(status));
166 return;
167 }
168 UnicodeString expected;
169 LocalPointer<Calendar> fromTime(Calendar::createInstance(enLocale, status));
170 LocalPointer<Calendar> toTime(Calendar::createInstance(enLocale, status));
171 if (U_FAILURE(status)) {
172 errln("Failure encountered: %s", u_errorName(status));
173 return;
174 }
175 FieldPosition pos(FieldPosition::DONT_CARE);
176 fromTime->set(2013, 3, 26);
177 toTime->set(2013, 3, 28);
178 dif->format(*fromTime, *toTime, expected, pos, status);
179 if (U_FAILURE(status)) {
180 errln("Failure encountered: %s", u_errorName(status));
181 return;
182 }
183 LocalPointer<DateIntervalInfo> dii(new DateIntervalInfo(Locale::getEnglish(), status), status);
184 if (U_FAILURE(status)) {
185 errln("Failure encountered: %s", u_errorName(status));
186 return;
187 }
188 dii->setIntervalPattern(ctou("yMd"), UCAL_DATE, ctou("M/d/y \\u2013 d"), status);
189 dif->setDateIntervalInfo(*dii, status);
190 if (U_FAILURE(status)) {
191 errln("Failure encountered: %s", u_errorName(status));
192 return;
193 }
194 dif.adoptInstead(DateIntervalFormat::createInstance("yMd", enLocale, status));
195 if (U_FAILURE(status)) {
196 errln("Failure encountered: %s", u_errorName(status));
197 return;
198 }
199 UnicodeString actual;
200 pos = 0;
201 dif->format(*fromTime, *toTime, actual, pos, status);
202 if (U_FAILURE(status)) {
203 errln("Failure encountered: %s", u_errorName(status));
204 return;
205 }
206 if (expected != actual) {
207 errln("DateIntervalFormat.setIntervalInfo should have no side effects.");
208 }
209 }
210
211 /*
212 status = U_ZERO_ERROR;
213 DateIntervalInfo* nonConstInf = inf->clone();
214 dtitvfmt->adoptDateIntervalInfo(nonConstInf, status);
215 anotherInf = dtitvfmt->getDateIntervalInfo();
216 if ( (*inf) != (*anotherInf) || U_FAILURE(status) ) {
217 dataerrln("ERROR: adoptDateIntervalInfo failed");
218 }
219 */
220
221 // ====== Test getDateFormat, setDateFormat, adoptDateFormat
222
223 status = U_ZERO_ERROR;
224 logln("Testing DateIntervalFormat getDateFormat");
225 /*
226 const DateFormat* fmt = another->getDateFormat();
227 dtitvfmt->setDateFormat(*fmt, status);
228 const DateFormat* anotherFmt = dtitvfmt->getDateFormat();
229 if ( (*fmt) != (*anotherFmt) || U_FAILURE(status) ) {
230 dataerrln("ERROR: getDateFormat/setDateFormat failed");
231 }
232
233 status = U_ZERO_ERROR;
234 DateFormat* nonConstFmt = fmt->clone();
235 dtitvfmt->adoptDateFormat(nonConstFmt, status);
236 anotherFmt = dtitvfmt->getDateFormat();
237 if ( (*fmt) != (*anotherFmt) || U_FAILURE(status) ) {
238 dataerrln("ERROR: adoptDateFormat failed");
239 }
240 delete fmt;
241 */
242
243
244 // ======= Test getStaticClassID()
245
246 logln("Testing getStaticClassID()");
247
248
249 if(dtitvfmt->getDynamicClassID() != DateIntervalFormat::getStaticClassID()) {
250 errln("ERROR: getDynamicClassID() didn't return the expected value");
251 }
252
253 delete another;
254
255 // ====== test constructor/copy constructor and assignment
256 /* they are protected, no test
257 logln("Testing DateIntervalFormat constructor and assignment operator");
258 status = U_ZERO_ERROR;
259
260 DateFormat* constFmt = dtitvfmt->getDateFormat()->clone();
261 inf = dtitvfmt->getDateIntervalInfo()->clone();
262
263
264 DateIntervalFormat* dtifmt = new DateIntervalFormat(fmt, inf, status);
265 if(U_FAILURE(status)) {
266 dataerrln("ERROR: Could not create DateIntervalFormat (default) - exiting");
267 return;
268 }
269
270 DateIntervalFormat* dtifmt2 = new(dtifmt);
271 if ( (*dtifmt) != (*dtifmt2) ) {
272 dataerrln("ERROR: Could not create DateIntervalFormat (default) - exiting");
273 return;
274 }
275
276 DateIntervalFormat dtifmt3 = (*dtifmt);
277 if ( (*dtifmt) != dtifmt3 ) {
278 dataerrln("ERROR: Could not create DateIntervalFormat (default) - exiting");
279 return;
280 }
281
282 delete dtifmt2;
283 delete dtifmt3;
284 delete dtifmt;
285 */
286
287
288 //===== test format and parse ==================
289 Formattable formattable;
290 formattable.setInt64(10);
291 UnicodeString res;
292 FieldPosition pos(FieldPosition::DONT_CARE);
293 status = U_ZERO_ERROR;
294 dtitvfmt->format(formattable, res, pos, status);
295 if ( status != U_ILLEGAL_ARGUMENT_ERROR ) {
296 dataerrln("ERROR: format non-date-interval object should set U_ILLEGAL_ARGUMENT_ERROR - exiting");
297 return;
298 }
299
300 DateInterval* dtitv = new DateInterval(3600*24*365, 3600*24*366);
301 formattable.adoptObject(dtitv);
302 res.remove();
303 pos = 0;
304 status = U_ZERO_ERROR;
305 dtitvfmt->format(formattable, res, pos, status);
306 if ( U_FAILURE(status) ) {
307 dataerrln("ERROR: format date interval failed - exiting");
308 return;
309 }
310
311 const DateFormat* dfmt = dtitvfmt->getDateFormat();
312 Calendar* fromCal = dfmt->getCalendar()->clone();
313 Calendar* toCal = dfmt->getCalendar()->clone();
314 res.remove();
315 pos = 0;
316 status = U_ZERO_ERROR;
317 dtitvfmt->format(*fromCal, *toCal, res, pos, status);
318 if ( U_FAILURE(status) ) {
319 dataerrln("ERROR: format date interval failed - exiting");
320 return;
321 }
322 delete fromCal;
323 delete toCal;
324
325
326 Formattable fmttable;
327 status = U_ZERO_ERROR;
328 // TODO: why do I need cast?
329 ((Format*)dtitvfmt)->parseObject(res, fmttable, status);
330 if ( status != U_INVALID_FORMAT_ERROR ) {
331 dataerrln("ERROR: parse should set U_INVALID_FORMAT_ERROR - exiting");
332 return;
333 }
334
335 delete dtitvfmt;
336
337 //====== test setting time zone
338 logln("Testing DateIntervalFormat set & format with different time zones, get time zone");
339 status = U_ZERO_ERROR;
340 dtitvfmt = DateIntervalFormat::createInstance("MMMdHHmm", Locale::getEnglish(), status);
341 if ( U_SUCCESS(status) ) {
342 UDate date1 = 1299090600000.0; // 2011-Mar-02 1030 in US/Pacific, 2011-Mar-03 0330 in Asia/Tokyo
343 UDate date2 = 1299115800000.0; // 2011-Mar-02 1730 in US/Pacific, 2011-Mar-03 1030 in Asia/Tokyo
344
345 DateInterval * dtitv12 = new DateInterval(date1, date2);
346 TimeZone * tzCalif = TimeZone::createTimeZone("US/Pacific");
347 TimeZone * tzTokyo = TimeZone::createTimeZone("Asia/Tokyo");
348 UnicodeString fmtCalif = UnicodeString(ctou("Mar 2, 10:30 \\u2013 17:30"));
349 UnicodeString fmtTokyo = UnicodeString(ctou("Mar 3, 03:30 \\u2013 10:30"));
350
351 dtitvfmt->adoptTimeZone(tzCalif);
352 res.remove();
353 pos = 0;
354 status = U_ZERO_ERROR;
355 dtitvfmt->format(dtitv12, res, pos, status);
356 if ( U_SUCCESS(status) ) {
357 if ( res.compare(fmtCalif) != 0 ) {
358 errln("ERROR: DateIntervalFormat::format for tzCalif, expect " + fmtCalif + ", get " + res);
359 }
360 } else {
361 errln("ERROR: DateIntervalFormat::format for tzCalif, status %s", u_errorName(status));
362 }
363
364 dtitvfmt->setTimeZone(*tzTokyo);
365 res.remove();
366 pos = 0;
367 status = U_ZERO_ERROR;
368 dtitvfmt->format(dtitv12, res, pos, status);
369 if ( U_SUCCESS(status) ) {
370 if ( res.compare(fmtTokyo) != 0 ) {
371 errln("ERROR: DateIntervalFormat::format for fmtTokyo, expect " + fmtTokyo + ", get " + res);
372 }
373 } else {
374 errln("ERROR: DateIntervalFormat::format for tzTokyo, status %s", u_errorName(status));
375 }
376
377 if ( dtitvfmt->getTimeZone() != *tzTokyo ) {
378 errln("ERROR: DateIntervalFormat::getTimeZone returns mismatch.");
379 }
380
381 delete tzTokyo; // tzCalif was owned by dtitvfmt which should have deleted it
382 delete dtitv12;
383 delete dtitvfmt;
384 } else {
385 errln("ERROR: DateIntervalFormat::createInstance(\"MdHH\", Locale::getEnglish(), ...), status %s", u_errorName(status));
386 }
387 //====== test format in testFormat()
388
389 //====== test DateInterval class (better coverage)
390 DateInterval dtitv1(3600*24*365, 3600*24*366);
391 DateInterval dtitv2(dtitv1);
392
393 if (!(dtitv1 == dtitv2)) {
394 errln("ERROR: Copy constructor failed for DateInterval.");
395 }
396
397 DateInterval dtitv3(3600*365, 3600*366);
398 dtitv3 = dtitv1;
399 if (!(dtitv3 == dtitv1)) {
400 errln("ERROR: Equal operator failed for DateInterval.");
401 }
402
403 DateInterval *dtitv4 = dtitv1.clone();
404 if (*dtitv4 != dtitv1) {
405 errln("ERROR: Equal operator failed for DateInterval.");
406 }
407 delete dtitv4;
408 }
409
410
411 /**
412 * Test format
413 */
testFormat()414 void DateIntervalFormatTest::testFormat() {
415 // first item is date pattern
416 // followed by a group of locale/from_data/to_data/skeleton/interval_data
417 // Note that from_data/to_data are specified using era names from root, for the calendar specified by locale.
418 const char* DATA[] = {
419 "GGGGG y MM dd HH:mm:ss", // pattern for from_data/to_data
420 // test root
421 "root", "CE 2007 11 10 10:10:10", "CE 2007 12 10 10:10:10", "yM", "2007-11 \\u2013 2007-12",
422
423 // test 'H' and 'h', using availableFormat in fallback
424 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 10 15:10:10", "Hms", "10:10:10 \\u2013 15:10:10",
425 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 10 15:10:10", "hms", "10:10:10 AM \\u2013 3:10:10 PM",
426
427 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "MMMM", "October 2007 \\u2013 October 2008",
428 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "MMM", "Oct 2007 \\u2013 Oct 2008",
429 // test skeleton with both date and time
430 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "dMMMyhm", "Nov 10, 2007, 10:10 AM \\u2013 Nov 20, 2007, 10:10 AM",
431
432 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 10 11:10:10", "dMMMyhm", "Nov 10, 2007, 10:10 \\u2013 11:10 AM",
433
434 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 10 11:10:10", "hms", "10:10:10 AM \\u2013 11:10:10 AM",
435 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 10 11:10:10", "Hms", "10:10:10 \\u2013 11:10:10",
436 "en", "CE 2007 11 10 20:10:10", "CE 2007 11 10 21:10:10", "Hms", "20:10:10 \\u2013 21:10:10",
437
438 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "EEEEdMMMMy", "Wednesday, October 10, 2007 \\u2013 Friday, October 10, 2008",
439
440 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "dMMMMy", "October 10, 2007 \\u2013 October 10, 2008",
441
442 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "dMMMM", "October 10, 2007 \\u2013 October 10, 2008",
443
444 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "MMMMy", "October 2007 \\u2013 October 2008",
445
446 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "EEEEdMMMM", "Wednesday, October 10, 2007 \\u2013 Friday, October 10, 2008",
447
448 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "EdMMMy", "Wed, Oct 10, 2007 \\u2013 Fri, Oct 10, 2008",
449
450 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "dMMMy", "Oct 10, 2007 \\u2013 Oct 10, 2008",
451
452 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "dMMM", "Oct 10, 2007 \\u2013 Oct 10, 2008",
453
454 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "MMMy", "Oct 2007 \\u2013 Oct 2008",
455
456 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "EdMMM", "Wed, Oct 10, 2007 \\u2013 Fri, Oct 10, 2008",
457
458 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "EdMy", "Wed, 10/10/2007 \\u2013 Fri, 10/10/2008",
459
460 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "dMy", "10/10/2007 \\u2013 10/10/2008",
461
462 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "dM", "10/10/2007 \\u2013 10/10/2008",
463
464 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "My", "10/2007 \\u2013 10/2008",
465
466 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "EdM", "Wed, 10/10/2007 \\u2013 Fri, 10/10/2008",
467
468 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "d", "10/10/2007 \\u2013 10/10/2008",
469
470 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "Ed", "10 Wed \\u2013 10 Fri",
471
472 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "y", "2007 \\u2013 2008",
473
474 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "M", "10/2007 \\u2013 10/2008",
475
476
477
478 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "hm", "10/10/2007, 10:10 AM \\u2013 10/10/2008, 10:10 AM",
479 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "Hm", "10/10/2007, 10:10 \\u2013 10/10/2008, 10:10",
480 "en", "CE 2007 10 10 20:10:10", "CE 2008 10 10 20:10:10", "Hm", "10/10/2007, 20:10 \\u2013 10/10/2008, 20:10",
481
482 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "hmv", "10/10/2007, 10:10 AM PT \\u2013 10/10/2008, 10:10 AM PT",
483
484 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "hmz", "10/10/2007, 10:10 AM PDT \\u2013 10/10/2008, 10:10 AM PDT",
485
486 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "h", "10/10/2007, 10 AM \\u2013 10/10/2008, 10 AM",
487
488 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "hv", "10/10/2007, 10 AM PT \\u2013 10/10/2008, 10 AM PT",
489
490 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "hz", "10/10/2007, 10 AM PDT \\u2013 10/10/2008, 10 AM PDT",
491
492 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "EEddMMyyyy", "Wed, 10/10/2007 \\u2013 Fri, 10/10/2008",
493
494 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "EddMMy", "Wed, 10/10/2007 \\u2013 Fri, 10/10/2008",
495
496 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "hhmm", "10/10/2007, 10:10 AM \\u2013 10/10/2008, 10:10 AM",
497
498 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "hhmmzz", "10/10/2007, 10:10 AM PDT \\u2013 10/10/2008, 10:10 AM PDT",
499
500 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "hms", "10/10/2007, 10:10:10 AM \\u2013 10/10/2008, 10:10:10 AM",
501
502 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "dMMMMMy", "O 10, 2007 \\u2013 O 10, 2008",
503
504 "en", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "EEEEEdM", "W, 10/10/2007 \\u2013 F, 10/10/2008",
505
506 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "EEEEdMMMMy", "Wednesday, October 10 \\u2013 Saturday, November 10, 2007",
507
508 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "dMMMMy", "October 10 \\u2013 November 10, 2007",
509
510 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "dMMMM", "October 10 \\u2013 November 10",
511
512 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "MMMMy", "October \\u2013 November 2007",
513
514 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "EEEEdMMMM", "Wednesday, October 10 \\u2013 Saturday, November 10",
515
516 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "EdMMMy", "Wed, Oct 10 \\u2013 Sat, Nov 10, 2007",
517
518 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "dMMMy", "Oct 10 \\u2013 Nov 10, 2007",
519
520 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "dMMM", "Oct 10 \\u2013 Nov 10",
521
522 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "MMMy", "Oct \\u2013 Nov 2007",
523
524 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "EdMMM", "Wed, Oct 10 \\u2013 Sat, Nov 10",
525
526 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "EdMy", "Wed, 10/10/2007 \\u2013 Sat, 11/10/2007",
527
528 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "dMy", "10/10/2007 \\u2013 11/10/2007",
529
530
531 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "My", "10/2007 \\u2013 11/2007",
532
533 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "EdM", "Wed, 10/10 \\u2013 Sat, 11/10",
534
535 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "d", "10/10 \\u2013 11/10",
536
537 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "Ed", "10 Wed \\u2013 10 Sat",
538
539 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "y", "2007",
540
541 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "M", "10 \\u2013 11",
542
543 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "MMM", "Oct \\u2013 Nov",
544
545 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "MMMM", "October \\u2013 November",
546
547 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "hm", "10/10/2007, 10:10 AM \\u2013 11/10/2007, 10:10 AM",
548 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "Hm", "10/10/2007, 10:10 \\u2013 11/10/2007, 10:10",
549 "en", "CE 2007 10 10 20:10:10", "CE 2007 11 10 20:10:10", "Hm", "10/10/2007, 20:10 \\u2013 11/10/2007, 20:10",
550
551 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "hmv", "10/10/2007, 10:10 AM PT \\u2013 11/10/2007, 10:10 AM PT",
552
553 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "hmz", "10/10/2007, 10:10 AM PDT \\u2013 11/10/2007, 10:10 AM PST",
554
555 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "h", "10/10/2007, 10 AM \\u2013 11/10/2007, 10 AM",
556
557 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "hv", "10/10/2007, 10 AM PT \\u2013 11/10/2007, 10 AM PT",
558
559 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "hz", "10/10/2007, 10 AM PDT \\u2013 11/10/2007, 10 AM PST",
560
561 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "EEddMMyyyy", "Wed, 10/10/2007 \\u2013 Sat, 11/10/2007",
562
563 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "EddMMy", "Wed, 10/10/2007 \\u2013 Sat, 11/10/2007",
564
565
566 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "hhmmzz", "10/10/2007, 10:10 AM PDT \\u2013 11/10/2007, 10:10 AM PST",
567
568 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "hms", "10/10/2007, 10:10:10 AM \\u2013 11/10/2007, 10:10:10 AM",
569
570 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "dMMMMMy", "O 10 \\u2013 N 10, 2007",
571
572 "en", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "EEEEEdM", "W, 10/10 \\u2013 S, 11/10",
573
574 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EEEEdMMMMy", "Saturday, November 10 \\u2013 Tuesday, November 20, 2007",
575
576 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "dMMMMy", "November 10 \\u2013 20, 2007",
577
578 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "dMMMM", "November 10 \\u2013 20",
579
580
581 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EEEEdMMMM", "Saturday, November 10 \\u2013 Tuesday, November 20",
582
583 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EdMMMy", "Sat, Nov 10 \\u2013 Tue, Nov 20, 2007",
584
585 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "dMMMy", "Nov 10 \\u2013 20, 2007",
586
587 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "dMMM", "Nov 10 \\u2013 20",
588
589 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "MMMy", "Nov 2007",
590
591 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EdMMM", "Sat, Nov 10 \\u2013 Tue, Nov 20",
592
593 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EdMy", "Sat, 11/10/2007 \\u2013 Tue, 11/20/2007",
594
595 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "dMy", "11/10/2007 \\u2013 11/20/2007",
596
597 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "dM", "11/10 \\u2013 11/20",
598
599 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "My", "11/2007",
600
601 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EdM", "Sat, 11/10 \\u2013 Tue, 11/20",
602
603 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "d", "10 \\u2013 20",
604
605 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "Ed", "10 Sat \\u2013 20 Tue",
606
607 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "y", "2007",
608
609 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "M", "11",
610
611 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "MMM", "Nov",
612
613 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "MMMM", "November",
614
615 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "hm", "11/10/2007, 10:10 AM \\u2013 11/20/2007, 10:10 AM",
616 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "Hm", "11/10/2007, 10:10 \\u2013 11/20/2007, 10:10",
617 "en", "CE 2007 11 10 20:10:10", "CE 2007 11 20 20:10:10", "Hm", "11/10/2007, 20:10 \\u2013 11/20/2007, 20:10",
618
619 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "hmv", "11/10/2007, 10:10 AM PT \\u2013 11/20/2007, 10:10 AM PT",
620
621 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "hmz", "11/10/2007, 10:10 AM PST \\u2013 11/20/2007, 10:10 AM PST",
622
623 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "h", "11/10/2007, 10 AM \\u2013 11/20/2007, 10 AM",
624
625 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "hv", "11/10/2007, 10 AM PT \\u2013 11/20/2007, 10 AM PT",
626
627 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "hz", "11/10/2007, 10 AM PST \\u2013 11/20/2007, 10 AM PST",
628
629 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EEddMMyyyy", "Sat, 11/10/2007 \\u2013 Tue, 11/20/2007",
630
631 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EddMMy", "Sat, 11/10/2007 \\u2013 Tue, 11/20/2007",
632
633 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "hhmm", "11/10/2007, 10:10 AM \\u2013 11/20/2007, 10:10 AM",
634
635 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "hhmmzz", "11/10/2007, 10:10 AM PST \\u2013 11/20/2007, 10:10 AM PST",
636
637 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "hms", "11/10/2007, 10:10:10 AM \\u2013 11/20/2007, 10:10:10 AM",
638 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "Hms", "11/10/2007, 10:10:10 \\u2013 11/20/2007, 10:10:10",
639 "en", "CE 2007 11 10 20:10:10", "CE 2007 11 20 20:10:10", "Hms", "11/10/2007, 20:10:10 \\u2013 11/20/2007, 20:10:10",
640
641 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "dMMMMMy", "N 10 \\u2013 20, 2007",
642
643 "en", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EEEEEdM", "S, 11/10 \\u2013 T, 11/20",
644
645 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "EEEEdMMMMy", "Wednesday, January 10, 2007",
646
647 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "dMMMMy", "January 10, 2007",
648
649 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "dMMMM", "January 10",
650
651 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "MMMMy", "January 2007",
652
653 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "EEEEdMMMM", "Wednesday, January 10",
654
655 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "EdMMMy", "Wed, Jan 10, 2007",
656
657 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "dMMMy", "Jan 10, 2007",
658
659 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "dMMM", "Jan 10",
660
661 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "MMMy", "Jan 2007",
662
663 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "EdMMM", "Wed, Jan 10",
664
665
666 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "dMy", "1/10/2007",
667
668 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "dM", "1/10",
669
670 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "My", "1/2007",
671
672 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "EdM", "Wed, 1/10",
673
674 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "d", "10",
675
676 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "Ed", "10 Wed",
677
678 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "y", "2007",
679
680 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "M", "1",
681
682 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "MMM", "Jan",
683
684 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "MMMM", "January",
685
686 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "hm", "10:00 AM \\u2013 2:10 PM",
687 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "Hm", "10:00 \\u2013 14:10",
688
689 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "hmv", "10:00 AM \\u2013 2:10 PM PT",
690
691 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "hmz", "10:00 AM \\u2013 2:10 PM PST",
692
693 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "h", "10 AM \\u2013 2 PM",
694 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "H", "10 \\u2013 14",
695
696
697 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "hz", "10 AM \\u2013 2 PM PST",
698
699 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "EEddMMyyyy", "Wed, 01/10/2007",
700
701 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "EddMMy", "Wed, 01/10/2007",
702
703 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "hhmm", "10:00 AM \\u2013 2:10 PM",
704 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "HHmm", "10:00 \\u2013 14:10",
705
706 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "hhmmzz", "10:00 AM \\u2013 2:10 PM PST",
707
708 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "hms", "10:00:10 AM \\u2013 2:10:10 PM",
709 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "Hms", "10:00:10 \\u2013 14:10:10",
710
711 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "dMMMMMy", "J 10, 2007",
712
713 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "EEEEEdM", "W, 1/10",
714 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "dMMMMy", "January 10, 2007",
715
716 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "dMMMM", "January 10",
717
718 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "MMMMy", "January 2007",
719
720 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "EEEEdMMMM", "Wednesday, January 10",
721
722 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "EdMMMy", "Wed, Jan 10, 2007",
723
724 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "dMMMy", "Jan 10, 2007",
725
726 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "dMMM", "Jan 10",
727
728
729 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "EdMMM", "Wed, Jan 10",
730
731 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "EdMy", "Wed, 1/10/2007",
732
733 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "dMy", "1/10/2007",
734
735
736 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "My", "1/2007",
737
738 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "EdM", "Wed, 1/10",
739
740 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "d", "10",
741
742
743 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "y", "2007",
744
745 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "M", "1",
746
747
748
749 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "hm", "10:00 \\u2013 10:20 AM",
750 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "Hm", "10:00 \\u2013 10:20",
751
752
753 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "hmz", "10:00 \\u2013 10:20 AM PST",
754
755
756 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "hv", "10 AM PT",
757
758
759
760 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "EddMMy", "Wed, 01/10/2007",
761
762 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "hhmm", "10:00 \\u2013 10:20 AM",
763 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "HHmm", "10:00 \\u2013 10:20",
764
765 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "hhmmzz", "10:00 \\u2013 10:20 AM PST",
766
767
768 "en", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "dMMMMMy", "J 10, 2007",
769
770
771 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "EEEEdMMMMy", "Wednesday, January 10, 2007",
772
773 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "dMMMMy", "January 10, 2007",
774
775
776 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "MMMMy", "January 2007",
777
778 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "EEEEdMMMM", "Wednesday, January 10",
779
780
781 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "dMMMy", "Jan 10, 2007",
782
783 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "dMMM", "Jan 10",
784
785
786 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "EdMMM", "Wed, Jan 10",
787
788 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "EdMy", "Wed, 1/10/2007",
789
790 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "dMy", "1/10/2007",
791
792
793 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "My", "1/2007",
794
795 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "EdM", "Wed, 1/10",
796
797 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "d", "10",
798
799
800 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "y", "2007",
801
802 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "M", "1",
803
804
805 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "MMMM", "January",
806
807 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "hm", "10:10 AM",
808 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "Hm", "10:10",
809
810
811 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "hmz", "10:10 AM PST",
812
813 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "h", "10 AM",
814
815 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "hv", "10 AM PT",
816
817
818 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "EEddMMyyyy", "Wed, 01/10/2007",
819
820
821 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "hhmm", "10:10 AM",
822 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "HHmm", "10:10",
823
824 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "hhmmzz", "10:10 AM PST",
825
826
827 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "dMMMMMy", "J 10, 2007",
828
829 "en", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "EEEEEdM", "W, 1/10",
830
831 "zh", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "EEEEdMMMMy", "2007\\u5e7410\\u670810\\u65e5\\u661f\\u671f\\u4e09\\u81f32008\\u5e7410\\u670810\\u65e5\\u661f\\u671f\\u4e94",
832
833
834 "zh", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "dMMMMy", "2007\\u5e7410\\u670810\\u65e5\\u81f311\\u670810\\u65e5",
835
836
837 "zh", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "MMMMy", "2007\\u5e7410\\u6708\\u81f311\\u6708",
838
839
840 "zh", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "hmv", "2007/10/10 \\u6D1B\\u6749\\u77F6\\u65F6\\u95F4 \\u4E0A\\u534810:10 \\u2013 2007/11/10 \\u6D1B\\u6749\\u77F6\\u65F6\\u95F4 \\u4E0A\\u534810:10",
841
842 "zh", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EEEEdMMMMy", "2007\\u5e7411\\u670810\\u65e5\\u661f\\u671f\\u516d\\u81f320\\u65e5\\u661f\\u671f\\u4e8c",
843
844
845 "zh", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "dMMMM", "11\\u670810\\u65e5\\u81f320\\u65e5",
846
847 "zh", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "MMMMy", "2007\\u5E7411\\u6708", // (fixed expected result per ticket:6626:)
848
849 "zh", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EEEEdMMMM", "11\\u670810\\u65e5\\u661f\\u671f\\u516d\\u81f320\\u65e5\\u661f\\u671f\\u4e8c",
850
851
852 "zh", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EdMy", "2007/11/10\\u5468\\u516d\\u81f32007/11/20\\u5468\\u4e8c",
853
854
855 "zh", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "dM", "11/10 \\u2013 11/20",
856
857 "zh", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "My", "2007\\u5E7411\\u6708",
858
859 "zh", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EdM", "11/10\\u5468\\u516d\\u81f311/20\\u5468\\u4e8c",
860
861
862 "zh", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "y", "2007\\u5E74", // (fixed expected result per ticket:6626:)
863
864 "zh", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "M", "11\\u6708",
865
866 "zh", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "MMM", "11\\u6708", // (fixed expected result per ticket:6626: and others)
867
868
869 "zh", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "hmz", "2007/11/10 GMT-8 \\u4e0a\\u534810:10 \\u2013 2007/11/20 GMT-8 \\u4e0a\\u534810:10",
870
871 "zh", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "h", "2007/11/10 \\u4e0a\\u534810\\u65f6 \\u2013 2007/11/20 \\u4e0a\\u534810\\u65f6",
872
873 "zh", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "EEEEdMMMMy", "2007\\u5e741\\u670810\\u65e5\\u661f\\u671f\\u4e09", // (fixed expected result per ticket:6626:)
874
875 "zh", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "hm", "\\u4e0a\\u534810:00\\u81f3\\u4e0b\\u53482:10",
876
877
878 "zh", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "hmz", "GMT-8 \\u4e0a\\u534810:00\\u81f3\\u4e0b\\u53482:10",
879
880 "zh", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "h", "\\u4e0a\\u534810\\u65F6\\u81f3\\u4e0b\\u53482\\u65f6",
881
882 "zh", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "hv", "\\u6D1B\\u6749\\u77F6\\u65F6\\u95F4 \\u4E0A\\u534810\\u65F6\\u81F3\\u4E0B\\u53482\\u65F6",
883
884 "zh", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "hm", "\\u4e0a\\u534810:00\\u81f310:20",
885
886 "zh", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "hmv", "\\u6D1B\\u6749\\u77F6\\u65F6\\u95F4 \\u4E0A\\u534810:00\\u81F310:20",
887
888 "zh", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "hz", "GMT-8\\u4e0a\\u534810\\u65f6",
889
890 "zh", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "hm", "\\u4e0a\\u534810:10",
891
892 "zh", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "h", "\\u4e0a\\u534810\\u65f6",
893
894 "de", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "EEEEdMMMy", "Mittwoch, 10. Okt. 2007 \\u2013 Freitag, 10. Okt. 2008",
895
896
897 "de", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "dMMM", "10. Okt. 2007 \\u2013 10. Okt. 2008",
898
899 "de", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "MMMy", "Okt. 2007 \\u2013 Okt. 2008",
900
901
902 "de", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "EdMy", "Mi., 10.10.2007 \\u2013 Fr., 10.10.2008",
903
904 "de", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "dMy", "10.10.2007 \\u2013 10.10.2008",
905
906
907 "de", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "My", "10.2007 \\u2013 10.2008",
908
909 "de", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "EdM", "Mi., 10.10.2007 \\u2013 Fr., 10.10.2008",
910
911
912 "de", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "y", "2007\\u20132008",
913
914 "de", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "M", "10.2007 \\u2013 10.2008",
915
916
917 "de", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "hm", "10.10.2007, 10:10 AM \\u2013 10.10.2008, 10:10 AM",
918 "de", "CE 2007 10 10 10:10:10", "CE 2008 10 10 10:10:10", "Hm", "10.10.2007, 10:10 \\u2013 10.10.2008, 10:10",
919
920 "de", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "EEEEdMMMy", "Mittwoch, 10. Okt. \\u2013 Samstag, 10. Nov. 2007",
921
922
923 "de", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "dMMM", "10. Okt. \\u2013 10. Nov.",
924
925 "de", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "MMMy", "Okt.\\u2013Nov. 2007",
926
927 "de", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "EEEEdMMM", "Mittwoch, 10. Okt. \\u2013 Samstag, 10. Nov.",
928
929
930 "de", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "dM", "10.10. \\u2013 10.11.",
931
932 "de", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "My", "10.2007 \\u2013 11.2007",
933
934
935 "de", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "d", "10.10. \\u2013 10.11.",
936
937 "de", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "y", "2007",
938
939
940 "de", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "MMM", "Okt.\\u2013Nov.",
941
942
943 "de", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "hms", "10.10.2007, 10:10:10 AM \\u2013 10.11.2007, 10:10:10 AM",
944 "de", "CE 2007 10 10 10:10:10", "CE 2007 11 10 10:10:10", "Hms", "10.10.2007, 10:10:10 \\u2013 10.11.2007, 10:10:10",
945
946 "de", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EEEEdMMMy", "Samstag, 10. \\u2013 Dienstag, 20. Nov. 2007",
947
948 "de", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "dMMMy", "10.\\u201320. Nov. 2007",
949
950
951 "de", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "MMMy", "Nov. 2007",
952
953 "de", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EEEEdMMM", "Samstag, 10. \\u2013 Dienstag, 20. Nov.",
954
955 "de", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "EdMy", "Sa., 10. \\u2013 Di., 20.11.2007",
956
957
958 "de", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "dM", "10.\\u201320.11.",
959
960 "de", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "My", "11.2007",
961
962
963 "de", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "d", "10.\\u201320.",
964
965 "de", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "y", "2007",
966
967
968 "de", "CE 2007 11 10 10:10:10", "CE 2007 11 20 10:10:10", "hmv", "10.11.2007, 10:10 AM Los Angeles Zeit \\u2013 20.11.2007, 10:10 AM Los Angeles Zeit",
969
970 "de", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "EEEEdMMMy", "Mittwoch, 10. Jan. 2007",
971
972
973 "de", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "dMMM", "10. Jan.",
974
975 "de", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "MMMy", "Jan. 2007",
976
977 "de", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "EEEEdMMM", "Mittwoch, 10. Jan.",
978
979 /* Following is an important test, because the 'h' in 'Uhr' is interpreted as a pattern
980 if not escaped properly. */
981 "de", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "h", "10 Uhr AM \\u2013 2 Uhr PM",
982 "de", "CE 2007 01 10 10:00:10", "CE 2007 01 10 14:10:10", "H", "10\\u201314 Uhr",
983
984 "de", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "EEEEdMMM", "Mittwoch, 10. Jan.",
985
986
987 "de", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "hmv", "10:00\\u201310:20 AM Los Angeles Zeit",
988
989 "de", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "hmz", "10:00\\u201310:20 AM GMT-8",
990
991 "de", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "h", "10 Uhr AM",
992 "de", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "H", "10 Uhr",
993
994
995 "de", "CE 2007 01 10 10:00:10", "CE 2007 01 10 10:20:10", "hz", "10 Uhr AM GMT-8",
996
997 "de", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "EEEEdMMMy", "Mittwoch, 10. Jan. 2007",
998
999
1000 "de", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "hmv", "10:10 AM Los Angeles Zeit",
1001
1002 "de", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "hmz", "10:10 AM GMT-8",
1003
1004
1005 "de", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "hv", "10 Uhr AM Los Angeles Zeit",
1006
1007 "de", "CE 2007 01 10 10:10:10", "CE 2007 01 10 10:10:20", "hz", "10 Uhr AM GMT-8",
1008
1009 // Thai (default calendar buddhist)
1010
1011 // BEGIN ANDROID-changed. Default calendar in Android is Gregorian for th locale.
1012 // "th", "BE 2550 10 10 10:10:10", "BE 2551 10 10 10:10:10", "EEEEdMMMy", "\\u0E27\\u0E31\\u0E19\\u0E1E\\u0E38\\u0E18\\u0E17\\u0E35\\u0E48 10 \\u0E15.\\u0E04. 2550 \\u2013 \\u0E27\\u0E31\\u0E19\\u0E28\\u0E38\\u0E01\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48 10 \\u0E15.\\u0E04. 2551",
1013
1014
1015 // "th", "BE 2550 10 10 10:10:10", "BE 2551 10 10 10:10:10", "dMMM", "10 \\u0E15.\\u0E04. 2550 \\u2013 10 \\u0E15.\\u0E04. 2551",
1016
1017 // "th", "BE 2550 10 10 10:10:10", "BE 2551 10 10 10:10:10", "MMMy", "\\u0E15.\\u0E04. 2550 \\u2013 \\u0E15.\\u0E04. 2551",
1018
1019
1020 // "th", "BE 2550 10 10 10:10:10", "BE 2551 10 10 10:10:10", "EdMy", "\\u0E1E. 10/10/2550 \\u2013 \\u0E28. 10/10/2551",
1021
1022 // "th", "BE 2550 10 10 10:10:10", "BE 2551 10 10 10:10:10", "dMy", "10/10/2550 \\u2013 10/10/2551",
1023
1024
1025 // "th", "BE 2550 10 10 10:10:10", "BE 2551 10 10 10:10:10", "My", "10/2550 \\u2013 10/2551",
1026
1027 // "th", "BE 2550 10 10 10:10:10", "BE 2551 10 10 10:10:10", "EdM", "\\u0E1E. 10/10/2550 \\u2013 \\u0E28. 10/10/2551",
1028
1029
1030 // "th", "BE 2550 10 10 10:10:10", "BE 2551 10 10 10:10:10", "y", "2550\\u20132551",
1031
1032 // "th", "BE 2550 10 10 10:10:10", "BE 2551 10 10 10:10:10", "M", "10/2550 \\u2013 10/2551",
1033
1034
1035 // "th", "BE 2550 10 10 10:10:10", "BE 2550 11 10 10:10:10", "EEEEdMMMy", "\\u0E27\\u0E31\\u0E19\\u0E1E\\u0E38\\u0E18\\u0E17\\u0E35\\u0E48 10 \\u0E15.\\u0E04. \\u2013 \\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48 10 \\u0E1E.\\u0E22. 2550",
1036
1037
1038 // "th", "BE 2550 10 10 10:10:10", "BE 2550 11 10 10:10:10", "dMMM", "10 \\u0E15.\\u0E04. \\u2013 10 \\u0E1E.\\u0E22.",
1039
1040 // "th", "BE 2550 10 10 10:10:10", "BE 2550 11 10 10:10:10", "MMMy", "\\u0E15.\\u0E04.\\u2013\\u0E1E.\\u0E22. 2550",
1041
1042 // "th", "2550 10 10 10:10:10", "2550 11 10 10:10:10", "dM", "10/10 \\u2013 10/11",
1043
1044 // "th", "BE 2550 10 10 10:10:10", "BE 2550 11 10 10:10:10", "My", "10/2550 \\u2013 11/2550",
1045
1046
1047 // "th", "BE 2550 10 10 10:10:10", "BE 2550 11 10 10:10:10", "d", "10/10 \\u2013 10/11",
1048
1049 // "th", "BE 2550 10 10 10:10:10", "BE 2550 11 10 10:10:10", "y", "\\u0E1E.\\u0E28. 2550",
1050
1051
1052 // "th", "BE 2550 10 10 10:10:10", "BE 2550 11 10 10:10:10", "MMM", "\\u0E15.\\u0E04.\\u2013\\u0E1E.\\u0E22.",
1053
1054 // "th", "2550 10 10 10:10:10", "2550 11 10 10:10:10", "y", "\\u0E1E.\\u0E28. 2550",
1055
1056 // "th", "2550 10 10 10:10:10", "2550 11 10 10:10:10", "MMM", "\\u0E15.\\u0E04.\\u2013\\u0E1E.\\u0E22.",
1057
1058 // Tests for Japanese calendar with eras, including new era in 2019 (Heisei 31 through April 30, then new era)
1059
1060 "en-u-ca-japanese", "H 31 03 15 09:00:00", "H 31 04 15 09:00:00", "GyMMMd", "Mar 15 \\u2013 Apr 15, 31 Heisei",
1061
1062 "en-u-ca-japanese", "H 31 03 15 09:00:00", "H 31 04 15 09:00:00", "GGGGGyMd", "3/15/31 \\u2013 4/15/31 H",
1063
1064 "en-u-ca-japanese", "S 64 01 05 09:00:00", "H 1 01 15 09:00:00", "GyMMMd", "Jan 5, 64 Sh\\u014Dwa \\u2013 Jan 15, 1 Heisei",
1065
1066 "en-u-ca-japanese", "S 64 01 05 09:00:00", "H 1 01 15 09:00:00", "GGGGGyMd", "1/5/64 S \\u2013 1/15/1 H",
1067
1068 "en-u-ca-japanese", "H 31 04 15 09:00:00", JP_ERA_2019_NARROW " 1 05 15 09:00:00", "GyMMMd", "Apr 15, 31 Heisei \\u2013 May 15, 1 " JP_ERA_2019_ROOT,
1069
1070 "en-u-ca-japanese", "H 31 04 15 09:00:00", JP_ERA_2019_NARROW " 1 05 15 09:00:00", "GGGGGyMd", "4/15/31 H \\u2013 5/15/1 " JP_ERA_2019_NARROW,
1071
1072
1073 "ja-u-ca-japanese", "H 31 03 15 09:00:00", "H 31 04 15 09:00:00", "GyMMMd", "\\u5E73\\u621031\\u5E743\\u670815\\u65E5\\uFF5E4\\u670815\\u65E5",
1074
1075 "ja-u-ca-japanese", "H 31 03 15 09:00:00", "H 31 04 15 09:00:00", "GGGGGyMd", "H31/03/15\\uFF5E31/04/15",
1076
1077 "ja-u-ca-japanese", "S 64 01 05 09:00:00", "H 1 01 15 09:00:00", "GyMMMd", "\\u662D\\u548C64\\u5E741\\u67085\\u65E5\\uFF5E\\u5E73\\u6210\\u5143\\u5E741\\u670815\\u65E5",
1078
1079 "ja-u-ca-japanese", "S 64 01 05 09:00:00", "H 1 01 15 09:00:00", "GGGGGyMd", "S64/01/05\\uFF5EH1/01/15",
1080
1081 "ja-u-ca-japanese", "H 31 04 15 09:00:00", JP_ERA_2019_NARROW " 1 05 15 09:00:00", "GGGGGyMd", "H31/04/15\\uFF5E" JP_ERA_2019_NARROW "1/05/15",
1082
1083 // END ANDROID-changed
1084 };
1085 expect(DATA, UPRV_LENGTHOF(DATA));
1086 }
1087
1088
1089 /**
1090 * Test handling of hour and day period metacharacters
1091 */
testHourMetacharacters()1092 void DateIntervalFormatTest::testHourMetacharacters() {
1093 // first item is date pattern
1094 // followed by a group of locale/from_data/to_data/skeleton/interval_data
1095 // Note that from_data/to_data are specified using era names from root, for the calendar specified by locale.
1096 const char* DATA[] = {
1097 "GGGGG y MM dd HH:mm:ss", // pattern for from_data/to_data
1098
1099 // This test is for tickets ICU-21154, ICU-21155, and ICU-21156 and is intended to verify
1100 // that all of the special skeleton characters for hours and day periods work as expected
1101 // with date intervals:
1102 // - If a, b, or B is included in the skeleton, it correctly sets the length of the day-period field
1103 // - If k or K is included, it behaves the same as H or h, except for the difference in the actual
1104 // number used for the hour.
1105 // - If j is included, it behaves the same as either h or H as appropriate, and multiple j's have the
1106 // intended effect on the length of the day period field (if there is one)
1107 // - If J is included, it correctly suppresses the day period field if j would include it
1108 // - If C is included, it behaves the same as j and brings up the correct day period field
1109 // - In all cases, if the day period of both ends of the range is the same, you only see it once
1110
1111 // baseline (h and H)
1112 "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "hh", "12 \\u2013 1 AM",
1113 "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "HH", "00\\u201301 Uhr",
1114
1115 // k and K (ICU-21154 and ICU-21156)
1116 "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "KK", "0 \\u2013 1 AM",
1117 "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "kk", "24\\u201301 Uhr",
1118
1119 // different lengths of the 'a' field
1120 "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "ha", "10 AM \\u2013 1 PM",
1121 "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "ha", "12 \\u2013 1 AM",
1122 "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 12:00:00", "haaaaa", "10 a \\u2013 12 p",
1123 "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "haaaaa", "12 \\u2013 1 a",
1124
1125 // j (ICU-21155)
1126 "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "jj", "10 AM \\u2013 1 PM",
1127 "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "jj", "12 \\u2013 1 AM",
1128 "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "jjjjj", "10 a \\u2013 1 p",
1129 "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "jjjjj", "12 \\u2013 1 a",
1130 "de", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "jj", "10\\u201313 Uhr",
1131 "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "jj", "00\\u201301 Uhr",
1132 "de", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "jjjjj", "10\\u201313 Uhr",
1133 "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "jjjjj", "00\\u201301 Uhr",
1134
1135 // b and B
1136 "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 12:00:00", "hb", "10 AM \\u2013 12 noon",
1137 "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 12:00:00", "hbbbbb", "10 a \\u2013 12 n",
1138 "en", "CE 2010 09 27 13:00:00", "CE 2010 09 27 14:00:00", "hb", "1 \\u2013 2 PM",
1139 "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "hB", "10 in the morning \\u2013 1 in the afternoon",
1140 "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "hB", "12 \\u2013 1 at night",
1141
1142 // J
1143 "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "J", "10 \\u2013 1",
1144 "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "J", "12 \\u2013 1",
1145 "de", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "J", "10\\u201313 Uhr",
1146 "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "J", "00\\u201301 Uhr",
1147
1148 // C
1149 // (for English and German, C should do the same thing as j)
1150 "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "CC", "10 AM \\u2013 1 PM",
1151 "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "CC", "12 \\u2013 1 AM",
1152 "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "CCCCC", "10 a \\u2013 1 p",
1153 "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "CCCCC", "12 \\u2013 1 a",
1154 "de", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "CC", "10\\u201313 Uhr",
1155 "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "CC", "00\\u201301 Uhr",
1156 "de", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "CCCCC", "10\\u201313 Uhr",
1157 "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "CCCCC", "00\\u201301 Uhr",
1158 // (for zh_HK and hi_IN, j maps to ha, but C maps to hB)
1159 "zh_HK", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "jj", "\\u4E0A\\u534810\\u6642\\u81F3\\u4E0B\\u53481\\u6642",
1160 "zh_HK", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "jj", "\\u4E0A\\u534812\\u6642\\u81F31\\u6642",
1161 "zh_HK", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "hB", "\\u4E0A\\u534810\\u6642 \\u2013 \\u4E0B\\u53481\\u6642",
1162 "zh_HK", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "hB", "\\u51CC\\u666812\\u20131\\u6642",
1163 "zh_HK", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "CC", "\\u4E0A\\u534810\\u6642\\u81F3\\u4E0B\\u53481\\u6642",
1164 "zh_HK", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "CC", "\\u4E0A\\u534812\\u6642\\u81F31\\u6642",
1165 "hi_IN", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "jj", "10 am \\u2013 1 pm",
1166 "hi_IN", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "jj", "12\\u20131 am",
1167 "hi_IN", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "hB", "\\u0938\\u0941\\u092C\\u0939 10 \\u2013 \\u0926\\u094B\\u092A\\u0939\\u0930 1",
1168 "hi_IN", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "hB", "\\u0930\\u093E\\u0924 12\\u20131",
1169 "hi_IN", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "CC", "\\u0938\\u0941\\u092C\\u0939 10 \\u2013 \\u0926\\u094B\\u092A\\u0939\\u0930 1",
1170 "hi_IN", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "CC", "\\u0930\\u093E\\u0924 12\\u20131",
1171
1172 // regression test for ICU-21342
1173 "en_GB", "CE 2010 09 27 00:00:00", "CE 2010 09 27 10:00:00", "kk", "24\\u201310",
1174 "en_GB", "CE 2010 09 27 00:00:00", "CE 2010 09 27 11:00:00", "kk", "24\\u201311",
1175 "en_GB", "CE 2010 09 27 00:00:00", "CE 2010 09 27 12:00:00", "kk", "24\\u201312",
1176 "en_GB", "CE 2010 09 27 00:00:00", "CE 2010 09 27 13:00:00", "kk", "24\\u201313",
1177
1178 // regression test for ICU-21343
1179 "de", "CE 2010 09 27 01:00:00", "CE 2010 09 27 10:00:00", "KK", "1 \\u2013 10 Uhr AM",
1180 };
1181 expect(DATA, UPRV_LENGTHOF(DATA));
1182 }
1183
1184
expect(const char ** data,int32_t data_length)1185 void DateIntervalFormatTest::expect(const char** data, int32_t data_length) {
1186 int32_t i = 0;
1187 UErrorCode ec = U_ZERO_ERROR;
1188 UnicodeString str, str2;
1189 const char* pattern = data[i++];
1190
1191 while (i<data_length) {
1192 const char* locName = data[i++];
1193 const char* datestr = data[i++];
1194 const char* datestr_2 = data[i++];
1195
1196 Locale loc(locName);
1197 LocalPointer<Calendar> defCal(Calendar::createInstance(loc, ec));
1198 if (U_FAILURE(ec)) {
1199 dataerrln("Calendar::createInstance fails for loc %s with: %s", locName, u_errorName(ec));
1200 return;
1201 }
1202 const char* calType = defCal->getType();
1203
1204 Locale refLoc("root");
1205 if (calType) {
1206 refLoc.setKeywordValue("calendar", calType, ec);
1207 }
1208 SimpleDateFormat ref(pattern, refLoc, ec);
1209 logln( "case %d, locale: %s\n", (i-1)/5, locName);
1210 if (U_FAILURE(ec)) {
1211 dataerrln("contruct SimpleDateFormat in expect failed: %s", u_errorName(ec));
1212 return;
1213 }
1214
1215 // 'f'
1216 logln("original date: %s - %s\n", datestr, datestr_2);
1217 UDate date = ref.parse(ctou(datestr), ec);
1218 if (!assertSuccess("parse 1st data in expect", ec)) return;
1219 UDate date_2 = ref.parse(ctou(datestr_2), ec);
1220 if (!assertSuccess("parse 2nd data in expect", ec)) return;
1221 DateInterval dtitv(date, date_2);
1222
1223 const UnicodeString& oneSkeleton(ctou(data[i++]));
1224
1225 DateIntervalFormat* dtitvfmt = DateIntervalFormat::createInstance(oneSkeleton, loc, ec);
1226 if (!assertSuccess("createInstance(skeleton) in expect", ec)) return;
1227 FieldPosition pos(FieldPosition::DONT_CARE);
1228 dtitvfmt->format(&dtitv, str.remove(), pos, ec);
1229 if (!assertSuccess("format in expect", ec)) return;
1230 assertEquals((UnicodeString)"\"" + locName + "\\" + oneSkeleton + "\\" + ctou(datestr) + "\\" + ctou(datestr_2) + "\"", ctou(data[i++]), str);
1231
1232 logln("interval date:" + str + "\"" + locName + "\", "
1233 + "\"" + datestr + "\", "
1234 + "\"" + datestr_2 + "\", " + oneSkeleton);
1235 delete dtitvfmt;
1236 }
1237 }
1238
1239
1240 /*
1241 * Test format using user defined DateIntervalInfo
1242 */
testFormatUserDII()1243 void DateIntervalFormatTest::testFormatUserDII() {
1244 // first item is date pattern
1245 const char* DATA[] = {
1246 "yyyy MM dd HH:mm:ss",
1247 "en", "2007 10 10 10:10:10", "2008 10 10 10:10:10", "Oct 10, 2007 --- Oct 10, 2008",
1248
1249 "en", "2007 10 10 10:10:10", "2007 11 10 10:10:10", "2007 Oct 10 - Nov 2007",
1250
1251 "en", "2007 11 10 10:10:10", "2007 11 20 10:10:10", "Nov 10, 2007 --- Nov 20, 2007",
1252
1253 "en", "2007 01 10 10:00:10", "2007 01 10 14:10:10", "Jan 10, 2007",
1254
1255 "en", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "Jan 10, 2007",
1256
1257 "en", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "Jan 10, 2007",
1258
1259 "zh", "2007 10 10 10:10:10", "2008 10 10 10:10:10", "2007\\u5e7410\\u670810\\u65e5 --- 2008\\u5e7410\\u670810\\u65e5",
1260
1261 "zh", "2007 10 10 10:10:10", "2007 11 10 10:10:10", "2007 10\\u6708 10 - 11\\u6708 2007",
1262
1263 "zh", "2007 11 10 10:10:10", "2007 11 20 10:10:10", "2007\\u5e7411\\u670810\\u65e5 --- 2007\\u5e7411\\u670820\\u65e5",
1264
1265 "zh", "2007 01 10 10:00:10", "2007 01 10 14:10:10", "2007\\u5e741\\u670810\\u65e5", // (fixed expected result per ticket:6626:)
1266
1267 "zh", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "2007\\u5e741\\u670810\\u65e5", // (fixed expected result per ticket:6626:)
1268
1269 "zh", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "2007\\u5e741\\u670810\\u65e5", // (fixed expected result per ticket:6626:)
1270
1271 "de", "2007 10 10 10:10:10", "2008 10 10 10:10:10", "10. Okt. 2007 --- 10. Okt. 2008",
1272
1273
1274 "de", "2007 11 10 10:10:10", "2007 11 20 10:10:10", "10. Nov. 2007 --- 20. Nov. 2007",
1275
1276 "de", "2007 01 10 10:00:10", "2007 01 10 14:10:10", "10. Jan. 2007",
1277
1278 "de", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "10. Jan. 2007",
1279
1280
1281 "es", "2007 10 10 10:10:10", "2008 10 10 10:10:10", "10 oct 2007 --- 10 oct 2008",
1282
1283 "es", "2007 10 10 10:10:10", "2007 11 10 10:10:10", "2007 oct 10 - nov 2007",
1284
1285 "es", "2007 11 10 10:10:10", "2007 11 20 10:10:10", "10 nov 2007 --- 20 nov 2007",
1286
1287 "es", "2007 01 10 10:00:10", "2007 01 10 14:10:10", "10 ene 2007",
1288
1289 "es", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "10 ene 2007",
1290
1291 "es", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "10 ene 2007",
1292 };
1293 expectUserDII(DATA, UPRV_LENGTHOF(DATA));
1294 }
1295
1296 /*
1297 * Test format using UDisplayContext
1298 */
1299 #define CAP_NONE UDISPCTX_CAPITALIZATION_NONE
1300 #define CAP_BEGIN UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
1301 #define CAP_LIST UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
1302 #define CAP_ALONE UDISPCTX_CAPITALIZATION_FOR_STANDALONE
1303 #define _DAY (24.0*60.0*60.0*1000.0)
1304
testContext()1305 void DateIntervalFormatTest::testContext() {
1306 static const UDate startDate = 1285599629000.0; // 2010-Sep-27 0800 in America/Los_Angeles
1307 typedef struct {
1308 const char * locale;
1309 const char * skeleton;
1310 UDisplayContext context;
1311 const UDate deltaDate;
1312 const UChar* expectResult;
1313 } DateIntervalContextItem;
1314 static const DateIntervalContextItem testItems[] = {
1315 { "cs", "MMMEd", CAP_NONE, 60.0*_DAY, u"po 27. 9. – pá 26. 11." },
1316 { "cs", "yMMMM", CAP_NONE, 60.0*_DAY, u"září–listopad 2010" },
1317 { "cs", "yMMMM", CAP_NONE, 1.0*_DAY, u"září 2010" },
1318 #if !UCONFIG_NO_BREAK_ITERATION
1319 { "cs", "MMMEd", CAP_BEGIN, 60.0*_DAY, u"Po 27. 9. – pá 26. 11." },
1320 { "cs", "yMMMM", CAP_BEGIN, 60.0*_DAY, u"Září–listopad 2010" },
1321 { "cs", "yMMMM", CAP_BEGIN, 1.0*_DAY, u"Září 2010" },
1322 { "cs", "MMMEd", CAP_LIST, 60.0*_DAY, u"Po 27. 9. – pá 26. 11." },
1323 { "cs", "yMMMM", CAP_LIST, 60.0*_DAY, u"Září–listopad 2010" },
1324 { "cs", "yMMMM", CAP_LIST, 1.0*_DAY, u"Září 2010" },
1325 #endif
1326 { "cs", "MMMEd", CAP_ALONE, 60.0*_DAY, u"po 27. 9. – pá 26. 11." },
1327 { "cs", "yMMMM", CAP_ALONE, 60.0*_DAY, u"září–listopad 2010" },
1328 { "cs", "yMMMM", CAP_ALONE, 1.0*_DAY, u"září 2010" },
1329 { nullptr, nullptr, CAP_NONE, 0, nullptr }
1330 };
1331 const DateIntervalContextItem* testItemPtr;
1332 for ( testItemPtr = testItems; testItemPtr->locale != nullptr; ++testItemPtr ) {
1333 UErrorCode status = U_ZERO_ERROR;
1334 Locale locale(testItemPtr->locale);
1335 UnicodeString skeleton(testItemPtr->skeleton, -1, US_INV);
1336 LocalPointer<DateIntervalFormat> fmt(DateIntervalFormat::createInstance(skeleton, locale, status));
1337 if (U_FAILURE(status)) {
1338 errln("createInstance failed for locale %s skeleton %s: %s",
1339 testItemPtr->locale, testItemPtr->skeleton, u_errorName(status));
1340 continue;
1341 }
1342 fmt->adoptTimeZone(TimeZone::createTimeZone("America/Los_Angeles"));
1343
1344 fmt->setContext(testItemPtr->context, status);
1345 if (U_FAILURE(status)) {
1346 errln("setContext failed for locale %s skeleton %s context %04X: %s",
1347 testItemPtr->locale, testItemPtr->skeleton, (unsigned)testItemPtr->context, u_errorName(status));
1348 } else {
1349 UDisplayContext getContext = fmt->getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
1350 if (U_FAILURE(status)) {
1351 errln("getContext failed for locale %s skeleton %s context %04X: %s",
1352 testItemPtr->locale, testItemPtr->skeleton, (unsigned)testItemPtr->context, u_errorName(status));
1353 } else if (getContext != testItemPtr->context) {
1354 errln("getContext failed for locale %s skeleton %s context %04X: got context %04X",
1355 testItemPtr->locale, testItemPtr->skeleton, (unsigned)testItemPtr->context, (unsigned)getContext);
1356 }
1357 }
1358
1359 status = U_ZERO_ERROR;
1360 DateInterval interval(startDate, startDate + testItemPtr->deltaDate);
1361 UnicodeString getResult;
1362 FieldPosition pos(FieldPosition::DONT_CARE);
1363 fmt->format(&interval, getResult, pos, status);
1364 if (U_FAILURE(status)) {
1365 errln("format failed for locale %s skeleton %s context %04X: %s",
1366 testItemPtr->locale, testItemPtr->skeleton, (unsigned)testItemPtr->context, u_errorName(status));
1367 continue;
1368 }
1369 UnicodeString expectResult(true, testItemPtr->expectResult, -1);
1370 if (getResult != expectResult) {
1371 errln(UnicodeString("format expected ") + expectResult + UnicodeString(" but got ") + getResult);
1372 }
1373 }
1374 }
1375
testSetIntervalPatternNoSideEffect()1376 void DateIntervalFormatTest::testSetIntervalPatternNoSideEffect() {
1377 UErrorCode ec = U_ZERO_ERROR;
1378 LocalPointer<DateIntervalInfo> dtitvinf(new DateIntervalInfo(ec), ec);
1379 if (U_FAILURE(ec)) {
1380 errln("Failure encountered: %s", u_errorName(ec));
1381 return;
1382 }
1383 UnicodeString expected;
1384 dtitvinf->getIntervalPattern(ctou("yMd"), UCAL_DATE, expected, ec);
1385 dtitvinf->setIntervalPattern(ctou("yMd"), UCAL_DATE, ctou("M/d/y \\u2013 d"), ec);
1386 if (U_FAILURE(ec)) {
1387 errln("Failure encountered: %s", u_errorName(ec));
1388 return;
1389 }
1390 dtitvinf.adoptInsteadAndCheckErrorCode(new DateIntervalInfo(ec), ec);
1391 if (U_FAILURE(ec)) {
1392 errln("Failure encountered: %s", u_errorName(ec));
1393 return;
1394 }
1395 UnicodeString actual;
1396 dtitvinf->getIntervalPattern(ctou("yMd"), UCAL_DATE, actual, ec);
1397 if (U_FAILURE(ec)) {
1398 errln("Failure encountered: %s", u_errorName(ec));
1399 return;
1400 }
1401 if (expected != actual) {
1402 errln("DateIntervalInfo.setIntervalPattern should have no side effects.");
1403 }
1404 }
1405
testYearFormats()1406 void DateIntervalFormatTest::testYearFormats() {
1407 const Locale &enLocale = Locale::getEnglish();
1408 UErrorCode status = U_ZERO_ERROR;
1409 LocalPointer<Calendar> fromTime(Calendar::createInstance(enLocale, status));
1410 LocalPointer<Calendar> toTime(Calendar::createInstance(enLocale, status));
1411 if (U_FAILURE(status)) {
1412 errln("Failure encountered: %s", u_errorName(status));
1413 return;
1414 }
1415 // April 26, 113. Three digit year so that we can test 2 digit years;
1416 // 4 digit years with padded 0's and full years.
1417 fromTime->set(113, 3, 26);
1418 // April 28, 113.
1419 toTime->set(113, 3, 28);
1420 {
1421 LocalPointer<DateIntervalFormat> dif(DateIntervalFormat::createInstance("yyyyMd", enLocale, status));
1422 if (U_FAILURE(status)) {
1423 dataerrln("Failure encountered: %s", u_errorName(status));
1424 return;
1425 }
1426 UnicodeString actual;
1427 UnicodeString expected(ctou("4/26/0113 \\u2013 4/28/0113"));
1428 FieldPosition pos;
1429 dif->format(*fromTime, *toTime, actual, pos, status);
1430 if (U_FAILURE(status)) {
1431 errln("Failure encountered: %s", u_errorName(status));
1432 return;
1433 }
1434 if (actual != expected) {
1435 errln("Expected " + expected + ", got: " + actual);
1436 }
1437 }
1438 {
1439 LocalPointer<DateIntervalFormat> dif(DateIntervalFormat::createInstance("yyMd", enLocale, status));
1440 if (U_FAILURE(status)) {
1441 errln("Failure encountered: %s", u_errorName(status));
1442 return;
1443 }
1444 UnicodeString actual;
1445 UnicodeString expected(ctou("4/26/13 \\u2013 4/28/13"));
1446 FieldPosition pos(FieldPosition::DONT_CARE);
1447 dif->format(*fromTime, *toTime, actual, pos, status);
1448 if (U_FAILURE(status)) {
1449 errln("Failure encountered: %s", u_errorName(status));
1450 return;
1451 }
1452 if (actual != expected) {
1453 errln("Expected " + expected + ", got: " + actual);
1454 }
1455 }
1456 {
1457 LocalPointer<DateIntervalFormat> dif(DateIntervalFormat::createInstance("yMd", enLocale, status));
1458 if (U_FAILURE(status)) {
1459 errln("Failure encountered: %s", u_errorName(status));
1460 return;
1461 }
1462 UnicodeString actual;
1463 UnicodeString expected(ctou("4/26/113 \\u2013 4/28/113"));
1464 FieldPosition pos(FieldPosition::DONT_CARE);
1465 dif->format(*fromTime, *toTime, actual, pos, status);
1466 if (U_FAILURE(status)) {
1467 errln("Failure encountered: %s", u_errorName(status));
1468 return;
1469 }
1470 if (actual != expected) {
1471 errln("Expected " + expected + ", got: " + actual);
1472 }
1473 }
1474 }
1475
expectUserDII(const char ** data,int32_t data_length)1476 void DateIntervalFormatTest::expectUserDII(const char** data,
1477 int32_t data_length) {
1478 int32_t i = 0;
1479 UnicodeString str;
1480 UErrorCode ec = U_ZERO_ERROR;
1481 const char* pattern = data[0];
1482 i++;
1483
1484 while ( i < data_length ) {
1485 const char* locName = data[i++];
1486 Locale loc(locName);
1487 SimpleDateFormat ref(pattern, loc, ec);
1488 if (U_FAILURE(ec)) {
1489 dataerrln("contruct SimpleDateFormat in expectUserDII failed: %s", u_errorName(ec));
1490 return;
1491 }
1492 const char* datestr = data[i++];
1493 const char* datestr_2 = data[i++];
1494 UDate date = ref.parse(ctou(datestr), ec);
1495 if (!assertSuccess("parse in expectUserDII", ec)) return;
1496 UDate date_2 = ref.parse(ctou(datestr_2), ec);
1497 if (!assertSuccess("parse in expectUserDII", ec)) return;
1498 DateInterval dtitv(date, date_2);
1499
1500 ec = U_ZERO_ERROR;
1501 // test user created DateIntervalInfo
1502 DateIntervalInfo* dtitvinf = new DateIntervalInfo(ec);
1503 dtitvinf->setFallbackIntervalPattern("{0} --- {1}", ec);
1504 dtitvinf->setIntervalPattern(UDAT_YEAR_ABBR_MONTH_DAY, UCAL_MONTH, "yyyy MMM d - MMM y",ec);
1505 if (!assertSuccess("DateIntervalInfo::setIntervalPattern", ec)) return;
1506 dtitvinf->setIntervalPattern(UDAT_YEAR_ABBR_MONTH_DAY, UCAL_HOUR_OF_DAY, "yyyy MMM d HH:mm - HH:mm", ec);
1507 if (!assertSuccess("DateIntervalInfo::setIntervalPattern", ec)) return;
1508 DateIntervalFormat* dtitvfmt = DateIntervalFormat::createInstance(UDAT_YEAR_ABBR_MONTH_DAY, loc, *dtitvinf, ec);
1509 delete dtitvinf;
1510 if (!assertSuccess("createInstance(skeleton,dtitvinf) in expectUserDII", ec)) return;
1511 FieldPosition pos(FieldPosition::DONT_CARE);
1512 dtitvfmt->format(&dtitv, str.remove(), pos, ec);
1513 if (!assertSuccess("format in expectUserDII", ec)) return;
1514 assertEquals((UnicodeString)"\"" + locName + "\\" + datestr + "\\" + datestr_2 + "\"", ctou(data[i++]), str);
1515 #ifdef DTIFMTTS_DEBUG
1516 char result[1000];
1517 char mesg[1000];
1518 PRINTMESG("interval format using user defined DateIntervalInfo\n");
1519 str.extract(0, str.length(), result, "UTF-8");
1520 sprintf(mesg, "interval date: %s\n", result);
1521 PRINTMESG(mesg);
1522 #endif
1523 delete dtitvfmt;
1524 }
1525 }
1526
1527
testStress()1528 void DateIntervalFormatTest::testStress() {
1529 if(quick){
1530 logln("Quick mode: Skipping test");
1531 return;
1532 }
1533 const char* DATA[] = {
1534 "yyyy MM dd HH:mm:ss",
1535 "2007 10 10 10:10:10", "2008 10 10 10:10:10",
1536 "2007 10 10 10:10:10", "2007 11 10 10:10:10",
1537 "2007 11 10 10:10:10", "2007 11 20 10:10:10",
1538 "2007 01 10 10:00:10", "2007 01 10 14:10:10",
1539 "2007 01 10 10:00:10", "2007 01 10 10:20:10",
1540 "2007 01 10 10:10:10", "2007 01 10 10:10:20",
1541 };
1542
1543 const char* testLocale[][3] = {
1544 //{"th", "", ""},
1545 {"en", "", ""},
1546 {"zh", "", ""},
1547 {"de", "", ""},
1548 {"ar", "", ""},
1549 {"en", "GB", ""},
1550 {"fr", "", ""},
1551 {"it", "", ""},
1552 {"nl", "", ""},
1553 {"zh", "TW", ""},
1554 {"ja", "", ""},
1555 {"pt", "BR", ""},
1556 {"ru", "", ""},
1557 {"pl", "", ""},
1558 {"tr", "", ""},
1559 {"es", "", ""},
1560 {"ko", "", ""},
1561 {"sv", "", ""},
1562 {"fi", "", ""},
1563 {"da", "", ""},
1564 {"pt", "PT", ""},
1565 {"ro", "", ""},
1566 {"hu", "", ""},
1567 {"he", "", ""},
1568 {"in", "", ""},
1569 {"cs", "", ""},
1570 {"el", "", ""},
1571 {"no", "", ""},
1572 {"vi", "", ""},
1573 {"bg", "", ""},
1574 {"hr", "", ""},
1575 {"lt", "", ""},
1576 {"sk", "", ""},
1577 {"sl", "", ""},
1578 {"sr", "", ""},
1579 {"ca", "", ""},
1580 {"lv", "", ""},
1581 {"uk", "", ""},
1582 {"hi", "", ""},
1583 };
1584
1585 uint32_t localeIndex;
1586 for ( localeIndex = 0; localeIndex < UPRV_LENGTHOF(testLocale); ++localeIndex ) {
1587 char locName[32];
1588 uprv_strcpy(locName, testLocale[localeIndex][0]);
1589 uprv_strcat(locName, testLocale[localeIndex][1]);
1590 stress(DATA, UPRV_LENGTHOF(DATA), Locale(testLocale[localeIndex][0], testLocale[localeIndex][1], testLocale[localeIndex][2]), locName);
1591 }
1592 }
1593
1594
stress(const char ** data,int32_t data_length,const Locale & loc,const char * locName)1595 void DateIntervalFormatTest::stress(const char** data, int32_t data_length,
1596 const Locale& loc, const char* locName) {
1597 UnicodeString skeleton[] = {
1598 "EEEEdMMMMy",
1599 "dMMMMy",
1600 "dMMMM",
1601 "MMMMy",
1602 "EEEEdMMMM",
1603 "EdMMMy",
1604 "dMMMy",
1605 "dMMM",
1606 "MMMy",
1607 "EdMMM",
1608 "EdMy",
1609 "dMy",
1610 "dM",
1611 "My",
1612 "EdM",
1613 "d",
1614 "Ed",
1615 "y",
1616 "M",
1617 "MMM",
1618 "MMMM",
1619 "hm",
1620 "hmv",
1621 "hmz",
1622 "h",
1623 "hv",
1624 "hz",
1625 "EEddMMyyyy", // following could be normalized
1626 "EddMMy",
1627 "hhmm",
1628 "hhmmzz",
1629 "hms", // following could not be normalized
1630 "dMMMMMy",
1631 "EEEEEdM",
1632 };
1633
1634 int32_t i = 0;
1635 UErrorCode ec = U_ZERO_ERROR;
1636 UnicodeString str, str2;
1637 SimpleDateFormat ref(data[i++], loc, ec);
1638 if (!assertSuccess("construct SimpleDateFormat", ec)) return;
1639
1640 #ifdef DTIFMTTS_DEBUG
1641 char result[1000];
1642 char mesg[1000];
1643 sprintf(mesg, "locale: %s\n", locName);
1644 PRINTMESG(mesg);
1645 #endif
1646
1647 while (i<data_length) {
1648
1649 // 'f'
1650 const char* datestr = data[i++];
1651 const char* datestr_2 = data[i++];
1652 #ifdef DTIFMTTS_DEBUG
1653 sprintf(mesg, "original date: %s - %s\n", datestr, datestr_2);
1654 PRINTMESG(mesg)
1655 #endif
1656 UDate date = ref.parse(ctou(datestr), ec);
1657 if (!assertSuccess("parse", ec)) return;
1658 UDate date_2 = ref.parse(ctou(datestr_2), ec);
1659 if (!assertSuccess("parse", ec)) return;
1660 DateInterval dtitv(date, date_2);
1661
1662 for ( uint32_t skeletonIndex = 0;
1663 skeletonIndex < UPRV_LENGTHOF(skeleton);
1664 ++skeletonIndex ) {
1665 const UnicodeString& oneSkeleton = skeleton[skeletonIndex];
1666 DateIntervalFormat* dtitvfmt = DateIntervalFormat::createInstance(oneSkeleton, loc, ec);
1667 if (!assertSuccess("createInstance(skeleton)", ec)) return;
1668 /*
1669 // reset the calendar to be Gregorian calendar for "th"
1670 if ( uprv_strcmp(locName, "th") == 0 ) {
1671 GregorianCalendar* gregCal = new GregorianCalendar(loc, ec);
1672 if (!assertSuccess("GregorianCalendar()", ec)) return;
1673 const DateFormat* dformat = dtitvfmt->getDateFormat();
1674 DateFormat* newOne = dformat->clone();
1675 newOne->adoptCalendar(gregCal);
1676 //dtitvfmt->adoptDateFormat(newOne, ec);
1677 dtitvfmt->setDateFormat(*newOne, ec);
1678 delete newOne;
1679 if (!assertSuccess("adoptDateFormat()", ec)) return;
1680 }
1681 */
1682 FieldPosition pos(FieldPosition::DONT_CARE);
1683 dtitvfmt->format(&dtitv, str.remove(), pos, ec);
1684 if (!assertSuccess("format", ec)) return;
1685 #ifdef DTIFMTTS_DEBUG
1686 oneSkeleton.extract(0, oneSkeleton.length(), result, "UTF-8");
1687 sprintf(mesg, "interval by skeleton: %s\n", result);
1688 PRINTMESG(mesg)
1689 str.extract(0, str.length(), result, "UTF-8");
1690 sprintf(mesg, "interval date: %s\n", result);
1691 PRINTMESG(mesg)
1692 #endif
1693 delete dtitvfmt;
1694 }
1695
1696 // test user created DateIntervalInfo
1697 ec = U_ZERO_ERROR;
1698 DateIntervalInfo* dtitvinf = new DateIntervalInfo(ec);
1699 dtitvinf->setFallbackIntervalPattern("{0} --- {1}", ec);
1700 dtitvinf->setIntervalPattern(UDAT_YEAR_ABBR_MONTH_DAY, UCAL_MONTH, "yyyy MMM d - MMM y",ec);
1701 if (!assertSuccess("DateIntervalInfo::setIntervalPattern", ec)) return;
1702 dtitvinf->setIntervalPattern(UDAT_YEAR_ABBR_MONTH_DAY, UCAL_HOUR_OF_DAY, "yyyy MMM d HH:mm - HH:mm", ec);
1703 if (!assertSuccess("DateIntervalInfo::setIntervalPattern", ec)) return;
1704 DateIntervalFormat* dtitvfmt = DateIntervalFormat::createInstance(UDAT_YEAR_ABBR_MONTH_DAY, loc, *dtitvinf, ec);
1705 delete dtitvinf;
1706 if (!assertSuccess("createInstance(skeleton,dtitvinf)", ec)) return;
1707 FieldPosition pos(FieldPosition::DONT_CARE);
1708 dtitvfmt->format(&dtitv, str.remove(), pos, ec);
1709 if ( uprv_strcmp(locName, "th") ) {
1710 if (!assertSuccess("format", ec)) return;
1711 #ifdef DTIFMTTS_DEBUG
1712 PRINTMESG("interval format using user defined DateIntervalInfo\n");
1713 str.extract(0, str.length(), result, "UTF-8");
1714 sprintf(mesg, "interval date: %s\n", result);
1715 PRINTMESG(mesg)
1716 #endif
1717 } else {
1718 // for "th", the default calendar is Budhist,
1719 // not Gregorian.
1720 assertTrue("Default calendar for \"th\" is Budhist", ec == U_ILLEGAL_ARGUMENT_ERROR);
1721 ec = U_ZERO_ERROR;
1722 }
1723 delete dtitvfmt;
1724 }
1725 }
1726
testTicket11583_2()1727 void DateIntervalFormatTest::testTicket11583_2() {
1728 UErrorCode status = U_ZERO_ERROR;
1729 LocalPointer<DateIntervalFormat> fmt(
1730 DateIntervalFormat::createInstance("yMMM", "es-US", status));
1731 if (!assertSuccess("Error create format object", status)) {
1732 return;
1733 }
1734 DateInterval interval((UDate) 1232364615000.0, (UDate) 1328787015000.0);
1735 UnicodeString appendTo;
1736 FieldPosition fpos(FieldPosition::DONT_CARE);
1737 UnicodeString expected("ene de 2009 \\u2013 feb de 2012");
1738 assertEquals(
1739 "",
1740 expected.unescape(),
1741 fmt->format(&interval, appendTo, fpos, status));
1742 if (!assertSuccess("Error formatting", status)) {
1743 return;
1744 }
1745 }
1746
1747
testTicket11985()1748 void DateIntervalFormatTest::testTicket11985() {
1749 UErrorCode status = U_ZERO_ERROR;
1750 LocalPointer<DateIntervalFormat> fmt(
1751 DateIntervalFormat::createInstance(UDAT_HOUR_MINUTE, Locale::getEnglish(), status));
1752 if (!assertSuccess("createInstance", status)) {
1753 return;
1754 }
1755 UnicodeString pattern;
1756 static_cast<const SimpleDateFormat*>(fmt->getDateFormat())->toPattern(pattern);
1757 assertEquals("Format pattern", "h:mm a", pattern);
1758 }
1759
1760 // Ticket 11669 - thread safety of DateIntervalFormat::format(). This test failed before
1761 // the implementation was fixed.
1762
1763 static const DateIntervalFormat *gIntervalFormatter = NULL; // The Formatter to be used concurrently by test threads.
1764 static const DateInterval *gInterval = NULL; // The date interval to be formatted concurrently.
1765 static const UnicodeString *gExpectedResult = NULL;
1766
threadFunc11669(int32_t threadNum)1767 void DateIntervalFormatTest::threadFunc11669(int32_t threadNum) {
1768 (void)threadNum;
1769 for (int loop=0; loop<1000; ++loop) {
1770 UErrorCode status = U_ZERO_ERROR;
1771 FieldPosition pos(FieldPosition::DONT_CARE);
1772 UnicodeString result;
1773 gIntervalFormatter->format(gInterval, result, pos, status);
1774 if (U_FAILURE(status)) {
1775 errln("%s:%d %s", __FILE__, __LINE__, u_errorName(status));
1776 return;
1777 }
1778 if (result != *gExpectedResult) {
1779 errln("%s:%d Expected \"%s\", got \"%s\"", __FILE__, __LINE__, CStr(*gExpectedResult)(), CStr(result)());
1780 return;
1781 }
1782 }
1783 }
1784
testTicket11669()1785 void DateIntervalFormatTest::testTicket11669() {
1786 UErrorCode status = U_ZERO_ERROR;
1787 LocalPointer<DateIntervalFormat> formatter(DateIntervalFormat::createInstance(UDAT_YEAR_MONTH_DAY, Locale::getEnglish(), status), status);
1788 LocalPointer<TimeZone> tz(TimeZone::createTimeZone("America/Los_Angleles"), status);
1789 LocalPointer<Calendar> intervalStart(Calendar::createInstance(*tz, Locale::getEnglish(), status), status);
1790 LocalPointer<Calendar> intervalEnd(Calendar::createInstance(*tz, Locale::getEnglish(), status), status);
1791 if (U_FAILURE(status)) {
1792 errcheckln(status, "%s:%d %s", __FILE__, __LINE__, u_errorName(status));
1793 return;
1794 }
1795
1796 intervalStart->set(2009, 6, 1, 14, 0);
1797 intervalEnd->set(2009, 6, 2, 14, 0);
1798 DateInterval interval(intervalStart->getTime(status), intervalEnd->getTime(status));
1799 FieldPosition pos(FieldPosition::DONT_CARE);
1800 UnicodeString expectedResult;
1801 formatter->format(&interval, expectedResult, pos, status);
1802 if (U_FAILURE(status)) {
1803 errln("%s:%d %s", __FILE__, __LINE__, u_errorName(status));
1804 return;
1805 }
1806
1807 gInterval = &interval;
1808 gIntervalFormatter = formatter.getAlias();
1809 gExpectedResult = &expectedResult;
1810
1811 ThreadPool<DateIntervalFormatTest> threads(this, 4, &DateIntervalFormatTest::threadFunc11669);
1812 threads.start();
1813 threads.join();
1814
1815 gInterval = NULL; // Don't leave dangling pointers lying around. Not strictly necessary.
1816 gIntervalFormatter = NULL;
1817 gExpectedResult = NULL;
1818 }
1819
1820
1821 // testTicket12065
1822 // Using a DateIntervalFormat to format shouldn't change its state in any way
1823 // that changes how the behavior of operator ==.
testTicket12065()1824 void DateIntervalFormatTest::testTicket12065() {
1825 UErrorCode status = U_ZERO_ERROR;
1826 LocalPointer<DateIntervalFormat> formatter(DateIntervalFormat::createInstance(UDAT_YEAR_MONTH_DAY, Locale::getEnglish(), status), status);
1827 if (formatter.isNull()) {
1828 dataerrln("FAIL: DateIntervalFormat::createInstance failed for Locale::getEnglish()");
1829 return;
1830 }
1831 LocalPointer<DateIntervalFormat> clone(formatter->clone());
1832 if (*formatter != *clone) {
1833 errln("%s:%d DateIntervalFormat and clone are not equal.", __FILE__, __LINE__);
1834 return;
1835 }
1836 DateInterval interval((UDate) 1232364615000.0, (UDate) 1328787015000.0);
1837 UnicodeString appendTo;
1838 FieldPosition fpos(FieldPosition::DONT_CARE);
1839 formatter->format(&interval, appendTo, fpos, status);
1840 if (*formatter != *clone) {
1841 errln("%s:%d DateIntervalFormat and clone are not equal after formatting.", __FILE__, __LINE__);
1842 return;
1843 }
1844 if (U_FAILURE(status)) {
1845 errln("%s:%d %s", __FILE__, __LINE__, u_errorName(status));
1846 }
1847 }
1848
1849
testFormattedDateInterval()1850 void DateIntervalFormatTest::testFormattedDateInterval() {
1851 IcuTestErrorCode status(*this, "testFormattedDateInterval");
1852 LocalPointer<DateIntervalFormat> fmt(DateIntervalFormat::createInstance(u"dMMMMy", "en-US", status), status);
1853
1854 {
1855 const char16_t* message = u"FormattedDateInterval test 1";
1856 const char16_t* expectedString = u"July 20 \u2013 25, 2018";
1857 LocalPointer<Calendar> input1(Calendar::createInstance("en-GB", status));
1858 if (status.errIfFailureAndReset()) { return; }
1859 LocalPointer<Calendar> input2(Calendar::createInstance("en-GB", status));
1860 if (status.errIfFailureAndReset()) { return; }
1861 input1->set(2018, 6, 20);
1862 input2->set(2018, 6, 25);
1863 FormattedDateInterval result = fmt->formatToValue(*input1, *input2, status);
1864 static const UFieldPositionWithCategory expectedFieldPositions[] = {
1865 // field, begin index, end index
1866 {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 0, 4},
1867 {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 0, 5, 7},
1868 {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 5, 7},
1869 {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 1, 10, 12},
1870 {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 10, 12},
1871 {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 14, 18}};
1872 checkMixedFormattedValue(
1873 message,
1874 result,
1875 expectedString,
1876 expectedFieldPositions,
1877 UPRV_LENGTHOF(expectedFieldPositions));
1878 }
1879
1880 {
1881 const char16_t* message = u"FormattedDateInterval identical dates test: no span field";
1882 const char16_t* expectedString = u"July 20, 2018";
1883 LocalPointer<Calendar> input1(Calendar::createInstance("en-GB", status));
1884 input1->set(2018, 6, 20);
1885 FormattedDateInterval result = fmt->formatToValue(*input1, *input1, status);
1886 static const UFieldPositionWithCategory expectedFieldPositions[] = {
1887 // field, begin index, end index
1888 {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 0, 4},
1889 {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 5, 7},
1890 {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 9, 13}};
1891 checkMixedFormattedValue(
1892 message,
1893 result,
1894 expectedString,
1895 expectedFieldPositions,
1896 UPRV_LENGTHOF(expectedFieldPositions));
1897 }
1898
1899 // Test sample code
1900 {
1901 LocalPointer<Calendar> input1(Calendar::createInstance("en-GB", status));
1902 LocalPointer<Calendar> input2(Calendar::createInstance("en-GB", status));
1903 input1->set(2018, 6, 20);
1904 input2->set(2018, 7, 3);
1905
1906 // Let fmt be a DateIntervalFormat for locale en-US and skeleton dMMMMy
1907 // Let input1 be July 20, 2018 and input2 be August 3, 2018:
1908 FormattedDateInterval result = fmt->formatToValue(*input1, *input2, status);
1909 assertEquals("Expected output from format",
1910 u"July 20 \u2013 August 3, 2018", result.toString(status));
1911 ConstrainedFieldPosition cfpos;
1912 cfpos.constrainField(UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 0);
1913 if (result.nextPosition(cfpos, status)) {
1914 assertEquals("Expect start index", 0, cfpos.getStart());
1915 assertEquals("Expect end index", 7, cfpos.getLimit());
1916 } else {
1917 // No such span: can happen if input dates are equal.
1918 }
1919 assertFalse("No more than one occurrence of the field",
1920 result.nextPosition(cfpos, status));
1921 }
1922
1923 // To test the fallback pattern behavior, make a custom DateIntervalInfo.
1924 DateIntervalInfo dtitvinf(status);
1925 dtitvinf.setFallbackIntervalPattern("<< {1} --- {0} >>", status);
1926 fmt.adoptInsteadAndCheckErrorCode(
1927 DateIntervalFormat::createInstance(u"dMMMMy", "en-US", dtitvinf, status),
1928 status);
1929
1930 {
1931 const char16_t* message = u"FormattedDateInterval with fallback format test 1";
1932 const char16_t* expectedString = u"<< July 25, 2018 --- July 20, 2018 >>";
1933 LocalPointer<Calendar> input1(Calendar::createInstance("en-GB", status));
1934 if (status.errIfFailureAndReset()) { return; }
1935 LocalPointer<Calendar> input2(Calendar::createInstance("en-GB", status));
1936 if (status.errIfFailureAndReset()) { return; }
1937 input1->set(2018, 6, 20);
1938 input2->set(2018, 6, 25);
1939 FormattedDateInterval result = fmt->formatToValue(*input1, *input2, status);
1940 static const UFieldPositionWithCategory expectedFieldPositions[] = {
1941 // field, begin index, end index
1942 {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 1, 3, 16},
1943 {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 3, 7},
1944 {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 8, 10},
1945 {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 12, 16},
1946 {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 0, 21, 34},
1947 {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 21, 25},
1948 {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 26, 28},
1949 {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 30, 34}};
1950 checkMixedFormattedValue(
1951 message,
1952 result,
1953 expectedString,
1954 expectedFieldPositions,
1955 UPRV_LENGTHOF(expectedFieldPositions));
1956 }
1957 }
1958
testCreateInstanceForAllLocales()1959 void DateIntervalFormatTest::testCreateInstanceForAllLocales() {
1960 IcuTestErrorCode status(*this, "testCreateInstanceForAllLocales");
1961 int32_t locale_count = 0;
1962 const Locale* locales = icu::Locale::getAvailableLocales(locale_count);
1963 // Iterate through all locales
1964 for (int32_t i = 0; i < locale_count; i++) {
1965 std::unique_ptr<icu::StringEnumeration> calendars(
1966 icu::Calendar::getKeywordValuesForLocale(
1967 "calendar", locales[i], FALSE, status));
1968 int32_t calendar_count = calendars->count(status);
1969 if (status.errIfFailureAndReset()) { break; }
1970 // In quick mode, only run 1/5 of locale combination
1971 // to make the test run faster.
1972 if (quick && (i % 5 != 0)) continue;
1973 LocalPointer<DateIntervalFormat> fmt(
1974 DateIntervalFormat::createInstance(u"dMMMMy", locales[i], status),
1975 status);
1976 if (status.errIfFailureAndReset(locales[i].getName())) {
1977 continue;
1978 }
1979 // Iterate through all calendars in this locale
1980 for (int32_t j = 0; j < calendar_count; j++) {
1981 // In quick mode, only run 1/7 of locale/calendar combination
1982 // to make the test run faster.
1983 if (quick && ((i * j) % 7 != 0)) continue;
1984 const char* calendar = calendars->next(nullptr, status);
1985 Locale locale(locales[i]);
1986 locale.setKeywordValue("calendar", calendar, status);
1987 fmt.adoptInsteadAndCheckErrorCode(
1988 DateIntervalFormat::createInstance(u"dMMMMy", locale, status),
1989 status);
1990 status.errIfFailureAndReset(locales[i].getName());
1991 }
1992 }
1993 }
1994
testFormatMillisecond()1995 void DateIntervalFormatTest::testFormatMillisecond() {
1996 struct
1997 {
1998 int year;
1999 int month;
2000 int day;
2001 int from_hour;
2002 int from_miniute;
2003 int from_second;
2004 int from_millisecond;
2005 int to_hour;
2006 int to_miniute;
2007 int to_second;
2008 int to_millisecond;
2009 const char* skeleton;
2010 const char16_t* expected;
2011 }
2012 kTestCases [] =
2013 {
2014 // From To
2015 // y m d h m s ms h m s ms skeleton expected
2016 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "ms", u"23:45"},
2017 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "msS", u"23:45.3"},
2018 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "msSS", u"23:45.32"},
2019 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "msSSS", u"23:45.321"},
2020 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "ms", u"23:45"},
2021 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "msS", u"23:45.3 \u2013 23:45.9"},
2022 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "msSS", u"23:45.32 \u2013 23:45.98"},
2023 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "msSSS", u"23:45.321 \u2013 23:45.987"},
2024 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "ms", u"23:45 \u2013 23:46"},
2025 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "msS", u"23:45.3 \u2013 23:46.9"},
2026 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "msSS", u"23:45.32 \u2013 23:46.98"},
2027 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "msSSS", u"23:45.321 \u2013 23:46.987"},
2028 { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "ms", u"23:45 \u2013 24:45"},
2029 { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "msS", u"23:45.3 \u2013 24:45.9"},
2030 { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "msSS", u"23:45.32 \u2013 24:45.98"},
2031 { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "msSSS", u"23:45.321 \u2013 24:45.987"},
2032 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "s", u"45"},
2033 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "sS", u"45.3"},
2034 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "sSS", u"45.32"},
2035 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "sSSS", u"45.321"},
2036 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "s", u"45"},
2037 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "sS", u"45.3 \u2013 45.9"},
2038 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "sSS", u"45.32 \u2013 45.98"},
2039 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "sSSS", u"45.321 \u2013 45.987"},
2040 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "s", u"45 \u2013 46"},
2041 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "sS", u"45.3 \u2013 46.9"},
2042 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "sSS", u"45.32 \u2013 46.98"},
2043 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "sSSS", u"45.321 \u2013 46.987"},
2044 { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "s", u"45 \u2013 45"},
2045 { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "sS", u"45.3 \u2013 45.9"},
2046 { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "sSS", u"45.32 \u2013 45.98"},
2047 { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "sSSS", u"45.321 \u2013 45.987"},
2048 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "S", u"3"},
2049 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "SS", u"32"},
2050 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "SSS", u"321"},
2051
2052 // Same millisecond but in different second.
2053 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 321, "S", u"3 \u2013 3"},
2054 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 321, "SS", u"32 \u2013 32"},
2055 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 321, "SSS", u"321 \u2013 321"},
2056
2057 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "S", u"3 \u2013 9"},
2058 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "SS", u"32 \u2013 98"},
2059 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "SSS", u"321 \u2013 987"},
2060 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "S", u"3 \u2013 9"},
2061 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "SS", u"32 \u2013 98"},
2062 { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "SSS", u"321 \u2013 987"},
2063 { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "S", u"3 \u2013 9"},
2064 { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "SS", u"32 \u2013 98"},
2065 { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "SSS", u"321 \u2013 987"},
2066 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr, nullptr},
2067 };
2068
2069 const Locale &enLocale = Locale::getEnglish();
2070 IcuTestErrorCode status(*this, "testFormatMillisecond");
2071 LocalPointer<Calendar> calendar(Calendar::createInstance(enLocale, status));
2072 if (status.errIfFailureAndReset()) { return; }
2073
2074 for (int32_t i = 0; kTestCases[i].year > 0; i++) {
2075 LocalPointer<DateIntervalFormat> fmt(DateIntervalFormat::createInstance(
2076 kTestCases[i].skeleton, enLocale, status));
2077 if (status.errIfFailureAndReset()) { continue; }
2078
2079 calendar->clear();
2080 calendar->set(kTestCases[i].year, kTestCases[i].month, kTestCases[i].day,
2081 kTestCases[i].from_hour, kTestCases[i].from_miniute, kTestCases[i].from_second);
2082 UDate from = calendar->getTime(status) + kTestCases[i].from_millisecond;
2083 if (status.errIfFailureAndReset()) { continue; }
2084
2085 calendar->clear();
2086 calendar->set(kTestCases[i].year, kTestCases[i].month, kTestCases[i].day,
2087 kTestCases[i].to_hour, kTestCases[i].to_miniute, kTestCases[i].to_second);
2088 UDate to = calendar->getTime(status) + kTestCases[i].to_millisecond;
2089 FormattedDateInterval res = fmt->formatToValue(DateInterval(from, to), status);
2090 if (status.errIfFailureAndReset()) { continue; }
2091
2092 UnicodeString formatted = res.toString(status);
2093 if (status.errIfFailureAndReset()) { continue; }
2094 if (formatted != kTestCases[i].expected) {
2095 std::string tmp1;
2096 std::string tmp2;
2097 errln("Case %d for skeleton %s : Got %s but expect %s",
2098 i, kTestCases[i].skeleton, formatted.toUTF8String<std::string>(tmp1).c_str(),
2099 UnicodeString(kTestCases[i].expected).toUTF8String<std::string>(tmp2).c_str());
2100 }
2101 }
2102 }
2103
testTicket20707()2104 void DateIntervalFormatTest::testTicket20707() {
2105 IcuTestErrorCode status(*this, "testTicket20707");
2106
2107 const char16_t timeZone[] = u"UTC";
2108 Locale locales[] = {"en-u-hc-h24", "en-u-hc-h23", "en-u-hc-h12", "en-u-hc-h11", "en", "en-u-hc-h25", "hi-IN-u-hc-h11"};
2109
2110 // Clomuns: hh, HH, kk, KK, jj, JJs, CC
2111 UnicodeString expected[][7] = {
2112 // Hour-cycle: k
2113 {u"12 AM", u"24", u"24", u"12 AM", u"24", u"0 (hour: 24)", u"12 AM"},
2114 // Hour-cycle: H
2115 {u"12 AM", u"00", u"00", u"12 AM", u"00", u"0 (hour: 00)", u"12 AM"},
2116 // Hour-cycle: h
2117 {u"12 AM", u"00", u"00", u"12 AM", u"12 AM", u"0 (hour: 12)", u"12 AM"},
2118 // Hour-cycle: K
2119 {u"0 AM", u"00", u"00", u"0 AM", u"0 AM", u"0 (hour: 00)", u"0 AM"},
2120 {u"12 AM", u"00", u"00", u"12 AM", u"12 AM", u"0 (hour: 12)", u"12 AM"},
2121 {u"12 AM", u"00", u"00", u"12 AM", u"12 AM", u"0 (hour: 12)", u"12 AM"},
2122 // Hour-cycle: K
2123 {u"0 am", u"00", u"00", u"0 am", u"0 am", u"0 (\u0918\u0902\u091F\u093E: 00)", u"\u0930\u093E\u0924 0"}
2124 };
2125
2126 int32_t i = 0;
2127 for (Locale locale : locales) {
2128 int32_t j = 0;
2129 for (const UnicodeString skeleton : {u"hh", u"HH", u"kk", u"KK", u"jj", u"JJs", u"CC"}) {
2130 LocalPointer<DateIntervalFormat> dtifmt(DateIntervalFormat::createInstance(skeleton, locale, status));
2131 if (status.errDataIfFailureAndReset()) {
2132 continue;
2133 }
2134 FieldPosition fposition;
2135 UnicodeString result;
2136 LocalPointer<Calendar> calendar(Calendar::createInstance(TimeZone::createTimeZone(timeZone), status));
2137 calendar->setTime(UDate(1563235200000), status);
2138 dtifmt->format(*calendar, *calendar, result, fposition, status);
2139
2140 assertEquals("Formatted result", expected[i][j++], result);
2141 }
2142 i++;
2143 }
2144 }
2145
getCategoryAndField(const FormattedDateInterval & formatted,std::vector<int32_t> & categories,std::vector<int32_t> & fields,IcuTestErrorCode & status)2146 void DateIntervalFormatTest::getCategoryAndField(
2147 const FormattedDateInterval& formatted,
2148 std::vector<int32_t>& categories,
2149 std::vector<int32_t>& fields,
2150 IcuTestErrorCode& status) {
2151 categories.clear();
2152 fields.clear();
2153 ConstrainedFieldPosition cfpos;
2154 while (formatted.nextPosition(cfpos, status)) {
2155 categories.push_back(cfpos.getCategory());
2156 fields.push_back(cfpos.getField());
2157 }
2158 }
2159
verifyCategoryAndField(const FormattedDateInterval & formatted,const std::vector<int32_t> & categories,const std::vector<int32_t> & fields,IcuTestErrorCode & status)2160 void DateIntervalFormatTest::verifyCategoryAndField(
2161 const FormattedDateInterval& formatted,
2162 const std::vector<int32_t>& categories,
2163 const std::vector<int32_t>& fields,
2164 IcuTestErrorCode& status) {
2165 ConstrainedFieldPosition cfpos;
2166 int32_t i = 0;
2167 while (formatted.nextPosition(cfpos, status)) {
2168 assertEquals("Category", cfpos.getCategory(), categories[i]);
2169 assertEquals("Field", cfpos.getField(), fields[i]);
2170 i++;
2171 }
2172 }
2173
testTicket21222GregorianEraDiff()2174 void DateIntervalFormatTest::testTicket21222GregorianEraDiff() {
2175 IcuTestErrorCode status(*this, "testTicket21222GregorianEraDiff");
2176
2177 LocalPointer<Calendar> cal(Calendar::createInstance(*TimeZone::getGMT(), status));
2178 if (U_FAILURE(status)) {
2179 errln("Failure encountered: %s", u_errorName(status));
2180 return;
2181 }
2182 std::vector<int32_t> expectedCategory;
2183 std::vector<int32_t> expectedField;
2184
2185 // Test Gregorian calendar
2186 LocalPointer<DateIntervalFormat> g(
2187 DateIntervalFormat::createInstance(
2188 u"h", Locale("en"), status));
2189 if (U_FAILURE(status)) {
2190 errln("Failure encountered: %s", u_errorName(status));
2191 return;
2192 }
2193 g->setTimeZone(*(TimeZone::getGMT()));
2194 cal->setTime(Calendar::getNow(), status);
2195 cal->set(123, UCAL_APRIL, 5, 6, 0);
2196 FormattedDateInterval formatted;
2197
2198 UDate date0123Apr5AD = cal->getTime(status);
2199
2200 cal->set(UCAL_YEAR, 124);
2201 UDate date0124Apr5AD = cal->getTime(status);
2202
2203 cal->set(UCAL_ERA, 0);
2204 UDate date0124Apr5BC = cal->getTime(status);
2205
2206 cal->set(UCAL_YEAR, 123);
2207 UDate date0123Apr5BC = cal->getTime(status);
2208
2209 DateInterval bothAD(date0123Apr5AD, date0124Apr5AD);
2210 DateInterval bothBC(date0124Apr5BC, date0123Apr5BC);
2211 DateInterval BCtoAD(date0123Apr5BC, date0124Apr5AD);
2212
2213 formatted = g->formatToValue(bothAD, status);
2214 assertEquals("Gregorian - calendar both dates in AD",
2215 u"4/5/123, 6 AM \u2013 4/5/124, 6 AM",
2216 formatted.toString(status));
2217
2218 formatted = g->formatToValue(bothBC, status);
2219 assertEquals("Gregorian - calendar both dates in BC",
2220 u"4/5/124, 6 AM \u2013 4/5/123, 6 AM",
2221 formatted.toString(status));
2222
2223 formatted = g->formatToValue(BCtoAD, status);
2224 assertEquals("Gregorian - BC to AD",
2225 u"4/5/123 B, 6 AM \u2013 4/5/124 A, 6 AM",
2226 formatted.toString(status));
2227 }
2228
testTicket21222ROCEraDiff()2229 void DateIntervalFormatTest::testTicket21222ROCEraDiff() {
2230 IcuTestErrorCode status(*this, "testTicket21222ROCEraDiff");
2231
2232 LocalPointer<Calendar> cal(Calendar::createInstance(*TimeZone::getGMT(), status));
2233 if (U_FAILURE(status)) {
2234 errln("Failure encountered: %s", u_errorName(status));
2235 return;
2236 }
2237 std::vector<int32_t> expectedCategory;
2238 std::vector<int32_t> expectedField;
2239
2240 // Test roc calendar
2241 LocalPointer<DateIntervalFormat> roc(
2242 DateIntervalFormat::createInstance(
2243 u"h", Locale("zh-Hant-TW@calendar=roc"), status));
2244 if (U_FAILURE(status)) {
2245 errln("Failure encountered: %s", u_errorName(status));
2246 return;
2247 }
2248 roc->setTimeZone(*(TimeZone::getGMT()));
2249
2250 FormattedDateInterval formatted;
2251 // set date1910Jan2 to 1910/1/2 AD which is prior to MG
2252 cal->set(1910, UCAL_JANUARY, 2, 6, 0);
2253 UDate date1910Jan2 = cal->getTime(status);
2254
2255 // set date1911Jan2 to 1911/1/2 AD which is also prior to MG
2256 cal->set(UCAL_YEAR, 1911);
2257 UDate date1911Jan2 = cal->getTime(status);
2258
2259 // set date1912Jan2 to 1912/1/2 AD which is after MG
2260 cal->set(UCAL_YEAR, 1912);
2261 UDate date1912Jan2 = cal->getTime(status);
2262
2263 // set date1913Jan2 to 1913/1/2 AD which is also after MG
2264 cal->set(UCAL_YEAR, 1913);
2265 UDate date1913Jan2 = cal->getTime(status);
2266
2267 DateInterval bothBeforeMG(date1910Jan2, date1911Jan2);
2268 DateInterval beforeAfterMG(date1911Jan2, date1913Jan2);
2269 DateInterval bothAfterMG(date1912Jan2, date1913Jan2);
2270
2271 formatted = roc->formatToValue(bothAfterMG, status);
2272 assertEquals("roc calendar - both dates in MG Era",
2273 u"民國1/1/2 上午6時 – 民國2/1/2 上午6時",
2274 formatted.toString(status));
2275 getCategoryAndField(formatted, expectedCategory,
2276 expectedField, status);
2277
2278 formatted = roc->formatToValue(beforeAfterMG, status);
2279 assertEquals("roc calendar - prior MG Era and in MG Era",
2280 u"民國前1/1/2 上午6時 – 民國2/1/2 上午6時",
2281 formatted.toString(status));
2282 verifyCategoryAndField(formatted, expectedCategory, expectedField, status);
2283
2284 formatted = roc->formatToValue(bothBeforeMG, status);
2285 assertEquals("roc calendar - both dates prior MG Era",
2286 u"民國前2/1/2 上午6時 – 民國前1/1/2 上午6時",
2287 formatted.toString(status));
2288 verifyCategoryAndField(formatted, expectedCategory, expectedField, status);
2289 }
2290
testTicket21222JapaneseEraDiff()2291 void DateIntervalFormatTest::testTicket21222JapaneseEraDiff() {
2292 IcuTestErrorCode status(*this, "testTicket21222JapaneseEraDiff");
2293
2294 LocalPointer<Calendar> cal(Calendar::createInstance(*TimeZone::getGMT(), status));
2295 if (U_FAILURE(status)) {
2296 errln("Failure encountered: %s", u_errorName(status));
2297 return;
2298 }
2299 std::vector<int32_t> expectedCategory;
2300 std::vector<int32_t> expectedField;
2301
2302 // Test roc calendar
2303 // Test Japanese calendar
2304 LocalPointer<DateIntervalFormat> japanese(
2305 DateIntervalFormat::createInstance(
2306 u"h", Locale("ja@calendar=japanese"), status));
2307 if (U_FAILURE(status)) {
2308 errln("Failure encountered: %s", u_errorName(status));
2309 return;
2310 }
2311 japanese->setTimeZone(*(TimeZone::getGMT()));
2312
2313 FormattedDateInterval formatted;
2314
2315 cal->set(2019, UCAL_MARCH, 2, 6, 0);
2316 UDate date2019Mar2 = cal->getTime(status);
2317
2318 cal->set(UCAL_MONTH, UCAL_APRIL);
2319 cal->set(UCAL_DAY_OF_MONTH, 3);
2320 UDate date2019Apr3 = cal->getTime(status);
2321
2322 cal->set(UCAL_MONTH, UCAL_MAY);
2323 cal->set(UCAL_DAY_OF_MONTH, 4);
2324 UDate date2019May4 = cal->getTime(status);
2325
2326 cal->set(UCAL_MONTH, UCAL_JUNE);
2327 cal->set(UCAL_DAY_OF_MONTH, 5);
2328 UDate date2019Jun5 = cal->getTime(status);
2329
2330 DateInterval bothBeforeReiwa(date2019Mar2, date2019Apr3);
2331 DateInterval beforeAfterReiwa(date2019Mar2, date2019May4);
2332 DateInterval bothAfterReiwa(date2019May4, date2019Jun5);
2333
2334 formatted = japanese->formatToValue(bothAfterReiwa, status);
2335 assertEquals("japanese calendar - both dates in Reiwa",
2336 u"R1/5/4 午前6時~R1/6/5 午前6時",
2337 formatted.toString(status));
2338 getCategoryAndField(formatted, expectedCategory,
2339 expectedField, status);
2340
2341 formatted = japanese->formatToValue(bothBeforeReiwa, status);
2342 assertEquals("japanese calendar - both dates before Reiwa",
2343 u"H31/3/2 午前6時~H31/4/3 午前6時",
2344 formatted.toString(status));
2345 verifyCategoryAndField(formatted, expectedCategory, expectedField, status);
2346
2347 formatted = japanese->formatToValue(beforeAfterReiwa, status);
2348 assertEquals("japanese calendar - date before and in Reiwa",
2349 u"H31/3/2 午前6時~R1/5/4 午前6時",
2350 formatted.toString(status));
2351 verifyCategoryAndField(formatted, expectedCategory, expectedField, status);
2352 }
2353
2354 #endif /* #if !UCONFIG_NO_FORMATTING */
2355