• 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) - exitting");
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) - exitting");
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) - exitting");
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) - exitting");
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) - exitting");
267         return;
268     }
269 
270     DateIntervalFormat* dtifmt2 = new(dtifmt);
271     if ( (*dtifmt) != (*dtifmt2) ) {
272         dataerrln("ERROR: Could not create DateIntervalFormat (default) - exitting");
273         return;
274     }
275 
276     DateIntervalFormat dtifmt3 = (*dtifmt);
277     if ( (*dtifmt) != dtifmt3 ) {
278         dataerrln("ERROR: Could not create DateIntervalFormat (default) - exitting");
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 - exitting");
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 - exitting");
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 - exitting");
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 - exitting");
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         "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",
1012 
1013 
1014         "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",
1015 
1016         "th", "BE 2550 10 10 10:10:10", "BE 2551 10 10 10:10:10", "MMMy", "\\u0E15.\\u0E04. 2550 \\u2013 \\u0E15.\\u0E04. 2551",
1017 
1018 
1019         "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",
1020 
1021         "th", "BE 2550 10 10 10:10:10", "BE 2551 10 10 10:10:10", "dMy", "10/10/2550 \\u2013 10/10/2551",
1022 
1023 
1024         "th", "BE 2550 10 10 10:10:10", "BE 2551 10 10 10:10:10", "My", "10/2550 \\u2013 10/2551",
1025 
1026         "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",
1027 
1028 
1029         "th", "BE 2550 10 10 10:10:10", "BE 2551 10 10 10:10:10", "y", "2550\\u20132551",
1030 
1031         "th", "BE 2550 10 10 10:10:10", "BE 2551 10 10 10:10:10", "M", "10/2550 \\u2013 10/2551",
1032 
1033 
1034         "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",
1035 
1036 
1037         "th", "BE 2550 10 10 10:10:10", "BE 2550 11 10 10:10:10", "dMMM", "10 \\u0E15.\\u0E04. \\u2013 10 \\u0E1E.\\u0E22.",
1038 
1039         "th", "BE 2550 10 10 10:10:10", "BE 2550 11 10 10:10:10", "MMMy", "\\u0E15.\\u0E04.\\u2013\\u0E1E.\\u0E22. 2550",
1040 
1041         "th", "2550 10 10 10:10:10", "2550 11 10 10:10:10", "dM", "10/10 \\u2013 10/11",
1042 
1043         "th", "BE 2550 10 10 10:10:10", "BE 2550 11 10 10:10:10", "My", "10/2550 \\u2013 11/2550",
1044 
1045 
1046         "th", "BE 2550 10 10 10:10:10", "BE 2550 11 10 10:10:10", "d", "10/10 \\u2013 10/11",
1047 
1048         "th", "BE 2550 10 10 10:10:10", "BE 2550 11 10 10:10:10", "y", "\\u0E1E.\\u0E28. 2550",
1049 
1050 
1051         "th", "BE 2550 10 10 10:10:10", "BE 2550 11 10 10:10:10", "MMM", "\\u0E15.\\u0E04.\\u2013\\u0E1E.\\u0E22.",
1052 
1053         // Tests for Japanese calendar with eras, including new era in 2019 (Heisei 31 through April 30, then new era)
1054 
1055         "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",
1056 
1057         "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",
1058 
1059         "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",
1060 
1061         "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",
1062 
1063         "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,
1064 
1065         "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,
1066 
1067 
1068         "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",
1069 
1070         "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",
1071 
1072         "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",
1073 
1074         "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",
1075 
1076         "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",
1077 
1078     };
1079     expect(DATA, UPRV_LENGTHOF(DATA));
1080 }
1081 
1082 
1083 /**
1084  * Test handling of hour and day period metacharacters
1085  */
testHourMetacharacters()1086 void DateIntervalFormatTest::testHourMetacharacters() {
1087     // first item is date pattern
1088     // followed by a group of locale/from_data/to_data/skeleton/interval_data
1089     // Note that from_data/to_data are specified using era names from root, for the calendar specified by locale.
1090     const char* DATA[] = {
1091         "GGGGG y MM dd HH:mm:ss", // pattern for from_data/to_data
1092 
1093         // This test is for tickets ICU-21154, ICU-21155, and ICU-21156 and is intended to verify
1094         // that all of the special skeleton characters for hours and day periods work as expected
1095         // with date intervals:
1096         // - If a, b, or B is included in the skeleton, it correctly sets the length of the day-period field
1097         // - If k or K is included, it behaves the same as H or h, except for the difference in the actual
1098         //   number used for the hour.
1099         // - If j is included, it behaves the same as either h or H as appropriate, and multiple j's have the
1100         //   intended effect on the length of the day period field (if there is one)
1101         // - If J is included, it correctly suppresses the day period field if j would include it
1102         // - If C is included, it behaves the same as j and brings up the correct day period field
1103         // - In all cases, if the day period of both ends of the range is the same, you only see it once
1104 
1105         // baseline (h and H)
1106         "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "hh", "12 \\u2013 1 AM",
1107         "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "HH", "00\\u201301 Uhr",
1108 
1109         // k and K (ICU-21154 and ICU-21156)
1110         "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "KK", "0 \\u2013 1 AM",
1111         "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "kk", "24\\u201301 Uhr",
1112 
1113         // different lengths of the 'a' field
1114         "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "ha", "10 AM \\u2013 1 PM",
1115         "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "ha", "12 \\u2013 1 AM",
1116         "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 12:00:00", "haaaaa", "10 a \\u2013 12 p",
1117         "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "haaaaa", "12 \\u2013 1 a",
1118 
1119         // j (ICU-21155)
1120         "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "jj", "10 AM \\u2013 1 PM",
1121         "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "jj", "12 \\u2013 1 AM",
1122         "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "jjjjj", "10 a \\u2013 1 p",
1123         "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "jjjjj", "12 \\u2013 1 a",
1124         "de", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "jj", "10\\u201313 Uhr",
1125         "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "jj", "00\\u201301 Uhr",
1126         "de", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "jjjjj", "10\\u201313 Uhr",
1127         "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "jjjjj", "00\\u201301 Uhr",
1128 
1129         // b and B
1130         "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 12:00:00", "hb", "10 AM \\u2013 12 noon",
1131         "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 12:00:00", "hbbbbb", "10 a \\u2013 12 n",
1132         "en", "CE 2010 09 27 13:00:00", "CE 2010 09 27 14:00:00", "hb", "1 \\u2013 2 PM",
1133         "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",
1134         "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "hB", "12 \\u2013 1 at night",
1135 
1136         // J
1137         "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "J", "10 \\u2013 1",
1138         "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "J", "12 \\u2013 1",
1139         "de", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "J", "10\\u201313 Uhr",
1140         "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "J", "00\\u201301 Uhr",
1141 
1142         // C
1143         // (for English and German, C should do the same thing as j)
1144         "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "CC", "10 AM \\u2013 1 PM",
1145         "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "CC", "12 \\u2013 1 AM",
1146         "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "CCCCC", "10 a \\u2013 1 p",
1147         "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "CCCCC", "12 \\u2013 1 a",
1148         "de", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "CC", "10\\u201313 Uhr",
1149         "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "CC", "00\\u201301 Uhr",
1150         "de", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "CCCCC", "10\\u201313 Uhr",
1151         "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "CCCCC", "00\\u201301 Uhr",
1152         // (for zh_HK and hi_IN, j maps to ha, but C maps to hB)
1153         "zh_HK", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "jj", "\\u4E0A\\u534810\\u6642\\u81F3\\u4E0B\\u53481\\u6642",
1154         "zh_HK", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "jj", "\\u4E0A\\u534812\\u6642\\u81F31\\u6642",
1155         "zh_HK", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "hB", "\\u4E0A\\u534810\\u6642 \\u2013 \\u4E0B\\u53481\\u6642",
1156         "zh_HK", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "hB", "\\u51CC\\u666812\\u20131\\u6642",
1157         "zh_HK", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "CC", "\\u4E0A\\u534810\\u6642 \\u2013 \\u4E0B\\u53481\\u6642",
1158         "zh_HK", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "CC", "\\u51CC\\u666812\\u20131\\u6642",
1159         "hi_IN", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "jj", "10 am \\u2013 1 pm",
1160         "hi_IN", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "jj", "12\\u20131 am",
1161         "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",
1162         "hi_IN", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "hB", "\\u0930\\u093E\\u0924 12\\u20131",
1163         "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",
1164         "hi_IN", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "CC", "\\u0930\\u093E\\u0924 12\\u20131",
1165 
1166          // regression test for ICU-21342
1167          "en_GB", "CE 2010 09 27 00:00:00", "CE 2010 09 27 10:00:00", "kk", "24\\u201310",
1168          "en_GB", "CE 2010 09 27 00:00:00", "CE 2010 09 27 11:00:00", "kk", "24\\u201311",
1169          "en_GB", "CE 2010 09 27 00:00:00", "CE 2010 09 27 12:00:00", "kk", "24\\u201312",
1170          "en_GB", "CE 2010 09 27 00:00:00", "CE 2010 09 27 13:00:00", "kk", "24\\u201313",
1171 
1172          // regression test for ICU-21343
1173          "de", "CE 2010 09 27 01:00:00", "CE 2010 09 27 10:00:00", "KK", "1 \\u2013 10 Uhr AM",
1174     };
1175     expect(DATA, UPRV_LENGTHOF(DATA));
1176 }
1177 
1178 
expect(const char ** data,int32_t data_length)1179 void DateIntervalFormatTest::expect(const char** data, int32_t data_length) {
1180     int32_t i = 0;
1181     UErrorCode ec = U_ZERO_ERROR;
1182     UnicodeString str, str2;
1183     const char* pattern = data[i++];
1184 
1185     while (i<data_length) {
1186         const char* locName = data[i++];
1187         const char* datestr = data[i++];
1188         const char* datestr_2 = data[i++];
1189 
1190         Locale loc(locName);
1191         LocalPointer<Calendar> defCal(Calendar::createInstance(loc, ec));
1192         if (U_FAILURE(ec)) {
1193             dataerrln("Calendar::createInstance fails for loc %s with: %s", locName, u_errorName(ec));
1194             return;
1195         }
1196         const char* calType = defCal->getType();
1197 
1198         Locale refLoc("root");
1199         if (calType) {
1200             refLoc.setKeywordValue("calendar", calType, ec);
1201         }
1202         SimpleDateFormat ref(pattern, refLoc, ec);
1203         logln( "case %d, locale: %s\n", (i-1)/5, locName);
1204         if (U_FAILURE(ec)) {
1205             dataerrln("contruct SimpleDateFormat in expect failed: %s", u_errorName(ec));
1206             return;
1207         }
1208 
1209         // 'f'
1210         logln("original date: %s - %s\n", datestr, datestr_2);
1211         UDate date = ref.parse(ctou(datestr), ec);
1212         if (!assertSuccess("parse 1st data in expect", ec)) return;
1213         UDate date_2 = ref.parse(ctou(datestr_2), ec);
1214         if (!assertSuccess("parse 2nd data in expect", ec)) return;
1215         DateInterval dtitv(date, date_2);
1216 
1217         const UnicodeString& oneSkeleton(ctou(data[i++]));
1218 
1219         DateIntervalFormat* dtitvfmt = DateIntervalFormat::createInstance(oneSkeleton, loc, ec);
1220         if (!assertSuccess("createInstance(skeleton) in expect", ec)) return;
1221         FieldPosition pos(FieldPosition::DONT_CARE);
1222         dtitvfmt->format(&dtitv, str.remove(), pos, ec);
1223         if (!assertSuccess("format in expect", ec)) return;
1224         assertEquals((UnicodeString)"\"" + locName + "\\" + oneSkeleton + "\\" + ctou(datestr) + "\\" + ctou(datestr_2) + "\"", ctou(data[i++]), str);
1225 
1226         logln("interval date:" + str + "\"" + locName + "\", "
1227                  + "\"" + datestr + "\", "
1228               + "\"" + datestr_2 + "\", " + oneSkeleton);
1229         delete dtitvfmt;
1230     }
1231 }
1232 
1233 
1234 /*
1235  * Test format using user defined DateIntervalInfo
1236  */
testFormatUserDII()1237 void DateIntervalFormatTest::testFormatUserDII() {
1238     // first item is date pattern
1239     const char* DATA[] = {
1240         "yyyy MM dd HH:mm:ss",
1241         "en", "2007 10 10 10:10:10", "2008 10 10 10:10:10", "Oct 10, 2007 --- Oct 10, 2008",
1242 
1243         "en", "2007 10 10 10:10:10", "2007 11 10 10:10:10", "2007 Oct 10 - Nov 2007",
1244 
1245         "en", "2007 11 10 10:10:10", "2007 11 20 10:10:10", "Nov 10, 2007 --- Nov 20, 2007",
1246 
1247         "en", "2007 01 10 10:00:10", "2007 01 10 14:10:10", "Jan 10, 2007",
1248 
1249         "en", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "Jan 10, 2007",
1250 
1251         "en", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "Jan 10, 2007",
1252 
1253         "zh", "2007 10 10 10:10:10", "2008 10 10 10:10:10", "2007\\u5e7410\\u670810\\u65e5 --- 2008\\u5e7410\\u670810\\u65e5",
1254 
1255         "zh", "2007 10 10 10:10:10", "2007 11 10 10:10:10", "2007 10\\u6708 10 - 11\\u6708 2007",
1256 
1257         "zh", "2007 11 10 10:10:10", "2007 11 20 10:10:10", "2007\\u5e7411\\u670810\\u65e5 --- 2007\\u5e7411\\u670820\\u65e5",
1258 
1259         "zh", "2007 01 10 10:00:10", "2007 01 10 14:10:10", "2007\\u5e741\\u670810\\u65e5", // (fixed expected result per ticket:6626:)
1260 
1261         "zh", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "2007\\u5e741\\u670810\\u65e5", // (fixed expected result per ticket:6626:)
1262 
1263         "zh", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "2007\\u5e741\\u670810\\u65e5", // (fixed expected result per ticket:6626:)
1264 
1265         "de", "2007 10 10 10:10:10", "2008 10 10 10:10:10", "10. Okt. 2007 --- 10. Okt. 2008",
1266 
1267 
1268         "de", "2007 11 10 10:10:10", "2007 11 20 10:10:10", "10. Nov. 2007 --- 20. Nov. 2007",
1269 
1270         "de", "2007 01 10 10:00:10", "2007 01 10 14:10:10", "10. Jan. 2007",
1271 
1272         "de", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "10. Jan. 2007",
1273 
1274 
1275         "es", "2007 10 10 10:10:10", "2008 10 10 10:10:10", "10 oct 2007 --- 10 oct 2008",
1276 
1277         "es", "2007 10 10 10:10:10", "2007 11 10 10:10:10", "2007 oct 10 - nov 2007",
1278 
1279         "es", "2007 11 10 10:10:10", "2007 11 20 10:10:10", "10 nov 2007 --- 20 nov 2007",
1280 
1281         "es", "2007 01 10 10:00:10", "2007 01 10 14:10:10", "10 ene 2007",
1282 
1283         "es", "2007 01 10 10:00:10", "2007 01 10 10:20:10", "10 ene 2007",
1284 
1285         "es", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "10 ene 2007",
1286     };
1287     expectUserDII(DATA, UPRV_LENGTHOF(DATA));
1288 }
1289 
1290 /*
1291  * Test format using UDisplayContext
1292  */
1293 #define CAP_NONE  UDISPCTX_CAPITALIZATION_NONE
1294 #define CAP_BEGIN UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
1295 #define CAP_LIST  UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
1296 #define CAP_ALONE UDISPCTX_CAPITALIZATION_FOR_STANDALONE
1297 #define _DAY    (24.0*60.0*60.0*1000.0)
1298 
testContext()1299 void DateIntervalFormatTest::testContext() {
1300     static const UDate startDate = 1285599629000.0; // 2010-Sep-27 0800 in America/Los_Angeles
1301     typedef struct {
1302         const char * locale;
1303         const char * skeleton;
1304         UDisplayContext context;
1305         const UDate  deltaDate;
1306         const UChar* expectResult;
1307     } DateIntervalContextItem;
1308     static const DateIntervalContextItem testItems[] = {
1309         { "cs",    "MMMEd",    CAP_NONE,  60.0*_DAY,  u"po 27. 9. – pá 26. 11." },
1310         { "cs",    "yMMMM",    CAP_NONE,  60.0*_DAY,  u"září–listopad 2010" },
1311         { "cs",    "yMMMM",    CAP_NONE,  1.0*_DAY,   u"září 2010" },
1312 #if !UCONFIG_NO_BREAK_ITERATION
1313         { "cs",    "MMMEd",    CAP_BEGIN, 60.0*_DAY,  u"Po 27. 9. – pá 26. 11." },
1314         { "cs",    "yMMMM",    CAP_BEGIN, 60.0*_DAY,  u"Září–listopad 2010" },
1315         { "cs",    "yMMMM",    CAP_BEGIN, 1.0*_DAY,   u"Září 2010" },
1316         { "cs",    "MMMEd",    CAP_LIST,  60.0*_DAY,  u"Po 27. 9. – pá 26. 11." },
1317         { "cs",    "yMMMM",    CAP_LIST,  60.0*_DAY,  u"Září–listopad 2010" },
1318         { "cs",    "yMMMM",    CAP_LIST,  1.0*_DAY,   u"Září 2010" },
1319 #endif
1320         { "cs",    "MMMEd",    CAP_ALONE, 60.0*_DAY,  u"po 27. 9. – pá 26. 11." },
1321         { "cs",    "yMMMM",    CAP_ALONE, 60.0*_DAY,  u"září–listopad 2010" },
1322         { "cs",    "yMMMM",    CAP_ALONE, 1.0*_DAY,   u"září 2010" },
1323         { nullptr, nullptr,    CAP_NONE,  0,          nullptr }
1324     };
1325     const DateIntervalContextItem* testItemPtr;
1326     for ( testItemPtr = testItems; testItemPtr->locale != nullptr; ++testItemPtr ) {
1327         UErrorCode status = U_ZERO_ERROR;
1328         Locale locale(testItemPtr->locale);
1329         UnicodeString skeleton(testItemPtr->skeleton, -1, US_INV);
1330         LocalPointer<DateIntervalFormat> fmt(DateIntervalFormat::createInstance(skeleton, locale, status));
1331         if (U_FAILURE(status)) {
1332             errln("createInstance failed for locale %s skeleton %s: %s",
1333                     testItemPtr->locale, testItemPtr->skeleton, u_errorName(status));
1334             continue;
1335         }
1336         fmt->adoptTimeZone(TimeZone::createTimeZone("America/Los_Angeles"));
1337 
1338         fmt->setContext(testItemPtr->context, status);
1339         if (U_FAILURE(status)) {
1340             errln("setContext failed for locale %s skeleton %s context %04X: %s",
1341                     testItemPtr->locale, testItemPtr->skeleton, (unsigned)testItemPtr->context, u_errorName(status));
1342         } else {
1343             UDisplayContext getContext = fmt->getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
1344             if (U_FAILURE(status)) {
1345                 errln("getContext failed for locale %s skeleton %s context %04X: %s",
1346                         testItemPtr->locale, testItemPtr->skeleton, (unsigned)testItemPtr->context, u_errorName(status));
1347             } else if (getContext != testItemPtr->context) {
1348                 errln("getContext failed for locale %s skeleton %s context %04X: got context %04X",
1349                         testItemPtr->locale, testItemPtr->skeleton, (unsigned)testItemPtr->context, (unsigned)getContext);
1350             }
1351         }
1352 
1353         status = U_ZERO_ERROR;
1354         DateInterval interval(startDate, startDate + testItemPtr->deltaDate);
1355         UnicodeString getResult;
1356         FieldPosition pos(FieldPosition::DONT_CARE);
1357         fmt->format(&interval, getResult, pos, status);
1358         if (U_FAILURE(status)) {
1359             errln("format failed for locale %s skeleton %s context %04X: %s",
1360                     testItemPtr->locale, testItemPtr->skeleton, (unsigned)testItemPtr->context, u_errorName(status));
1361             continue;
1362         }
1363         UnicodeString expectResult(true, testItemPtr->expectResult, -1);
1364         if (getResult != expectResult) {
1365             errln(UnicodeString("format expected ") + expectResult + UnicodeString(" but got ") + getResult);
1366         }
1367     }
1368 }
1369 
testSetIntervalPatternNoSideEffect()1370 void DateIntervalFormatTest::testSetIntervalPatternNoSideEffect() {
1371     UErrorCode ec = U_ZERO_ERROR;
1372     LocalPointer<DateIntervalInfo> dtitvinf(new DateIntervalInfo(ec), ec);
1373     if (U_FAILURE(ec)) {
1374         errln("Failure encountered: %s", u_errorName(ec));
1375         return;
1376     }
1377     UnicodeString expected;
1378     dtitvinf->getIntervalPattern(ctou("yMd"), UCAL_DATE, expected, ec);
1379     dtitvinf->setIntervalPattern(ctou("yMd"), UCAL_DATE, ctou("M/d/y \\u2013 d"), ec);
1380     if (U_FAILURE(ec)) {
1381         errln("Failure encountered: %s", u_errorName(ec));
1382         return;
1383     }
1384     dtitvinf.adoptInsteadAndCheckErrorCode(new DateIntervalInfo(ec), ec);
1385     if (U_FAILURE(ec)) {
1386         errln("Failure encountered: %s", u_errorName(ec));
1387         return;
1388     }
1389     UnicodeString actual;
1390     dtitvinf->getIntervalPattern(ctou("yMd"), UCAL_DATE, actual, ec);
1391     if (U_FAILURE(ec)) {
1392         errln("Failure encountered: %s", u_errorName(ec));
1393         return;
1394     }
1395     if (expected != actual) {
1396         errln("DateIntervalInfo.setIntervalPattern should have no side effects.");
1397     }
1398 }
1399 
testYearFormats()1400 void DateIntervalFormatTest::testYearFormats() {
1401     const Locale &enLocale = Locale::getEnglish();
1402     UErrorCode status = U_ZERO_ERROR;
1403     LocalPointer<Calendar> fromTime(Calendar::createInstance(enLocale, status));
1404     LocalPointer<Calendar> toTime(Calendar::createInstance(enLocale, status));
1405     if (U_FAILURE(status)) {
1406         errln("Failure encountered: %s", u_errorName(status));
1407         return;
1408     }
1409     // April 26, 113. Three digit year so that we can test 2 digit years;
1410     // 4 digit years with padded 0's and full years.
1411     fromTime->set(113, 3, 26);
1412     // April 28, 113.
1413     toTime->set(113, 3, 28);
1414     {
1415         LocalPointer<DateIntervalFormat> dif(DateIntervalFormat::createInstance("yyyyMd", enLocale, status));
1416         if (U_FAILURE(status)) {
1417             dataerrln("Failure encountered: %s", u_errorName(status));
1418             return;
1419         }
1420         UnicodeString actual;
1421         UnicodeString expected(ctou("4/26/0113 \\u2013 4/28/0113"));
1422         FieldPosition pos;
1423         dif->format(*fromTime, *toTime, actual, pos, status);
1424         if (U_FAILURE(status)) {
1425             errln("Failure encountered: %s", u_errorName(status));
1426             return;
1427         }
1428         if (actual != expected) {
1429             errln("Expected " + expected + ", got: " + actual);
1430         }
1431     }
1432     {
1433         LocalPointer<DateIntervalFormat> dif(DateIntervalFormat::createInstance("yyMd", enLocale, status));
1434         if (U_FAILURE(status)) {
1435             errln("Failure encountered: %s", u_errorName(status));
1436             return;
1437         }
1438         UnicodeString actual;
1439         UnicodeString expected(ctou("4/26/13 \\u2013 4/28/13"));
1440         FieldPosition pos(FieldPosition::DONT_CARE);
1441         dif->format(*fromTime, *toTime, actual, pos, status);
1442         if (U_FAILURE(status)) {
1443             errln("Failure encountered: %s", u_errorName(status));
1444             return;
1445         }
1446         if (actual != expected) {
1447             errln("Expected " + expected + ", got: " + actual);
1448         }
1449     }
1450     {
1451         LocalPointer<DateIntervalFormat> dif(DateIntervalFormat::createInstance("yMd", enLocale, status));
1452         if (U_FAILURE(status)) {
1453             errln("Failure encountered: %s", u_errorName(status));
1454             return;
1455         }
1456         UnicodeString actual;
1457         UnicodeString expected(ctou("4/26/113 \\u2013 4/28/113"));
1458         FieldPosition pos(FieldPosition::DONT_CARE);
1459         dif->format(*fromTime, *toTime, actual, pos, status);
1460         if (U_FAILURE(status)) {
1461             errln("Failure encountered: %s", u_errorName(status));
1462             return;
1463         }
1464         if (actual != expected) {
1465             errln("Expected " + expected + ", got: " + actual);
1466         }
1467     }
1468 }
1469 
expectUserDII(const char ** data,int32_t data_length)1470 void DateIntervalFormatTest::expectUserDII(const char** data,
1471                                            int32_t data_length) {
1472     int32_t i = 0;
1473     UnicodeString str;
1474     UErrorCode ec = U_ZERO_ERROR;
1475     const char* pattern = data[0];
1476     i++;
1477 
1478     while ( i < data_length ) {
1479         const char* locName = data[i++];
1480         Locale loc(locName);
1481         SimpleDateFormat ref(pattern, loc, ec);
1482         if (U_FAILURE(ec)) {
1483             dataerrln("contruct SimpleDateFormat in expectUserDII failed: %s", u_errorName(ec));
1484             return;
1485         }
1486         const char* datestr = data[i++];
1487         const char* datestr_2 = data[i++];
1488         UDate date = ref.parse(ctou(datestr), ec);
1489         if (!assertSuccess("parse in expectUserDII", ec)) return;
1490         UDate date_2 = ref.parse(ctou(datestr_2), ec);
1491         if (!assertSuccess("parse in expectUserDII", ec)) return;
1492         DateInterval dtitv(date, date_2);
1493 
1494         ec = U_ZERO_ERROR;
1495         // test user created DateIntervalInfo
1496         DateIntervalInfo* dtitvinf = new DateIntervalInfo(ec);
1497         dtitvinf->setFallbackIntervalPattern("{0} --- {1}", ec);
1498         dtitvinf->setIntervalPattern(UDAT_YEAR_ABBR_MONTH_DAY, UCAL_MONTH, "yyyy MMM d - MMM y",ec);
1499         if (!assertSuccess("DateIntervalInfo::setIntervalPattern", ec)) return;
1500         dtitvinf->setIntervalPattern(UDAT_YEAR_ABBR_MONTH_DAY, UCAL_HOUR_OF_DAY, "yyyy MMM d HH:mm - HH:mm", ec);
1501         if (!assertSuccess("DateIntervalInfo::setIntervalPattern", ec)) return;
1502         DateIntervalFormat* dtitvfmt = DateIntervalFormat::createInstance(UDAT_YEAR_ABBR_MONTH_DAY, loc, *dtitvinf, ec);
1503         delete dtitvinf;
1504         if (!assertSuccess("createInstance(skeleton,dtitvinf) in expectUserDII", ec)) return;
1505         FieldPosition pos(FieldPosition::DONT_CARE);
1506         dtitvfmt->format(&dtitv, str.remove(), pos, ec);
1507         if (!assertSuccess("format in expectUserDII", ec)) return;
1508         assertEquals((UnicodeString)"\"" + locName + "\\" + datestr + "\\" + datestr_2 + "\"", ctou(data[i++]), str);
1509 #ifdef DTIFMTTS_DEBUG
1510         char result[1000];
1511         char mesg[1000];
1512         PRINTMESG("interval format using user defined DateIntervalInfo\n");
1513         str.extract(0,  str.length(), result, "UTF-8");
1514         sprintf(mesg, "interval date: %s\n", result);
1515         PRINTMESG(mesg);
1516 #endif
1517         delete dtitvfmt;
1518     }
1519 }
1520 
1521 
testStress()1522 void DateIntervalFormatTest::testStress() {
1523     if(quick){
1524     	logln("Quick mode: Skipping test");
1525     	return;
1526     }
1527 	const char* DATA[] = {
1528         "yyyy MM dd HH:mm:ss",
1529         "2007 10 10 10:10:10", "2008 10 10 10:10:10",
1530         "2007 10 10 10:10:10", "2007 11 10 10:10:10",
1531         "2007 11 10 10:10:10", "2007 11 20 10:10:10",
1532         "2007 01 10 10:00:10", "2007 01 10 14:10:10",
1533         "2007 01 10 10:00:10", "2007 01 10 10:20:10",
1534         "2007 01 10 10:10:10", "2007 01 10 10:10:20",
1535     };
1536 
1537     const char* testLocale[][3] = {
1538         //{"th", "", ""},
1539         {"en", "", ""},
1540         {"zh", "", ""},
1541         {"de", "", ""},
1542         {"ar", "", ""},
1543         {"en", "GB",  ""},
1544         {"fr", "", ""},
1545         {"it", "", ""},
1546         {"nl", "", ""},
1547         {"zh", "TW",  ""},
1548         {"ja", "", ""},
1549         {"pt", "BR", ""},
1550         {"ru", "", ""},
1551         {"pl", "", ""},
1552         {"tr", "", ""},
1553         {"es", "", ""},
1554         {"ko", "", ""},
1555         {"sv", "", ""},
1556         {"fi", "", ""},
1557         {"da", "", ""},
1558         {"pt", "PT", ""},
1559         {"ro", "", ""},
1560         {"hu", "", ""},
1561         {"he", "", ""},
1562         {"in", "", ""},
1563         {"cs", "", ""},
1564         {"el", "", ""},
1565         {"no", "", ""},
1566         {"vi", "", ""},
1567         {"bg", "", ""},
1568         {"hr", "", ""},
1569         {"lt", "", ""},
1570         {"sk", "", ""},
1571         {"sl", "", ""},
1572         {"sr", "", ""},
1573         {"ca", "", ""},
1574         {"lv", "", ""},
1575         {"uk", "", ""},
1576         {"hi", "", ""},
1577     };
1578 
1579     uint32_t localeIndex;
1580     for ( localeIndex = 0; localeIndex < UPRV_LENGTHOF(testLocale); ++localeIndex ) {
1581         char locName[32];
1582         uprv_strcpy(locName, testLocale[localeIndex][0]);
1583         uprv_strcat(locName, testLocale[localeIndex][1]);
1584         stress(DATA, UPRV_LENGTHOF(DATA), Locale(testLocale[localeIndex][0], testLocale[localeIndex][1], testLocale[localeIndex][2]), locName);
1585     }
1586 }
1587 
1588 
stress(const char ** data,int32_t data_length,const Locale & loc,const char * locName)1589 void DateIntervalFormatTest::stress(const char** data, int32_t data_length,
1590                                     const Locale& loc, const char* locName) {
1591     UnicodeString skeleton[] = {
1592         "EEEEdMMMMy",
1593         "dMMMMy",
1594         "dMMMM",
1595         "MMMMy",
1596         "EEEEdMMMM",
1597         "EdMMMy",
1598         "dMMMy",
1599         "dMMM",
1600         "MMMy",
1601         "EdMMM",
1602         "EdMy",
1603         "dMy",
1604         "dM",
1605         "My",
1606         "EdM",
1607         "d",
1608         "Ed",
1609         "y",
1610         "M",
1611         "MMM",
1612         "MMMM",
1613         "hm",
1614         "hmv",
1615         "hmz",
1616         "h",
1617         "hv",
1618         "hz",
1619         "EEddMMyyyy", // following could be normalized
1620         "EddMMy",
1621         "hhmm",
1622         "hhmmzz",
1623         "hms",  // following could not be normalized
1624         "dMMMMMy",
1625         "EEEEEdM",
1626     };
1627 
1628     int32_t i = 0;
1629     UErrorCode ec = U_ZERO_ERROR;
1630     UnicodeString str, str2;
1631     SimpleDateFormat ref(data[i++], loc, ec);
1632     if (!assertSuccess("construct SimpleDateFormat", ec)) return;
1633 
1634 #ifdef DTIFMTTS_DEBUG
1635     char result[1000];
1636     char mesg[1000];
1637     sprintf(mesg, "locale: %s\n", locName);
1638     PRINTMESG(mesg);
1639 #endif
1640 
1641     while (i<data_length) {
1642 
1643         // 'f'
1644         const char* datestr = data[i++];
1645         const char* datestr_2 = data[i++];
1646 #ifdef DTIFMTTS_DEBUG
1647         sprintf(mesg, "original date: %s - %s\n", datestr, datestr_2);
1648         PRINTMESG(mesg)
1649 #endif
1650         UDate date = ref.parse(ctou(datestr), ec);
1651         if (!assertSuccess("parse", ec)) return;
1652         UDate date_2 = ref.parse(ctou(datestr_2), ec);
1653         if (!assertSuccess("parse", ec)) return;
1654         DateInterval dtitv(date, date_2);
1655 
1656         for ( uint32_t skeletonIndex = 0;
1657               skeletonIndex < UPRV_LENGTHOF(skeleton);
1658               ++skeletonIndex ) {
1659             const UnicodeString& oneSkeleton = skeleton[skeletonIndex];
1660             DateIntervalFormat* dtitvfmt = DateIntervalFormat::createInstance(oneSkeleton, loc, ec);
1661             if (!assertSuccess("createInstance(skeleton)", ec)) return;
1662             /*
1663             // reset the calendar to be Gregorian calendar for "th"
1664             if ( uprv_strcmp(locName, "th") == 0 ) {
1665                 GregorianCalendar* gregCal = new GregorianCalendar(loc, ec);
1666                 if (!assertSuccess("GregorianCalendar()", ec)) return;
1667                 const DateFormat* dformat = dtitvfmt->getDateFormat();
1668                 DateFormat* newOne = dformat->clone();
1669                 newOne->adoptCalendar(gregCal);
1670                 //dtitvfmt->adoptDateFormat(newOne, ec);
1671                 dtitvfmt->setDateFormat(*newOne, ec);
1672                 delete newOne;
1673                 if (!assertSuccess("adoptDateFormat()", ec)) return;
1674             }
1675             */
1676             FieldPosition pos(FieldPosition::DONT_CARE);
1677             dtitvfmt->format(&dtitv, str.remove(), pos, ec);
1678             if (!assertSuccess("format", ec)) return;
1679 #ifdef DTIFMTTS_DEBUG
1680             oneSkeleton.extract(0,  oneSkeleton.length(), result, "UTF-8");
1681             sprintf(mesg, "interval by skeleton: %s\n", result);
1682             PRINTMESG(mesg)
1683             str.extract(0,  str.length(), result, "UTF-8");
1684             sprintf(mesg, "interval date: %s\n", result);
1685             PRINTMESG(mesg)
1686 #endif
1687             delete dtitvfmt;
1688         }
1689 
1690         // test user created DateIntervalInfo
1691         ec = U_ZERO_ERROR;
1692         DateIntervalInfo* dtitvinf = new DateIntervalInfo(ec);
1693         dtitvinf->setFallbackIntervalPattern("{0} --- {1}", ec);
1694         dtitvinf->setIntervalPattern(UDAT_YEAR_ABBR_MONTH_DAY, UCAL_MONTH, "yyyy MMM d - MMM y",ec);
1695         if (!assertSuccess("DateIntervalInfo::setIntervalPattern", ec)) return;
1696         dtitvinf->setIntervalPattern(UDAT_YEAR_ABBR_MONTH_DAY, UCAL_HOUR_OF_DAY, "yyyy MMM d HH:mm - HH:mm", ec);
1697         if (!assertSuccess("DateIntervalInfo::setIntervalPattern", ec)) return;
1698         DateIntervalFormat* dtitvfmt = DateIntervalFormat::createInstance(UDAT_YEAR_ABBR_MONTH_DAY, loc, *dtitvinf, ec);
1699         delete dtitvinf;
1700         if (!assertSuccess("createInstance(skeleton,dtitvinf)", ec)) return;
1701         FieldPosition pos(FieldPosition::DONT_CARE);
1702         dtitvfmt->format(&dtitv, str.remove(), pos, ec);
1703         if ( uprv_strcmp(locName, "th") ) {
1704             if (!assertSuccess("format", ec)) return;
1705 #ifdef DTIFMTTS_DEBUG
1706             PRINTMESG("interval format using user defined DateIntervalInfo\n");
1707             str.extract(0,  str.length(), result, "UTF-8");
1708             sprintf(mesg, "interval date: %s\n", result);
1709             PRINTMESG(mesg)
1710 #endif
1711         } else {
1712             // for "th", the default calendar is Budhist,
1713             // not Gregorian.
1714             assertTrue("Default calendar for \"th\" is Budhist", ec == U_ILLEGAL_ARGUMENT_ERROR);
1715             ec = U_ZERO_ERROR;
1716         }
1717         delete dtitvfmt;
1718     }
1719 }
1720 
testTicket11583_2()1721 void DateIntervalFormatTest::testTicket11583_2() {
1722     UErrorCode status = U_ZERO_ERROR;
1723     LocalPointer<DateIntervalFormat> fmt(
1724             DateIntervalFormat::createInstance("yMMM", "es-US", status));
1725     if (!assertSuccess("Error create format object", status)) {
1726         return;
1727     }
1728     DateInterval interval((UDate) 1232364615000.0, (UDate) 1328787015000.0);
1729     UnicodeString appendTo;
1730     FieldPosition fpos(FieldPosition::DONT_CARE);
1731     UnicodeString expected("ene. de 2009 \\u2013 feb. de 2012");
1732     assertEquals(
1733             "",
1734             expected.unescape(),
1735             fmt->format(&interval, appendTo, fpos, status));
1736     if (!assertSuccess("Error formatting", status)) {
1737         return;
1738     }
1739 }
1740 
1741 
testTicket11985()1742 void DateIntervalFormatTest::testTicket11985() {
1743     UErrorCode status = U_ZERO_ERROR;
1744     LocalPointer<DateIntervalFormat> fmt(
1745             DateIntervalFormat::createInstance(UDAT_HOUR_MINUTE, Locale::getEnglish(), status));
1746     if (!assertSuccess("createInstance", status)) {
1747         return;
1748     }
1749     UnicodeString pattern;
1750     static_cast<const SimpleDateFormat*>(fmt->getDateFormat())->toPattern(pattern);
1751     assertEquals("Format pattern", "h:mm a", pattern);
1752 }
1753 
1754 // Ticket 11669 - thread safety of DateIntervalFormat::format(). This test failed before
1755 //                the implementation was fixed.
1756 
1757 static const DateIntervalFormat *gIntervalFormatter = NULL;      // The Formatter to be used concurrently by test threads.
1758 static const DateInterval *gInterval = NULL;                     // The date interval to be formatted concurrently.
1759 static const UnicodeString *gExpectedResult = NULL;
1760 
threadFunc11669(int32_t threadNum)1761 void DateIntervalFormatTest::threadFunc11669(int32_t threadNum) {
1762     (void)threadNum;
1763     for (int loop=0; loop<1000; ++loop) {
1764         UErrorCode status = U_ZERO_ERROR;
1765         FieldPosition pos(FieldPosition::DONT_CARE);
1766         UnicodeString result;
1767         gIntervalFormatter->format(gInterval, result, pos, status);
1768         if (U_FAILURE(status)) {
1769             errln("%s:%d %s", __FILE__, __LINE__, u_errorName(status));
1770             return;
1771         }
1772         if (result != *gExpectedResult) {
1773             errln("%s:%d Expected \"%s\", got \"%s\"", __FILE__, __LINE__, CStr(*gExpectedResult)(), CStr(result)());
1774             return;
1775         }
1776     }
1777 }
1778 
testTicket11669()1779 void DateIntervalFormatTest::testTicket11669() {
1780     UErrorCode status = U_ZERO_ERROR;
1781     LocalPointer<DateIntervalFormat> formatter(DateIntervalFormat::createInstance(UDAT_YEAR_MONTH_DAY, Locale::getEnglish(), status), status);
1782     LocalPointer<TimeZone> tz(TimeZone::createTimeZone("America/Los_Angleles"), status);
1783     LocalPointer<Calendar> intervalStart(Calendar::createInstance(*tz, Locale::getEnglish(), status), status);
1784     LocalPointer<Calendar> intervalEnd(Calendar::createInstance(*tz, Locale::getEnglish(), status), status);
1785     if (U_FAILURE(status)) {
1786         errcheckln(status, "%s:%d %s", __FILE__, __LINE__, u_errorName(status));
1787         return;
1788     }
1789 
1790     intervalStart->set(2009, 6, 1, 14, 0);
1791     intervalEnd->set(2009, 6, 2, 14, 0);
1792     DateInterval interval(intervalStart->getTime(status), intervalEnd->getTime(status));
1793     FieldPosition pos(FieldPosition::DONT_CARE);
1794     UnicodeString expectedResult;
1795     formatter->format(&interval, expectedResult, pos, status);
1796     if (U_FAILURE(status)) {
1797         errln("%s:%d %s", __FILE__, __LINE__, u_errorName(status));
1798         return;
1799     }
1800 
1801     gInterval = &interval;
1802     gIntervalFormatter = formatter.getAlias();
1803     gExpectedResult = &expectedResult;
1804 
1805     ThreadPool<DateIntervalFormatTest> threads(this, 4, &DateIntervalFormatTest::threadFunc11669);
1806     threads.start();
1807     threads.join();
1808 
1809     gInterval = NULL;             // Don't leave dangling pointers lying around. Not strictly necessary.
1810     gIntervalFormatter = NULL;
1811     gExpectedResult = NULL;
1812 }
1813 
1814 
1815 // testTicket12065
1816 //    Using a DateIntervalFormat to format shouldn't change its state in any way
1817 //    that changes how the behavior of operator ==.
testTicket12065()1818 void DateIntervalFormatTest::testTicket12065() {
1819     UErrorCode status = U_ZERO_ERROR;
1820     LocalPointer<DateIntervalFormat> formatter(DateIntervalFormat::createInstance(UDAT_YEAR_MONTH_DAY, Locale::getEnglish(), status), status);
1821     if (formatter.isNull()) {
1822         dataerrln("FAIL: DateIntervalFormat::createInstance failed for Locale::getEnglish()");
1823         return;
1824     }
1825     LocalPointer<DateIntervalFormat> clone(formatter->clone());
1826     if (*formatter != *clone) {
1827         errln("%s:%d DateIntervalFormat and clone are not equal.", __FILE__, __LINE__);
1828         return;
1829     }
1830     DateInterval interval((UDate) 1232364615000.0, (UDate) 1328787015000.0);
1831     UnicodeString appendTo;
1832     FieldPosition fpos(FieldPosition::DONT_CARE);
1833     formatter->format(&interval, appendTo, fpos, status);
1834     if (*formatter != *clone) {
1835         errln("%s:%d DateIntervalFormat and clone are not equal after formatting.", __FILE__, __LINE__);
1836         return;
1837     }
1838     if (U_FAILURE(status)) {
1839         errln("%s:%d %s", __FILE__, __LINE__, u_errorName(status));
1840     }
1841 }
1842 
1843 
testFormattedDateInterval()1844 void DateIntervalFormatTest::testFormattedDateInterval() {
1845     IcuTestErrorCode status(*this, "testFormattedDateInterval");
1846     LocalPointer<DateIntervalFormat> fmt(DateIntervalFormat::createInstance(u"dMMMMy", "en-US", status), status);
1847 
1848     {
1849         const char16_t* message = u"FormattedDateInterval test 1";
1850         const char16_t* expectedString = u"July 20 \u2013 25, 2018";
1851         LocalPointer<Calendar> input1(Calendar::createInstance("en-GB", status));
1852         if (status.errIfFailureAndReset()) { return; }
1853         LocalPointer<Calendar> input2(Calendar::createInstance("en-GB", status));
1854         if (status.errIfFailureAndReset()) { return; }
1855         input1->set(2018, 6, 20);
1856         input2->set(2018, 6, 25);
1857         FormattedDateInterval result = fmt->formatToValue(*input1, *input2, status);
1858         static const UFieldPositionWithCategory expectedFieldPositions[] = {
1859             // field, begin index, end index
1860             {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 0, 4},
1861             {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 0, 5, 7},
1862             {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 5, 7},
1863             {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 1, 10, 12},
1864             {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 10, 12},
1865             {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 14, 18}};
1866         checkMixedFormattedValue(
1867             message,
1868             result,
1869             expectedString,
1870             expectedFieldPositions,
1871             UPRV_LENGTHOF(expectedFieldPositions));
1872     }
1873 
1874     {
1875         const char16_t* message = u"FormattedDateInterval identical dates test: no span field";
1876         const char16_t* expectedString = u"July 20, 2018";
1877         LocalPointer<Calendar> input1(Calendar::createInstance("en-GB", status));
1878         input1->set(2018, 6, 20);
1879         FormattedDateInterval result = fmt->formatToValue(*input1, *input1, status);
1880         static const UFieldPositionWithCategory expectedFieldPositions[] = {
1881             // field, begin index, end index
1882             {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 0, 4},
1883             {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 5, 7},
1884             {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 9, 13}};
1885         checkMixedFormattedValue(
1886             message,
1887             result,
1888             expectedString,
1889             expectedFieldPositions,
1890             UPRV_LENGTHOF(expectedFieldPositions));
1891     }
1892 
1893     // Test sample code
1894     {
1895         LocalPointer<Calendar> input1(Calendar::createInstance("en-GB", status));
1896         LocalPointer<Calendar> input2(Calendar::createInstance("en-GB", status));
1897         input1->set(2018, 6, 20);
1898         input2->set(2018, 7, 3);
1899 
1900         // Let fmt be a DateIntervalFormat for locale en-US and skeleton dMMMMy
1901         // Let input1 be July 20, 2018 and input2 be August 3, 2018:
1902         FormattedDateInterval result = fmt->formatToValue(*input1, *input2, status);
1903         assertEquals("Expected output from format",
1904             u"July 20 \u2013 August 3, 2018", result.toString(status));
1905         ConstrainedFieldPosition cfpos;
1906         cfpos.constrainField(UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 0);
1907         if (result.nextPosition(cfpos, status)) {
1908             assertEquals("Expect start index", 0, cfpos.getStart());
1909             assertEquals("Expect end index", 7, cfpos.getLimit());
1910         } else {
1911             // No such span: can happen if input dates are equal.
1912         }
1913         assertFalse("No more than one occurrence of the field",
1914             result.nextPosition(cfpos, status));
1915     }
1916 
1917     // To test the fallback pattern behavior, make a custom DateIntervalInfo.
1918     DateIntervalInfo dtitvinf(status);
1919     dtitvinf.setFallbackIntervalPattern("<< {1} --- {0} >>", status);
1920     fmt.adoptInsteadAndCheckErrorCode(
1921         DateIntervalFormat::createInstance(u"dMMMMy", "en-US", dtitvinf, status),
1922         status);
1923 
1924     {
1925         const char16_t* message = u"FormattedDateInterval with fallback format test 1";
1926         const char16_t* expectedString = u"<< July 25, 2018 --- July 20, 2018 >>";
1927         LocalPointer<Calendar> input1(Calendar::createInstance("en-GB", status));
1928         if (status.errIfFailureAndReset()) { return; }
1929         LocalPointer<Calendar> input2(Calendar::createInstance("en-GB", status));
1930         if (status.errIfFailureAndReset()) { return; }
1931         input1->set(2018, 6, 20);
1932         input2->set(2018, 6, 25);
1933         FormattedDateInterval result = fmt->formatToValue(*input1, *input2, status);
1934         static const UFieldPositionWithCategory expectedFieldPositions[] = {
1935             // field, begin index, end index
1936             {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 1, 3, 16},
1937             {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 3, 7},
1938             {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 8, 10},
1939             {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 12, 16},
1940             {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 0, 21, 34},
1941             {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 21, 25},
1942             {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 26, 28},
1943             {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 30, 34}};
1944         checkMixedFormattedValue(
1945             message,
1946             result,
1947             expectedString,
1948             expectedFieldPositions,
1949             UPRV_LENGTHOF(expectedFieldPositions));
1950     }
1951 }
1952 
testCreateInstanceForAllLocales()1953 void DateIntervalFormatTest::testCreateInstanceForAllLocales() {
1954     IcuTestErrorCode status(*this, "testCreateInstanceForAllLocales");
1955     int32_t locale_count = 0;
1956     const Locale* locales = icu::Locale::getAvailableLocales(locale_count);
1957     // Iterate through all locales
1958     for (int32_t i = 0; i < locale_count; i++) {
1959         std::unique_ptr<icu::StringEnumeration> calendars(
1960             icu::Calendar::getKeywordValuesForLocale(
1961                 "calendar", locales[i], FALSE, status));
1962         int32_t calendar_count = calendars->count(status);
1963         if (status.errIfFailureAndReset()) { break; }
1964         // In quick mode, only run 1/5 of locale combination
1965         // to make the test run faster.
1966         if (quick && (i % 5 != 0)) continue;
1967         LocalPointer<DateIntervalFormat> fmt(
1968             DateIntervalFormat::createInstance(u"dMMMMy", locales[i], status),
1969             status);
1970         if (status.errIfFailureAndReset(locales[i].getName())) {
1971             continue;
1972         }
1973         // Iterate through all calendars in this locale
1974         for (int32_t j = 0; j < calendar_count; j++) {
1975             // In quick mode, only run 1/7 of locale/calendar combination
1976             // to make the test run faster.
1977             if (quick && ((i * j) % 7 != 0)) continue;
1978             const char* calendar = calendars->next(nullptr, status);
1979             Locale locale(locales[i]);
1980             locale.setKeywordValue("calendar", calendar, status);
1981             fmt.adoptInsteadAndCheckErrorCode(
1982                 DateIntervalFormat::createInstance(u"dMMMMy", locale, status),
1983                 status);
1984             status.errIfFailureAndReset(locales[i].getName());
1985         }
1986     }
1987 }
1988 
testFormatMillisecond()1989 void DateIntervalFormatTest::testFormatMillisecond() {
1990     struct
1991     {
1992         int year;
1993         int month;
1994         int day;
1995         int from_hour;
1996         int from_miniute;
1997         int from_second;
1998         int from_millisecond;
1999         int to_hour;
2000         int to_miniute;
2001         int to_second;
2002         int to_millisecond;
2003         const char* skeleton;
2004         const char16_t* expected;
2005     }
2006     kTestCases [] =
2007     {
2008         //           From            To
2009         //   y  m  d   h  m   s   ms   h  m   s   ms   skeleton  expected
2010         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "ms",     u"23:45"},
2011         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "msS",    u"23:45.3"},
2012         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "msSS",   u"23:45.32"},
2013         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "msSSS",  u"23:45.321"},
2014         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "ms",     u"23:45"},
2015         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "msS",    u"23:45.3 \u2013 23:45.9"},
2016         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "msSS",   u"23:45.32 \u2013 23:45.98"},
2017         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "msSSS",  u"23:45.321 \u2013 23:45.987"},
2018         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "ms",     u"23:45 \u2013 23:46"},
2019         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "msS",    u"23:45.3 \u2013 23:46.9"},
2020         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "msSS",   u"23:45.32 \u2013 23:46.98"},
2021         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "msSSS",  u"23:45.321 \u2013 23:46.987"},
2022         { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "ms",     u"23:45 \u2013 24:45"},
2023         { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "msS",    u"23:45.3 \u2013 24:45.9"},
2024         { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "msSS",   u"23:45.32 \u2013 24:45.98"},
2025         { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "msSSS",  u"23:45.321 \u2013 24:45.987"},
2026         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "s",      u"45"},
2027         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "sS",     u"45.3"},
2028         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "sSS",    u"45.32"},
2029         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "sSSS",   u"45.321"},
2030         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "s",      u"45"},
2031         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "sS",     u"45.3 \u2013 45.9"},
2032         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "sSS",    u"45.32 \u2013 45.98"},
2033         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "sSSS",   u"45.321 \u2013 45.987"},
2034         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "s",      u"45 \u2013 46"},
2035         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "sS",     u"45.3 \u2013 46.9"},
2036         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "sSS",    u"45.32 \u2013 46.98"},
2037         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "sSSS",   u"45.321 \u2013 46.987"},
2038         { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "s",      u"45 \u2013 45"},
2039         { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "sS",     u"45.3 \u2013 45.9"},
2040         { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "sSS",    u"45.32 \u2013 45.98"},
2041         { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "sSSS",   u"45.321 \u2013 45.987"},
2042         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "S",      u"3"},
2043         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "SS",     u"32"},
2044         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 321, "SSS",    u"321"},
2045 
2046         // Same millisecond but in different second.
2047         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 321, "S",      u"3 \u2013 3"},
2048         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 321, "SS",     u"32 \u2013 32"},
2049         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 321, "SSS",    u"321 \u2013 321"},
2050 
2051         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "S",      u"3 \u2013 9"},
2052         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "SS",     u"32 \u2013 98"},
2053         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 45, 987, "SSS",    u"321 \u2013 987"},
2054         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "S",      u"3 \u2013 9"},
2055         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "SS",     u"32 \u2013 98"},
2056         { 2019, 2, 10, 1, 23, 45, 321, 1, 23, 46, 987, "SSS",    u"321 \u2013 987"},
2057         { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "S",      u"3 \u2013 9"},
2058         { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "SS",     u"32 \u2013 98"},
2059         { 2019, 2, 10, 1, 23, 45, 321, 2, 24, 45, 987, "SSS",    u"321 \u2013 987"},
2060         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr, nullptr},
2061     };
2062 
2063     const Locale &enLocale = Locale::getEnglish();
2064     IcuTestErrorCode status(*this, "testFormatMillisecond");
2065     LocalPointer<Calendar> calendar(Calendar::createInstance(enLocale, status));
2066     if (status.errIfFailureAndReset()) { return; }
2067 
2068     for (int32_t i = 0; kTestCases[i].year > 0; i++) {
2069         LocalPointer<DateIntervalFormat> fmt(DateIntervalFormat::createInstance(
2070             kTestCases[i].skeleton, enLocale, status));
2071         if (status.errIfFailureAndReset()) { continue; }
2072 
2073         calendar->clear();
2074         calendar->set(kTestCases[i].year, kTestCases[i].month, kTestCases[i].day,
2075                       kTestCases[i].from_hour, kTestCases[i].from_miniute, kTestCases[i].from_second);
2076         UDate from = calendar->getTime(status) + kTestCases[i].from_millisecond;
2077         if (status.errIfFailureAndReset()) { continue; }
2078 
2079         calendar->clear();
2080         calendar->set(kTestCases[i].year, kTestCases[i].month, kTestCases[i].day,
2081                       kTestCases[i].to_hour, kTestCases[i].to_miniute, kTestCases[i].to_second);
2082         UDate to = calendar->getTime(status) + kTestCases[i].to_millisecond;
2083         FormattedDateInterval  res = fmt->formatToValue(DateInterval(from, to), status);
2084         if (status.errIfFailureAndReset()) { continue; }
2085 
2086         UnicodeString formatted = res.toString(status);
2087         if (status.errIfFailureAndReset()) { continue; }
2088         if (formatted != kTestCases[i].expected) {
2089             std::string tmp1;
2090             std::string tmp2;
2091             errln("Case %d for skeleton %s : Got %s but expect %s",
2092                   i, kTestCases[i].skeleton, formatted.toUTF8String<std::string>(tmp1).c_str(),
2093                   UnicodeString(kTestCases[i].expected).toUTF8String<std::string>(tmp2).c_str());
2094         }
2095     }
2096 }
2097 
testTicket20707()2098 void DateIntervalFormatTest::testTicket20707() {
2099     IcuTestErrorCode status(*this, "testTicket20707");
2100 
2101     const char16_t timeZone[] = u"UTC";
2102     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"};
2103 
2104     // Clomuns: hh, HH, kk, KK, jj, JJs, CC
2105     UnicodeString expected[][7] = {
2106         // Hour-cycle: k
2107         {u"12 AM", u"24", u"24", u"12 AM", u"24", u"0 (hour: 24)", u"12 AM"},
2108         // Hour-cycle: H
2109         {u"12 AM", u"00", u"00", u"12 AM", u"00", u"0 (hour: 00)", u"12 AM"},
2110         // Hour-cycle: h
2111         {u"12 AM", u"00", u"00", u"12 AM", u"12 AM", u"0 (hour: 12)", u"12 AM"},
2112         // Hour-cycle: K
2113         {u"0 AM", u"00", u"00", u"0 AM", u"0 AM", u"0 (hour: 00)", u"0 AM"},
2114         {u"12 AM", u"00", u"00", u"12 AM", u"12 AM", u"0 (hour: 12)", u"12 AM"},
2115         {u"12 AM", u"00", u"00", u"12 AM", u"12 AM", u"0 (hour: 12)", u"12 AM"},
2116         // Hour-cycle: K
2117         {u"0 am", u"00", u"00", u"0 am", u"0 am", u"0 (\u0918\u0902\u091F\u093E: 00)", u"\u0930\u093E\u0924 0"}
2118     };
2119 
2120     int32_t i = 0;
2121     for (Locale locale : locales) {
2122         int32_t j = 0;
2123         for (const UnicodeString skeleton : {u"hh", u"HH", u"kk", u"KK", u"jj", u"JJs", u"CC"}) {
2124             LocalPointer<DateIntervalFormat> dtifmt(DateIntervalFormat::createInstance(skeleton, locale, status));
2125             if (status.errDataIfFailureAndReset()) {
2126                 continue;
2127             }
2128             FieldPosition fposition;
2129             UnicodeString result;
2130             LocalPointer<Calendar> calendar(Calendar::createInstance(TimeZone::createTimeZone(timeZone), status));
2131             calendar->setTime(UDate(1563235200000), status);
2132             dtifmt->format(*calendar, *calendar, result, fposition, status);
2133 
2134             assertEquals("Formatted result", expected[i][j++], result);
2135         }
2136         i++;
2137     }
2138 }
2139 
getCategoryAndField(const FormattedDateInterval & formatted,std::vector<int32_t> & categories,std::vector<int32_t> & fields,IcuTestErrorCode & status)2140 void DateIntervalFormatTest::getCategoryAndField(
2141         const FormattedDateInterval& formatted,
2142         std::vector<int32_t>& categories,
2143         std::vector<int32_t>& fields,
2144         IcuTestErrorCode& status) {
2145     categories.clear();
2146     fields.clear();
2147     ConstrainedFieldPosition cfpos;
2148     while (formatted.nextPosition(cfpos, status)) {
2149         categories.push_back(cfpos.getCategory());
2150         fields.push_back(cfpos.getField());
2151     }
2152 }
2153 
verifyCategoryAndField(const FormattedDateInterval & formatted,const std::vector<int32_t> & categories,const std::vector<int32_t> & fields,IcuTestErrorCode & status)2154 void DateIntervalFormatTest::verifyCategoryAndField(
2155         const FormattedDateInterval& formatted,
2156         const std::vector<int32_t>& categories,
2157         const std::vector<int32_t>& fields,
2158         IcuTestErrorCode& status) {
2159     ConstrainedFieldPosition cfpos;
2160     int32_t i = 0;
2161     while (formatted.nextPosition(cfpos, status)) {
2162         assertEquals("Category", cfpos.getCategory(), categories[i]);
2163         assertEquals("Field", cfpos.getField(), fields[i]);
2164         i++;
2165     }
2166 }
2167 
testTicket21222GregorianEraDiff()2168 void DateIntervalFormatTest::testTicket21222GregorianEraDiff() {
2169     IcuTestErrorCode status(*this, "testTicket21222GregorianEraDiff");
2170 
2171     LocalPointer<Calendar> cal(Calendar::createInstance(*TimeZone::getGMT(), status));
2172     if (U_FAILURE(status)) {
2173         errln("Failure encountered: %s", u_errorName(status));
2174         return;
2175     }
2176     std::vector<int32_t> expectedCategory;
2177     std::vector<int32_t> expectedField;
2178 
2179     // Test Gregorian calendar
2180     LocalPointer<DateIntervalFormat> g(
2181         DateIntervalFormat::createInstance(
2182             u"h", Locale("en"), status));
2183     if (U_FAILURE(status)) {
2184         errln("Failure encountered: %s", u_errorName(status));
2185         return;
2186     }
2187     g->setTimeZone(*(TimeZone::getGMT()));
2188     cal->setTime(Calendar::getNow(), status);
2189     cal->set(123, UCAL_APRIL, 5, 6, 0);
2190     FormattedDateInterval formatted;
2191 
2192     UDate date0123Apr5AD = cal->getTime(status);
2193 
2194     cal->set(UCAL_YEAR, 124);
2195     UDate date0124Apr5AD = cal->getTime(status);
2196 
2197     cal->set(UCAL_ERA, 0);
2198     UDate date0124Apr5BC = cal->getTime(status);
2199 
2200     cal->set(UCAL_YEAR, 123);
2201     UDate date0123Apr5BC = cal->getTime(status);
2202 
2203     DateInterval bothAD(date0123Apr5AD, date0124Apr5AD);
2204     DateInterval bothBC(date0124Apr5BC, date0123Apr5BC);
2205     DateInterval BCtoAD(date0123Apr5BC, date0124Apr5AD);
2206 
2207     formatted = g->formatToValue(bothAD, status);
2208     assertEquals("Gregorian - calendar both dates in AD",
2209                  u"4/5/123, 6 AM \u2013 4/5/124, 6 AM",
2210                  formatted.toString(status));
2211 
2212     formatted = g->formatToValue(bothBC, status);
2213     assertEquals("Gregorian - calendar both dates in BC",
2214                  u"4/5/124, 6 AM \u2013 4/5/123, 6 AM",
2215                  formatted.toString(status));
2216 
2217     formatted = g->formatToValue(BCtoAD, status);
2218     assertEquals("Gregorian - BC to AD",
2219                  u"4 5, 123 BC, 6 AM \u2013 4 5, 124 AD, 6 AM",
2220                  formatted.toString(status));
2221 }
2222 
testTicket21222ROCEraDiff()2223 void DateIntervalFormatTest::testTicket21222ROCEraDiff() {
2224     IcuTestErrorCode status(*this, "testTicket21222ROCEraDiff");
2225 
2226     LocalPointer<Calendar> cal(Calendar::createInstance(*TimeZone::getGMT(), status));
2227     if (U_FAILURE(status)) {
2228         errln("Failure encountered: %s", u_errorName(status));
2229         return;
2230     }
2231     std::vector<int32_t> expectedCategory;
2232     std::vector<int32_t> expectedField;
2233 
2234     // Test roc calendar
2235     LocalPointer<DateIntervalFormat> roc(
2236         DateIntervalFormat::createInstance(
2237             u"h", Locale("zh-Hant-TW@calendar=roc"), status));
2238     if (U_FAILURE(status)) {
2239         errln("Failure encountered: %s", u_errorName(status));
2240         return;
2241     }
2242     roc->setTimeZone(*(TimeZone::getGMT()));
2243 
2244     FormattedDateInterval formatted;
2245     // set date1910Jan2 to 1910/1/2 AD which is prior to MG
2246     cal->set(1910, UCAL_JANUARY, 2, 6, 0);
2247     UDate date1910Jan2 = cal->getTime(status);
2248 
2249     // set date1911Jan2 to 1911/1/2 AD which is also prior to MG
2250     cal->set(UCAL_YEAR, 1911);
2251     UDate date1911Jan2 = cal->getTime(status);
2252 
2253     // set date1912Jan2 to 1912/1/2 AD which is after MG
2254     cal->set(UCAL_YEAR, 1912);
2255     UDate date1912Jan2 = cal->getTime(status);
2256 
2257     // set date1913Jan2 to 1913/1/2 AD which is also after MG
2258     cal->set(UCAL_YEAR, 1913);
2259     UDate date1913Jan2 = cal->getTime(status);
2260 
2261     DateInterval bothBeforeMG(date1910Jan2, date1911Jan2);
2262     DateInterval beforeAfterMG(date1911Jan2, date1913Jan2);
2263     DateInterval bothAfterMG(date1912Jan2, date1913Jan2);
2264 
2265     formatted = roc->formatToValue(bothAfterMG, status);
2266     assertEquals("roc calendar - both dates in MG Era",
2267                  u"民國1/1/2 6 上午 – 民國2/1/2 6 上午",
2268                  formatted.toString(status));
2269     getCategoryAndField(formatted, expectedCategory,
2270                         expectedField, status);
2271 
2272     formatted = roc->formatToValue(beforeAfterMG, status);
2273     assertEquals("roc calendar - prior MG Era and in MG Era",
2274                  u"民國前1年1月2日 6 上午 – 民國2年1月2日 6 上午",
2275                  formatted.toString(status));
2276     verifyCategoryAndField(formatted, expectedCategory, expectedField, status);
2277 
2278     formatted = roc->formatToValue(bothBeforeMG, status);
2279     assertEquals("roc calendar - both dates prior MG Era",
2280                  u"民國前2/1/2 6 上午 – 民國前1/1/2 6 上午",
2281                  formatted.toString(status));
2282     verifyCategoryAndField(formatted, expectedCategory, expectedField, status);
2283 }
2284 
testTicket21222JapaneseEraDiff()2285 void DateIntervalFormatTest::testTicket21222JapaneseEraDiff() {
2286     IcuTestErrorCode status(*this, "testTicket21222JapaneseEraDiff");
2287 
2288     LocalPointer<Calendar> cal(Calendar::createInstance(*TimeZone::getGMT(), status));
2289     if (U_FAILURE(status)) {
2290         errln("Failure encountered: %s", u_errorName(status));
2291         return;
2292     }
2293     std::vector<int32_t> expectedCategory;
2294     std::vector<int32_t> expectedField;
2295 
2296     // Test roc calendar
2297     // Test Japanese calendar
2298     LocalPointer<DateIntervalFormat> japanese(
2299         DateIntervalFormat::createInstance(
2300             u"h", Locale("ja@calendar=japanese"), status));
2301     if (U_FAILURE(status)) {
2302         errln("Failure encountered: %s", u_errorName(status));
2303         return;
2304     }
2305     japanese->setTimeZone(*(TimeZone::getGMT()));
2306 
2307     FormattedDateInterval formatted;
2308 
2309     cal->set(2019, UCAL_MARCH, 2, 6, 0);
2310     UDate date2019Mar2 = cal->getTime(status);
2311 
2312     cal->set(UCAL_MONTH, UCAL_APRIL);
2313     cal->set(UCAL_DAY_OF_MONTH, 3);
2314     UDate date2019Apr3 = cal->getTime(status);
2315 
2316     cal->set(UCAL_MONTH, UCAL_MAY);
2317     cal->set(UCAL_DAY_OF_MONTH, 4);
2318     UDate date2019May4 = cal->getTime(status);
2319 
2320     cal->set(UCAL_MONTH, UCAL_JUNE);
2321     cal->set(UCAL_DAY_OF_MONTH, 5);
2322     UDate date2019Jun5 = cal->getTime(status);
2323 
2324     DateInterval bothBeforeReiwa(date2019Mar2, date2019Apr3);
2325     DateInterval beforeAfterReiwa(date2019Mar2, date2019May4);
2326     DateInterval bothAfterReiwa(date2019May4, date2019Jun5);
2327 
2328     formatted = japanese->formatToValue(bothAfterReiwa, status);
2329     assertEquals("japanese calendar - both dates in Reiwa",
2330                  u"R1/5/4 午前6時~R1/6/5 午前6時",
2331                  formatted.toString(status));
2332     getCategoryAndField(formatted, expectedCategory,
2333                         expectedField, status);
2334 
2335     formatted = japanese->formatToValue(bothBeforeReiwa, status);
2336     assertEquals("japanese calendar - both dates before Reiwa",
2337                  u"H31/3/2 午前6時~H31/4/3 午前6時",
2338                  formatted.toString(status));
2339     verifyCategoryAndField(formatted, expectedCategory, expectedField, status);
2340 
2341     formatted = japanese->formatToValue(beforeAfterReiwa, status);
2342     assertEquals("japanese calendar - date before and in Reiwa",
2343                  u"平成31年3月2日 午前6時~令和元年5月4日 午前6時",
2344                  formatted.toString(status));
2345     verifyCategoryAndField(formatted, expectedCategory, expectedField, status);
2346 }
2347 
2348 #endif /* #if !UCONFIG_NO_FORMATTING */
2349