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