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