1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html#License
3/*
4 *******************************************************************************
5 * Copyright (C) 2001-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
8 */
9
10/**
11 * Port From:   ICU4C v1.8.1 : format : DateFormatTest
12 * Source File: $ICU4CRoot/source/test/intltest/dtfmttst.cpp
13 **/
14
15package com.ibm.icu.dev.test.format;
16
17import java.io.ByteArrayInputStream;
18import java.io.ByteArrayOutputStream;
19import java.io.IOException;
20import java.io.ObjectInputStream;
21import java.io.ObjectOutputStream;
22import java.text.AttributedCharacterIterator;
23import java.text.CharacterIterator;
24import java.text.FieldPosition;
25import java.text.ParseException;
26import java.text.ParsePosition;
27import java.util.ArrayList;
28import java.util.Arrays;
29import java.util.Date;
30import java.util.EnumSet;
31import java.util.HashSet;
32import java.util.Iterator;
33import java.util.List;
34import java.util.Locale;
35import java.util.Map;
36import java.util.ResourceBundle;
37import java.util.Set;
38
39import org.junit.Test;
40
41import com.ibm.icu.impl.ICUData;
42import com.ibm.icu.impl.ICUResourceBundle;
43import com.ibm.icu.text.ChineseDateFormat;
44import com.ibm.icu.text.ChineseDateFormat.Field;
45import com.ibm.icu.text.ChineseDateFormatSymbols;
46import com.ibm.icu.text.DateFormat;
47import com.ibm.icu.text.DateFormat.BooleanAttribute;
48import com.ibm.icu.text.DateFormatSymbols;
49import com.ibm.icu.text.DisplayContext;
50import com.ibm.icu.text.NumberFormat;
51import com.ibm.icu.text.SimpleDateFormat;
52import com.ibm.icu.text.TimeZoneFormat;
53import com.ibm.icu.text.TimeZoneFormat.ParseOption;
54import com.ibm.icu.util.BuddhistCalendar;
55import com.ibm.icu.util.Calendar;
56import com.ibm.icu.util.ChineseCalendar;
57import com.ibm.icu.util.GregorianCalendar;
58import com.ibm.icu.util.HebrewCalendar;
59import com.ibm.icu.util.IslamicCalendar;
60import com.ibm.icu.util.JapaneseCalendar;
61import com.ibm.icu.util.TimeZone;
62import com.ibm.icu.util.ULocale;
63import com.ibm.icu.util.UResourceBundle;
64import com.ibm.icu.util.VersionInfo;
65
66public class DateFormatTest extends com.ibm.icu.dev.test.TestFmwk {
67    /**
68     * Verify that patterns have the correct values and could produce the
69     * the DateFormat instances that contain the correct localized patterns.
70     */
71    @Test
72    public void TestPatterns() {
73        final String[][] EXPECTED = {
74                {DateFormat.YEAR, "y","en","y"},
75
76                {DateFormat.QUARTER, "QQQQ", "en", "QQQQ"},
77                {DateFormat.ABBR_QUARTER, "QQQ", "en", "QQQ"},
78                {DateFormat.YEAR_QUARTER, "yQQQQ", "en", "QQQQ y"},
79                {DateFormat.YEAR_ABBR_QUARTER, "yQQQ", "en", "QQQ y"},
80
81                {DateFormat.MONTH, "MMMM", "en", "LLLL"},
82                {DateFormat.ABBR_MONTH, "MMM", "en", "LLL"},
83                {DateFormat.NUM_MONTH, "M", "en", "L"},
84                {DateFormat.YEAR_MONTH, "yMMMM","en","MMMM y"},
85                {DateFormat.YEAR_ABBR_MONTH, "yMMM","en","MMM y"},
86                {DateFormat.YEAR_NUM_MONTH, "yM","en","M/y"},
87
88                {DateFormat.DAY, "d","en","d"},
89                {DateFormat.YEAR_MONTH_DAY, "yMMMMd", "en", "MMMM d, y"},
90                {DateFormat.YEAR_ABBR_MONTH_DAY, "yMMMd", "en", "MMM d, y"},
91                {DateFormat.YEAR_NUM_MONTH_DAY, "yMd", "en", "M/d/y"},
92
93                {DateFormat.WEEKDAY, "EEEE", "en", "cccc"},
94                {DateFormat.ABBR_WEEKDAY, "E", "en", "ccc"},
95
96                {DateFormat.YEAR_MONTH_WEEKDAY_DAY, "yMMMMEEEEd", "en", "EEEE, MMMM d, y"},
97                {DateFormat.YEAR_ABBR_MONTH_WEEKDAY_DAY, "yMMMEd", "en", "EEE, MMM d, y"},
98                {DateFormat.YEAR_NUM_MONTH_WEEKDAY_DAY, "yMEd", "en", "EEE, M/d/y"},
99
100                {DateFormat.MONTH_DAY, "MMMMd","en","MMMM d"},
101                {DateFormat.ABBR_MONTH_DAY, "MMMd","en","MMM d"},
102                {DateFormat.NUM_MONTH_DAY, "Md","en","M/d"},
103
104                {DateFormat.MONTH_WEEKDAY_DAY, "MMMMEEEEd","en","EEEE, MMMM d"},
105                {DateFormat.ABBR_MONTH_WEEKDAY_DAY, "MMMEd","en","EEE, MMM d"},
106                {DateFormat.NUM_MONTH_WEEKDAY_DAY, "MEd","en","EEE, M/d"},
107
108                {DateFormat.HOUR, "j", "en", "h a"}, // (fixed expected result per ticket 6872<-6626)
109                {DateFormat.HOUR24, "H", "en", "HH"}, // (fixed expected result per ticket 6872<-6626
110
111                {DateFormat.MINUTE, "m", "en", "m"},
112                {DateFormat.HOUR_MINUTE, "jm","en","h:mm a"}, // (fixed expected result per ticket 6872<-7180)
113                {DateFormat.HOUR24_MINUTE, "Hm", "en", "HH:mm"}, // (fixed expected result per ticket 6872<-6626)
114
115                {DateFormat.SECOND, "s", "en", "s"},
116                {DateFormat.HOUR_MINUTE_SECOND, "jms","en","h:mm:ss a"}, // (fixed expected result per ticket 6872<-7180)
117                {DateFormat.HOUR24_MINUTE_SECOND, "Hms","en","HH:mm:ss"}, // (fixed expected result per ticket 6872<-6626)
118                {DateFormat.MINUTE_SECOND, "ms", "en", "mm:ss"}, // (fixed expected result per ticket 6872<-6626)
119
120                {DateFormat.LOCATION_TZ, "VVVV", "en", "VVVV"},
121                {DateFormat.GENERIC_TZ, "vvvv", "en", "vvvv"},
122                {DateFormat.ABBR_GENERIC_TZ, "v", "en", "v"},
123                {DateFormat.SPECIFIC_TZ, "zzzz", "en", "zzzz"},
124                {DateFormat.ABBR_SPECIFIC_TZ, "z", "en", "z"},
125                {DateFormat.ABBR_UTC_TZ, "ZZZZ", "en", "ZZZZ"},
126
127                {}, // marker for starting combinations
128
129                {DateFormat.YEAR_NUM_MONTH_DAY + DateFormat.ABBR_UTC_TZ, "yMdZZZZ", "en", "M/d/y, ZZZZ"},
130                {DateFormat.MONTH_DAY + DateFormat.LOCATION_TZ, "MMMMdVVVV", "en", "MMMM d, VVVV"},
131        };
132        Date testDate = new Date(2012-1900, 6, 1, 14, 58, 59); // just for verbose log
133
134        List<String> expectedSkeletons = new ArrayList<String>(DateFormat.DATE_SKELETONS);
135        expectedSkeletons.addAll(DateFormat.TIME_SKELETONS);
136        expectedSkeletons.addAll(DateFormat.ZONE_SKELETONS);
137        boolean combinations = false;
138
139        List<String> testedSkeletons = new ArrayList<String>();
140
141        for (int i = 0; i < EXPECTED.length; i++) {
142            if (EXPECTED[i].length == 0) {
143                combinations = true;
144                continue;
145            }
146            boolean ok = true;
147            // Verify that patterns have the correct values
148            String actualPattern = EXPECTED[i][0];
149            if (!combinations) {
150                testedSkeletons.add(actualPattern);
151            }
152            String expectedPattern = EXPECTED[i][1];
153            ULocale locale = new ULocale(EXPECTED[i][2], "", "");
154            if (!actualPattern.equals(expectedPattern)) {
155                errln("FAILURE! Expected pattern: " + expectedPattern +
156                        " but was: " + actualPattern);
157                ok=false;
158            }
159
160            // Verify that DataFormat instances produced contain the correct
161            // localized patterns
162            DateFormat date1 = DateFormat.getPatternInstance(actualPattern,
163                    locale);
164            DateFormat date2 = DateFormat.getPatternInstance(Calendar.getInstance(locale),
165                    actualPattern, locale);
166
167            String expectedLocalPattern = EXPECTED[i][3];
168            String actualLocalPattern1 = ((SimpleDateFormat)date1).toLocalizedPattern();
169            String actualLocalPattern2 = ((SimpleDateFormat)date2).toLocalizedPattern();
170            if (!actualLocalPattern1.equals(expectedLocalPattern)) {
171                errln("FAILURE! Expected local pattern: " + expectedLocalPattern
172                        + " but was: " + actualLocalPattern1);
173                ok=false;
174            }
175            if (!actualLocalPattern2.equals(expectedLocalPattern)) {
176                errln("FAILURE! Expected local pattern: " + expectedLocalPattern
177                        + " but was: " + actualLocalPattern2);
178                ok=false;
179            }
180            if (ok && isVerbose()) {
181                logln(date1.format(testDate) + "\t\t" + Arrays.asList(EXPECTED[i]));
182            }
183        }
184        assertEquals("All skeletons are tested (and in an iterable list)",
185                new HashSet<String>(expectedSkeletons), new HashSet<String>(testedSkeletons));
186        assertEquals("All skeletons are tested (and in an iterable list), and in the right order.", expectedSkeletons, testedSkeletons);
187    }
188
189    // Test written by Wally Wedel and emailed to me.
190    @Test
191    public void TestWallyWedel() {
192        /*
193         * Instantiate a TimeZone so we can get the ids.
194         */
195        //TimeZone tz = new SimpleTimeZone(7, ""); //The variable is never used
196        /*
197         * Computational variables.
198         */
199        int offset, hours, minutes, seconds;
200        /*
201         * Instantiate a SimpleDateFormat set up to produce a full time
202         zone name.
203         */
204        SimpleDateFormat sdf = new SimpleDateFormat("zzzz");
205        /*
206         * A String array for the time zone ids.
207         */
208
209        final String[] ids = TimeZone.getAvailableIDs();
210        int ids_length = ids.length; //when fixed the bug should comment it out
211
212        /*
213         * How many ids do we have?
214         */
215        logln("Time Zone IDs size:" + ids_length);
216        /*
217         * Column headings (sort of)
218         */
219        logln("Ordinal ID offset(h:m) name");
220        /*
221         * Loop through the tzs.
222         */
223        Date today = new Date();
224        Calendar cal = Calendar.getInstance();
225        for (int i = 0; i < ids_length; i++) {
226            logln(i + " " + ids[i]);
227            TimeZone ttz = TimeZone.getTimeZone(ids[i]);
228            // offset = ttz.getRawOffset();
229            cal.setTimeZone(ttz);
230            cal.setTime(today);
231            offset = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET);
232            // logln(i + " " + ids[i] + " offset " + offset);
233            String sign = "+";
234            if (offset < 0) {
235                sign = "-";
236                offset = -offset;
237            }
238            hours = offset / 3600000;
239            minutes = (offset % 3600000) / 60000;
240            seconds = (offset % 60000) / 1000;
241            String dstOffset = sign + (hours < 10 ? "0" : "") + hours
242                    + ":" + (minutes < 10 ? "0" : "") + minutes;
243            if (seconds != 0) {
244                dstOffset += ":" + (seconds < 10 ? "0" : "") + seconds;
245            }
246            /*
247             * Instantiate a date so we can display the time zone name.
248             */
249            sdf.setTimeZone(ttz);
250            /*
251             * Format the output.
252             */
253            StringBuffer fmtOffset = new StringBuffer("");
254            FieldPosition pos = new FieldPosition(0);
255
256            try {
257                fmtOffset = sdf.format(today, fmtOffset, pos);
258            } catch (Exception e) {
259                logln("Exception:" + e);
260                continue;
261            }
262            // UnicodeString fmtOffset = tzS.toString();
263            String fmtDstOffset = null;
264            if (fmtOffset.toString().startsWith("GMT")) {
265                //fmtDstOffset = fmtOffset.substring(3);
266                fmtDstOffset = fmtOffset.substring(3, fmtOffset.length());
267            }
268            /*
269             * Show our result.
270             */
271
272            boolean ok = fmtDstOffset == null || fmtDstOffset.equals("") || fmtDstOffset.equals(dstOffset);
273            if (ok) {
274                logln(i + " " + ids[i] + " " + dstOffset + " "
275                      + fmtOffset + (fmtDstOffset != null ? " ok" : " ?"));
276            } else {
277                errln(i + " " + ids[i] + " " + dstOffset + " " + fmtOffset + " *** FAIL ***");
278            }
279
280        }
281    }
282
283    @Test
284    public void TestEquals() {
285        DateFormat fmtA = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.FULL);
286        DateFormat fmtB = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.FULL);
287        if (!fmtA.equals(fmtB))
288            errln("FAIL");
289    }
290
291    /**
292     * Test the parsing of 2-digit years.
293     */
294    @Test
295    public void TestTwoDigitYearDSTParse() {
296
297        SimpleDateFormat fullFmt = new SimpleDateFormat("EEE MMM dd HH:mm:ss.SSS zzz yyyy G");
298        SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yy h:mm:ss 'o''clock' a z", Locale.ENGLISH);
299        String s = "03-Apr-04 2:20:47 o'clock AM PST";
300
301        /*
302         * SimpleDateFormat(pattern, locale) Construct a SimpleDateDateFormat using
303         * the given pattern, the locale and using the TimeZone.getDefault();
304         * So it need to add the timezone offset on hour field.
305         * ps. the Method Calendar.getTime() used by SimpleDateFormat.parse() always
306         * return Date value with TimeZone.getDefault() [Richard/GCL]
307         */
308
309        TimeZone defaultTZ = TimeZone.getDefault();
310        TimeZone PST = TimeZone.getTimeZone("PST");
311        int defaultOffset = defaultTZ.getRawOffset();
312        int PSTOffset = PST.getRawOffset();
313        int hour = 2 + (defaultOffset - PSTOffset) / (60*60*1000);
314        // hour is the expected hour of day, in units of seconds
315        hour = ((hour < 0) ? hour + 24 : hour) * 60*60;
316        try {
317            Date d = fmt.parse(s);
318            Calendar cal = Calendar.getInstance();
319            cal.setTime(d);
320            //DSTOffset
321            hour += defaultTZ.inDaylightTime(d) ? 1 : 0;
322
323            logln(s + " P> " + ((DateFormat) fullFmt).format(d));
324            // hr is the actual hour of day, in units of seconds
325            // adjust for DST
326            int hr = cal.get(Calendar.HOUR_OF_DAY) * 60*60 -
327                cal.get(Calendar.DST_OFFSET) / 1000;
328            if (hr != hour)
329                errln("FAIL: Hour (-DST) = " + hr / (60*60.0)+
330                      "; expected " + hour / (60*60.0));
331        } catch (ParseException e) {
332            errln("Parse Error:" + e.getMessage());
333        }
334
335    }
336
337    /**
338     * Verify that returned field position indices are correct.
339     */
340    @Test
341    public void TestFieldPosition() {
342        int i, j, exp;
343        StringBuffer buf = new StringBuffer();
344
345        // Verify data
346        if (VersionInfo.ICU_VERSION.compareTo(VersionInfo.getInstance(3, 7)) >= 0) {
347            DateFormatSymbols rootSyms = new DateFormatSymbols(new Locale("", "", ""));
348            assertEquals("patternChars", PATTERN_CHARS, rootSyms.getLocalPatternChars());
349        }
350
351        assertTrue("DATEFORMAT_FIELD_NAMES", DATEFORMAT_FIELD_NAMES.length == DateFormat.FIELD_COUNT);
352        if(DateFormat.FIELD_COUNT != PATTERN_CHARS.length() + 1){ // +1 for missing TIME_SEPARATOR pattern char
353            errln("Did not get the correct value for DateFormat.FIELD_COUNT. Expected:  "+ PATTERN_CHARS.length() + 1);
354        }
355
356        // Create test formatters
357        final int COUNT = 4;
358        DateFormat[] dateFormats = new DateFormat[COUNT];
359        dateFormats[0] = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.US);
360        dateFormats[1] = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.FRANCE);
361        // Make the pattern "G y M d..."
362        buf.append(PATTERN_CHARS);
363        for (j=buf.length()-1; j>=0; --j) buf.insert(j, ' ');
364        dateFormats[2] = new SimpleDateFormat(buf.toString(), Locale.US);
365        // Make the pattern "GGGG yyyy MMMM dddd..."
366        for (j=buf.length()-1; j>=0; j-=2) {
367            for (i=0; i<3; ++i) {
368                buf.insert(j, buf.charAt(j));
369            }
370        }
371        dateFormats[3] = new SimpleDateFormat(buf.toString(), Locale.US);
372
373        Date aug13 = new Date((long) 871508052513.0);
374
375        // Expected output field values for above DateFormats on aug13
376        // Fields are given in order of DateFormat field number
377        final String EXPECTED[] = {
378             "", "1997", "August", "13", "", "", "34", "12", "", "Wednesday",
379             "", "", "", "", "PM", "2", "", "Pacific Daylight Time", "", "",
380             "", "", "", "", "", "", "", "", "", "",
381             "", "", "", "", "", "", "", "",
382
383             "", "1997", "ao\u00FBt", "13", "", "14", "34", "12", "", "mercredi",
384             "", "", "", "", "", "", "", "heure d\u2019\u00E9t\u00E9 du Pacifique", "", "",
385             "", "", "", "", "", "", "", "", "", "",
386             "", "", "", "", "", "", "", "",
387
388            "AD", "1997", "8", "13", "14", "14", "34", "12", "5", "Wed",
389            "225", "2", "33", "3", "PM", "2", "2", "PDT", "1997", "4",
390            "1997", "2450674", "52452513", "-0700", "PT", "4", "8", "3", "3", "uslax",
391            "1997", "GMT-7", "-07", "-07", "1997", "PM", "in the afternoon", "",
392
393            "Anno Domini", "1997", "August", "0013", "0014", "0014", "0034", "0012", "5130", "Wednesday",
394            "0225", "0002", "0033", "0003", "PM", "0002", "0002", "Pacific Daylight Time", "1997", "Wednesday",
395            "1997", "2450674", "52452513", "GMT-07:00", "Pacific Time", "Wednesday", "August", "3rd quarter", "3rd quarter", "Los Angeles Time",
396            "1997", "GMT-07:00", "-0700", "-0700", "1997", "PM", "in the afternoon", "",
397        };
398
399        assertTrue("data size", EXPECTED.length == COUNT * DateFormat.FIELD_COUNT);
400
401        final DateFormat.Field[] DTFMT_FIELDS = {
402            DateFormat.Field.AM_PM,
403            DateFormat.Field.DAY_OF_MONTH,
404            DateFormat.Field.DAY_OF_WEEK,
405            DateFormat.Field.DAY_OF_WEEK_IN_MONTH,
406            DateFormat.Field.DAY_OF_YEAR,
407
408            DateFormat.Field.DOW_LOCAL,
409            DateFormat.Field.ERA,
410            DateFormat.Field.EXTENDED_YEAR,
411            DateFormat.Field.HOUR_OF_DAY0,
412            DateFormat.Field.HOUR_OF_DAY1,
413
414            DateFormat.Field.HOUR0,
415            DateFormat.Field.HOUR1,
416            DateFormat.Field.JULIAN_DAY,
417            DateFormat.Field.MILLISECOND,
418            DateFormat.Field.MILLISECONDS_IN_DAY,
419
420            DateFormat.Field.MINUTE,
421            DateFormat.Field.MONTH,
422            DateFormat.Field.QUARTER,
423            DateFormat.Field.SECOND,
424            DateFormat.Field.TIME_ZONE,
425
426            DateFormat.Field.WEEK_OF_MONTH,
427            DateFormat.Field.WEEK_OF_YEAR,
428            DateFormat.Field.YEAR,
429            DateFormat.Field.YEAR_WOY,
430        };
431
432        final String[][] EXPECTED_BY_FIELD = {
433            {"PM", "13", "Wednesday", "", "",
434             "", "", "", "", "",
435             "", "2", "", "", "",
436             "34", "August", "", "12", "Pacific Daylight Time",
437             "", "", "1997", ""},
438
439            {"", "13", "mercredi", "", "",
440             "", "", "", "14", "",
441             "", "", "", "", "",
442             "34", "ao\u00FBt", "", "12", "heure d\u2019\u00E9t\u00E9 du Pacifique",
443             "", "", "1997", ""},
444
445            {"PM", "13", "Wed", "2", "225",
446             "4", "AD", "1997", "14", "14",
447             "2", "2", "2450674", "5", "52452513",
448             "34", "8", "3", "12", "PDT",
449             "3", "33", "1997", "1997"},
450
451            {"PM", "0013", "Wednesday", "0002", "0225",
452             "Wednesday", "Anno Domini", "1997", "0014", "0014",
453             "0002", "0002", "2450674", "5130", "52452513",
454             "0034", "August", "3rd quarter", "0012", "Pacific Daylight Time",
455             "0003", "0033", "1997", "1997"},
456        };
457
458        TimeZone PT = TimeZone.getTimeZone("America/Los_Angeles");
459        for (j = 0, exp = 0; j < COUNT; ++j) {
460            //  String str;
461            DateFormat df = dateFormats[j];
462            df.setTimeZone(PT);
463            logln(" Pattern = " + ((SimpleDateFormat) df).toPattern());
464            try {
465                logln("  Result = " + df.format(aug13));
466            } catch (Exception e) {
467                errln("FAIL: " + e);
468                e.printStackTrace();
469                continue;
470            }
471
472            FieldPosition pos;
473            String field;
474
475            for (i = 0; i < DateFormat.FIELD_COUNT; ++i, ++exp) {
476                pos = new FieldPosition(i);
477                buf.setLength(0);
478                df.format(aug13, buf, pos);
479                field = buf.substring(pos.getBeginIndex(), pos.getEndIndex());
480                assertEquals("pattern#" + j + " field #" + i + " " + DATEFORMAT_FIELD_NAMES[i],
481                             EXPECTED[exp], field);
482            }
483
484            // FieldPostion initialized by DateFormat.Field trac#6089
485            for(i = 0; i < DTFMT_FIELDS.length; i++) {
486                // The format method only set position for the first occurrence of
487                // the specified field.
488                pos = new FieldPosition(DTFMT_FIELDS[i]);
489                buf.setLength(0);
490                df.format(aug13, buf, pos);
491                field = buf.substring(pos.getBeginIndex(), pos.getEndIndex());
492                assertEquals("pattern#" + j + " " + DTFMT_FIELDS[i].toString(), EXPECTED_BY_FIELD[j][i], field);
493            }
494        }
495    }
496    /**
497     * This MUST be kept in sync with DateFormatSymbols.patternChars.
498     */
499    static final String PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB";
500
501    /**
502     * A list of the DateFormat.Field.
503     * This MUST be kept in sync with PATTERN_CHARS above.
504     */
505    static final DateFormat.Field[] DATEFORMAT_FIELDS = {
506        DateFormat.Field.ERA,           // G
507        DateFormat.Field.YEAR,          // y
508        DateFormat.Field.MONTH,         // M
509        DateFormat.Field.DAY_OF_MONTH,  // d
510        DateFormat.Field.HOUR_OF_DAY1,  // k
511        DateFormat.Field.HOUR_OF_DAY0,  // H
512        DateFormat.Field.MINUTE,        // m
513        DateFormat.Field.SECOND,        // s
514        DateFormat.Field.MILLISECOND,   // S
515        DateFormat.Field.DAY_OF_WEEK,   // E
516        DateFormat.Field.DAY_OF_YEAR,   // D
517        DateFormat.Field.DAY_OF_WEEK_IN_MONTH,  // F
518        DateFormat.Field.WEEK_OF_YEAR,  // w
519        DateFormat.Field.WEEK_OF_MONTH, // W
520        DateFormat.Field.AM_PM,         // a
521        DateFormat.Field.HOUR1,         // h
522        DateFormat.Field.HOUR0,         // K
523        DateFormat.Field.TIME_ZONE,     // z
524        DateFormat.Field.YEAR_WOY,      // Y
525        DateFormat.Field.DOW_LOCAL,     // e
526        DateFormat.Field.EXTENDED_YEAR, // u
527        DateFormat.Field.JULIAN_DAY,    // g
528        DateFormat.Field.MILLISECONDS_IN_DAY,   // A
529        DateFormat.Field.TIME_ZONE,     // Z
530        DateFormat.Field.TIME_ZONE,     // v
531        DateFormat.Field.DAY_OF_WEEK,   // c
532        DateFormat.Field.MONTH,         // L
533        DateFormat.Field.QUARTER,       // Q
534        DateFormat.Field.QUARTER,       // q
535        DateFormat.Field.TIME_ZONE,     // V
536        DateFormat.Field.YEAR,          // U
537        DateFormat.Field.TIME_ZONE,     // O
538        DateFormat.Field.TIME_ZONE,     // X
539        DateFormat.Field.TIME_ZONE,     // x
540        DateFormat.Field.RELATED_YEAR,  // r
541        DateFormat.Field.AM_PM_MIDNIGHT_NOON,  // b
542        DateFormat.Field.FLEXIBLE_DAY_PERIOD,  // B
543        DateFormat.Field.TIME_SEPARATOR,// (no pattern character currently specified for this)
544    };
545
546    /**
547     * A list of the names of all the fields in DateFormat.
548     * This MUST be kept in sync with DateFormat.
549     */
550    static final String DATEFORMAT_FIELD_NAMES[] = {
551        "ERA_FIELD",
552        "YEAR_FIELD",
553        "MONTH_FIELD",
554        "DATE_FIELD",
555        "HOUR_OF_DAY1_FIELD",
556        "HOUR_OF_DAY0_FIELD",
557        "MINUTE_FIELD",
558        "SECOND_FIELD",
559        "MILLISECOND_FIELD",
560        "DAY_OF_WEEK_FIELD",
561        "DAY_OF_YEAR_FIELD",
562        "DAY_OF_WEEK_IN_MONTH_FIELD",
563        "WEEK_OF_YEAR_FIELD",
564        "WEEK_OF_MONTH_FIELD",
565        "AM_PM_FIELD",
566        "HOUR1_FIELD",
567        "HOUR0_FIELD",
568        "TIMEZONE_FIELD",
569        "YEAR_WOY_FIELD",
570        "DOW_LOCAL_FIELD",
571        "EXTENDED_YEAR_FIELD",
572        "JULIAN_DAY_FIELD",
573        "MILLISECONDS_IN_DAY_FIELD",
574        "TIMEZONE_RFC_FIELD",
575        "GENERIC_TIMEZONE_FIELD",
576        "STAND_ALONE_DAY_FIELD",
577        "STAND_ALONE_MONTH_FIELD",
578        "QUARTER_FIELD",
579        "STAND_ALONE_QUARTER_FIELD",
580        "TIMEZONE_SPECIAL_FIELD",
581        "YEAR_NAME_FIELD",
582        "TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD",
583        "TIMEZONE_ISO_FIELD",
584        "TIMEZONE_ISO_LOCAL_FIELD",
585        "RELATED_YEAR",
586        "AM_PM_MIDNIGHT_NOON_FIELD",
587        "FLEXIBLE_DAY_PERIOD_FIELD",
588        "TIME_SEPARATOR",
589    };
590
591    /**
592     * General parse/format tests.  Add test cases as needed.
593     */
594    @Test
595    public void TestGeneral() {
596
597        String DATA[] = {
598            "yyyy MM dd HH:mm:ss.SSS",
599
600            // Milliseconds are left-justified, since they format as fractions of a second
601            // Both format and parse should round HALF_UP
602            "y/M/d H:mm:ss.S", "fp", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.5", "2004 03 10 16:36:31.500",
603            "y/M/d H:mm:ss.SS", "fp", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.56", "2004 03 10 16:36:31.560",
604            "y/M/d H:mm:ss.SSS", "F", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.567",
605            "y/M/d H:mm:ss.SSSS", "pf", "2004/3/10 16:36:31.5679", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.5670",
606        };
607        expect(DATA, new Locale("en", "", ""));
608    }
609
610    @Test
611    public void TestGenericTime() {
612
613
614        // any zone pattern should parse any zone
615        Locale en = new Locale("en", "", "");
616        String ZDATA[] = {
617            "yyyy MM dd HH:mm zzz",
618            // round trip
619            "y/M/d H:mm zzzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Standard Time",
620            "y/M/d H:mm zzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
621            "y/M/d H:mm vvvv", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
622            "y/M/d H:mm v", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PT",
623            // non-generic timezone string influences dst offset even if wrong for date/time
624            "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PDT", "2004 01 01 01:00 PDT", "2004/1/1 0:00 PST",
625            "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 PDT", "2004 01 01 01:00 PDT", "2004/1/1 0:00 Pacific Time",
626            "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PST", "2004 07 01 02:00 PDT", "2004/7/1 2:00 PDT",
627            "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 PST", "2004 07 01 02:00 PDT", "2004/7/1 2:00 Pacific Time",
628            // generic timezone generates dst offset appropriate for local time
629            "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
630            "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
631            "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
632            "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 Pacific Time",
633            // daylight savings time transition edge cases.
634            // time to parse does not really exist, PT interpreted as earlier time
635            "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PT", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PDT",
636            "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PST", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PDT",
637            "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PDT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PST",
638            "y/M/d H:mm v", "pf", "2005/4/3 2:30 PT", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PT",
639            "y/M/d H:mm v", "pf", "2005/4/3 2:30 PST", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PT",
640            "y/M/d H:mm v", "pf", "2005/4/3 2:30 PDT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PT",
641            "y/M/d H:mm", "pf", "2005/4/3 2:30", "2005 04 03 03:30 PDT", "2005/4/3 3:30",
642            // time to parse is ambiguous, PT interpreted as later time
643            "y/M/d H:mm zzz", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30 PST",
644            "y/M/d H:mm v", "pf", "2005/10/30 1:30 PT", "2005 10 30  01:30 PST", "2005/10/30 1:30 PT",
645            "y/M/d H:mm", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30",
646
647            "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PT", "2004 10 31 01:30 PST", "2004/10/31 1:30 PST",
648             "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PST", "2004 10 31 01:30 PST", "2004/10/31 1:30 PST",
649             "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PDT", "2004 10 31 01:30 PDT", "2004/10/31 1:30 PDT",
650             "y/M/d H:mm v", "pf", "2004/10/31 1:30 PT", "2004 10 31 01:30 PST", "2004/10/31 1:30 PT",
651             "y/M/d H:mm v", "pf", "2004/10/31 1:30 PST", "2004 10 31 01:30 PST", "2004/10/31 1:30 PT",
652             "y/M/d H:mm v", "pf", "2004/10/31 1:30 PDT", "2004 10 31 01:30 PDT", "2004/10/31 1:30 PT",
653             "y/M/d H:mm", "pf", "2004/10/31 1:30", "2004 10 31 01:30 PST", "2004/10/31 1:30",
654            // Below is actually an invalid test case.  See the note in #5910.  Disable the case for now.
655            // TODO: Revisit after 3.8
656            //"y/M/d H:mm vvvv", "pf", "2004/10/31 1:30 Argentina Time", "2004 10 30 21:30 PDT", "2004/10/31 1:30 Argentina Time",
657        };
658        expect(ZDATA, en, true);
659
660        logln("cross format/parse tests");
661        final String basepat = "yy/MM/dd H:mm ";
662        final SimpleDateFormat[] formats = {
663            new SimpleDateFormat(basepat + "v", en),
664            new SimpleDateFormat(basepat + "vvvv", en),
665            new SimpleDateFormat(basepat + "zzz", en),
666            new SimpleDateFormat(basepat + "zzzz", en)
667        };
668
669        final SimpleDateFormat univ = new SimpleDateFormat("yyyy MM dd HH:mm zzz", en);
670
671     // To allow cross pattern parsing, we need to set ParseOption.ALL_STYLES
672        TimeZoneFormat tzfmt = univ.getTimeZoneFormat().cloneAsThawed();
673        tzfmt.setDefaultParseOptions(EnumSet.of(ParseOption.ALL_STYLES));
674        tzfmt.freeze();
675        univ.setTimeZoneFormat(tzfmt);
676        for (SimpleDateFormat sdf : formats) {
677            sdf.setTimeZoneFormat(tzfmt);
678        }
679
680        final String[] times = { "2004 01 02 03:04 PST", "2004 07 08 09:10 PDT" };
681        for (int i = 0; i < times.length; ++i) {
682            try {
683                Date d = univ.parse(times[i]);
684                logln("time: " + d);
685                for (int j = 0; j < formats.length; ++j) {
686                    String test = formats[j].format(d);
687                    logln("test: '" + test + "'");
688                    for (int k = 0; k < formats.length; ++k) {
689                        try {
690                            Date t = formats[k].parse(test);
691                            if (!d.equals(t)) {
692                                errln("format " + k +
693                                      " incorrectly parsed output of format " + j +
694                                      " (" + test + "), returned " +
695                                      t + " instead of " + d);
696                            } else {
697                                logln("format " + k + " parsed ok");
698                            }
699                        }
700                        catch (ParseException e) {
701                            errln("format " + k +
702                                  " could not parse output of format " + j +
703                                  " (" + test + ")");
704                        }
705                    }
706                }
707            }
708            catch (ParseException e) {
709                errln("univ could not parse: " + times[i]);
710            }
711        }
712
713    }
714
715    @Test
716    public void TestGenericTimeZoneOrder() {
717        // generic times should parse the same no matter what the placement of the time zone string
718        // should work for standard and daylight times
719
720        String XDATA[] = {
721            "yyyy MM dd HH:mm zzz",
722            // standard time, explicit daylight/standard
723            "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
724            "y/M/d zzz H:mm", "pf", "2004/1/1 PT 1:00", "2004 01 01 01:00 PST", "2004/1/1 PST 1:00",
725            "zzz y/M/d H:mm", "pf", "PT 2004/1/1 1:00", "2004 01 01 01:00 PST", "PST 2004/1/1 1:00",
726
727            // standard time, generic
728            "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
729            "y/M/d vvvv H:mm", "pf", "2004/1/1 PT 1:00", "2004 01 01 01:00 PST", "2004/1/1 Pacific Time 1:00",
730            "vvvv y/M/d H:mm", "pf", "PT 2004/1/1 1:00", "2004 01 01 01:00 PST", "Pacific Time 2004/1/1 1:00",
731
732            // daylight time, explicit daylight/standard
733            "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
734            "y/M/d zzz H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 PDT 1:00",
735            "zzz y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "PDT 2004/7/1 1:00",
736
737            // daylight time, generic
738            "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 Pacific Time",
739            "y/M/d vvvv H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 Pacific Time 1:00",
740            "vvvv y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "Pacific Time 2004/7/1 1:00",
741        };
742        Locale en = new Locale("en", "", "");
743        expect(XDATA, en, true);
744    }
745
746    @Test
747    public void TestTimeZoneDisplayName() {
748        Calendar cal = new GregorianCalendar();
749        SimpleDateFormat testfmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
750        testfmt.setTimeZone(TimeZone.getTimeZone("Etc/GMT"));
751
752        for (int i = 0; i < fallbackTests.length; ++i) {
753            String[] info = fallbackTests[i];
754            logln(info[0] + ";" + info[1] + ";" + info[2] + ";" + info[3]);
755
756            long time = 0;
757            try {
758                Date testd = testfmt.parse(info[2]);
759                time = testd.getTime();
760            } catch (ParseException pe) {
761                errln("Failed to parse test date data");
762                continue;
763            }
764            ULocale l = new ULocale(info[0]);
765            TimeZone tz = TimeZone.getTimeZone(info[1]);
766            SimpleDateFormat fmt = new SimpleDateFormat(info[3], l);
767            cal.setTimeInMillis(time);
768            cal.setTimeZone(tz);
769            String result = fmt.format(cal);
770            if (!result.equals(info[4])) {
771                errln(info[0] + ";" + info[1] + ";" + info[2] + ";" + info[3] + " expected: '" +
772                      info[4] + "' but got: '" + result + "'");
773            }
774        }
775    }
776
777    private static final String GMT_BG = "\u0413\u0440\u0438\u043D\u0443\u0438\u0447";
778    private static final String GMT_ZH = "GMT";
779    //private static final String GMT_ZH = "\u683C\u6797\u5C3C\u6CBB\u6807\u51C6\u65F6\u95F4";
780    //private static final String GMT_BG = "GMT";
781
782    private static final String[][] fallbackTests  = {
783        { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
784        { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
785        { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZZ", "-08:00", "-8:00" },
786        { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "PST", "America/Los_Angeles" },
787        { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "Pacific Standard Time", "America/Los_Angeles" },
788        { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
789        { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
790        { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "PDT", "America/Los_Angeles" },
791        { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "Pacific Daylight Time", "America/Los_Angeles" },
792        { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "PT", "America/Los_Angeles" },
793        { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Pacific Time", "America/Los_Angeles" },
794        { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "Los Angeles Time", "America/Los_Angeles" },
795        { "en_GB", "America/Los_Angeles", "2004-01-15T12:00:00Z", "z", "GMT-8", "America/Los_Angeles" },
796        { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "Z", "-0700", "-7:00" },
797        { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
798        { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "z", "MST", "America/Phoenix" },
799        { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "zzzz", "Mountain Standard Time", "America/Phoenix" },
800        { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
801        { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
802        { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "z", "MST", "America/Phoenix" },
803        { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "zzzz", "Mountain Standard Time", "America/Phoenix" },
804        { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "v", "MST", "America/Phoenix" },
805        { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "vvvv", "Mountain Standard Time", "America/Phoenix" },
806        { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "VVVV", "Phoenix Time", "America/Phoenix" },
807
808        { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
809        { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
810        { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
811        { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
812        { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
813        { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
814        { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
815        { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
816        { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Time", "America/Buenos_Aires" },
817        { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentina Standard Time", "America/Buenos_Aires" },
818        { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "VVVV", "Buenos Aires Time", "America/Buenos_Aires" },
819
820        { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
821        { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
822        { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
823        { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
824        { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
825        { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
826        { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
827        { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
828        { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Time", "America/Buenos_Aires" },
829        { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentina Standard Time", "America/Buenos_Aires" },
830        { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "VVVV", "Buenos Aires Time", "America/Buenos_Aires" },
831
832        { "en", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
833        { "en", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
834        { "en", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
835        { "en", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "Cuba Standard Time", "-5:00" },
836        { "en", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
837        { "en", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
838        { "en", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
839        { "en", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "Cuba Daylight Time", "-4:00" },
840        { "en", "America/Havana", "2004-07-15T00:00:00Z", "v", "Cuba Time", "America/Havana" },
841        { "en", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Cuba Time", "America/Havana" },
842        { "en", "America/Havana", "2004-07-15T00:00:00Z", "VVVV", "Cuba Time", "America/Havana" },
843
844        { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
845        { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
846        { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
847        { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "Australian Eastern Daylight Time", "+11:00" },
848        { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
849        { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
850        { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
851        { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "Australian Eastern Standard Time", "+10:00" },
852        { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Sydney Time", "Australia/Sydney" },
853        { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Eastern Australia Time", "Australia/Sydney" },
854        { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "VVVV", "Sydney Time", "Australia/Sydney" },
855
856        { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
857        { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
858        { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
859        { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "Australian Eastern Daylight Time", "+11:00" },
860        { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
861        { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
862        { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
863        { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "Australian Eastern Standard Time", "+10:00" },
864        { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Sydney Time", "Australia/Sydney" },
865        { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Eastern Australia Time", "Australia/Sydney" },
866        { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "VVVV", "Sydney Time", "Australia/Sydney" },
867
868        { "en", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
869        { "en", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
870        { "en", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
871        { "en", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "Greenwich Mean Time", "+0:00" },
872        { "en", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
873        { "en", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
874        { "en", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "Europe/London" },
875        { "en", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "British Summer Time", "Europe/London" },
876    // icu en.txt has exemplar city for this time zone
877        { "en", "Europe/London", "2004-07-15T00:00:00Z", "v", "United Kingdom Time", "Europe/London" },
878        { "en", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "United Kingdom Time", "Europe/London" },
879        { "en", "Europe/London", "2004-07-15T00:00:00Z", "VVVV", "United Kingdom Time", "Europe/London" },
880
881        { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
882        { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
883        { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
884        { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
885        { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
886        { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
887        { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
888        { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
889        { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
890        { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
891
892        // JB#5150
893        { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
894        { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
895        { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
896        { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "India Standard Time", "+5:30" },
897        { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
898        { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
899        { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
900        { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "India Standard Time", "+5:30" },
901        { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "India Time", "Asia/Calcutta" },
902        { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "India Standard Time", "Asia/Calcutta" },
903
904        // Proper CLDR primary zone support #9733
905        { "en", "America/Santiago", "2013-01-01T00:00:00Z", "VVVV", "Chile Time", "America/Santiago" },
906        { "en", "Pacific/Easter", "2013-01-01T00:00:00Z", "VVVV", "Easter Time", "Pacific/Easter" },
907
908        // ==========
909
910        { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
911        { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
912        { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "-8:00" },
913        { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "Nordamerikanische Westk\u00fcsten-Normalzeit", "-8:00" },
914        { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
915        { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
916        { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "-7:00" },
917        { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "Nordamerikanische Westk\u00fcsten-Sommerzeit", "-7:00" },
918        { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "Los Angeles Zeit", "America/Los_Angeles" },
919        { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Nordamerikanische Westk\u00fcstenzeit", "America/Los_Angeles" },
920
921        { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
922        { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
923        { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
924        { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
925        { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
926        { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
927        { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
928        { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
929        { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Zeit", "America/Buenos_Aires" },
930        { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentinische Normalzeit", "America/Buenos_Aires" },
931
932        { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
933        { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
934        { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
935        { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
936        { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
937        { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
938        { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
939        { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
940        { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Zeit", "America/Buenos_Aires" },
941        { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentinische Normalzeit", "America/Buenos_Aires" },
942
943        { "de", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
944        { "de", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
945        { "de", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
946        { "de", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "Kubanische Normalzeit", "-5:00" },
947        { "de", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
948        { "de", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
949        { "de", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
950        { "de", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "Kubanische Sommerzeit", "-4:00" },
951        { "de", "America/Havana", "2004-07-15T00:00:00Z", "v", "Kuba Zeit", "America/Havana" },
952        { "de", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Kubanische Zeit", "America/Havana" },
953        // added to test proper fallback of country name
954        { "de_CH", "America/Havana", "2004-07-15T00:00:00Z", "v", "Kuba Zeit", "America/Havana" },
955        { "de_CH", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Kubanische Zeit", "America/Havana" },
956
957        { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
958        { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
959        { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
960        { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "Ostaustralische Sommerzeit", "+11:00" },
961        { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
962        { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
963        { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
964        { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "Ostaustralische Normalzeit", "+10:00" },
965        { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Sydney Zeit", "Australia/Sydney" },
966        { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Ostaustralische Zeit", "Australia/Sydney" },
967
968        { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
969        { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
970        { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
971        { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "Ostaustralische Sommerzeit", "+11:00" },
972        { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
973        { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
974        { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
975        { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "Ostaustralische Normalzeit", "+10:00" },
976        { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Sydney Zeit", "Australia/Sydney" },
977        { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Ostaustralische Zeit", "Australia/Sydney" },
978
979        { "de", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
980        { "de", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
981        { "de", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
982        { "de", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "Mittlere Greenwich-Zeit", "+0:00" },
983        { "de", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
984        { "de", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
985        { "de", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
986        { "de", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "Britische Sommerzeit", "+1:00" },
987        { "de", "Europe/London", "2004-07-15T00:00:00Z", "v", "Vereinigtes K\u00f6nigreich Zeit", "Europe/London" },
988        { "de", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "Vereinigtes K\u00f6nigreich Zeit", "Europe/London" },
989
990        { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
991        { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
992        { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
993        { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
994        { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
995        { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
996        { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
997        { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
998        { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
999        { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
1000
1001        // JB#5150
1002        { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
1003        { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
1004        { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
1005        { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "Indische Zeit", "+5:30" },
1006        { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
1007        { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
1008        { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
1009        { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "Indische Zeit", "+5:30" },
1010        { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "Indien Zeit", "Asia/Calcutta" },
1011        { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "Indische Zeit", "Asia/Calcutta" },
1012
1013        // ==========
1014
1015        { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
1016        { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", GMT_ZH+"-08:00", "-8:00" },
1017        { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", GMT_ZH+"-8", "America/Los_Angeles" },
1018        { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\u5317\u7f8e\u592a\u5e73\u6d0b\u6807\u51c6\u65f6\u95f4", "America/Los_Angeles" },
1019        { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
1020        { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", GMT_ZH+"-07:00", "-7:00" },
1021        { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", GMT_ZH+"-7", "America/Los_Angeles" },
1022        { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\u5317\u7f8e\u592a\u5e73\u6d0b\u590f\u4ee4\u65f6\u95f4", "America/Los_Angeles" },
1023    // icu zh.txt has exemplar city for this time zone
1024        { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\u6D1B\u6749\u77F6\u65F6\u95F4", "America/Los_Angeles" },
1025        { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\u5317\u7f8e\u592a\u5e73\u6d0b\u65f6\u95f4", "America/Los_Angeles" },
1026
1027        { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
1028        { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", GMT_ZH+"-03:00", "-3:00" },
1029        { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", GMT_ZH+"-3", "-3:00" },
1030        { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\u963f\u6839\u5ef7\u6807\u51c6\u65f6\u95f4", "-3:00" },
1031        { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
1032        { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", GMT_ZH+"-03:00", "-3:00" },
1033        { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", GMT_ZH+"-3", "-3:00" },
1034        { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\u963f\u6839\u5ef7\u6807\u51c6\u65f6\u95f4", "-3:00" },
1035    // icu zh.txt does not have info for this time zone
1036        { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\u5E03\u5B9C\u8BFA\u65AF\u827E\u5229\u65AF\u65F6\u95F4", "America/Buenos_Aires" },
1037        { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\u963f\u6839\u5ef7\u6807\u51c6\u65f6\u95f4", "America/Buenos_Aires" },
1038
1039        { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
1040        { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", GMT_ZH+"-03:00", "-3:00" },
1041        { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", GMT_ZH+"-3", "-3:00" },
1042        { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\u963f\u6839\u5ef7\u6807\u51c6\u65f6\u95f4", "-3:00" },
1043        { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
1044        { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", GMT_ZH+"-03:00", "-3:00" },
1045        { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", GMT_ZH+"-3", "-3:00" },
1046        { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\u963f\u6839\u5ef7\u6807\u51c6\u65f6\u95f4", "-3:00" },
1047        { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\u5E03\u5B9C\u8BFA\u65AF\u827E\u5229\u65AF\u65F6\u95F4", "America/Buenos_Aires" },
1048        { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\u963f\u6839\u5ef7\u6807\u51c6\u65f6\u95f4", "America/Buenos_Aires" },
1049
1050        { "zh", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
1051        { "zh", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", GMT_ZH+"-05:00", "-5:00" },
1052        { "zh", "America/Havana", "2004-01-15T00:00:00Z", "z", GMT_ZH+"-5", "-5:00" },
1053        { "zh", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\u53e4\u5df4\u6807\u51c6\u65f6\u95f4", "-5:00" },
1054        { "zh", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
1055        { "zh", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", GMT_ZH+"-04:00", "-4:00" },
1056        { "zh", "America/Havana", "2004-07-15T00:00:00Z", "z", GMT_ZH+"-4", "-4:00" },
1057        { "zh", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\u53e4\u5df4\u590f\u4ee4\u65f6\u95f4", "-4:00" },
1058        { "zh", "America/Havana", "2004-07-15T00:00:00Z", "v", "\u53e4\u5df4\u65f6\u95f4", "America/Havana" },
1059        { "zh", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\u53e4\u5df4\u65f6\u95f4", "America/Havana" },
1060
1061        { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
1062        { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", GMT_ZH+"+11:00", "+11:00" },
1063        { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "z", GMT_ZH+"+11", "+11:00" },
1064        { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\u6fb3\u5927\u5229\u4e9a\u4e1c\u90e8\u590f\u4ee4\u65f6\u95f4", "+11:00" },
1065        { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
1066        { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", GMT_ZH+"+10:00", "+10:00" },
1067        { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "z", GMT_ZH+"+10", "+10:00" },
1068        { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\u6fb3\u5927\u5229\u4e9a\u4e1c\u90e8\u6807\u51c6\u65f6\u95f4", "+10:00" },
1069        { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\u6089\u5C3C\u65F6\u95F4", "Australia/Sydney" },
1070        { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\u6fb3\u5927\u5229\u4e9a\u4e1c\u90e8\u65f6\u95f4", "Australia/Sydney" },
1071
1072        { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
1073        { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", GMT_ZH+"+11:00", "+11:00" },
1074        { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", GMT_ZH+"+11", "+11:00" },
1075        { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\u6fb3\u5927\u5229\u4e9a\u4e1c\u90e8\u590f\u4ee4\u65f6\u95f4", "+11:00" },
1076        { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
1077        { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", GMT_ZH+"+10:00", "+10:00" },
1078        { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", GMT_ZH+"+10", "+10:00" },
1079        { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\u6fb3\u5927\u5229\u4e9a\u4e1c\u90e8\u6807\u51c6\u65f6\u95f4",  "+10:00" },
1080        { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\u6089\u5C3C\u65F6\u95F4", "Australia/Sydney" },
1081        { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\u6fb3\u5927\u5229\u4e9a\u4e1c\u90e8\u65f6\u95f4", "Australia/Sydney" },
1082
1083        { "zh", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
1084        { "zh", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", GMT_ZH, "+0:00" },
1085        { "zh", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
1086        { "zh", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\u683C\u6797\u5C3C\u6CBB\u6807\u51C6\u65F6\u95F4", "+0:00" },
1087        { "zh", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
1088        { "zh", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", GMT_ZH+"+01:00", "+1:00" },
1089        { "zh", "Europe/London", "2004-07-15T00:00:00Z", "z", GMT_ZH+"+1", "+1:00" },
1090        { "zh", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\u82f1\u56fd\u590f\u4ee4\u65f6\u95f4", "+1:00" },
1091        { "zh", "Europe/London", "2004-07-15T00:00:00Z", "v", "\u82f1\u56fd\u65f6\u95f4", "Europe/London" },
1092        { "zh", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\u82f1\u56fd\u65f6\u95f4", "Europe/London" },
1093        { "zh", "Europe/London", "2004-07-15T00:00:00Z", "VVVV", "\u82f1\u56fd\u65f6\u95f4", "Europe/London" },
1094
1095        { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
1096        { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", GMT_ZH+"-03:00", "-3:00" },
1097        { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", GMT_ZH+"-3", "-3:00" },
1098        { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", GMT_ZH+"-03:00", "-3:00" },
1099        { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
1100        { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", GMT_ZH+"-03:00", "-3:00" },
1101        { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", GMT_ZH+"-3", "-3:00" },
1102        { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", GMT_ZH+"-03:00", "-3:00" },
1103        { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", GMT_ZH+"-3", "-3:00" },
1104        { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", GMT_ZH+"-03:00", "-3:00" },
1105
1106        // JB#5150
1107        { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
1108        { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", GMT_ZH+"+05:30", "+5:30" },
1109        { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", GMT_ZH+"+5:30", "+5:30" },
1110        { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\u5370\u5ea6\u65f6\u95f4", "+5:30" },
1111        { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
1112        { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", GMT_ZH+"+05:30", "+5:30" },
1113        { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", GMT_ZH+"+5:30", "+05:30" },
1114        { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\u5370\u5ea6\u65f6\u95f4", "+5:30" },
1115        { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\u5370\u5ea6\u65f6\u95f4", "Asia/Calcutta" },
1116        { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\u5370\u5EA6\u65f6\u95f4", "Asia/Calcutta" },
1117
1118        // ==========
1119
1120        { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
1121        { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
1122        { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "-8:00" },
1123        { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\u0909\u0924\u094d\u0924\u0930\u0940 \u0905\u092e\u0947\u0930\u093f\u0915\u0940 \u092a\u094d\u0930\u0936\u093e\u0902\u0924 \u092e\u093e\u0928\u0915 \u0938\u092e\u092f", "-8:00" },
1124        { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
1125        { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
1126        { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "-7:00" },
1127        { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\u0909\u0924\u094d\u0924\u0930\u0940 \u0905\u092e\u0947\u0930\u093f\u0915\u0940 \u092a\u094d\u0930\u0936\u093e\u0902\u0924 \u0921\u0947\u0932\u093e\u0907\u091f \u0938\u092e\u092f", "-7:00" },
1128        { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\u0932\u0949\u0938 \u090f\u0902\u091c\u093f\u0932\u094d\u0938 \u0938\u092e\u092f", "America/Los_Angeles" },
1129        { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\u0909\u0924\u094d\u0924\u0930\u0940 \u0905\u092e\u0947\u0930\u093f\u0915\u0940 \u092a\u094d\u0930\u0936\u093e\u0902\u0924 \u0938\u092e\u092f", "America/Los_Angeles" },
1130
1131        { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
1132        { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1133        { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1134        { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\u0905\u0930\u094D\u091C\u0947\u0902\u091F\u0940\u0928\u093E \u092E\u093E\u0928\u0915 \u0938\u092E\u092F", "-3:00" },
1135        { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
1136        { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1137        { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1138        { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\u0905\u0930\u094D\u091C\u0947\u0902\u091F\u0940\u0928\u093E \u092E\u093E\u0928\u0915 \u0938\u092E\u092F", "-3:00" },
1139        { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\u092C\u094D\u092F\u0942\u0928\u0938 \u0906\u092F\u0930\u0938 \u0938\u092E\u092F", "America/Buenos_Aires" },
1140        { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\u0905\u0930\u094D\u091C\u0947\u0902\u091F\u0940\u0928\u093E \u092E\u093E\u0928\u0915 \u0938\u092E\u092F", "America/Buenos_Aires" },
1141
1142        { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
1143        { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1144        { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1145        { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\u0905\u0930\u094D\u091C\u0947\u0902\u091F\u0940\u0928\u093E \u092E\u093E\u0928\u0915 \u0938\u092E\u092F", "-3:00" },
1146        { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
1147        { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1148        { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1149        { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\u0905\u0930\u094D\u091C\u0947\u0902\u091F\u0940\u0928\u093E \u092E\u093E\u0928\u0915 \u0938\u092E\u092F", "-3:00" },
1150        { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\u092C\u094D\u092F\u0942\u0928\u0938 \u0906\u092F\u0930\u0938 \u0938\u092E\u092F", "America/Buenos_Aires" },
1151        { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\u0905\u0930\u094D\u091C\u0947\u0902\u091F\u0940\u0928\u093E \u092E\u093E\u0928\u0915 \u0938\u092E\u092F", "America/Buenos_Aires" },
1152
1153        { "hi", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
1154        { "hi", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
1155        { "hi", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
1156        { "hi", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\u0915\u094d\u092f\u0942\u092c\u093e \u092e\u093e\u0928\u0915 \u0938\u092e\u092f", "-5:00" },
1157        { "hi", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
1158        { "hi", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
1159        { "hi", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
1160        { "hi", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\u0915\u094d\u092f\u0942\u092c\u093e \u0921\u0947\u0932\u093e\u0907\u091f \u0938\u092e\u092f", "-4:00" },
1161        { "hi", "America/Havana", "2004-07-15T00:00:00Z", "v", "\u0915\u094d\u092f\u0942\u092c\u093e \u0938\u092E\u092F", "America/Havana" },
1162        { "hi", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\u0915\u094d\u092f\u0942\u092c\u093e \u0938\u092e\u092f", "America/Havana" },
1163
1164        { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
1165        { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
1166        { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
1167        { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\u0911\u0938\u094d\u200d\u091f\u094d\u0930\u0947\u0932\u093f\u092f\u093e\u0908 \u092a\u0942\u0930\u094d\u0935\u0940 \u0921\u0947\u0932\u093e\u0907\u091f \u0938\u092e\u092f", "+11:00" },
1168        { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
1169        { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
1170        { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
1171        { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\u0911\u0938\u094D\u200D\u091F\u094D\u0930\u0947\u0932\u093F\u092F\u093E\u0908 \u092A\u0942\u0930\u094D\u0935\u0940 \u092E\u093E\u0928\u0915 \u0938\u092E\u092F", "+10:00" },
1172        { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\u0938\u093F\u0921\u0928\u0940 \u0938\u092E\u092F", "Australia/Sydney" },
1173        { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\u092a\u0942\u0930\u094d\u0935\u0940 \u0911\u0938\u094d\u091f\u094d\u0930\u0947\u0932\u093f\u092f\u093e \u0938\u092e\u092f", "Australia/Sydney" },
1174
1175        { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
1176        { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
1177        { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
1178        { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\u0911\u0938\u094d\u200d\u091f\u094d\u0930\u0947\u0932\u093f\u092f\u093e\u0908 \u092a\u0942\u0930\u094d\u0935\u0940 \u0921\u0947\u0932\u093e\u0907\u091f \u0938\u092e\u092f", "+11:00" },
1179        { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
1180        { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
1181        { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
1182        { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\u0911\u0938\u094D\u200D\u091F\u094D\u0930\u0947\u0932\u093F\u092F\u093E\u0908 \u092A\u0942\u0930\u094D\u0935\u0940 \u092E\u093E\u0928\u0915 \u0938\u092E\u092F", "+10:00" },
1183        { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\u0938\u093F\u0921\u0928\u0940 \u0938\u092E\u092F", "Australia/Sydney" },
1184        { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\u092a\u0942\u0930\u094d\u0935\u0940 \u0911\u0938\u094d\u091f\u094d\u0930\u0947\u0932\u093f\u092f\u093e \u0938\u092e\u092f", "Australia/Sydney" },
1185
1186        { "hi", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
1187        { "hi", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
1188        { "hi", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
1189        { "hi", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\u0917\u094d\u0930\u0940\u0928\u0935\u093f\u091a \u092e\u0940\u0928 \u091f\u093e\u0907\u092e", "+0:00" },
1190        { "hi", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
1191        { "hi", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
1192        { "hi", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
1193        { "hi", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\u092c\u094d\u0930\u093f\u091f\u093f\u0936 \u0917\u094d\u0930\u0940\u0937\u094d\u092e\u0915\u093e\u0932\u0940\u0928 \u0938\u092e\u092f", "+1:00" },
1194        { "hi", "Europe/London", "2004-07-15T00:00:00Z", "v", "\u092f\u0942\u0928\u093e\u0907\u091f\u0947\u0921 \u0915\u093f\u0902\u0917\u0921\u092e \u0938\u092e\u092f", "Europe/London" },
1195        { "hi", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\u092f\u0942\u0928\u093e\u0907\u091f\u0947\u0921 \u0915\u093f\u0902\u0917\u0921\u092e \u0938\u092e\u092f", "Europe/London" },
1196
1197        { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
1198        { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1199        { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1200        { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
1201        { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
1202        { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1203        { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1204        { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
1205        { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
1206        { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
1207
1208        { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
1209        { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
1210        { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "IST", "+5:30" },
1211        { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\u092D\u093E\u0930\u0924\u0940\u092F \u092E\u093E\u0928\u0915 \u0938\u092E\u092F", "+5:30" },
1212        { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
1213        { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30"," +5:30" },
1214        { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "IST", "+05:30" },
1215        { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\u092D\u093E\u0930\u0924\u0940\u092F \u092E\u093E\u0928\u0915 \u0938\u092E\u092F", "+5:30" },
1216        { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "IST", "Asia/Calcutta" },
1217        { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\u092D\u093E\u0930\u0924\u0940\u092F \u092E\u093E\u0928\u0915 \u0938\u092E\u092F", "Asia/Calcutta" },
1218
1219        // ==========
1220
1221        { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
1222        { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", GMT_BG+"-08:00", "-8:00" },
1223        { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", GMT_BG+"-8", "America/Los_Angeles" },
1224        { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\u0421\u0435\u0432\u0435\u0440\u043d\u043e\u0430\u043c\u0435\u0440\u0438\u043a\u0430\u043d\u0441\u043a\u043e \u0442\u0438\u0445\u043e\u043e\u043a\u0435\u0430\u043d\u0441\u043a\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e \u0432\u0440\u0435\u043c\u0435", "America/Los_Angeles" },
1225        { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
1226        { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", GMT_BG+"-07:00", "-7:00" },
1227        { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", GMT_BG+"-7", "America/Los_Angeles" },
1228        { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\u0421\u0435\u0432\u0435\u0440\u043d\u043e\u0430\u043c\u0435\u0440\u0438\u043a\u0430\u043d\u0441\u043a\u043e \u0442\u0438\u0445\u043e\u043e\u043a\u0435\u0430\u043d\u0441\u043a\u043e \u043b\u044f\u0442\u043d\u043e \u0447\u0430\u0441\u043e\u0432\u043e \u0432\u0440\u0435\u043c\u0435", "America/Los_Angeles" },
1229    // icu bg.txt has exemplar city for this time zone
1230        { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\u041B\u043E\u0441 \u0410\u043D\u0434\u0436\u0435\u043B\u0438\u0441", "America/Los_Angeles" },
1231        { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\u0421\u0435\u0432\u0435\u0440\u043d\u043e\u0430\u043c\u0435\u0440\u0438\u043a\u0430\u043d\u0441\u043a\u043e \u0442\u0438\u0445\u043e\u043e\u043a\u0435\u0430\u043d\u0441\u043a\u043e \u0432\u0440\u0435\u043c\u0435", "America/Los_Angeles" },
1232        { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "\u041B\u043E\u0441 \u0410\u043D\u0434\u0436\u0435\u043B\u0438\u0441", "America/Los_Angeles" },
1233
1234        { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
1235        { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", GMT_BG+"-03:00", "-3:00" },
1236        { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", GMT_BG+"-3", "-3:00" },
1237        { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\u0410\u0440\u0436\u0435\u043D\u0442\u0438\u043D\u0441\u043a\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e \u0432\u0440\u0435\u043c\u0435", "-3:00" },
1238        { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
1239        { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", GMT_BG+"-03:00", "-3:00" },
1240        { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", GMT_BG+"-3", "-3:00" },
1241        { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\u0410\u0440\u0436\u0435\u043D\u0442\u0438\u043D\u0441\u043a\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e \u0432\u0440\u0435\u043c\u0435", "-3:00" },
1242        { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\u0411\u0443\u0435\u043D\u043E\u0441 \u0410\u0439\u0440\u0435\u0441", "America/Buenos_Aires" },
1243        { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\u0410\u0440\u0436\u0435\u043D\u0442\u0438\u043D\u0441\u043a\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e \u0432\u0440\u0435\u043c\u0435", "America/Buenos_Aires" },
1244
1245        { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
1246        { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", GMT_BG+"-03:00", "-3:00" },
1247        { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", GMT_BG+"-3", "-3:00" },
1248        { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\u0410\u0440\u0436\u0435\u043D\u0442\u0438\u043D\u0441\u043a\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e \u0432\u0440\u0435\u043c\u0435", "-3:00" },
1249        { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
1250        { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", GMT_BG+"-03:00", "-3:00" },
1251        { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", GMT_BG+"-3", "-3:00" },
1252        { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\u0410\u0440\u0436\u0435\u043D\u0442\u0438\u043D\u0441\u043a\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e \u0432\u0440\u0435\u043c\u0435", "-3:00" },
1253    // icu bg.txt does not have info for this time zone
1254        { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\u0411\u0443\u0435\u043D\u043E\u0441 \u0410\u0439\u0440\u0435\u0441", "America/Buenos_Aires" },
1255        { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\u0410\u0440\u0436\u0435\u043D\u0442\u0438\u043D\u0441\u043a\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e \u0432\u0440\u0435\u043c\u0435", "America/Buenos_Aires" },
1256
1257        { "bg", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
1258        { "bg", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", GMT_BG+"-05:00", "-5:00" },
1259        { "bg", "America/Havana", "2004-01-15T00:00:00Z", "z", GMT_BG+"-5", "-5:00" },
1260        { "bg", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\u041a\u0443\u0431\u0438\u043d\u0441\u043a\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e \u0432\u0440\u0435\u043c\u0435", "-5:00" },
1261        { "bg", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
1262        { "bg", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", GMT_BG+"-04:00", "-4:00" },
1263        { "bg", "America/Havana", "2004-07-15T00:00:00Z", "z", GMT_BG+"-4", "-4:00" },
1264        { "bg", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\u041a\u0443\u0431\u0438\u043d\u0441\u043a\u043e \u043b\u044f\u0442\u043d\u043e \u0447\u0430\u0441\u043e\u0432\u043e \u0432\u0440\u0435\u043c\u0435", "-4:00" },
1265        { "bg", "America/Havana", "2004-07-15T00:00:00Z", "v", "\u041a\u0443\u0431\u0430", "America/Havana" },
1266        { "bg", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\u041a\u0443\u0431\u0438\u043d\u0441\u043a\u043e \u0432\u0440\u0435\u043C\u0435", "America/Havana" },
1267
1268        { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
1269        { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", GMT_BG+"+11:00", "+11:00" },
1270        { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "z", GMT_BG+"+11", "+11:00" },
1271        { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\u0410\u0432\u0441\u0442\u0440\u0430\u043B\u0438\u044F \u2013 \u0438\u0437\u0442\u043E\u0447\u043D\u043E \u043B\u044F\u0442\u043D\u043E \u0447\u0430\u0441\u043E\u0432\u043E \u0432\u0440\u0435\u043C\u0435", "+11:00" },
1272        { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
1273        { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", GMT_BG+"+10:00", "+10:00" },
1274        { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "z", GMT_BG+"+10", "+10:00" },
1275        { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\u0410\u0432\u0441\u0442\u0440\u0430\u043B\u0438\u044F \u2013 \u0438\u0437\u0442\u043E\u0447\u043D\u043E \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u043E \u0432\u0440\u0435\u043C\u0435", "+10:00" },
1276        { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\u0421\u0438\u0434\u043D\u0438", "Australia/Sydney" },
1277        { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\u0410\u0432\u0441\u0442\u0440\u0430\u043B\u0438\u044F \u2013 \u0438\u0437\u0442\u043E\u0447\u043D\u043E \u0432\u0440\u0435\u043C\u0435", "Australia/Sydney" },
1278
1279        { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
1280        { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", GMT_BG+"+11:00", "+11:00" },
1281        { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", GMT_BG+"+11", "+11:00" },
1282        { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\u0410\u0432\u0441\u0442\u0440\u0430\u043B\u0438\u044F \u2013 \u0438\u0437\u0442\u043E\u0447\u043D\u043E \u043B\u044F\u0442\u043D\u043E \u0447\u0430\u0441\u043E\u0432\u043E \u0432\u0440\u0435\u043C\u0435", "+11:00" },
1283        { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
1284        { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", GMT_BG+"+10:00", "+10:00" },
1285        { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", GMT_BG+"+10", "+10:00" },
1286        { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\u0410\u0432\u0441\u0442\u0440\u0430\u043B\u0438\u044F \u2013 \u0438\u0437\u0442\u043E\u0447\u043D\u043E \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u043E \u0432\u0440\u0435\u043C\u0435", "+10:00" },
1287        { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\u0421\u0438\u0434\u043D\u0438", "Australia/Sydney" },
1288        { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\u0410\u0432\u0441\u0442\u0440\u0430\u043B\u0438\u044F \u2013 \u0438\u0437\u0442\u043E\u0447\u043D\u043E \u0432\u0440\u0435\u043C\u0435", "Australia/Sydney" },
1289
1290        { "bg", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
1291        { "bg", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", GMT_BG, "+0:00" },
1292        { "bg", "Europe/London", "2004-01-15T00:00:00Z", "z", GMT_BG, "+0:00" },
1293        { "bg", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\u0421\u0440\u0435\u0434\u043d\u043e \u0433\u0440\u0438\u043d\u0443\u0438\u0447\u043a\u043e \u0432\u0440\u0435\u043c\u0435", "+0:00" },
1294        { "bg", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
1295        { "bg", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", GMT_BG+"+01:00", "+1:00" },
1296        { "bg", "Europe/London", "2004-07-15T00:00:00Z", "z", GMT_BG+"+1", "+1:00" },
1297        { "bg", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\u0411\u0440\u0438\u0442\u0430\u043d\u0441\u043a\u043e \u043b\u044f\u0442\u043d\u043e \u0447\u0430\u0441\u043e\u0432\u043e \u0432\u0440\u0435\u043c\u0435", "+1:00" },
1298        { "bg", "Europe/London", "2004-07-15T00:00:00Z", "v", "\u041e\u0431\u0435\u0434\u0438\u043d\u0435\u043d\u043e\u0442\u043e \u043a\u0440\u0430\u043b\u0441\u0442\u0432\u043e", "Europe/London" },
1299        { "bg", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\u041e\u0431\u0435\u0434\u0438\u043d\u0435\u043d\u043e\u0442\u043e \u043a\u0440\u0430\u043b\u0441\u0442\u0432\u043e", "Europe/London" },
1300
1301        { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
1302        { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", GMT_BG+"-03:00", "-3:00" },
1303        { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", GMT_BG+"-3", "-3:00" },
1304        { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", GMT_BG+"-03:00", "-3:00" },
1305        { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
1306        { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", GMT_BG+"-03:00", "-3:00" },
1307        { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", GMT_BG+"-3", "-3:00" },
1308        { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", GMT_BG+"-03:00", "-3:00" },
1309        { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", GMT_BG+"-3", "-3:00" },
1310        { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", GMT_BG+"-03:00", "-3:00" },
1311
1312        // JB#5150
1313        { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
1314        { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", GMT_BG+"+05:30", "+5:30" },
1315        { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", GMT_BG+"+5:30", "+5:30" },
1316        { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\u0418\u043D\u0434\u0438\u0439\u0441\u043A\u043E \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u043E \u0432\u0440\u0435\u043C\u0435", "+5:30" },
1317        { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
1318        { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", GMT_BG+"+05:30", "+5:30" },
1319        { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", GMT_BG+"+5:30", "+05:30" },
1320        { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\u0418\u043D\u0434\u0438\u0439\u0441\u043A\u043E \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u043E \u0432\u0440\u0435\u043C\u0435", "+5:30" },
1321        { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\u0418\u043D\u0434\u0438\u044F", "Asia/Calcutta" },
1322        { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\u0418\u043D\u0434\u0438\u0439\u0441\u043A\u043E \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u043E \u0432\u0440\u0435\u043C\u0435", "Asia/Calcutta" },
1323
1324    // ==========
1325
1326        { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
1327        { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
1328        { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "America/Los_Angeles" },
1329        { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\u30a2\u30e1\u30ea\u30ab\u592a\u5e73\u6d0b\u6a19\u6e96\u6642", "America/Los_Angeles" },
1330        { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
1331        { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
1332        { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "America/Los_Angeles" },
1333        { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\u30a2\u30e1\u30ea\u30ab\u592a\u5e73\u6d0b\u590f\u6642\u9593", "America/Los_Angeles" },
1334    // icu ja.txt has exemplar city for this time zone
1335        { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\u30ED\u30B5\u30F3\u30BC\u30EB\u30B9\u6642\u9593", "America/Los_Angeles" },
1336        { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\u30A2\u30E1\u30EA\u30AB\u592A\u5E73\u6D0B\u6642\u9593", "America/Los_Angeles" },
1337        { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "\u30ED\u30B5\u30F3\u30BC\u30EB\u30B9\u6642\u9593", "America/Los_Angeles" },
1338
1339        { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
1340        { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1341        { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1342        { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\u30A2\u30EB\u30BC\u30F3\u30C1\u30F3\u6A19\u6E96\u6642", "-3:00" },
1343        { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
1344        { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1345        { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1346        { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\u30A2\u30EB\u30BC\u30F3\u30C1\u30F3\u6A19\u6E96\u6642", "-3:00" },
1347    // icu ja.txt does not have info for this time zone
1348        { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\u30D6\u30A8\u30CE\u30B9\u30A2\u30A4\u30EC\u30B9\u6642\u9593", "America/Buenos_Aires" },
1349        { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\u30A2\u30EB\u30BC\u30F3\u30C1\u30F3\u6A19\u6E96\u6642", "America/Buenos_Aires" },
1350
1351        { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
1352        { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1353        { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1354        { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\u30A2\u30EB\u30BC\u30F3\u30C1\u30F3\u6A19\u6E96\u6642", "-3:00" },
1355        { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
1356        { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1357        { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1358        { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\u30A2\u30EB\u30BC\u30F3\u30C1\u30F3\u6A19\u6E96\u6642", "-3:00" },
1359    // icu ja.txt does not have info for this time zone
1360        { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\u30D6\u30A8\u30CE\u30B9\u30A2\u30A4\u30EC\u30B9\u6642\u9593", "America/Buenos_Aires" },
1361        { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\u30A2\u30EB\u30BC\u30F3\u30C1\u30F3\u6A19\u6E96\u6642", "America/Buenos_Aires" },
1362
1363        { "ja", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
1364        { "ja", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
1365        { "ja", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
1366        { "ja", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\u30AD\u30E5\u30FC\u30D0\u6A19\u6E96\u6642", "-5:00" },
1367        { "ja", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
1368        { "ja", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
1369        { "ja", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
1370        { "ja", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\u30AD\u30E5\u30FC\u30D0\u590F\u6642\u9593", "-4:00" },
1371        { "ja", "America/Havana", "2004-07-15T00:00:00Z", "v", "\u30ad\u30e5\u30fc\u30d0\u6642\u9593", "America/Havana" },
1372        { "ja", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\u30ad\u30e5\u30fc\u30d0\u6642\u9593", "America/Havana" },
1373
1374        { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
1375        { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
1376        { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
1377        { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2\u6771\u90E8\u590F\u6642\u9593", "+11:00" },
1378        { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
1379        { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
1380        { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
1381        { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2\u6771\u90E8\u6A19\u6E96\u6642", "+10:00" },
1382    // icu ja.txt does not have info for this time zone
1383        { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\u30B7\u30C9\u30CB\u30FC\u6642\u9593", "Australia/Sydney" },
1384        { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2\u6771\u90E8\u6642\u9593", "Australia/Sydney" },
1385
1386        { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
1387        { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
1388        { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
1389        { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2\u6771\u90E8\u590F\u6642\u9593", "+11:00" },
1390        { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
1391        { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
1392        { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
1393        { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2\u6771\u90E8\u6A19\u6E96\u6642", "+10:00" },
1394        { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\u30B7\u30C9\u30CB\u30FC\u6642\u9593", "Australia/Sydney" },
1395        { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\u30AA\u30FC\u30B9\u30C8\u30E9\u30EA\u30A2\u6771\u90E8\u6642\u9593", "Australia/Sydney" },
1396
1397        { "ja", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
1398        { "ja", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
1399        { "ja", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
1400        { "ja", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\u30B0\u30EA\u30CB\u30C3\u30B8\u6A19\u6E96\u6642", "+0:00" },
1401        { "ja", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
1402        { "ja", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
1403        { "ja", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
1404        { "ja", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\u82f1\u56fd\u590f\u6642\u9593", "+1:00" },
1405        { "ja", "Europe/London", "2004-07-15T00:00:00Z", "v", "\u30a4\u30ae\u30ea\u30b9\u6642\u9593", "Europe/London" },
1406        { "ja", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\u30a4\u30ae\u30ea\u30b9\u6642\u9593", "Europe/London" },
1407        { "ja", "Europe/London", "2004-07-15T00:00:00Z", "VVVV", "\u30a4\u30ae\u30ea\u30b9\u6642\u9593", "Europe/London" },
1408
1409        { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
1410        { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1411        { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1412        { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
1413        { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
1414        { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1415        { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1416        { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
1417        { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
1418        { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
1419
1420        // JB#5150
1421        { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
1422        { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
1423        { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
1424        { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\u30A4\u30F3\u30C9\u6A19\u6E96\u6642", "+5:30" },
1425        { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
1426        { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
1427        { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
1428        { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\u30A4\u30F3\u30C9\u6A19\u6E96\u6642", "+5:30" },
1429        { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\u30A4\u30F3\u30C9\u6642\u9593", "Asia/Calcutta" },
1430        { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\u30A4\u30F3\u30C9\u6A19\u6E96\u6642", "Asia/Calcutta" },
1431
1432    // ==========
1433    // - We want a locale here that doesn't have anything in the way of translations
1434    // - so we can test the fallback behavior.  If "ti" translates some stuff we will
1435    // - need to choose a different locale.
1436
1437        { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
1438        { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
1439        { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "-8:00" },
1440        { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "GMT-08:00", "-8:00" },
1441        { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
1442        { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
1443        { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "-7:00" },
1444        { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "GMT-07:00", "-7:00" },
1445        { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "Los Angeles", "America/Los_Angeles" },
1446        { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Los Angeles", "America/Los_Angeles" },
1447
1448        { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
1449        { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1450        { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1451        { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
1452        { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
1453        { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1454        { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1455        { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
1456        { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires", "America/Buenos_Aires" },
1457        { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Buenos Aires", "America/Buenos_Aires" },
1458
1459        { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
1460        { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1461        { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1462        { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
1463        { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
1464        { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1465        { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1466        { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
1467        { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires", "America/Buenos_Aires" },
1468        { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Buenos Aires", "America/Buenos_Aires" },
1469
1470        { "ti", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
1471        { "ti", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
1472        { "ti", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
1473        { "ti", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "GMT-05:00", "-5:00" },
1474        { "ti", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
1475        { "ti", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
1476        { "ti", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
1477        { "ti", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "GMT-04:00", "-4:00" },
1478        { "ti", "America/Havana", "2004-07-15T00:00:00Z", "v", "CU", "America/Havana" },
1479        { "ti", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "CU", "America/Havana" },
1480
1481        { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
1482        { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
1483        { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
1484        { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "GMT+11:00", "+11:00" },
1485        { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
1486        { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
1487        { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
1488        { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "GMT+10:00", "+10:00" },
1489        { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Sydney", "Australia/Sydney" },
1490        { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Sydney", "Australia/Sydney" },
1491
1492        { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
1493        { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
1494        { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
1495        { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "GMT+11:00", "+11:00" },
1496        { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
1497        { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
1498        { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
1499        { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "GMT+10:00", "+10:00" },
1500        { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Sydney", "Australia/Sydney" },
1501        { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Sydney", "Australia/Sydney" },
1502
1503        { "ti", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
1504        { "ti", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
1505        { "ti", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
1506        { "ti", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "GMT", "+0:00" },
1507        { "ti", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
1508        { "ti", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
1509        { "ti", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
1510        { "ti", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "GMT+01:00", "+1:00" },
1511        { "ti", "Europe/London", "2004-07-15T00:00:00Z", "v", "GB", "Europe/London" },
1512        { "ti", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "GB", "Europe/London" },
1513
1514        { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
1515        { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1516        { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1517        { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
1518        { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
1519        { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
1520        { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
1521        { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
1522        { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
1523        { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
1524
1525        // JB#5150
1526        { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
1527        { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
1528        { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
1529        { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "GMT+05:30", "+5:30" },
1530        { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
1531        { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
1532        { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
1533        { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "GMT+05:30", "+5:30" },
1534        { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "IN", "Asia/Calcutta" },
1535        { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "IN", "Asia/Calcutta" },
1536
1537        // Ticket#8589 Partial location name to use country name if the zone is the golden
1538        // zone for the time zone's country.
1539        { "en_MX", "America/Chicago", "1995-07-15T00:00:00Z", "vvvv", "Central Time (United States)", "America/Chicago"},
1540
1541        // Tests proper handling of time zones that should have empty sets when inherited from the parent.
1542        // For example, en_GB understands CET as Central European Time, but en_HK, which inherits from en_GB
1543        // does not
1544        { "en_GB", "Europe/Paris", "2004-01-15T00:00:00Z", "zzzz", "Central European Standard Time", "+1:00"},
1545        { "en_GB", "Europe/Paris", "2004-07-15T00:00:00Z", "zzzz", "Central European Summer Time", "+2:00"},
1546        { "en_GB", "Europe/Paris", "2004-01-15T00:00:00Z", "z", "CET", "+1:00"},
1547        { "en_GB", "Europe/Paris", "2004-07-15T00:00:00Z", "z", "CEST", "+2:00"},
1548        { "en_HK", "Europe/Paris", "2004-01-15T00:00:00Z", "zzzz", "Central European Standard Time", "+1:00"},
1549        { "en_HK", "Europe/Paris", "2004-07-15T00:00:00Z", "zzzz", "Central European Summer Time", "+2:00"},
1550        { "en_HK", "Europe/Paris", "2004-01-15T00:00:00Z", "z", "GMT+1", "+1:00"},
1551        { "en_HK", "Europe/Paris", "2004-07-15T00:00:00Z", "z", "GMT+2", "+2:00"},
1552    };
1553
1554    /**
1555     * Verify that strings which contain incomplete specifications are parsed
1556     * correctly.  In some instances, this means not being parsed at all, and
1557     * returning an appropriate error.
1558     */
1559    @Test
1560    public void TestPartialParse994() {
1561
1562        SimpleDateFormat f = new SimpleDateFormat();
1563        Calendar cal = Calendar.getInstance();
1564        cal.clear();
1565        cal.set(1997, 1 - 1, 17, 10, 11, 42);
1566        Date date = null;
1567        tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10:11:42", cal.getTime());
1568        tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10:", date);
1569        tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10", date);
1570        tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 ", date);
1571        tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17", date);
1572    }
1573
1574    // internal test subroutine, used by TestPartialParse994
1575    public void tryPat994(SimpleDateFormat format, String pat, String str, Date expected) {
1576        Date Null = null;
1577        logln("Pattern \"" + pat + "\"   String \"" + str + "\"");
1578        try {
1579            format.applyPattern(pat);
1580            Date date = format.parse(str);
1581            String f = ((DateFormat) format).format(date);
1582            logln(" parse(" + str + ") -> " + date);
1583            logln(" format -> " + f);
1584            if (expected.equals(Null) || !date.equals(expected))
1585                errln("FAIL: Expected null"); //" + expected);
1586            if (!f.equals(str))
1587                errln("FAIL: Expected " + str);
1588        } catch (ParseException e) {
1589            logln("ParseException: " + e.getMessage());
1590            if (!(expected ==Null))
1591                errln("FAIL: Expected " + expected);
1592        } catch (Exception e) {
1593            errln("*** Exception:");
1594            e.printStackTrace();
1595        }
1596    }
1597
1598    /**
1599     * Verify the behavior of patterns in which digits for different fields run together
1600     * without intervening separators.
1601     */
1602    @Test
1603    public void TestRunTogetherPattern985() {
1604        String format = "yyyyMMddHHmmssSSS";
1605        String now, then;
1606        //UBool flag;
1607        SimpleDateFormat formatter = new SimpleDateFormat(format);
1608        Date date1 = new Date();
1609        now = ((DateFormat) formatter).format(date1);
1610        logln(now);
1611        ParsePosition pos = new ParsePosition(0);
1612        Date date2 = formatter.parse(now, pos);
1613        if (date2 == null)
1614            then = "Parse stopped at " + pos.getIndex();
1615        else
1616            then = ((DateFormat) formatter).format(date2);
1617        logln(then);
1618        if (date2 == null || !date2.equals(date1))
1619            errln("FAIL");
1620    }
1621
1622    /**
1623     * Verify the behavior of patterns in which digits for different fields run together
1624     * without intervening separators.
1625     */
1626    @Test
1627    public void TestRunTogetherPattern917() {
1628        SimpleDateFormat fmt;
1629        String myDate;
1630        fmt = new SimpleDateFormat("yyyy/MM/dd");
1631        myDate = "1997/02/03";
1632        Calendar cal = Calendar.getInstance();
1633        cal.clear();
1634        cal.set(1997, 2 - 1, 3);
1635        _testIt917(fmt, myDate, cal.getTime());
1636        fmt = new SimpleDateFormat("yyyyMMdd");
1637        myDate = "19970304";
1638        cal.clear();
1639        cal.set(1997, 3 - 1, 4);
1640        _testIt917(fmt, myDate, cal.getTime());
1641
1642    }
1643
1644    // internal test subroutine, used by TestRunTogetherPattern917
1645    private void _testIt917(SimpleDateFormat fmt, String str, Date expected) {
1646        logln("pattern=" + fmt.toPattern() + "   string=" + str);
1647        Date o = new Date();
1648        o = (Date) ((DateFormat) fmt).parseObject(str, new ParsePosition(0));
1649        logln("Parsed object: " + o);
1650        if (o == null || !o.equals(expected))
1651            errln("FAIL: Expected " + expected);
1652        String formatted = o==null? "null" : ((DateFormat) fmt).format(o);
1653        logln( "Formatted string: " + formatted);
1654        if (!formatted.equals(str))
1655            errln( "FAIL: Expected " + str);
1656    }
1657
1658    /**
1659     * Verify the handling of Czech June and July, which have the unique attribute that
1660     * one is a proper prefix substring of the other.
1661     */
1662    @Test
1663    public void TestCzechMonths459() {
1664        DateFormat fmt = DateFormat.getDateInstance(DateFormat.FULL, new Locale("cs", "", ""));
1665        logln("Pattern " + ((SimpleDateFormat) fmt).toPattern());
1666        Calendar cal = Calendar.getInstance();
1667        cal.clear();
1668        cal.set(1997, Calendar.JUNE, 15);
1669        Date june = cal.getTime();
1670        cal.clear();
1671        cal.set(1997, Calendar.JULY, 15);
1672        Date july = cal.getTime();
1673        String juneStr = fmt.format(june);
1674        String julyStr = fmt.format(july);
1675        try {
1676            logln("format(June 15 1997) = " + juneStr);
1677            Date d = fmt.parse(juneStr);
1678            String s = fmt.format(d);
1679            int month, yr, day;
1680            cal.setTime(d);
1681            yr = cal.get(Calendar.YEAR);
1682            month = cal.get(Calendar.MONTH);
1683            day = cal.get(Calendar.DAY_OF_MONTH);
1684            logln("  . parse . " + s + " (month = " + month + ")");
1685            if (month != Calendar.JUNE)
1686                errln("FAIL: Month should be June");
1687            if (yr != 1997)
1688                errln("FAIL: Year should be 1997");
1689            if (day != 15)
1690                errln("FAIL: day should be 15");
1691            logln("format(July 15 1997) = " + julyStr);
1692            d = fmt.parse(julyStr);
1693            s = fmt.format(d);
1694            cal.setTime(d);
1695            yr = cal.get(Calendar.YEAR) - 1900;
1696            month = cal.get(Calendar.MONTH);
1697            day = cal.get(Calendar.DAY_OF_WEEK);
1698            logln("  . parse . " + s + " (month = " + month + ")");
1699            if (month != Calendar.JULY)
1700                errln("FAIL: Month should be July");
1701        } catch (ParseException e) {
1702            errln(e.getMessage());
1703        }
1704    }
1705
1706    /**
1707     * Test the handling of 'D' in patterns.
1708     */
1709    @Test
1710    public void TestLetterDPattern212() {
1711        String dateString = "1995-040.05:01:29";
1712        String bigD = "yyyy-DDD.hh:mm:ss";
1713        String littleD = "yyyy-ddd.hh:mm:ss";
1714        Calendar cal = Calendar.getInstance();
1715        cal.clear();
1716        cal.set(1995, 0, 1, 5, 1, 29);
1717        Date expLittleD = cal.getTime();
1718        Date expBigD = new Date((long) (expLittleD.getTime() + 39 * 24 * 3600000.0));
1719        expLittleD = expBigD; // Expect the same, with default lenient parsing
1720        logln("dateString= " + dateString);
1721        SimpleDateFormat formatter = new SimpleDateFormat(bigD);
1722        ParsePosition pos = new ParsePosition(0);
1723        Date myDate = formatter.parse(dateString, pos);
1724        logln("Using " + bigD + " . " + myDate);
1725        if (!myDate.equals(expBigD))
1726            errln("FAIL: Expected " + expBigD);
1727        formatter = new SimpleDateFormat(littleD);
1728        pos = new ParsePosition(0);
1729        myDate = formatter.parse(dateString, pos);
1730        logln("Using " + littleD + " . " + myDate);
1731        if (!myDate.equals(expLittleD))
1732            errln("FAIL: Expected " + expLittleD);
1733    }
1734
1735    /**
1736     * Test the day of year pattern.
1737     */
1738    @Test
1739    public void TestDayOfYearPattern195() {
1740        Calendar cal = Calendar.getInstance();
1741        Date today = cal.getTime();
1742        int year,month,day;
1743        year = cal.get(Calendar.YEAR);
1744        month = cal.get(Calendar.MONTH);
1745        day = cal.get(Calendar.DAY_OF_MONTH);
1746        cal.clear();
1747        cal.set(year, month, day);
1748        Date expected = cal.getTime();
1749        logln("Test Date: " + today);
1750        SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance();
1751        tryPattern(sdf, today, null, expected);
1752        tryPattern(sdf, today, "G yyyy DDD", expected);
1753    }
1754
1755    // interl test subroutine, used by TestDayOfYearPattern195
1756    public void tryPattern(SimpleDateFormat sdf, Date d, String pattern, Date expected) {
1757        if (pattern != null)
1758            sdf.applyPattern(pattern);
1759        logln("pattern: " + sdf.toPattern());
1760        String formatResult = ((DateFormat) sdf).format(d);
1761        logln(" format -> " + formatResult);
1762        try {
1763            Date d2 = sdf.parse(formatResult);
1764            logln(" parse(" + formatResult + ") -> " + d2);
1765            if (!d2.equals(expected))
1766                errln("FAIL: Expected " + expected);
1767            String format2 = ((DateFormat) sdf).format(d2);
1768            logln(" format -> " + format2);
1769            if (!formatResult.equals(format2))
1770                errln("FAIL: Round trip drift");
1771        } catch (Exception e) {
1772            errln(e.getMessage());
1773        }
1774    }
1775
1776    /**
1777     * Test the handling of single quotes in patterns.
1778     */
1779    @Test
1780    public void TestQuotePattern161() {
1781        SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy 'at' hh:mm:ss a zzz", Locale.US);
1782        Calendar cal = Calendar.getInstance();
1783        cal.clear();
1784        cal.set(1997, Calendar.AUGUST, 13, 10, 42, 28);
1785        Date currentTime_1 = cal.getTime();
1786        String dateString = ((DateFormat) formatter).format(currentTime_1);
1787        String exp = "08/13/1997 at 10:42:28 AM ";
1788        logln("format(" + currentTime_1 + ") = " + dateString);
1789        if (!dateString.substring(0, exp.length()).equals(exp))
1790            errln("FAIL: Expected " + exp);
1791
1792    }
1793
1794    /**
1795     * Verify the correct behavior when handling invalid input strings.
1796     */
1797    @Test
1798    public void TestBadInput135() {
1799        int looks[] = {DateFormat.SHORT, DateFormat.MEDIUM, DateFormat.LONG, DateFormat.FULL};
1800        int looks_length = looks.length;
1801        final String[] strings = {"Mar 15", "Mar 15 1997", "asdf", "3/1/97 1:23:", "3/1/00 1:23:45 AM"};
1802        int strings_length = strings.length;
1803        DateFormat full = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.US);
1804        String expected = "March 1, 2000 at 1:23:45 AM ";
1805        for (int i = 0; i < strings_length; ++i) {
1806            final String text = strings[i];
1807            for (int j = 0; j < looks_length; ++j) {
1808                int dateLook = looks[j];
1809                for (int k = 0; k < looks_length; ++k) {
1810                    int timeLook = looks[k];
1811                    DateFormat df = DateFormat.getDateTimeInstance(dateLook, timeLook, Locale.US);
1812                    String prefix = text + ", " + dateLook + "/" + timeLook + ": ";
1813                    try {
1814                        Date when = df.parse(text);
1815                        if (when == null) {
1816                            errln(prefix + "SHOULD NOT HAPPEN: parse returned null.");
1817                            continue;
1818                        }
1819                        if (when != null) {
1820                            String format;
1821                            format = full.format(when);
1822                            logln(prefix + "OK: " + format);
1823                            if (!format.substring(0, expected.length()).equals(expected)) {
1824                                errln("FAIL: Expected <" + expected + ">, but got <"
1825                                        + format.substring(0, expected.length()) + ">");
1826                            }
1827                        }
1828                    } catch(java.text.ParseException e) {
1829                        logln(e.getMessage());
1830                    }
1831                }
1832            }
1833        }
1834    }
1835
1836    /**
1837     * Verify the correct behavior when parsing an array of inputs against an
1838     * array of patterns, with known results.  The results are encoded after
1839     * the input strings in each row.
1840     */
1841    @Test
1842    public void TestBadInput135a() {
1843
1844        SimpleDateFormat dateParse = new SimpleDateFormat("", Locale.US);
1845        final String ss;
1846        Date date;
1847        String[] parseFormats ={"MMMM d, yyyy", "MMMM d yyyy", "M/d/yy",
1848                                "d MMMM, yyyy", "d MMMM yyyy",  "d MMMM",
1849                                "MMMM d", "yyyy", "h:mm a MMMM d, yyyy" };
1850        String[] inputStrings = {
1851            "bogus string", null, null, null, null, null, null, null, null, null,
1852                "April 1, 1997", "April 1, 1997", null, null, null, null, null, "April 1", null, null,
1853                "Jan 1, 1970", "January 1, 1970", null, null, null, null, null, "January 1", null, null,
1854                "Jan 1 2037", null, "January 1 2037", null, null, null, null, "January 1", null, null,
1855                "1/1/70", null, null, "1/1/70", null, null, null, null, "0001", null,
1856                "5 May 1997", null, null, null, null, "5 May 1997", "5 May", null, "0005", null,
1857                "16 May", null, null, null, null, null, "16 May", null, "0016", null,
1858                "April 30", null, null, null, null, null, null, "April 30", null, null,
1859                "1998", null, null, null, null, null, null, null, "1998", null,
1860                "1", null, null, null, null, null, null, null, "0001", null,
1861                "3:00 pm Jan 1, 1997", null, null, null, null, null, null, null, "0003", "3:00 PM January 1, 1997",
1862                };
1863        final int PF_LENGTH = parseFormats.length;
1864        final int INPUT_LENGTH = inputStrings.length;
1865
1866        dateParse.applyPattern("d MMMM, yyyy");
1867        dateParse.setTimeZone(TimeZone.getDefault());
1868        ss = "not parseable";
1869        //    String thePat;
1870        logln("Trying to parse \"" + ss + "\" with " + dateParse.toPattern());
1871        try {
1872            date = dateParse.parse(ss);
1873        } catch (Exception ex) {
1874            logln("FAIL:" + ex);
1875        }
1876        for (int i = 0; i < INPUT_LENGTH; i += (PF_LENGTH + 1)) {
1877            ParsePosition parsePosition = new ParsePosition(0);
1878            String s = inputStrings[i];
1879            for (int index = 0; index < PF_LENGTH; ++index) {
1880                final String expected = inputStrings[i + 1 + index];
1881                dateParse.applyPattern(parseFormats[index]);
1882                dateParse.setTimeZone(TimeZone.getDefault());
1883                try {
1884                    parsePosition.setIndex(0);
1885                    date = dateParse.parse(s, parsePosition);
1886                    if (parsePosition.getIndex() != 0) {
1887                        String s1, s2;
1888                        s1 = s.substring(0, parsePosition.getIndex());
1889                        s2 = s.substring(parsePosition.getIndex(), s.length());
1890                        if (date == null) {
1891                            errln("ERROR: null result fmt=\"" + parseFormats[index]
1892                                    + "\" pos=" + parsePosition.getIndex()
1893                                    + " " + s1 + "|" + s2);
1894                        } else {
1895                            String result = ((DateFormat) dateParse).format(date);
1896                            logln("Parsed \"" + s + "\" using \"" + dateParse.toPattern() + "\" to: " + result);
1897                            if (expected == null)
1898                                errln("FAIL: Expected parse failure for <" + result + ">");
1899                            else
1900                                if (!result.equals(expected))
1901                                    errln("FAIL: Expected " + expected);
1902                        }
1903                    } else
1904                        if (expected != null) {
1905                            errln("FAIL: Expected " + expected + " from \"" + s
1906                                    + "\" with \"" + dateParse.toPattern()+ "\"");
1907                        }
1908                } catch (Exception ex) {
1909                    logln("FAIL:" + ex);
1910                }
1911            }
1912        }
1913
1914    }
1915
1916    /**
1917     * Test the parsing of two-digit years.
1918     */
1919    @Test
1920    public void TestTwoDigitYear() {
1921        DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
1922        Calendar cal = Calendar.getInstance();
1923        cal.clear();
1924        cal.set(130 + 1900, Calendar.JUNE, 5);
1925        parse2DigitYear(fmt, "6/5/30", cal.getTime());
1926        cal.clear();
1927        cal.set(50 + 1900, Calendar.JUNE, 4);
1928        parse2DigitYear(fmt, "6/4/50", cal.getTime());
1929    }
1930
1931    // internal test subroutine, used by TestTwoDigitYear
1932    public void parse2DigitYear(DateFormat fmt, String str, Date expected) {
1933        try {
1934            Date d = fmt.parse(str);
1935            logln("Parsing \""+ str+ "\" with "+ ((SimpleDateFormat) fmt).toPattern()
1936                    + "  => "+ d);
1937            if (!d.equals(expected))
1938                errln( "FAIL: Expected " + expected);
1939        } catch (ParseException e) {
1940            errln(e.getMessage());
1941        }
1942    }
1943
1944    /**
1945     * Test the formatting of time zones.
1946     */
1947    @Test
1948    public void TestDateFormatZone061() {
1949        Date date;
1950        DateFormat formatter;
1951        date = new Date(859248000000L);
1952        logln("Date 1997/3/25 00:00 GMT: " + date);
1953        formatter = new SimpleDateFormat("dd-MMM-yyyyy HH:mm", Locale.UK);
1954        formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
1955        String temp = formatter.format(date);
1956        logln("Formatted in GMT to: " + temp);
1957        try {
1958            Date tempDate = formatter.parse(temp);
1959            logln("Parsed to: " + tempDate);
1960            if (!tempDate.equals(date))
1961                errln("FAIL: Expected " + date + " Got: " + tempDate);
1962        } catch (Throwable t) {
1963            System.out.println(t);
1964        }
1965
1966    }
1967
1968    /**
1969     * Test the formatting of time zones.
1970     */
1971    @Test
1972    public void TestDateFormatZone146() {
1973        TimeZone saveDefault = TimeZone.getDefault();
1974
1975        //try {
1976        TimeZone thedefault = TimeZone.getTimeZone("GMT");
1977        TimeZone.setDefault(thedefault);
1978        // java.util.Locale.setDefault(new java.util.Locale("ar", "", ""));
1979
1980        // check to be sure... its GMT all right
1981        TimeZone testdefault = TimeZone.getDefault();
1982        String testtimezone = testdefault.getID();
1983        if (testtimezone.equals("GMT"))
1984            logln("Test timezone = " + testtimezone);
1985        else
1986            errln("Test timezone should be GMT, not " + testtimezone);
1987
1988        // now try to use the default GMT time zone
1989        GregorianCalendar greenwichcalendar = new GregorianCalendar(1997, 3, 4, 23, 0);
1990        //*****************************greenwichcalendar.setTimeZone(TimeZone.getDefault());
1991        //greenwichcalendar.set(1997, 3, 4, 23, 0);
1992        // try anything to set hour to 23:00 !!!
1993        greenwichcalendar.set(Calendar.HOUR_OF_DAY, 23);
1994        // get time
1995        Date greenwichdate = greenwichcalendar.getTime();
1996        // format every way
1997        String DATA[] = {
1998                "simple format:  ", "04/04/97 23:00 GMT",
1999                "MM/dd/yy HH:mm zzz", "full format:    ",
2000                "Friday, April 4, 1997 11:00:00 o'clock PM GMT",
2001                "EEEE, MMMM d, yyyy h:mm:ss 'o''clock' a zzz",
2002                "long format:    ", "April 4, 1997 11:00:00 PM GMT",
2003                "MMMM d, yyyy h:mm:ss a z", "default format: ",
2004                "04-Apr-97 11:00:00 PM", "dd-MMM-yy h:mm:ss a",
2005                "short format:   ", "4/4/97 11:00 PM",
2006                "M/d/yy h:mm a"};
2007        int DATA_length = DATA.length;
2008
2009        for (int i = 0; i < DATA_length; i += 3) {
2010            DateFormat fmt = new SimpleDateFormat(DATA[i + 2], Locale.ENGLISH);
2011            fmt.setCalendar(greenwichcalendar);
2012            String result = fmt.format(greenwichdate);
2013            logln(DATA[i] + result);
2014            if (!result.equals(DATA[i + 1]))
2015                errln("FAIL: Expected " + DATA[i + 1] + ", got " + result);
2016        }
2017        //}
2018        //finally {
2019        TimeZone.setDefault(saveDefault);
2020        //}
2021
2022    }
2023
2024    /**
2025     * Test the formatting of dates in different locales.
2026     */
2027    @Test
2028    public void TestLocaleDateFormat() {
2029        Date testDate = new Date(874306800000L); //Mon Sep 15 00:00:00 PDT 1997
2030        DateFormat dfFrench = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.FRENCH);
2031        DateFormat dfUS = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.US);
2032        //Set TimeZone = PDT
2033        TimeZone tz = TimeZone.getTimeZone("PST");
2034        dfFrench.setTimeZone(tz);
2035        dfUS.setTimeZone(tz);
2036        String expectedFRENCH_JDK12 = "lundi 15 septembre 1997 \u00E0 00:00:00 heure d\u2019\u00E9t\u00E9 du Pacifique";
2037        //String expectedFRENCH = "lundi 15 septembre 1997 00 h 00 PDT";
2038        String expectedUS = "Monday, September 15, 1997 at 12:00:00 AM Pacific Daylight Time";
2039        logln("Date set to : " + testDate);
2040        String out = dfFrench.format(testDate);
2041        logln("Date Formated with French Locale " + out);
2042        //fix the jdk resources differences between jdk 1.2 and jdk 1.3
2043        /* our own data only has GMT-xxxx information here
2044        String javaVersion = System.getProperty("java.version");
2045        if (javaVersion.startsWith("1.2")) {
2046            if (!out.equals(expectedFRENCH_JDK12))
2047                errln("FAIL: Expected " + expectedFRENCH_JDK12+" Got "+out);
2048        } else {
2049            if (!out.equals(expectedFRENCH))
2050                errln("FAIL: Expected " + expectedFRENCH);
2051        }
2052        */
2053        if (!out.equals(expectedFRENCH_JDK12))
2054            errln("FAIL: Expected " + expectedFRENCH_JDK12+" Got "+out);
2055        out = dfUS.format(testDate);
2056        logln("Date Formated with US Locale " + out);
2057        if (!out.equals(expectedUS))
2058            errln("FAIL: Expected " + expectedUS+" Got "+out);
2059    }
2060
2061    @Test
2062    public void TestFormattingLocaleTimeSeparator() {
2063        Date date = new Date(874266720000L);  // Sun Sep 14 21:52:00 CET 1997
2064        TimeZone tz = TimeZone.getTimeZone("CET");
2065
2066        DateFormat dfArab = DateFormat.getTimeInstance(DateFormat.SHORT, new ULocale("ar"));
2067        DateFormat dfLatn = DateFormat.getTimeInstance(DateFormat.SHORT, new ULocale("ar-u-nu-latn"));
2068
2069        dfArab.setTimeZone(tz);
2070        dfLatn.setTimeZone(tz);
2071
2072        String expectedArab = "\u0669:\u0665\u0662 \u0645";
2073        String expectedLatn = "9:52 \u0645";
2074
2075        String actualArab = dfArab.format(date);
2076        String actualLatn = dfLatn.format(date);
2077
2078        if (!actualArab.equals(expectedArab)) {
2079            errln("FAIL: Expected " + expectedArab + " Got " + actualArab);
2080        }
2081        if (!actualLatn.equals(expectedLatn)) {
2082            errln("FAIL: Expected " + expectedLatn + " Got " + actualLatn);
2083        }
2084    }
2085
2086    /**
2087     * Test the formatting of dates with the 'NONE' keyword.
2088     */
2089    @Test
2090    public void TestDateFormatNone() {
2091        Date testDate = new Date(874306800000L); //Mon Sep 15 00:00:00 PDT 1997
2092        DateFormat dfFrench = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.NONE, Locale.FRENCH);
2093        //Set TimeZone = PDT
2094        TimeZone tz = TimeZone.getTimeZone("PST");
2095        dfFrench.setTimeZone(tz);
2096        String expectedFRENCH_JDK12 = "lundi 15 septembre 1997";
2097        //String expectedFRENCH = "lundi 15 septembre 1997 00 h 00 PDT";
2098        logln("Date set to : " + testDate);
2099        String out = dfFrench.format(testDate);
2100        logln("Date Formated with French Locale " + out);
2101        if (!out.equals(expectedFRENCH_JDK12))
2102            errln("FAIL: Expected " + expectedFRENCH_JDK12+" Got "+out);
2103    }
2104
2105
2106    /**
2107     * Test DateFormat(Calendar) API
2108     */
2109    @Test
2110    public void TestDateFormatCalendar() {
2111        DateFormat date=null, time=null, full=null;
2112        Calendar cal=null;
2113        ParsePosition pos = new ParsePosition(0);
2114        String str;
2115        Date when;
2116
2117        /* Create a formatter for date fields. */
2118        date = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
2119        if (date == null) {
2120            errln("FAIL: getDateInstance failed");
2121            return;
2122        }
2123
2124        /* Create a formatter for time fields. */
2125        time = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.US);
2126        if (time == null) {
2127            errln("FAIL: getTimeInstance failed");
2128            return;
2129        }
2130
2131        /* Create a full format for output */
2132        full = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL,
2133                                              Locale.US);
2134        if (full == null) {
2135            errln("FAIL: getInstance failed");
2136            return;
2137        }
2138
2139        /* Create a calendar */
2140        cal = Calendar.getInstance(Locale.US);
2141        if (cal == null) {
2142            errln("FAIL: Calendar.getInstance failed");
2143            return;
2144        }
2145
2146        /* Parse the date */
2147        cal.clear();
2148        str = "4/5/2001";
2149        pos.setIndex(0);
2150        date.parse(str, cal, pos);
2151        if (pos.getIndex() != str.length()) {
2152            errln("FAIL: DateFormat.parse(4/5/2001) failed at " +
2153                  pos.getIndex());
2154            return;
2155        }
2156
2157        /* Parse the time */
2158        str = "5:45 PM";
2159        pos.setIndex(0);
2160        time.parse(str, cal, pos);
2161        if (pos.getIndex() != str.length()) {
2162            errln("FAIL: DateFormat.parse(17:45) failed at " +
2163                  pos.getIndex());
2164            return;
2165        }
2166
2167        /* Check result */
2168        when = cal.getTime();
2169        str = full.format(when);
2170        // Thursday, April 5, 2001 5:45:00 PM PDT 986517900000
2171        if (when.getTime() == 986517900000.0) {
2172            logln("Ok: Parsed result: " + str);
2173        } else {
2174            errln("FAIL: Parsed result: " + str + ", exp 4/5/2001 5:45 PM");
2175        }
2176    }
2177
2178    /**
2179     * Test DateFormat's parsing of space characters.  See jitterbug 1916.
2180     */
2181    @Test
2182    public void TestSpaceParsing() {
2183
2184        String DATA[] = {
2185            "yyyy MM dd HH:mm:ss",
2186
2187            // pattern, input, expected output (in quotes)
2188            "MMMM d yy", " 04 05 06",  null, // MMMM wants Apr/April
2189            null,        "04 05 06",   null,
2190            "MM d yy",   " 04 05 06",  "2006 04 05 00:00:00",
2191            null,        "04 05 06",   "2006 04 05 00:00:00",
2192            "MMMM d yy", " Apr 05 06", "2006 04 05 00:00:00",
2193            null,        "Apr 05 06",  "2006 04 05 00:00:00",
2194
2195            "hh:mm:ss a", "12:34:56 PM", "1970 01 01 12:34:56",
2196            null,         "12:34:56PM",  "1970 01 01 12:34:56",
2197            // parsing the following comes with using a TIME_SEPARATOR
2198            // pattern character, which has been withdrawn.
2199            //null,         "12.34.56PM",  "1970 01 01 12:34:56",
2200            //null,         "12 : 34 : 56  PM", "1970 01 01 12:34:56",
2201        };
2202
2203        expectParse(DATA, new Locale("en", "", ""));
2204    }
2205
2206    /**
2207     * Test handling of "HHmmss" pattern.
2208     */
2209    @Test
2210    public void TestExactCountFormat() {
2211        String DATA[] = {
2212            "yyyy MM dd HH:mm:ss",
2213
2214            // pattern, input, expected parse or null if expect parse failure
2215            "HHmmss", "123456", "1970 01 01 12:34:56",
2216            null,     "12345",  "1970 01 01 01:23:45",
2217            null,     "1234",   null,
2218            null,     "00-05",  null,
2219            null,     "12-34",  null,
2220            null,     "00+05",  null,
2221            "ahhmm",  "PM730",  "1970 01 01 19:30:00",
2222        };
2223
2224        expectParse(DATA, new Locale("en", "", ""));
2225    }
2226
2227    /**
2228     * Test handling of white space.
2229     */
2230    @Test
2231    public void TestWhiteSpaceParsing() {
2232        String DATA[] = {
2233            "yyyy MM dd",
2234
2235            // pattern, input, expected parse or null if expect parse failure
2236
2237            // Pattern space run should parse input text space run
2238            "MM   d yy",   " 04 01 03",    "2003 04 01",
2239            null,          " 04  01   03 ", "2003 04 01",
2240        };
2241
2242        expectParse(DATA, new Locale("en", "", ""));
2243    }
2244
2245    @Test
2246    public void TestInvalidPattern() {
2247        Exception e = null;
2248        SimpleDateFormat f = null;
2249        String out = null;
2250        try {
2251            f = new SimpleDateFormat("Yesterday");
2252            out = f.format(new Date(0));
2253        } catch (IllegalArgumentException e1) {
2254            e = e1;
2255        }
2256        if (e != null) {
2257            logln("Ok: Received " + e.getMessage());
2258        } else {
2259            errln("FAIL: Expected exception, got " + f.toPattern() +
2260                  "; " + out);
2261        }
2262    }
2263
2264    @Test
2265    public void TestGreekMay() {
2266        Date date = new Date(-9896080848000L);
2267        SimpleDateFormat fmt = new SimpleDateFormat("EEEE, dd MMMM yyyy h:mm:ss a",
2268                             new Locale("el", "", ""));
2269        String str = fmt.format(date);
2270        ParsePosition pos = new ParsePosition(0);
2271        Date d2 = fmt.parse(str, pos);
2272        if (!date.equals(d2)) {
2273            errln("FAIL: unable to parse strings where case-folding changes length");
2274        }
2275    }
2276
2277    @Test
2278    public void TestErrorChecking() {
2279        try {
2280            DateFormat.getDateTimeInstance(-1, -1, Locale.US);
2281            errln("Expected exception for getDateTimeInstance(-1, -1, Locale)");
2282        }
2283        catch(IllegalArgumentException e) {
2284            logln("one ok");
2285        }
2286        catch(Exception e) {
2287            warnln("Expected IllegalArgumentException, got: " + e);
2288        }
2289
2290        try {
2291            DateFormat df = new SimpleDateFormat("aaNNccc");
2292            df.format(new Date());
2293            errln("Expected exception for format with bad pattern");
2294        }
2295        catch(IllegalArgumentException ex) {
2296            logln("two ok");
2297        }
2298        catch(Exception e) {
2299            warnln("Expected IllegalArgumentException, got: " + e);
2300        }
2301
2302        {
2303            SimpleDateFormat fmt = new SimpleDateFormat("dd/MM/yy"); // opposite of text
2304            fmt.set2DigitYearStart(getDate(2003, Calendar.DECEMBER, 25));
2305            String text = "12/25/03";
2306            Calendar xcal = new GregorianCalendar();
2307            xcal.setLenient(false);
2308            ParsePosition pp = new ParsePosition(0);
2309            fmt.parse(text, xcal, pp); // should get parse error on second field, not lenient
2310            if (pp.getErrorIndex() == -1) {
2311                errln("Expected parse error");
2312            } else {
2313                logln("three ok");
2314            }
2315        }
2316    }
2317
2318    @Test
2319    public void TestChineseDateFormatLocalizedPatternChars() {
2320        // jb 4904
2321        // make sure we can display localized versions of the chars used in the default
2322        // chinese date format patterns
2323        Calendar chineseCalendar = new ChineseCalendar();
2324        chineseCalendar.setTimeInMillis((new Date()).getTime());
2325        SimpleDateFormat longChineseDateFormat =
2326            (SimpleDateFormat)chineseCalendar.getDateTimeFormat(DateFormat.LONG, DateFormat.LONG, Locale.CHINA );
2327        DateFormatSymbols dfs = new ChineseDateFormatSymbols( chineseCalendar, Locale.CHINA );
2328        longChineseDateFormat.setDateFormatSymbols( dfs );
2329        // This next line throws the exception
2330        try {
2331            longChineseDateFormat.toLocalizedPattern();
2332        }
2333        catch (Exception e) {
2334            errln("could not localized pattern: " + e.getMessage());
2335        }
2336    }
2337
2338    @Test
2339    public void TestCoverage() {
2340        Date now = new Date();
2341        Calendar cal = new GregorianCalendar();
2342        DateFormat f = DateFormat.getTimeInstance();
2343        logln("time: " + f.format(now));
2344
2345        int hash = f.hashCode(); // sigh, everyone overrides this
2346
2347        f = DateFormat.getInstance(cal);
2348        if(hash == f.hashCode()){
2349            errln("FAIL: hashCode equal for inequal objects");
2350        }
2351        logln("time again: " + f.format(now));
2352
2353        f = DateFormat.getTimeInstance(cal, DateFormat.FULL);
2354        logln("time yet again: " + f.format(now));
2355
2356        f = DateFormat.getDateInstance();
2357        logln("time yet again: " + f.format(now));
2358
2359        ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME,"de_DE");
2360        DateFormatSymbols sym = new DateFormatSymbols(rb, Locale.GERMANY);
2361        DateFormatSymbols sym2 = (DateFormatSymbols)sym.clone();
2362        if (sym.hashCode() != sym2.hashCode()) {
2363            errln("fail, date format symbols hashcode not equal");
2364        }
2365        if (!sym.equals(sym2)) {
2366            errln("fail, date format symbols not equal");
2367        }
2368
2369        Locale foo = new Locale("fu", "FU", "BAR");
2370        rb = null;
2371        sym = new DateFormatSymbols(GregorianCalendar.class, foo);
2372        sym.equals(null);
2373
2374        sym = new ChineseDateFormatSymbols();
2375        sym = new ChineseDateFormatSymbols(new Locale("en_US"));
2376        try{
2377            sym = new ChineseDateFormatSymbols(null, new Locale("en_US"));
2378            errln("ChineseDateFormatSymbols(Calender, Locale) was suppose to return a null " +
2379                    "pointer exception for a null paramater.");
2380        } catch(Exception e){}
2381        sym = new ChineseDateFormatSymbols(new ChineseCalendar(), new Locale("en_US"));
2382        try{
2383            sym = new ChineseDateFormatSymbols(null, new ULocale("en_US"));
2384            errln("ChineseDateFormatSymbols(Calender, ULocale) was suppose to return a null " +
2385                    "pointer exception for a null paramater.");
2386        } catch(Exception e){}
2387        sym = new ChineseDateFormatSymbols(new ChineseCalendar(), foo);
2388        // cover new ChineseDateFormatSymbols(Calendar, ULocale)
2389        ChineseCalendar ccal = new ChineseCalendar();
2390        sym = new ChineseDateFormatSymbols(ccal, ULocale.CHINA); //gclsh1 add
2391
2392        StringBuffer buf = new StringBuffer();
2393        FieldPosition pos = new FieldPosition(0);
2394
2395        f.format((Object)cal, buf, pos);
2396        f.format((Object)now, buf, pos);
2397        f.format((Object)new Long(now.getTime()), buf, pos);
2398        try {
2399            f.format((Object)"Howdy", buf, pos);
2400        }
2401        catch (Exception e) {
2402        }
2403
2404        NumberFormat nf = f.getNumberFormat();
2405        f.setNumberFormat(nf);
2406
2407        boolean lenient = f.isLenient();
2408        f.setLenient(lenient);
2409
2410        ULocale uloc = f.getLocale(ULocale.ACTUAL_LOCALE);
2411
2412        DateFormat sdfmt = new SimpleDateFormat();
2413
2414        if (f.hashCode() != f.hashCode()) {
2415            errln("hashCode is not stable");
2416        }
2417        if (!f.equals(f)) {
2418            errln("f != f");
2419        }
2420        if (f.equals(null)) {
2421            errln("f should not equal null");
2422        }
2423        if (f.equals(sdfmt)) {
2424            errln("A time instance shouldn't equal a default date format");
2425        }
2426
2427        Date d;
2428        {
2429            ChineseDateFormat fmt = new ChineseDateFormat("yymm", Locale.US);
2430            try {
2431                fmt.parse("2"); // fewer symbols than required 2
2432                errln("whoops");
2433            }
2434            catch (ParseException e) {
2435                logln("ok");
2436            }
2437
2438            try {
2439                fmt.parse("2255"); // should succeed with obeycount
2440                logln("ok");
2441            }
2442            catch (ParseException e) {
2443                errln("whoops");
2444            }
2445
2446            try {
2447                fmt.parse("ni hao"); // not a number, should fail
2448                errln("whoops ni hao");
2449            }
2450            catch (ParseException e) {
2451                logln("ok ni hao");
2452            }
2453        }
2454        {
2455            Calendar xcal = new GregorianCalendar();
2456            xcal.set(Calendar.HOUR_OF_DAY, 0);
2457            DateFormat fmt = new SimpleDateFormat("k");
2458            StringBuffer xbuf = new StringBuffer();
2459            FieldPosition fpos = new FieldPosition(Calendar.HOUR_OF_DAY);
2460            fmt.format(xcal, xbuf, fpos);
2461            try {
2462                fmt.parse(xbuf.toString());
2463                logln("ok");
2464
2465                xbuf.setLength(0);
2466                xcal.set(Calendar.HOUR_OF_DAY, 25);
2467                fmt.format(xcal, xbuf, fpos);
2468                Date d2 = fmt.parse(xbuf.toString());
2469                logln("ok again - d2=" + d2);
2470            }
2471            catch (ParseException e) {
2472                errln("whoops");
2473            }
2474        }
2475
2476        {
2477            // cover gmt+hh:mm
2478            DateFormat fmt = new SimpleDateFormat("MM/dd/yy z");
2479            try {
2480                d = fmt.parse("07/10/53 GMT+10:00");
2481                logln("ok : d = " + d);
2482            }
2483            catch (ParseException e) {
2484                errln("Parse of 07/10/53 GMT+10:00 for pattern MM/dd/yy z");
2485            }
2486
2487            // cover invalid separator after GMT
2488            {
2489                ParsePosition pp = new ParsePosition(0);
2490                String text = "07/10/53 GMT=10:00";
2491                d = fmt.parse(text, pp);
2492                if(pp.getIndex()!=12){
2493                    errln("Parse of 07/10/53 GMT=10:00 for pattern MM/dd/yy z");
2494                }
2495                logln("Parsing of the text stopped at pos: " + pp.getIndex() + " as expected and length is "+text.length());
2496            }
2497
2498            // cover bad text after GMT+.
2499            try {
2500                fmt.parse("07/10/53 GMT+blecch");
2501                logln("ok GMT+blecch");
2502            }
2503            catch (ParseException e) {
2504                errln("whoops GMT+blecch");
2505            }
2506
2507            // cover bad text after GMT+hh:.
2508            try {
2509                fmt.parse("07/10/53 GMT+07:blecch");
2510                logln("ok GMT+xx:blecch");
2511            }
2512            catch (ParseException e) {
2513                errln("whoops GMT+xx:blecch");
2514            }
2515
2516            // cover no ':' GMT+#, # < 24 (hh)
2517            try {
2518                d = fmt.parse("07/10/53 GMT+07");
2519                logln("ok GMT+07");
2520            }
2521            catch (ParseException e) {
2522                errln("Parse of 07/10/53 GMT+07 for pattern MM/dd/yy z");
2523            }
2524
2525            // cover no ':' GMT+#, # > 24 (hhmm)
2526            try {
2527                d = fmt.parse("07/10/53 GMT+0730");
2528                logln("ok");
2529            }
2530            catch (ParseException e) {
2531                errln("Parse of 07/10/53 GMT+0730 for pattern MM/dd/yy z");
2532            }
2533
2534            // cover GMT+#, # with second field
2535            try {
2536                d = fmt.parse("07/10/53 GMT+07:30:15");
2537                logln("ok GMT+07:30:15");
2538            }
2539            catch (ParseException e) {
2540                errln("Parse of 07/10/53 GMT+07:30:15 for pattern MM/dd/yy z");
2541            }
2542
2543            // cover no ':' GMT+#, # with second field, no leading zero
2544            try {
2545                d = fmt.parse("07/10/53 GMT+73015");
2546                logln("ok GMT+73015");
2547            }
2548            catch (ParseException e) {
2549                errln("Parse of 07/10/53 GMT+73015 for pattern MM/dd/yy z");
2550            }
2551
2552            // cover no ':' GMT+#, # with 1 digit second field
2553            try {
2554                d = fmt.parse("07/10/53 GMT+07300");
2555                logln("ok GMT+07300");
2556            }
2557            catch (ParseException e) {
2558                errln("Parse of 07/10/53 GMT+07300 for pattern MM/dd/yy z");
2559            }
2560
2561            // cover raw digits with no leading sign (bad RFC822)
2562            try {
2563                d = fmt.parse("07/10/53 07");
2564                errln("Parse of 07/10/53 07 for pattern MM/dd/yy z passed!");
2565            }
2566            catch (ParseException e) {
2567                logln("ok");
2568            }
2569
2570            // cover raw digits (RFC822)
2571            try {
2572                d = fmt.parse("07/10/53 +07");
2573                logln("ok");
2574            }
2575            catch (ParseException e) {
2576                errln("Parse of 07/10/53 +07 for pattern MM/dd/yy z failed");
2577            }
2578
2579            // cover raw digits (RFC822)
2580            try {
2581                d = fmt.parse("07/10/53 -0730");
2582                logln("ok");
2583            }
2584            catch (ParseException e) {
2585                errln("Parse of 07/10/53 -00730 for pattern MM/dd/yy z failed");
2586            }
2587
2588            // cover raw digits (RFC822) in DST
2589            try {
2590                fmt.setTimeZone(TimeZone.getTimeZone("PDT"));
2591                d = fmt.parse("07/10/53 -0730");
2592                logln("ok");
2593            }
2594            catch (ParseException e) {
2595                errln("Parse of 07/10/53 -0730 for pattern MM/dd/yy z failed");
2596            }
2597        }
2598
2599        // TODO: revisit toLocalizedPattern
2600        if (false) {
2601            SimpleDateFormat fmt = new SimpleDateFormat("aabbcc");
2602            try {
2603                String pat = fmt.toLocalizedPattern();
2604                errln("whoops, shouldn't have been able to localize aabbcc");
2605            }
2606            catch (IllegalArgumentException e) {
2607                logln("aabbcc localize ok");
2608            }
2609        }
2610
2611        {
2612            SimpleDateFormat fmt = new SimpleDateFormat("'aabbcc");
2613            try {
2614                fmt.toLocalizedPattern();
2615                errln("whoops, localize unclosed quote");
2616            }
2617            catch (IllegalArgumentException e) {
2618                logln("localize unclosed quote ok");
2619            }
2620        }
2621        {
2622            SimpleDateFormat fmt = new SimpleDateFormat("MM/dd/yy z");
2623            String text = "08/15/58 DBDY"; // bogus time zone
2624            try {
2625                fmt.parse(text);
2626                errln("recognized bogus time zone DBDY");
2627            }
2628            catch (ParseException e) {
2629                logln("time zone ex ok");
2630            }
2631        }
2632
2633        {
2634            // force fallback to default timezone when fmt timezone
2635            // is not named
2636            SimpleDateFormat fmt = new SimpleDateFormat("MM/dd/yy z");
2637            // force fallback to default time zone, still fails
2638            fmt.setTimeZone(TimeZone.getTimeZone("GMT+0147")); // not in equivalency group
2639            String text = "08/15/58 DBDY";
2640            try {
2641                fmt.parse(text);
2642                errln("Parse of 07/10/53 DBDY for pattern MM/dd/yy z passed");
2643            }
2644            catch (ParseException e) {
2645                logln("time zone ex2 ok");
2646            }
2647
2648            // force success on fallback
2649            text = "08/15/58 " + TimeZone.getDefault().getDisplayName(true, TimeZone.SHORT);
2650            try {
2651                fmt.parse(text);
2652                logln("found default tz");
2653            }
2654            catch (ParseException e) {
2655                errln("whoops, got parse exception");
2656            }
2657        }
2658
2659        {
2660            // force fallback to symbols list of timezones when neither
2661            // fmt and default timezone is named
2662            SimpleDateFormat fmt = new SimpleDateFormat("MM/dd/yy z");
2663            TimeZone oldtz = TimeZone.getDefault();
2664            TimeZone newtz = TimeZone.getTimeZone("GMT+0137"); // nonstandard tz
2665            fmt.setTimeZone(newtz);
2666            TimeZone.setDefault(newtz); // todo: fix security issue
2667
2668            // fallback to symbol list, but fail
2669            String text = "08/15/58 DBDY"; // try to parse the bogus time zone
2670            try {
2671                fmt.parse(text);
2672                errln("Parse of 07/10/53 DBDY for pattern MM/dd/yy z passed");
2673            }
2674            catch (ParseException e) {
2675                logln("time zone ex3 ok");
2676            }
2677            catch (Exception e) {
2678                // hmmm... this shouldn't happen.  don't want to exit this
2679                // fn with timezone improperly set, so just in case
2680                TimeZone.setDefault(oldtz);
2681                throw new IllegalStateException(e.getMessage());
2682            }
2683        }
2684
2685        {
2686            //cover getAvailableULocales
2687            final ULocale[] locales = DateFormat.getAvailableULocales();
2688            long count = locales.length;
2689            if (count==0) {
2690                errln(" got a empty list for getAvailableULocales");
2691            }else{
2692                logln("" + count + " available ulocales");
2693            }
2694        }
2695
2696        {
2697            //cover DateFormatSymbols.getDateFormatBundle
2698            cal = new GregorianCalendar();
2699            Locale loc = Locale.getDefault();
2700            DateFormatSymbols mysym = new DateFormatSymbols(cal, loc);
2701            if (mysym == null)
2702                errln("FAIL: constructs DateFormatSymbols with calendar and locale failed");
2703
2704            uloc = ULocale.getDefault();
2705            // These APIs are obsolete and return null
2706            ResourceBundle resb = DateFormatSymbols.getDateFormatBundle(cal, loc);
2707            ResourceBundle resb2 = DateFormatSymbols.getDateFormatBundle(cal, uloc);
2708            ResourceBundle resb3 = DateFormatSymbols.getDateFormatBundle(cal.getClass(), loc);
2709            ResourceBundle resb4 = DateFormatSymbols.getDateFormatBundle(cal.getClass(), uloc);
2710
2711            if (resb != null) {
2712                logln("resb is not null");
2713            }
2714            if (resb2 != null) {
2715                logln("resb2 is not null");
2716            }
2717            if (resb3 != null) {
2718                logln("resb3 is not null");
2719            }
2720            if (resb4 != null) {
2721                logln("resb4 is not null");
2722            }
2723        }
2724
2725        {
2726            //cover DateFormatSymbols.getInstance
2727            DateFormatSymbols datsym1 = DateFormatSymbols.getInstance();
2728            DateFormatSymbols datsym2 = new DateFormatSymbols();
2729            if (!datsym1.equals(datsym2)) {
2730                errln("FAIL: DateFormatSymbols returned by getInstance()" +
2731                        "does not match new DateFormatSymbols().");
2732            }
2733            datsym1 = DateFormatSymbols.getInstance(Locale.JAPAN);
2734            datsym2 = DateFormatSymbols.getInstance(ULocale.JAPAN);
2735            if (!datsym1.equals(datsym2)) {
2736                errln("FAIL: DateFormatSymbols returned by getInstance(Locale.JAPAN)" +
2737                        "does not match the one returned by getInstance(ULocale.JAPAN).");
2738            }
2739        }
2740        {
2741            //cover DateFormatSymbols.getAvailableLocales/getAvailableULocales
2742            Locale[] allLocales = DateFormatSymbols.getAvailableLocales();
2743            if (allLocales.length == 0) {
2744                errln("FAIL: Got a empty list for DateFormatSymbols.getAvailableLocales");
2745            } else {
2746                logln("PASS: " + allLocales.length +
2747                        " available locales returned by DateFormatSymbols.getAvailableLocales");
2748            }
2749
2750            ULocale[] allULocales = DateFormatSymbols.getAvailableULocales();
2751            if (allULocales.length == 0) {
2752                errln("FAIL: Got a empty list for DateFormatSymbols.getAvailableLocales");
2753            } else {
2754                logln("PASS: " + allULocales.length +
2755                        " available locales returned by DateFormatSymbols.getAvailableULocales");
2756            }
2757        }
2758    }
2759
2760    @Test
2761    public void TestStandAloneMonths()
2762    {
2763        String EN_DATA[] = {
2764            "yyyy MM dd HH:mm:ss",
2765
2766            "yyyy LLLL dd H:mm:ss", "fp", "2004 03 10 16:36:31", "2004 March 10 16:36:31", "2004 03 10 16:36:31",
2767            "yyyy LLL dd H:mm:ss",  "fp", "2004 03 10 16:36:31", "2004 Mar 10 16:36:31",   "2004 03 10 16:36:31",
2768            "yyyy LLLL dd H:mm:ss", "F",  "2004 03 10 16:36:31", "2004 March 10 16:36:31",
2769            "yyyy LLL dd H:mm:ss",  "pf", "2004 Mar 10 16:36:31", "2004 03 10 16:36:31", "2004 Mar 10 16:36:31",
2770
2771            "LLLL", "fp", "1970 01 01 0:00:00", "January",   "1970 01 01 0:00:00",
2772            "LLLL", "fp", "1970 02 01 0:00:00", "February",  "1970 02 01 0:00:00",
2773            "LLLL", "fp", "1970 03 01 0:00:00", "March",     "1970 03 01 0:00:00",
2774            "LLLL", "fp", "1970 04 01 0:00:00", "April",     "1970 04 01 0:00:00",
2775            "LLLL", "fp", "1970 05 01 0:00:00", "May",       "1970 05 01 0:00:00",
2776            "LLLL", "fp", "1970 06 01 0:00:00", "June",      "1970 06 01 0:00:00",
2777            "LLLL", "fp", "1970 07 01 0:00:00", "July",      "1970 07 01 0:00:00",
2778            "LLLL", "fp", "1970 08 01 0:00:00", "August",    "1970 08 01 0:00:00",
2779            "LLLL", "fp", "1970 09 01 0:00:00", "September", "1970 09 01 0:00:00",
2780            "LLLL", "fp", "1970 10 01 0:00:00", "October",   "1970 10 01 0:00:00",
2781            "LLLL", "fp", "1970 11 01 0:00:00", "November",  "1970 11 01 0:00:00",
2782            "LLLL", "fp", "1970 12 01 0:00:00", "December",  "1970 12 01 0:00:00",
2783
2784            "LLL", "fp", "1970 01 01 0:00:00", "Jan", "1970 01 01 0:00:00",
2785            "LLL", "fp", "1970 02 01 0:00:00", "Feb", "1970 02 01 0:00:00",
2786            "LLL", "fp", "1970 03 01 0:00:00", "Mar", "1970 03 01 0:00:00",
2787            "LLL", "fp", "1970 04 01 0:00:00", "Apr", "1970 04 01 0:00:00",
2788            "LLL", "fp", "1970 05 01 0:00:00", "May", "1970 05 01 0:00:00",
2789            "LLL", "fp", "1970 06 01 0:00:00", "Jun", "1970 06 01 0:00:00",
2790            "LLL", "fp", "1970 07 01 0:00:00", "Jul", "1970 07 01 0:00:00",
2791            "LLL", "fp", "1970 08 01 0:00:00", "Aug", "1970 08 01 0:00:00",
2792            "LLL", "fp", "1970 09 01 0:00:00", "Sep", "1970 09 01 0:00:00",
2793            "LLL", "fp", "1970 10 01 0:00:00", "Oct", "1970 10 01 0:00:00",
2794            "LLL", "fp", "1970 11 01 0:00:00", "Nov", "1970 11 01 0:00:00",
2795            "LLL", "fp", "1970 12 01 0:00:00", "Dec", "1970 12 01 0:00:00",
2796        };
2797
2798        String CS_DATA[] = {
2799            "yyyy MM dd HH:mm:ss",
2800
2801            "yyyy LLLL dd H:mm:ss", "fp", "2004 04 10 16:36:31", "2004 duben 10 16:36:31", "2004 04 10 16:36:31",
2802            "yyyy MMMM dd H:mm:ss", "fp", "2004 04 10 16:36:31", "2004 dubna 10 16:36:31", "2004 04 10 16:36:31",
2803            "yyyy LLL dd H:mm:ss",  "fp", "2004 04 10 16:36:31", "2004 dub 10 16:36:31",   "2004 04 10 16:36:31",
2804            "yyyy LLLL dd H:mm:ss", "F",  "2004 04 10 16:36:31", "2004 duben 10 16:36:31",
2805            "yyyy MMMM dd H:mm:ss", "F",  "2004 04 10 16:36:31", "2004 dubna 10 16:36:31",
2806            "yyyy LLLL dd H:mm:ss", "pf", "2004 duben 10 16:36:31", "2004 04 10 16:36:31", "2004 duben 10 16:36:31",
2807            "yyyy MMMM dd H:mm:ss", "pf", "2004 dubna 10 16:36:31", "2004 04 10 16:36:31", "2004 dubna 10 16:36:31",
2808
2809            "LLLL", "fp", "1970 01 01 0:00:00", "leden",               "1970 01 01 0:00:00",
2810            "LLLL", "fp", "1970 02 01 0:00:00", "\u00FAnor",           "1970 02 01 0:00:00",
2811            "LLLL", "fp", "1970 03 01 0:00:00", "b\u0159ezen",         "1970 03 01 0:00:00",
2812            "LLLL", "fp", "1970 04 01 0:00:00", "duben",               "1970 04 01 0:00:00",
2813            "LLLL", "fp", "1970 05 01 0:00:00", "kv\u011Bten",         "1970 05 01 0:00:00",
2814            "LLLL", "fp", "1970 06 01 0:00:00", "\u010Derven",         "1970 06 01 0:00:00",
2815            "LLLL", "fp", "1970 07 01 0:00:00", "\u010Dervenec",       "1970 07 01 0:00:00",
2816            "LLLL", "fp", "1970 08 01 0:00:00", "srpen",               "1970 08 01 0:00:00",
2817            "LLLL", "fp", "1970 09 01 0:00:00", "z\u00E1\u0159\u00ED", "1970 09 01 0:00:00",
2818            "LLLL", "fp", "1970 10 01 0:00:00", "\u0159\u00EDjen",     "1970 10 01 0:00:00",
2819            "LLLL", "fp", "1970 11 01 0:00:00", "listopad",            "1970 11 01 0:00:00",
2820            "LLLL", "fp", "1970 12 01 0:00:00", "prosinec",            "1970 12 01 0:00:00",
2821
2822            "LLL", "fp", "1970 01 01 0:00:00", "led",                  "1970 01 01 0:00:00",
2823            "LLL", "fp", "1970 02 01 0:00:00", "\u00FAno",             "1970 02 01 0:00:00",
2824            "LLL", "fp", "1970 03 01 0:00:00", "b\u0159e",             "1970 03 01 0:00:00",
2825            "LLL", "fp", "1970 04 01 0:00:00", "dub",                  "1970 04 01 0:00:00",
2826            "LLL", "fp", "1970 05 01 0:00:00", "kv\u011B",             "1970 05 01 0:00:00",
2827            "LLL", "fp", "1970 06 01 0:00:00", "\u010Dvn",             "1970 06 01 0:00:00",
2828            "LLL", "fp", "1970 07 01 0:00:00", "\u010Dvc",             "1970 07 01 0:00:00",
2829            "LLL", "fp", "1970 08 01 0:00:00", "srp",                  "1970 08 01 0:00:00",
2830            "LLL", "fp", "1970 09 01 0:00:00", "z\u00E1\u0159",        "1970 09 01 0:00:00",
2831            "LLL", "fp", "1970 10 01 0:00:00", "\u0159\u00EDj",        "1970 10 01 0:00:00",
2832            "LLL", "fp", "1970 11 01 0:00:00", "lis",                  "1970 11 01 0:00:00",
2833            "LLL", "fp", "1970 12 01 0:00:00", "pro",                  "1970 12 01 0:00:00",
2834        };
2835
2836        expect(EN_DATA, new Locale("en", "", ""));
2837        expect(CS_DATA, new Locale("cs", "", ""));
2838    }
2839
2840    @Test
2841    public void TestStandAloneDays()
2842    {
2843        String EN_DATA[] = {
2844            "yyyy MM dd HH:mm:ss",
2845
2846            "cccc", "fp", "1970 01 04 0:00:00", "Sunday",    "1970 01 04 0:00:00",
2847            "cccc", "fp", "1970 01 05 0:00:00", "Monday",    "1970 01 05 0:00:00",
2848            "cccc", "fp", "1970 01 06 0:00:00", "Tuesday",   "1970 01 06 0:00:00",
2849            "cccc", "fp", "1970 01 07 0:00:00", "Wednesday", "1970 01 07 0:00:00",
2850            "cccc", "fp", "1970 01 01 0:00:00", "Thursday",  "1970 01 01 0:00:00",
2851            "cccc", "fp", "1970 01 02 0:00:00", "Friday",    "1970 01 02 0:00:00",
2852            "cccc", "fp", "1970 01 03 0:00:00", "Saturday",  "1970 01 03 0:00:00",
2853
2854            "ccc", "fp", "1970 01 04 0:00:00", "Sun", "1970 01 04 0:00:00",
2855            "ccc", "fp", "1970 01 05 0:00:00", "Mon", "1970 01 05 0:00:00",
2856            "ccc", "fp", "1970 01 06 0:00:00", "Tue", "1970 01 06 0:00:00",
2857            "ccc", "fp", "1970 01 07 0:00:00", "Wed", "1970 01 07 0:00:00",
2858            "ccc", "fp", "1970 01 01 0:00:00", "Thu", "1970 01 01 0:00:00",
2859            "ccc", "fp", "1970 01 02 0:00:00", "Fri", "1970 01 02 0:00:00",
2860            "ccc", "fp", "1970 01 03 0:00:00", "Sat", "1970 01 03 0:00:00",
2861        };
2862
2863        String CS_DATA[] = {
2864            "yyyy MM dd HH:mm:ss",
2865
2866            "cccc", "fp", "1970 01 04 0:00:00", "ned\u011Ble",       "1970 01 04 0:00:00",
2867            "cccc", "fp", "1970 01 05 0:00:00", "pond\u011Bl\u00ED", "1970 01 05 0:00:00",
2868            "cccc", "fp", "1970 01 06 0:00:00", "\u00FAter\u00FD",   "1970 01 06 0:00:00",
2869            "cccc", "fp", "1970 01 07 0:00:00", "st\u0159eda",       "1970 01 07 0:00:00",
2870            "cccc", "fp", "1970 01 01 0:00:00", "\u010Dtvrtek",      "1970 01 01 0:00:00",
2871            "cccc", "fp", "1970 01 02 0:00:00", "p\u00E1tek",        "1970 01 02 0:00:00",
2872            "cccc", "fp", "1970 01 03 0:00:00", "sobota",            "1970 01 03 0:00:00",
2873
2874            "ccc", "fp", "1970 01 04 0:00:00", "ne",      "1970 01 04 0:00:00",
2875            "ccc", "fp", "1970 01 05 0:00:00", "po",      "1970 01 05 0:00:00",
2876            "ccc", "fp", "1970 01 06 0:00:00", "\u00FAt", "1970 01 06 0:00:00",
2877            "ccc", "fp", "1970 01 07 0:00:00", "st",      "1970 01 07 0:00:00",
2878            "ccc", "fp", "1970 01 01 0:00:00", "\u010Dt", "1970 01 01 0:00:00",
2879            "ccc", "fp", "1970 01 02 0:00:00", "p\u00E1", "1970 01 02 0:00:00",
2880            "ccc", "fp", "1970 01 03 0:00:00", "so",      "1970 01 03 0:00:00",
2881        };
2882
2883        expect(EN_DATA, new Locale("en", "", ""));
2884        expect(CS_DATA, new Locale("cs", "", ""));
2885    }
2886
2887    @Test
2888    public void TestShortDays()
2889    {
2890        String EN_DATA[] = {
2891            "yyyy MM dd HH:mm:ss",
2892
2893            "EEEEEE, MMM d y", "fp", "2013 01 13 0:00:00", "Su, Jan 13 2013", "2013 01 13 0:00:00",
2894            "EEEEEE, MMM d y", "fp", "2013 01 16 0:00:00", "We, Jan 16 2013", "2013 01 16 0:00:00",
2895            "EEEEEE d",        "fp", "1970 01 17 0:00:00", "Sa 17",           "1970 01 17 0:00:00",
2896            "cccccc d",        "fp", "1970 01 17 0:00:00", "Sa 17",           "1970 01 17 0:00:00",
2897            "cccccc",          "fp", "1970 01 03 0:00:00", "Sa",              "1970 01 03 0:00:00",
2898        };
2899
2900        String SV_DATA[] = {
2901            "yyyy MM dd HH:mm:ss",
2902
2903            "EEEEEE d MMM y",  "fp", "2013 01 13 0:00:00", "s\u00F6 13 jan. 2013", "2013 01 13 0:00:00",
2904            "EEEEEE d MMM y",  "fp", "2013 01 16 0:00:00", "on 16 jan. 2013",      "2013 01 16 0:00:00",
2905            "EEEEEE d",        "fp", "1970 01 17 0:00:00", "l\u00F6 17",          "1970 01 17 0:00:00",
2906            "cccccc d",        "fp", "1970 01 17 0:00:00", "l\u00F6 17",          "1970 01 17 0:00:00",
2907            "cccccc",          "fp", "1970 01 03 0:00:00", "l\u00F6",             "1970 01 03 0:00:00",
2908        };
2909
2910        expect(EN_DATA, new Locale("en", "", ""));
2911        expect(SV_DATA, new Locale("sv", "", ""));
2912    }
2913
2914    @Test
2915    public void TestNarrowNames()
2916    {
2917        String EN_DATA[] = {
2918                "yyyy MM dd HH:mm:ss",
2919
2920                "yyyy MMMMM dd H:mm:ss", "2004 03 10 16:36:31", "2004 M 10 16:36:31",
2921                "yyyy LLLLL dd H:mm:ss",  "2004 03 10 16:36:31", "2004 M 10 16:36:31",
2922
2923                "MMMMM", "1970 01 01 0:00:00", "J",
2924                "MMMMM", "1970 02 01 0:00:00", "F",
2925                "MMMMM", "1970 03 01 0:00:00", "M",
2926                "MMMMM", "1970 04 01 0:00:00", "A",
2927                "MMMMM", "1970 05 01 0:00:00", "M",
2928                "MMMMM", "1970 06 01 0:00:00", "J",
2929                "MMMMM", "1970 07 01 0:00:00", "J",
2930                "MMMMM", "1970 08 01 0:00:00", "A",
2931                "MMMMM", "1970 09 01 0:00:00", "S",
2932                "MMMMM", "1970 10 01 0:00:00", "O",
2933                "MMMMM", "1970 11 01 0:00:00", "N",
2934                "MMMMM", "1970 12 01 0:00:00", "D",
2935
2936                "LLLLL", "1970 01 01 0:00:00", "J",
2937                "LLLLL", "1970 02 01 0:00:00", "F",
2938                "LLLLL", "1970 03 01 0:00:00", "M",
2939                "LLLLL", "1970 04 01 0:00:00", "A",
2940                "LLLLL", "1970 05 01 0:00:00", "M",
2941                "LLLLL", "1970 06 01 0:00:00", "J",
2942                "LLLLL", "1970 07 01 0:00:00", "J",
2943                "LLLLL", "1970 08 01 0:00:00", "A",
2944                "LLLLL", "1970 09 01 0:00:00", "S",
2945                "LLLLL", "1970 10 01 0:00:00", "O",
2946                "LLLLL", "1970 11 01 0:00:00", "N",
2947                "LLLLL", "1970 12 01 0:00:00", "D",
2948
2949                "EEEEE", "1970 01 04 0:00:00", "S",
2950                "EEEEE", "1970 01 05 0:00:00", "M",
2951                "EEEEE", "1970 01 06 0:00:00", "T",
2952                "EEEEE", "1970 01 07 0:00:00", "W",
2953                "EEEEE", "1970 01 01 0:00:00", "T",
2954                "EEEEE", "1970 01 02 0:00:00", "F",
2955                "EEEEE", "1970 01 03 0:00:00", "S",
2956
2957                "ccccc", "1970 01 04 0:00:00", "S",
2958                "ccccc", "1970 01 05 0:00:00", "M",
2959                "ccccc", "1970 01 06 0:00:00", "T",
2960                "ccccc", "1970 01 07 0:00:00", "W",
2961                "ccccc", "1970 01 01 0:00:00", "T",
2962                "ccccc", "1970 01 02 0:00:00", "F",
2963                "ccccc", "1970 01 03 0:00:00", "S",
2964
2965                "h:mm a",     "2015 01 01 10:00:00", "10:00 AM",
2966                "h:mm a",     "2015 01 01 22:00:00", "10:00 PM",
2967                "h:mm aaaaa", "2015 01 01 10:00:00", "10:00 a",
2968                "h:mm aaaaa", "2015 01 01 22:00:00", "10:00 p",
2969            };
2970
2971            String CS_DATA[] = {
2972                "yyyy MM dd HH:mm:ss",
2973
2974                "yyyy LLLLL dd H:mm:ss", "2004 04 10 16:36:31", "2004 4 10 16:36:31",
2975                "yyyy MMMMM dd H:mm:ss", "2004 04 10 16:36:31", "2004 4 10 16:36:31",
2976
2977                "MMMMM", "1970 01 01 0:00:00", "1",
2978                "MMMMM", "1970 02 01 0:00:00", "2",
2979                "MMMMM", "1970 03 01 0:00:00", "3",
2980                "MMMMM", "1970 04 01 0:00:00", "4",
2981                "MMMMM", "1970 05 01 0:00:00", "5",
2982                "MMMMM", "1970 06 01 0:00:00", "6",
2983                "MMMMM", "1970 07 01 0:00:00", "7",
2984                "MMMMM", "1970 08 01 0:00:00", "8",
2985                "MMMMM", "1970 09 01 0:00:00", "9",
2986                "MMMMM", "1970 10 01 0:00:00", "10",
2987                "MMMMM", "1970 11 01 0:00:00", "11",
2988                "MMMMM", "1970 12 01 0:00:00", "12",
2989
2990                "LLLLL", "1970 01 01 0:00:00", "1",
2991                "LLLLL", "1970 02 01 0:00:00", "2",
2992                "LLLLL", "1970 03 01 0:00:00", "3",
2993                "LLLLL", "1970 04 01 0:00:00", "4",
2994                "LLLLL", "1970 05 01 0:00:00", "5",
2995                "LLLLL", "1970 06 01 0:00:00", "6",
2996                "LLLLL", "1970 07 01 0:00:00", "7",
2997                "LLLLL", "1970 08 01 0:00:00", "8",
2998                "LLLLL", "1970 09 01 0:00:00", "9",
2999                "LLLLL", "1970 10 01 0:00:00", "10",
3000                "LLLLL", "1970 11 01 0:00:00", "11",
3001                "LLLLL", "1970 12 01 0:00:00", "12",
3002
3003                "EEEEE", "1970 01 04 0:00:00", "N",
3004                "EEEEE", "1970 01 05 0:00:00", "P",
3005                "EEEEE", "1970 01 06 0:00:00", "\u00DA",
3006                "EEEEE", "1970 01 07 0:00:00", "S",
3007                "EEEEE", "1970 01 01 0:00:00", "\u010C",
3008                "EEEEE", "1970 01 02 0:00:00", "P",
3009                "EEEEE", "1970 01 03 0:00:00", "S",
3010
3011                "ccccc", "1970 01 04 0:00:00", "N",
3012                "ccccc", "1970 01 05 0:00:00", "P",
3013                "ccccc", "1970 01 06 0:00:00", "\u00DA",
3014                "ccccc", "1970 01 07 0:00:00", "S",
3015                "ccccc", "1970 01 01 0:00:00", "\u010C",
3016                "ccccc", "1970 01 02 0:00:00", "P",
3017                "ccccc", "1970 01 03 0:00:00", "S",
3018
3019                "h:mm a",     "2015 01 01 10:00:00", "10:00 dop.",
3020                "h:mm a",     "2015 01 01 22:00:00", "10:00 odp.",
3021                "h:mm aaaaa", "2015 01 01 10:00:00", "10:00 dop.",
3022                "h:mm aaaaa", "2015 01 01 22:00:00", "10:00 odp.",
3023            };
3024
3025            String CA_DATA[] = {
3026                "yyyy MM dd HH:mm:ss",
3027
3028                "h:mm a",     "2015 01 01 10:00:00", "10:00 a. m.",
3029                "h:mm a",     "2015 01 01 22:00:00", "10:00 p. m.",
3030                "h:mm aaaaa", "2015 01 01 10:00:00", "10:00 a. m.",
3031                "h:mm aaaaa", "2015 01 01 22:00:00", "10:00 p. m.",
3032            };
3033
3034            expectFormat(EN_DATA, new Locale("en", "", ""));
3035            expectFormat(CS_DATA, new Locale("cs", "", ""));
3036            expectFormat(CA_DATA, new Locale("ca", "", ""));
3037    }
3038
3039    @Test
3040    public void TestEras()
3041    {
3042        String EN_DATA[] = {
3043            "yyyy MM dd",
3044
3045            "MMMM dd yyyy G",    "fp", "1951 07 17", "July 17 1951 AD",          "1951 07 17",
3046            "MMMM dd yyyy GG",   "fp", "1951 07 17", "July 17 1951 AD",          "1951 07 17",
3047            "MMMM dd yyyy GGG",  "fp", "1951 07 17", "July 17 1951 AD",          "1951 07 17",
3048            "MMMM dd yyyy GGGG", "fp", "1951 07 17", "July 17 1951 Anno Domini", "1951 07 17",
3049
3050            "MMMM dd yyyy G",    "fp", "-438 07 17", "July 17 0439 BC",            "-438 07 17",
3051            "MMMM dd yyyy GG",   "fp", "-438 07 17", "July 17 0439 BC",            "-438 07 17",
3052            "MMMM dd yyyy GGG",  "fp", "-438 07 17", "July 17 0439 BC",            "-438 07 17",
3053            "MMMM dd yyyy GGGG", "fp", "-438 07 17", "July 17 0439 Before Christ", "-438 07 17",
3054       };
3055
3056        expect(EN_DATA, new Locale("en", "", ""));
3057    }
3058
3059    @Test
3060    public void TestQuarters()
3061    {
3062        String EN_DATA[] = {
3063            "yyyy MM dd",
3064
3065            "Q",    "fp", "1970 01 01", "1",           "1970 01 01",
3066            "QQ",   "fp", "1970 04 01", "02",          "1970 04 01",
3067            "QQQ",  "fp", "1970 07 01", "Q3",          "1970 07 01",
3068            "QQQQ", "fp", "1970 10 01", "4th quarter", "1970 10 01",
3069
3070            "q",    "fp", "1970 01 01", "1",           "1970 01 01",
3071            "qq",   "fp", "1970 04 01", "02",          "1970 04 01",
3072            "qqq",  "fp", "1970 07 01", "Q3",          "1970 07 01",
3073            "qqqq", "fp", "1970 10 01", "4th quarter", "1970 10 01",
3074
3075            "Qyy",  "fp", "2015 04 01", "215",         "2015 04 01",
3076            "QQyy", "fp", "2015 07 01", "0315",        "2015 07 01",
3077        };
3078
3079        expect(EN_DATA, new Locale("en", "", ""));
3080    }
3081
3082    /**
3083     * Test DateFormat's parsing of default GMT variants.  See ticket#6135
3084     */
3085    @Test
3086    public void TestGMTParsing() {
3087        String DATA[] = {
3088            "HH:mm:ss Z",
3089
3090            // pattern, input, expected output (in quotes)
3091            "HH:mm:ss Z",       "10:20:30 GMT+03:00",   "10:20:30 +0300",
3092            "HH:mm:ss Z",       "10:20:30 UT-02:00",    "10:20:30 -0200",
3093            "HH:mm:ss Z",       "10:20:30 GMT",         "10:20:30 +0000",
3094            "HH:mm:ss vvvv",    "10:20:30 UT+10:00",    "10:20:30 +1000",
3095            "HH:mm:ss zzzz",    "10:20:30 UTC",         "10:20:30 +0000",   // standalone "UTC"
3096            "ZZZZ HH:mm:ss",    "UT 10:20:30",          "10:20:30 +0000",
3097            "z HH:mm:ss",       "UT+0130 10:20:30",     "10:20:30 +0130",
3098            "z HH:mm:ss",       "UTC+0130 10:20:30",    "10:20:30 +0130",
3099            // Note: GMT-1100 no longer works because of the introduction of the short
3100            // localized GMT support. Previous implementation support this level of
3101            // leniency (no separator char in localized GMT format), but the new
3102            // implementation handles GMT-11 as the legitimate short localized GMT format
3103            // and stop at there. Otherwise, roundtrip would be broken.
3104            //"HH mm Z ss",       "10 20 GMT-1100 30",      "10:20:30 -1100",
3105            "HH mm Z ss",       "10 20 GMT-11 30",      "10:20:30 -1100",
3106            "HH:mm:ssZZZZZ",    "14:25:45Z",            "14:25:45 +0000",
3107            "HH:mm:ssZZZZZ",    "15:00:00-08:00",       "15:00:00 -0800",
3108        };
3109        expectParse(DATA, new Locale("en", "", ""));
3110    }
3111
3112    /**
3113     * Test parsing.  Input is an array that starts with the following
3114     * header:
3115     *
3116     * [0]   = pattern string to parse [i+2] with
3117     *
3118     * followed by test cases, each of which is 3 array elements:
3119     *
3120     * [i]   = pattern, or null to reuse prior pattern
3121     * [i+1] = input string
3122     * [i+2] = expected parse result (parsed with pattern [0])
3123     *
3124     * If expect parse failure, then [i+2] should be null.
3125     */
3126    void expectParse(String[] data, Locale loc) {
3127        Date FAIL = null;
3128        String FAIL_STR = "parse failure";
3129        int i = 0;
3130
3131        SimpleDateFormat fmt = new SimpleDateFormat("", loc);
3132        SimpleDateFormat ref = new SimpleDateFormat(data[i++], loc);
3133        SimpleDateFormat gotfmt = new SimpleDateFormat("G yyyy MM dd HH:mm:ss z", loc);
3134
3135        String currentPat = null;
3136        while (i<data.length) {
3137            String pattern  = data[i++];
3138            String input    = data[i++];
3139            String expected = data[i++];
3140
3141            if (pattern != null) {
3142                fmt.applyPattern(pattern);
3143                currentPat = pattern;
3144            }
3145            String gotstr = FAIL_STR;
3146            Date got;
3147            try {
3148                got = fmt.parse(input);
3149                gotstr = gotfmt.format(got);
3150            } catch (ParseException e1) {
3151                got = FAIL;
3152            }
3153
3154            Date exp = FAIL;
3155            String expstr = FAIL_STR;
3156            if (expected != null) {
3157                expstr = expected;
3158                try {
3159                    exp = ref.parse(expstr);
3160                } catch (ParseException e2) {
3161                    errln("FAIL: Internal test error");
3162                }
3163            }
3164
3165            if (got == exp || (got != null && got.equals(exp))) {
3166                logln("Ok: " + input + " x " +
3167                      currentPat + " => " + gotstr);
3168            } else {
3169                errln("FAIL: " + input + " x " +
3170                      currentPat + " => " + gotstr + ", expected " +
3171                      expstr);
3172            }
3173        }
3174    }
3175
3176    /**
3177     * Test formatting.  Input is an array of String that starts
3178     * with a single 'header' element
3179     *
3180     * [0]   = reference dateformat pattern string (ref)
3181     *
3182     * followed by test cases, each of which is 4 or 5 elements:
3183     *
3184     * [i]   = test dateformat pattern string (test), or null to reuse prior test pattern
3185     * [i+1] = data string A
3186     * [i+2] = data string B
3187     *
3188     * Formats a date, checks the result.
3189     *
3190     * Examples:
3191     * "y/M/d H:mm:ss.SSS", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.567"
3192     * -- ref.parse A, get t0
3193     * -- test.format t0, get r0
3194     * -- compare r0 to B, fail if not equal
3195     */
3196    void expectFormat(String[] data, Locale loc)
3197    {
3198        int i = 1;
3199        String currentPat = null;
3200        SimpleDateFormat ref = new SimpleDateFormat(data[0], loc);
3201
3202        while (i<data.length) {
3203            SimpleDateFormat fmt = new SimpleDateFormat("", loc);
3204            String pattern  = data[i++];
3205            if (pattern != null) {
3206                fmt.applyPattern(pattern);
3207                currentPat = pattern;
3208            }
3209
3210            String datestr = data[i++];
3211            String string = data[i++];
3212            Date date = null;
3213
3214            try {
3215                date = ref.parse(datestr);
3216            } catch (ParseException e) {
3217                errln("FAIL: Internal test error; can't parse " + datestr);
3218                continue;
3219            }
3220
3221            assertEquals("\"" + currentPat + "\".format(" + datestr + ")",
3222                         string,
3223                         fmt.format(date));
3224        }
3225    }
3226
3227    /**
3228     * Test formatting and parsing.  Input is an array of String that starts
3229     * with a single 'header' element
3230     *
3231     * [0]   = reference dateformat pattern string (ref)
3232     *
3233     * followed by test cases, each of which is 4 or 5 elements:
3234     *
3235     * [i]   = test dateformat pattern string (test), or null to reuse prior test pattern
3236     * [i+1] = control string, either "fp", "pf", or "F".
3237     * [i+2] = data string A
3238     * [i+3] = data string B
3239     * [i+4] = data string C (not present for 'F' control string)
3240     *
3241     * Note: the number of data strings depends on the control string.
3242     *
3243     * fp formats a date, checks the result, then parses the result and checks against a (possibly different) date
3244     * pf parses a string, checks the result, then formats the result and checks against a (possibly different) string
3245     * F is a shorthand for fp when the second date is the same as the first
3246     * P is a shorthand for pf when the second string is the same as the first
3247     *
3248     * Examples:
3249     * (fp) "y/M/d H:mm:ss.SS", "fp", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.56", "2004 03 10 16:36:31.560",
3250     * -- ref.parse A, get t0
3251     * -- test.format t0, get r0
3252     * -- compare r0 to B, fail if not equal
3253     * -- test.parse B, get t1
3254     * -- ref.parse C, get t2
3255     * -- compare t1 and t2, fail if not equal
3256     *
3257     * (F) "y/M/d H:mm:ss.SSS", "F", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.567"
3258     * -- ref.parse A, get t0
3259     * -- test.format t0, get r0
3260     * -- compare r0 to B, fail if not equal
3261     * -- test.parse B, get t1
3262     * -- compare t1 and t0, fail if not equal
3263     *
3264     * (pf) "y/M/d H:mm:ss.SSSS", "pf", "2004/3/10 16:36:31.5679", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.5670",
3265     * -- test.parse A, get t0
3266     * -- ref.parse B, get t1
3267     * -- compare t0 to t1, fail if not equal
3268     * -- test.format t1, get r0
3269     * -- compare r0 and C, fail if not equal
3270     *
3271     * (P) "y/M/d H:mm:ss.SSSS", "P", "2004/3/10 16:36:31.5679", "2004 03 10 16:36:31.567"",
3272     * -- test.parse A, get t0
3273     * -- ref.parse B, get t1
3274     * -- compare t0 to t1, fail if not equal
3275     * -- test.format t1, get r0
3276     * -- compare r0 and A, fail if not equal
3277     */
3278    void expect(String[] data, Locale loc) {
3279        expect(data, loc, false);
3280    }
3281
3282    void expect(String[] data, Locale loc, boolean parseAllTZStyles) {
3283        int i = 1;
3284        SimpleDateFormat univ = new SimpleDateFormat("EE G yyyy MM dd HH:mm:ss.SSS zzz", loc);
3285        String currentPat = null;
3286        SimpleDateFormat ref = new SimpleDateFormat(data[0], loc);
3287
3288        while (i<data.length) {
3289            SimpleDateFormat fmt = new SimpleDateFormat("", loc);
3290
3291            if (parseAllTZStyles) {
3292                TimeZoneFormat tzfmt = fmt.getTimeZoneFormat().cloneAsThawed();
3293                tzfmt.setDefaultParseOptions(EnumSet.of(ParseOption.ALL_STYLES)).freeze();
3294                fmt.setTimeZoneFormat(tzfmt);
3295            }
3296
3297            String pattern  = data[i++];
3298            if (pattern != null) {
3299                fmt.applyPattern(pattern);
3300                currentPat = pattern;
3301            }
3302
3303            String control = data[i++];
3304
3305            if (control.equals("fp") || control.equals("F")) {
3306                // 'f'
3307                String datestr = data[i++];
3308                String string = data[i++];
3309                String datestr2 = datestr;
3310                if (control.length() == 2) {
3311                    datestr2 = data[i++];
3312                }
3313                Date date = null;
3314                try {
3315                    date = ref.parse(datestr);
3316                } catch (ParseException e) {
3317                    errln("FAIL: Internal test error; can't parse " + datestr);
3318                    continue;
3319                }
3320                assertEquals("\"" + currentPat + "\".format(" + datestr + ")",
3321                             string,
3322                             fmt.format(date));
3323                // 'p'
3324                if (!datestr2.equals(datestr)) {
3325                    try {
3326                        date = ref.parse(datestr2);
3327                    } catch (ParseException e2) {
3328                        errln("FAIL: Internal test error; can't parse " + datestr2);
3329                        continue;
3330                    }
3331                }
3332                try {
3333                    Date parsedate = fmt.parse(string);
3334                    assertEquals("\"" + currentPat + "\".parse(" + string + ")",
3335                                 univ.format(date),
3336                                 univ.format(parsedate));
3337                } catch (ParseException e3) {
3338                    errln("FAIL: \"" + currentPat + "\".parse(" + string + ") => " +
3339                          e3);
3340                    continue;
3341                }
3342            }
3343            else if (control.equals("pf") || control.equals("P")) {
3344                // 'p'
3345                String string = data[i++];
3346                String datestr = data[i++];
3347                String string2 = string;
3348                if (control.length() == 2) {
3349                    string2 = data[i++];
3350                }
3351
3352                Date date = null;
3353                try {
3354                    date = ref.parse(datestr);
3355                } catch (ParseException e) {
3356                    errln("FAIL: Internal test error; can't parse " + datestr);
3357                    continue;
3358                }
3359                try {
3360                    Date parsedate = fmt.parse(string);
3361                    assertEquals("\"" + currentPat + "\".parse(" + string + ")",
3362                                 univ.format(date),
3363                                 univ.format(parsedate));
3364                } catch (ParseException e2) {
3365                    errln("FAIL: \"" + currentPat + "\".parse(" + string + ") => " +
3366                          e2);
3367                    continue;
3368                }
3369                // 'f'
3370                assertEquals("\"" + currentPat + "\".format(" + datestr + ")",
3371                             string2,
3372                             fmt.format(date));
3373            }
3374            else {
3375                errln("FAIL: Invalid control string " + control);
3376                return;
3377            }
3378        }
3379    }
3380    /*
3381    @Test
3382    public void TestJB4757(){
3383        DateFormat dfmt = DateFormat.getDateInstance(DateFormat.FULL, ULocale.ROOT);
3384    }
3385    */
3386
3387    /*
3388     * Test case for formatToCharacterIterator
3389     */
3390    @Test
3391    public void TestFormatToCharacterIterator() {
3392        // Generate pattern string including all pattern letters with various length
3393        AttributedCharacterIterator acit;
3394        final char SEPCHAR = '~';
3395        String[] patterns = new String[5];
3396        StringBuffer sb = new StringBuffer();
3397        for (int i = 0; i < patterns.length; i++) {
3398            sb.setLength(0);
3399            for (int j = 0; j < PATTERN_CHARS.length(); j++) {
3400                if (j != 0) {
3401                    for (int k = 0; k <= i; k++) {
3402                        sb.append(SEPCHAR);
3403                    }
3404                }
3405                char letter = PATTERN_CHARS.charAt(j);
3406                for (int k = 0; k <= i; k++) {
3407                    sb.append(letter);
3408                }
3409            }
3410            patterns[i] = sb.toString();
3411        }
3412        if (isVerbose()) {
3413            for (int i = 0; i < patterns.length; i++) {
3414                logln("patterns[" + i + "] = " + patterns[i]);
3415            }
3416        }
3417
3418        Calendar cal = Calendar.getInstance();
3419        cal.set(2007, Calendar.JULY, 16, 8, 20, 25);
3420        cal.set(Calendar.MILLISECOND, 567);
3421        final Date d = cal.getTime();
3422
3423        // Test AttributedCharacterIterator returned by SimpleDateFormat
3424        for (int i = 0; i < patterns.length; i++) {
3425            SimpleDateFormat sdf = new SimpleDateFormat(patterns[i]);
3426            acit = sdf.formatToCharacterIterator(d);
3427            int patidx = 0;
3428
3429            while (true) {
3430                Map map = acit.getAttributes();
3431                int limit = acit.getRunLimit();
3432                if (map.isEmpty()) {
3433                    // Must be pattern literal - '~'
3434                    while (acit.getIndex() < limit) {
3435                        if (acit.current() != SEPCHAR) {
3436                            errln("FAIL: Invalid pattern literal at " + acit.current() + " in patterns[" + i + "]");
3437                        }
3438                        acit.next();
3439                    }
3440                } else {
3441                    Set keySet = map.keySet();
3442                    if (keySet.size() == 1) {
3443                        // Check the attribute
3444                        Iterator keyIterator = keySet.iterator();
3445                        DateFormat.Field attr = (DateFormat.Field)keyIterator.next();
3446                        if (!DATEFORMAT_FIELDS[patidx].equals(attr)) {
3447                            errln("FAIL: The attribute at " + acit.getIndex() + " in patterns[" + i + "" +
3448                                    "] is " + attr + " - Expected: " + DATEFORMAT_FIELDS[patidx]);
3449                        }
3450                    } else {
3451                        // SimpleDateFormat#formatToCharacterIterator never set multiple
3452                        // attributes to a single text run.
3453                        errln("FAIL: Multiple attributes were set");
3454                    }
3455                    patidx++;
3456                    // Move to the run limit
3457                    acit.setIndex(limit);
3458                }
3459                if (acit.current() == CharacterIterator.DONE) {
3460                    break;
3461                }
3462            }
3463        }
3464
3465        // ChineseDateFormat has pattern letter 'l' for leap month marker in addition to regular DateFormat
3466        cal.clear();
3467        cal.set(2009, Calendar.JUNE, 22); // 26x78-5-30
3468        Date nonLeapMonthDate = cal.getTime(); // non-leap month
3469        cal.set(2009, Calendar.JUNE, 23); // 26x78-5*-1
3470        Date leapMonthDate = cal.getTime(); // leap month
3471
3472        ChineseDateFormat cdf = new ChineseDateFormat("y'x'G-Ml-d", ULocale.US);
3473        acit = cdf.formatToCharacterIterator(nonLeapMonthDate);
3474        Set keys = acit.getAllAttributeKeys();
3475        if (keys.contains(ChineseDateFormat.Field.IS_LEAP_MONTH)) {
3476            errln("FAIL: separate IS_LEAP_MONTH field should not be present for a Chinese calendar non-leap date"
3477                    + cdf.format(nonLeapMonthDate));
3478        }
3479        acit = cdf.formatToCharacterIterator(leapMonthDate);
3480        keys = acit.getAllAttributeKeys();
3481        if (keys.contains(ChineseDateFormat.Field.IS_LEAP_MONTH)) {
3482            errln("FAIL: separate IS_LEAP_MONTH field should no longer be present for a Chinese calendar leap date"
3483                    + cdf.format(leapMonthDate));
3484        }
3485    }
3486
3487    /*
3488     * API coverage test case for formatToCharacterIterator
3489     */
3490    @Test
3491    public void TestFormatToCharacterIteratorCoverage() {
3492        // Calling formatToCharacterIterator, using various argument types
3493        DateFormat df = DateFormat.getDateTimeInstance();
3494        AttributedCharacterIterator acit = null;
3495
3496        Calendar cal = Calendar.getInstance();
3497        try {
3498            acit = df.formatToCharacterIterator(cal);
3499            if (acit == null) {
3500                errln("FAIL: null AttributedCharacterIterator returned by formatToCharacterIterator(Calendar)");
3501            }
3502        } catch (IllegalArgumentException iae) {
3503            errln("FAIL: Calendar must be accepted by formatToCharacterIterator");
3504        }
3505
3506        Date d = cal.getTime();
3507        try {
3508            acit = df.formatToCharacterIterator(d);
3509            if (acit == null) {
3510                errln("FAIL: null AttributedCharacterIterator returned by formatToCharacterIterator(Date)");
3511            }
3512        } catch (IllegalArgumentException iae) {
3513            errln("FAIL: Date must be accepted by formatToCharacterIterator");
3514        }
3515
3516        Number num = new Long(d.getTime());
3517        try {
3518            acit = df.formatToCharacterIterator(num);
3519            if (acit == null) {
3520                errln("FAIL: null AttributedCharacterIterator returned by formatToCharacterIterator(Number)");
3521            }
3522        } catch (IllegalArgumentException iae) {
3523            errln("FAIL: Number must be accepted by formatToCharacterIterator");
3524        }
3525
3526        boolean isException = false;
3527        String str = df.format(d);
3528        try {
3529            acit = df.formatToCharacterIterator(str);
3530            if (acit == null) {
3531                errln("FAIL: null AttributedCharacterIterator returned by formatToCharacterIterator(String)");
3532            }
3533        } catch (IllegalArgumentException iae) {
3534            logln("IllegalArgumentException is thrown by formatToCharacterIterator");
3535            isException = true;
3536        }
3537        if (!isException) {
3538            errln("FAIL: String must not be accepted by formatToCharacterIterator");
3539        }
3540
3541        // DateFormat.Field#ofCalendarField and getCalendarField
3542        for (int i = 0; i < DATEFORMAT_FIELDS.length; i++) {
3543            int calField = DATEFORMAT_FIELDS[i].getCalendarField();
3544            if (calField != -1) {
3545                DateFormat.Field field = DateFormat.Field.ofCalendarField(calField);
3546                if (field != DATEFORMAT_FIELDS[i]) {
3547                    errln("FAIL: " + field + " is returned for a Calendar field " + calField
3548                            + " - Expected: " + DATEFORMAT_FIELDS[i]);
3549                }
3550            }
3551        }
3552
3553        // IllegalArgument for ofCalendarField
3554        isException = false;
3555        try {
3556            DateFormat.Field.ofCalendarField(-1);
3557        } catch (IllegalArgumentException iae) {
3558            logln("IllegalArgumentException is thrown by ofCalendarField");
3559            isException = true;
3560        }
3561        if (!isException) {
3562            errln("FAIL: IllegalArgumentException must be thrown by ofCalendarField for calendar field value -1");
3563        }
3564
3565        // ChineseDateFormat.Field#ofCalendarField and getCalendarField
3566        int ccalField = ChineseDateFormat.Field.IS_LEAP_MONTH.getCalendarField();
3567        if (ccalField != Calendar.IS_LEAP_MONTH) {
3568            errln("FAIL: ChineseCalendar field " + ccalField + " is returned for ChineseDateFormat.Field.IS_LEAP_MONTH.getCalendarField()");
3569        } else {
3570            DateFormat.Field cfield = ChineseDateFormat.Field.ofCalendarField(ccalField);
3571            if (cfield != ChineseDateFormat.Field.IS_LEAP_MONTH) {
3572                errln("FAIL: " + cfield + " is returned for a ChineseCalendar field " + ccalField
3573                        + " - Expected: " + ChineseDateFormat.Field.IS_LEAP_MONTH);
3574            }
3575        }
3576    }
3577
3578    /*
3579     * Test for checking SimpleDateFormat/DateFormatSymbols creation
3580     * honor the calendar keyword in the given locale.  See ticket#6100
3581     */
3582    @Test
3583    public void TestCalendarType() {
3584        final String testPattern = "GGGG y MMMM d EEEE";
3585
3586        final ULocale[] testLocales = {
3587                new ULocale("de"),
3588                new ULocale("fr_FR@calendar=gregorian"),
3589                new ULocale("en@calendar=islamic"),
3590                new ULocale("ja_JP@calendar=japanese"),
3591                new ULocale("zh_Hans_CN@calendar=bogus"),
3592                new ULocale("ko_KR@calendar=dangi"),
3593        };
3594
3595        SimpleDateFormat[] formatters = new SimpleDateFormat[5];
3596        for (int i = 0; i < testLocales.length; i++) {
3597            // Create a locale with no keywords
3598            StringBuffer locStrBuf = new StringBuffer();
3599            if (testLocales[i].getLanguage().length() > 0) {
3600                locStrBuf.append(testLocales[i].getLanguage());
3601            }
3602            if (testLocales[i].getScript().length() > 0) {
3603                locStrBuf.append('_');
3604                locStrBuf.append(testLocales[i].getScript());
3605            }
3606            if (testLocales[i].getCountry().length() > 0) {
3607                locStrBuf.append('_');
3608                locStrBuf.append(testLocales[i].getCountry());
3609            }
3610            ULocale locNoKeywords = new ULocale(locStrBuf.toString());
3611
3612            Calendar cal = Calendar.getInstance(testLocales[i]);
3613
3614            // Calendar getDateFormat method
3615            DateFormat df = cal.getDateTimeFormat(DateFormat.MEDIUM, DateFormat.MEDIUM, locNoKeywords);
3616            if (df instanceof SimpleDateFormat) {
3617                formatters[0] = (SimpleDateFormat)df;
3618                formatters[0].applyPattern(testPattern);
3619            } else {
3620                formatters[0] = null;
3621            }
3622
3623            // DateFormat constructor with locale
3624            df = DateFormat.getDateInstance(DateFormat.MEDIUM, testLocales[i]);
3625            if (df instanceof SimpleDateFormat) {
3626                formatters[1] = (SimpleDateFormat)df;
3627                formatters[1].applyPattern(testPattern);
3628            } else {
3629                formatters[1] = null;
3630            }
3631
3632            // DateFormat constructor with Calendar
3633            df = DateFormat.getDateInstance(cal, DateFormat.MEDIUM, locNoKeywords);
3634            if (df instanceof SimpleDateFormat) {
3635                formatters[2] = (SimpleDateFormat)df;
3636                formatters[2].applyPattern(testPattern);
3637            } else {
3638                formatters[2] = null;
3639            }
3640
3641            // SimpleDateFormat constructor
3642            formatters[3] = new SimpleDateFormat(testPattern, testLocales[i]);
3643
3644            // SimpleDateFormat with DateFormatSymbols
3645            DateFormatSymbols dfs = new DateFormatSymbols(testLocales[i]);
3646            formatters[4] = new SimpleDateFormat(testPattern, dfs, testLocales[i]);
3647
3648            // All SimpleDateFormat instances should produce the exact
3649            // same result.
3650            String expected = null;
3651            Date d = new Date();
3652            for (int j = 0; j < formatters.length; j++) {
3653                if (formatters[j] != null) {
3654                    String tmp = formatters[j].format(d);
3655                    if (expected == null) {
3656                        expected = tmp;
3657                    } else if (!expected.equals(tmp)) {
3658                        errln("FAIL: formatter[" + j + "] returned \"" + tmp + "\" in locale " +
3659                                testLocales[i] + " - expected: " + expected);
3660                    }
3661                }
3662            }
3663        }
3664    }
3665
3666    /*
3667     * Test for format/parse method with calendar which is different
3668     * from what DateFormat instance internally use.  See ticket#6420.
3669     */
3670    @Test
3671    public void TestRoundtripWithCalendar() {
3672        TimeZone tz = TimeZone.getTimeZone("Europe/Paris");
3673        TimeZone gmt = TimeZone.getTimeZone("Etc/GMT");
3674
3675        final Calendar[] calendars = {
3676            new GregorianCalendar(tz),
3677            new BuddhistCalendar(tz),
3678            new HebrewCalendar(tz),
3679            new IslamicCalendar(tz),
3680            new JapaneseCalendar(tz),
3681        };
3682
3683        final String pattern = "GyMMMMdEEEEHHmmssVVVV";
3684
3685        //FIXME The formatters commented out below are currently failing because of
3686        // the calendar calculation problem reported by #6691
3687
3688        // The order of test formatters mus match the order of calendars above.
3689        final DateFormat[] formatters = {
3690            DateFormat.getPatternInstance(pattern, new ULocale("en_US")), //calendar=gregorian
3691            DateFormat.getPatternInstance(pattern, new ULocale("th_TH")), //calendar=buddhist
3692            DateFormat.getPatternInstance(pattern, new ULocale("he_IL@calendar=hebrew")),
3693//            DateFormat.getPatternInstance(pattern, new ULocale("ar_EG@calendar=islamic")),
3694//            DateFormat.getPatternInstance(pattern, new ULocale("ja_JP@calendar=japanese")),
3695        };
3696
3697        Date d = new Date();
3698        StringBuffer buf = new StringBuffer();
3699        FieldPosition fpos = new FieldPosition(0);
3700        ParsePosition ppos = new ParsePosition(0);
3701
3702        for (int i = 0; i < formatters.length; i++) {
3703            buf.setLength(0);
3704            fpos.setBeginIndex(0);
3705            fpos.setEndIndex(0);
3706            calendars[i].setTime(d);
3707
3708            // Normal case output - the given calendar matches the calendar
3709            // used by the formatter
3710            formatters[i].format(calendars[i], buf, fpos);
3711            String refStr = buf.toString();
3712
3713            for (int j = 0; j < calendars.length; j++) {
3714                if (j == i) {
3715                    continue;
3716                }
3717                buf.setLength(0);
3718                fpos.setBeginIndex(0);
3719                fpos.setEndIndex(0);
3720                calendars[j].setTime(d);
3721
3722                // Even the different calendar type is specified,
3723                // we should get the same result.
3724                formatters[i].format(calendars[j], buf, fpos);
3725                if (!refStr.equals(buf.toString())) {
3726                    errln("FAIL: Different format result with a different calendar for the same time -"
3727                            + "\n Reference calendar type=" + calendars[i].getType()
3728                            + "\n Another calendar type=" + calendars[j].getType()
3729                            + "\n Expected result=" + refStr
3730                            + "\n Actual result=" + buf.toString());
3731                }
3732            }
3733
3734            calendars[i].setTimeZone(gmt);
3735            calendars[i].clear();
3736            ppos.setErrorIndex(-1);
3737            ppos.setIndex(0);
3738
3739            // Normal case parse result - the given calendar matches the calendar
3740            // used by the formatter
3741            formatters[i].parse(refStr, calendars[i], ppos);
3742
3743            for (int j = 0; j < calendars.length; j++) {
3744                if (j == i) {
3745                    continue;
3746                }
3747                calendars[j].setTimeZone(gmt);
3748                calendars[j].clear();
3749                ppos.setErrorIndex(-1);
3750                ppos.setIndex(0);
3751
3752                // Even the different calendar type is specified,
3753                // we should get the same time and time zone.
3754                formatters[i].parse(refStr, calendars[j], ppos);
3755                if (calendars[i].getTimeInMillis() != calendars[j].getTimeInMillis()
3756                        || !calendars[i].getTimeZone().equals(calendars[j].getTimeZone())) {
3757                    errln("FAIL: Different parse result with a different calendar for the same string -"
3758                            + "\n Reference calendar type=" + calendars[i].getType()
3759                            + "\n Another calendar type=" + calendars[j].getType()
3760                            + "\n Date string=" + refStr
3761                            + "\n Expected time=" + calendars[i].getTimeInMillis()
3762                            + "\n Expected time zone=" + calendars[i].getTimeZone().getID()
3763                            + "\n Actual time=" + calendars[j].getTimeInMillis()
3764                            + "\n Actual time zone=" + calendars[j].getTimeZone().getID());
3765                }
3766            }
3767        }
3768    }
3769
3770    // based on TestRelativeDateFormat() in icu/trunk/source/test/cintltst/cdattst.c
3771    @Test
3772    public void TestRelativeDateFormat() {
3773        ULocale loc = ULocale.US;
3774        TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
3775        Calendar cal = new GregorianCalendar(tz, loc);
3776        Date now = new Date();
3777        cal.setTime(now);
3778        cal.set(Calendar.HOUR_OF_DAY, 18);
3779        cal.set(Calendar.MINUTE, 49);
3780        cal.set(Calendar.SECOND, 0);
3781        Date today = cal.getTime();
3782        String minutesStr = "49"; // minutes string to search for in formatted result
3783        int[] dateStylesList = { DateFormat.RELATIVE_FULL, DateFormat.RELATIVE_LONG, DateFormat.RELATIVE_MEDIUM, DateFormat.RELATIVE_SHORT };
3784
3785        for (int i = 0; i < dateStylesList.length; i++) {
3786            int dateStyle = dateStylesList[i];
3787            DateFormat fmtRelDateTime = DateFormat.getDateTimeInstance(dateStyle, DateFormat.SHORT, loc);
3788            DateFormat fmtRelDate = DateFormat.getDateInstance(dateStyle, loc);
3789            DateFormat fmtTime = DateFormat.getTimeInstance(DateFormat.SHORT, loc);
3790
3791            for (int dayOffset = -2; dayOffset <= 2; dayOffset++ ) {
3792                StringBuffer dateTimeStr = new StringBuffer(64);
3793                StringBuffer dateStr = new StringBuffer(64);
3794                StringBuffer timeStr = new StringBuffer(64);
3795                FieldPosition fp = new FieldPosition(DateFormat.MINUTE_FIELD);
3796                cal.setTime(today);
3797                cal.add(Calendar.DATE, dayOffset);
3798
3799                fmtRelDateTime.format(cal, dateTimeStr, fp);
3800                fmtRelDate.format(cal, dateStr, new FieldPosition(0) );
3801                fmtTime.format(cal, timeStr, new FieldPosition(0) );
3802                logln(dayOffset + ", " + dateStyle + ", " + dateTimeStr);
3803                logln(dayOffset + ", " + dateStyle + ", " + dateStr);
3804                logln(dayOffset + ", " + dateStyle + ", " + timeStr);
3805
3806                // check that dateStr is in dateTimeStr
3807                if ( dateTimeStr.toString().indexOf( dateStr.toString() ) < 0 ) {
3808                    errln("relative date string not found in datetime format with timeStyle SHORT, dateStyle " +
3809                            dateStyle + " for dayOffset " + dayOffset );
3810                    errln("datetime format is " + dateTimeStr.toString() + ", date string is " + dateStr.toString() );
3811                }
3812                // check that timeStr is in dateTimeStr
3813                if ( dateTimeStr.toString().indexOf( timeStr.toString() ) < 0 ) {
3814                    errln("short time string not found in datetime format with timeStyle SHORT, dateStyle " +
3815                            dateStyle + " for dayOffset " + dayOffset );
3816                    errln("datetime format is " + dateTimeStr.toString() + ", time string is " + timeStr.toString() );
3817                }
3818                // check index of minutesStr
3819                int minutesStrIndex = dateTimeStr.toString().indexOf( minutesStr );
3820                if ( fp.getBeginIndex() != minutesStrIndex ) {
3821                    errln("FieldPosition beginIndex " + fp.getBeginIndex() + " instead of " + minutesStrIndex + " for datetime format with timeStyle SHORT, dateStyle " +
3822                            dateStyle + " for dayOffset " + dayOffset );
3823                    errln("datetime format is " + dateTimeStr.toString() );
3824                }
3825            }
3826        }
3827    }
3828
3829    @Test
3830    public void Test6880() {
3831        Date d1, d2, dp1, dp2, dexp1, dexp2;
3832        String s1, s2;
3833
3834        TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");
3835        GregorianCalendar gcal = new GregorianCalendar(tz);
3836
3837        gcal.clear();
3838        gcal.set(1900, Calendar.JANUARY, 1, 12, 00);    // offset 8:05:43
3839        d1 = gcal.getTime();
3840
3841        gcal.clear();
3842        gcal.set(1950, Calendar.JANUARY, 1, 12, 00);    // offset 8:00
3843        d2 = gcal.getTime();
3844
3845        gcal.clear();
3846        gcal.set(1970, Calendar.JANUARY, 1, 12, 00);
3847        dexp2 = gcal.getTime();
3848        dexp1 = new Date(dexp2.getTime() - (5*60 + 43)*1000);   // subtract 5m43s
3849
3850        DateFormat fmt = DateFormat.getTimeInstance(DateFormat.FULL, new ULocale("zh"));
3851        fmt.setTimeZone(tz);
3852
3853        s1 = fmt.format(d1);
3854        s2 = fmt.format(d2);
3855
3856        try {
3857            dp1 = fmt.parse(s1);
3858            dp2 = fmt.parse(s2);
3859
3860            if (!dp1.equals(dexp1)) {
3861                errln("FAIL: Failed to parse " + s1 + " parsed: " + dp1 + " expected: " + dexp1);
3862            }
3863            if (!dp2.equals(dexp2)) {
3864                errln("FAIL: Failed to parse " + s2 + " parsed: " + dp2 + " expected: " + dexp2);
3865            }
3866        } catch (ParseException pe) {
3867            errln("FAIL: Parse failure");
3868        }
3869    }
3870
3871    /*
3872     * Tests the constructor public SimpleDateFormat(String pattern, String override, ULocale loc)
3873     */
3874    @Test
3875    public void TestSimpleDateFormatConstructor_String_String_ULocale() {
3876        try {
3877            SimpleDateFormat sdf = new SimpleDateFormat("", "", null);
3878            sdf = (SimpleDateFormat) sdf.clone();
3879        } catch (Exception e) {
3880            errln("SimpleDateFormat(String pattern, String override, ULocale loc) "
3881                    + "was not suppose to return an exception when constructing a new " + "SimpleDateFormat object.");
3882        }
3883    }
3884
3885    /*
3886     * Tests the method public static DateFormat.Field ofCalendarField(int calendarField)
3887     */
3888    @Test
3889    public void TestOfCalendarField() {
3890        // Tests when if (calendarField == ChineseCalendar.IS_LEAP_MONTH) is false
3891        int[] cases = { Calendar.IS_LEAP_MONTH - 1};
3892        for (int i = 0; i < cases.length; i++) {
3893            try {
3894                Field.ofCalendarField(cases[i]);
3895            } catch (Exception e) {
3896                errln("Field.ofCalendarField(int) is not suppose to " + "return an exception for parameter " + cases[i]);
3897            }
3898        }
3899    }
3900
3901    /* Tests the method public final static DateFormat getPatternInstance */
3902    @Test
3903    public void TestGetPatternInstance(){
3904        //public final static DateFormat getPatternInstance(String pattern)
3905        try{
3906            @SuppressWarnings("unused")
3907            DateFormat df = DateFormat.getPatternInstance("");
3908            df = DateFormat.getPatternInstance("", new Locale("en_US"));
3909            df = DateFormat.getPatternInstance(null, "", new Locale("en_US"));
3910        } catch(Exception e) {
3911            errln("DateFormat.getPatternInstance is not suppose to return an exception.");
3912        }
3913    }
3914
3915    /*
3916     * Test case for very long numeric field patterns (ticket#7595)
3917     */
3918    @Test
3919    public void TestLongNumericPattern() {
3920        String DATA[] = {
3921            "yyyy MM dd",
3922
3923            "yyyy.MM.dd", "fp", "2010 04 01",
3924            "2010.04.01", "2010 04 01",
3925
3926            "yyyyyyyyyy.MM.dd", "fp", "2010 04 01",
3927            "0000002010.04.01", "2010 04 01",
3928
3929            "yyyyyyyyyyy.MM.dd", "fp", "2010 04 01",
3930            "00000002010.04.01", "2010 04 01",
3931
3932            "yyyyyyyyyyy.M.dddddddddd", "fp", "2010 04 01",
3933            "00000002010.4.0000000001", "2010 04 01",
3934
3935            "y.M.ddddddddddd", "fp", "2010 10 11",
3936            "2010.10.00000000011", "2010 10 11",
3937        };
3938        expect(DATA, new Locale("en", "", ""));
3939    }
3940
3941    /*
3942     * Test case for very long contiguous numeric patterns (ticket#7480)
3943     */
3944    @Test
3945    public void TestLongContiguousNumericPattern() {
3946        String DATA[] = {
3947                "yyyy-MM-dd HH:mm:ss.SSS",
3948
3949                "yyyyMMddHHmmssSSSSSS", "fp", "2010-04-16 12:23:34.456",
3950                "20100416122334456000", "2010-04-16 12:23:34.456",
3951
3952                "yyyyyyMMddHHHHmmmmssssSSSSSS", "fp", "2010-04-16 12:23:34.456",
3953                "0020100416001200230034456000", "2010-04-16 12:23:34.456",
3954        };
3955            expect(DATA, new Locale("en", "", ""));
3956    }
3957
3958    /*
3959 * Test case for ISO Era processing (ticket#7357)
3960 */
3961    @Test
3962    public void TestISOEra()
3963    {
3964
3965        String data[] = {
3966        // input, output
3967        "BC 4004-10-23T07:00:00Z", "BC 4004-10-23T07:00:00Z",
3968        "AD 4004-10-23T07:00:00Z", "AD 4004-10-23T07:00:00Z",
3969        "-4004-10-23T07:00:00Z"  , "BC 4005-10-23T07:00:00Z",
3970        "4004-10-23T07:00:00Z"   , "AD 4004-10-23T07:00:00Z",
3971        };
3972
3973        int numData = 8;
3974
3975        // create formatter
3976        SimpleDateFormat fmt1 = new SimpleDateFormat("GGG yyyy-MM-dd'T'HH:mm:ss'Z");
3977
3978        for (int i = 0; i < numData; i += 2)
3979        {
3980
3981            // create input string
3982            String in = data[i];
3983
3984            // parse string to date
3985            Date dt1;
3986            try
3987            {
3988                dt1 = fmt1.parse(in);
3989            }
3990            catch (Exception e)
3991            {
3992                errln("DateFormat.parse is not suppose to return an exception.");
3993                break;
3994            }
3995            // format date back to string
3996            String out;
3997            out = fmt1.format(dt1);
3998
3999            // check that roundtrip worked as expected
4000            String expected = data[i + 1];
4001            if (!out.equals(expected))
4002            {
4003                errln((String)"FAIL: " + in + " -> " + out + " expected -> " + expected);
4004            }
4005        }
4006    }
4007
4008    @Test
4009    public void TestFormalChineseDate() {
4010
4011        String pattern = "y\u5e74M\u6708d\u65e5";
4012        String override = "y=hanidec;M=hans;d=hans";
4013
4014        // create formatter
4015        SimpleDateFormat sdf = new SimpleDateFormat(pattern,override,ULocale.CHINA);
4016
4017        Calendar cal = Calendar.getInstance(ULocale.ENGLISH);
4018        cal.clear(Calendar.MILLISECOND);
4019        cal.set(2009, 6, 28, 0,0,0);
4020        FieldPosition pos = new FieldPosition(0);
4021        StringBuffer result = new StringBuffer();
4022        sdf.format(cal,result,pos);
4023        String res1 = result.toString();
4024        String expected = "\u4e8c\u3007\u3007\u4e5d\u5e74\u4e03\u6708\u4e8c\u5341\u516b\u65e5";
4025        if (! res1.equals(expected)) {
4026            errln((String)"FAIL: -> " + result.toString() + " expected -> " + expected);
4027        }
4028        ParsePosition pp = new ParsePosition(0);
4029        Date parsedate = sdf.parse(expected, pp);
4030        long time1 = parsedate.getTime();
4031        long time2 = cal.getTimeInMillis();
4032        if ( time1 != time2 ) {
4033            errln("FAIL: parsed -> " + parsedate.toString() + " expected -> " + cal.toString());
4034        }
4035    }
4036
4037    @Test
4038    public void TestOverrideNumberForamt() {
4039        SimpleDateFormat fmt = new SimpleDateFormat("MM/dd/yy z");
4040
4041        // test override get/set NumberFormat
4042        for (int i = 0; i < 100; i++) {
4043            NumberFormat check_nf = NumberFormat.getInstance(new ULocale("en_US"));
4044            fmt.setNumberFormat("y", check_nf);
4045            NumberFormat get_nf = fmt.getNumberFormat('y');
4046            if (!get_nf.equals(check_nf))
4047                errln("FAIL: getter and setter do not work");
4048        }
4049
4050        NumberFormat reused_nf = NumberFormat.getInstance(new ULocale("en_US"));
4051        fmt.setNumberFormat("y", reused_nf);
4052        fmt.setNumberFormat(reused_nf); // test the same override NF will not crash
4053
4054        // DATA[i][0] is to tell which field to set, DATA[i][1] is the expected result
4055        String[][] DATA = {
4056                { "", "\u521D\u516D \u5341\u4E94" },
4057                { "M", "\u521D\u516D 15" },
4058                { "Mo", "\u521D\u516D \u5341\u4E94" },
4059                { "Md", "\u521D\u516D \u5341\u4E94" },
4060                { "MdMMd", "\u521D\u516D \u5341\u4E94" },
4061                { "mixed", "\u521D\u516D \u5341\u4E94" },
4062        };
4063
4064        NumberFormat override = NumberFormat.getInstance(new ULocale("en@numbers=hanidays"));
4065        Calendar cal = Calendar.getInstance();
4066        cal.set(1997, Calendar.JUNE, 15);
4067        Date test_date = cal.getTime();
4068
4069        for (int i = 0; i < DATA.length; i++) {
4070            fmt = new SimpleDateFormat("MM d", new ULocale("en_US"));
4071            String field = DATA[i][0];
4072
4073            if (field == "") { // use the one w/o field
4074                fmt.setNumberFormat(override);
4075            } else if (field == "mixed") { // set 1 field at first but then full override, both(M & d) should be override
4076                NumberFormat single_override = NumberFormat.getInstance(new ULocale("en@numbers=hebr"));
4077                fmt.setNumberFormat("M", single_override);
4078                fmt.setNumberFormat(override);
4079            } else if (field == "Mo") { // o is invalid field
4080                try {
4081                    fmt.setNumberFormat(field, override);
4082                } catch (IllegalArgumentException e) {
4083                    logln("IllegalArgumentException is thrown for invalid fields");
4084                    continue;
4085                }
4086            } else {
4087                fmt.setNumberFormat(field, override);
4088            }
4089            String result = fmt.format(test_date);
4090            String expected  = DATA[i][1];
4091
4092            if (!result.equals(expected))
4093                errln((String) "FAIL: -> " + result.toString() + " expected -> " + expected);
4094        }
4095    }
4096
4097    @Test
4098    public void TestParsePosition() {
4099        class ParseTestData {
4100            String pattern; // format pattern
4101            String input;   // input date string
4102            int startPos;   // start position
4103            int resPos;     // expected result parse position
4104
4105            ParseTestData(String pattern, String dateStr) {
4106                this.pattern = pattern;
4107                this.input = dateStr;
4108                this.startPos = 0;
4109                this.resPos = dateStr.length();
4110            }
4111
4112            ParseTestData(String pattern, String lead, String dateStr, String trail) {
4113                this.pattern = pattern;
4114                this.input = lead + dateStr + trail;
4115                this.startPos = lead.length();
4116                this.resPos = lead.length() + dateStr.length();
4117            }
4118        }
4119
4120        ParseTestData[] TestData = {
4121            new ParseTestData("yyyy-MM-dd HH:mm:ssZ", "2010-01-10 12:30:00+0500"),
4122            new ParseTestData("yyyy-MM-dd HH:mm:ss ZZZZ", "2010-01-10 12:30:00 GMT+05:00"),
4123            new ParseTestData("Z HH:mm:ss", "-0100 13:20:30"),
4124            new ParseTestData("y-M-d Z", "", "2011-8-25 -0400", " Foo"),
4125            new ParseTestData("y/M/d H:mm:ss z", "2011/7/1 12:34:00 PDT"),
4126            new ParseTestData("y/M/d H:mm:ss z", "+123", "2011/7/1 12:34:00 PDT", " PST"),
4127            new ParseTestData("vvvv a h:mm:ss", "Pacific Time AM 10:21:45"),
4128            new ParseTestData("HH:mm v M/d", "111", "14:15 PT 8/10", " 12345"),
4129            new ParseTestData("'time zone:' VVVV 'date:' yyyy-MM-dd", "xxxx", "time zone: Los Angeles Time date: 2010-02-25", "xxxx"),
4130        };
4131
4132        for (ParseTestData data : TestData) {
4133            SimpleDateFormat sdf = new SimpleDateFormat(data.pattern);
4134            ParsePosition pos = new ParsePosition(data.startPos);
4135            /* Date d = */sdf.parse(data.input, pos);
4136            if (pos.getIndex() != data.resPos) {
4137                errln("FAIL: Parsing [" + data.input + "] with pattern [" + data.pattern + "] returns position - "
4138                        + pos.getIndex() + ", expected - " + data.resPos);
4139            }
4140        }
4141    }
4142
4143    @Test
4144    public void TestChineseDateFormatSymbols() {
4145        class ChineseDateFormatSymbolItem {
4146            public ULocale locale;
4147            String marker;
4148            public ChineseDateFormatSymbolItem(ULocale loc, String mrk) {
4149                locale = loc;
4150                marker = mrk;
4151            }
4152        };
4153        final ChineseDateFormatSymbolItem[] items = {
4154            new ChineseDateFormatSymbolItem( ULocale.ENGLISH, "bis" ),
4155            new ChineseDateFormatSymbolItem( ULocale.SIMPLIFIED_CHINESE, "\u95F0" ),
4156            new ChineseDateFormatSymbolItem( ULocale.TRADITIONAL_CHINESE, "\u958F" ),
4157        };
4158        ChineseCalendar cal = new ChineseCalendar();
4159        for ( ChineseDateFormatSymbolItem item: items ) {
4160            ChineseDateFormatSymbols cdfSymbols = new ChineseDateFormatSymbols(cal, item.locale);
4161            if ( !cdfSymbols.getLeapMonth(0).contentEquals("") || !cdfSymbols.getLeapMonth(1).contentEquals(item.marker) ) {
4162                errln("FAIL: isLeapMonth [0],[1] for locale " + item.locale + "; expected \"\", \"" + item.marker + "\"; got \"" + cdfSymbols.getLeapMonth(0) + "\", \"" + cdfSymbols.getLeapMonth(1) + "\"");
4163            }
4164        }
4165    }
4166
4167    @Test
4168    public void TestMonthPatterns() {
4169        class ChineseCalTestDate {
4170            public int era;
4171            public int year;
4172            public int month; // here 1-based
4173            public int isLeapMonth;
4174            public int day;
4175             // Simple constructor
4176            public ChineseCalTestDate(int e, int y, int m, int il, int d) {
4177                era = e;
4178                year = y;
4179                month = m;
4180                isLeapMonth = il;
4181                day = d;
4182            }
4183        };
4184        final ChineseCalTestDate[] dates = {
4185            //                      era yr mo lp da
4186            new ChineseCalTestDate( 78, 29, 4, 0, 2 ), // (in chinese era 78) gregorian 2012-4-22
4187            new ChineseCalTestDate( 78, 29, 4, 1, 2 ), // (in chinese era 78) gregorian 2012-5-22
4188            new ChineseCalTestDate( 78, 29, 5, 0, 2 ), // (in chinese era 78) gregorian 2012-6-20
4189        };
4190        class MonthPatternItem {
4191            public String locale;
4192            public int style;
4193            public String[] dateString;
4194             // Simple constructor
4195            public MonthPatternItem(String loc, int styl, String dateStr0, String dateStr1, String dateStr2) {
4196                locale = loc;
4197                style = styl;
4198                dateString = new String[3];
4199                dateString[0] = dateStr0;
4200                dateString[1] = dateStr1;
4201                dateString[2] = dateStr2;
4202            }
4203        };
4204        final MonthPatternItem[] items = {
4205            new MonthPatternItem( "root@calendar=chinese",    DateFormat.LONG,  "2012(ren-chen) M04 2",  "2012(ren-chen) M04bis 2",  "2012(ren-chen) M05 2" ),
4206            new MonthPatternItem( "root@calendar=chinese",    DateFormat.SHORT, "2012-04-02",            "2012-04bis-02",            "2012-05-02" ),
4207            new MonthPatternItem( "root@calendar=chinese",    -1,               "29-4-2",                "29-4bis-2",                "29-5-2" ),
4208            new MonthPatternItem( "root@calendar=chinese",    -2,               "78x29-4-2",             "78x29-4bis-2",             "78x29-5-2" ),
4209            new MonthPatternItem( "root@calendar=chinese",    -3,               "ren-chen-4-2",          "ren-chen-4bis-2",          "ren-chen-5-2" ),
4210            new MonthPatternItem( "root@calendar=chinese",    -4,               "ren-chen M04 2",        "ren-chen M04bis 2",        "ren-chen M05 2" ),
4211            new MonthPatternItem( "en@calendar=gregorian",    -3,               "2012-4-22",             "2012-5-22",                "2012-6-20" ),
4212            new MonthPatternItem( "en@calendar=chinese",      DateFormat.LONG,  "Fourth Month 2, 2012(ren-chen)", "Fourth Monthbis 2, 2012(ren-chen)", "Fifth Month 2, 2012(ren-chen)" ),
4213            new MonthPatternItem( "en@calendar=chinese",      DateFormat.SHORT, "4/2/2012",              "4bis/2/2012",              "5/2/2012" ),
4214            new MonthPatternItem( "zh@calendar=chinese",      DateFormat.LONG,  "2012\u58EC\u8FB0\u5E74\u56DB\u6708\u521D\u4E8C",
4215                                                                                "2012\u58EC\u8FB0\u5E74\u95F0\u56DB\u6708\u521D\u4E8C",
4216                                                                                "2012\u58EC\u8FB0\u5E74\u4E94\u6708\u521D\u4E8C" ),
4217            new MonthPatternItem( "zh@calendar=chinese",      DateFormat.SHORT, "2012/4/2",              "2012/\u95F04/2",           "2012/5/2" ),
4218            new MonthPatternItem( "zh@calendar=chinese",      -3,               "\u58EC\u8FB0-4-2",
4219                                                                                "\u58EC\u8FB0-\u95F04-2",
4220                                                                                "\u58EC\u8FB0-5-2" ),
4221            new MonthPatternItem( "zh@calendar=chinese",      -4,               "\u58EC\u8FB0 \u56DB\u6708 2",
4222                                                                                "\u58EC\u8FB0 \u95F0\u56DB\u6708 2",
4223                                                                                "\u58EC\u8FB0 \u4E94\u6708 2" ),
4224            new MonthPatternItem( "zh_Hant@calendar=chinese", DateFormat.LONG,  "2012\u58EC\u8FB0\u5E74\u56DB\u6708\u521D\u4E8C",
4225                                                                                "2012\u58EC\u8FB0\u5E74\u958F\u56DB\u6708\u521D\u4E8C",
4226                                                                                "2012\u58EC\u8FB0\u5E74\u4E94\u6708\u521D\u4E8C" ),
4227            new MonthPatternItem( "zh_Hant@calendar=chinese", DateFormat.SHORT, "2012/4/2",              "2012/\u958F4/2",           "2012/5/2" ),
4228            new MonthPatternItem( "fr@calendar=chinese",      DateFormat.LONG,  "2 s\u00ECyu\u00E8 ren-chen",  "2 s\u00ECyu\u00E8bis ren-chen",  "2 w\u01D4yu\u00E8 ren-chen" ),
4229            new MonthPatternItem( "fr@calendar=chinese",      DateFormat.SHORT, "2/4/29",                      "2/4bis/29",                      "2/5/29" ),
4230            new MonthPatternItem( "en@calendar=dangi",        DateFormat.LONG,  "Third Monthbis 2, 2012(ren-chen)", "Fourth Month 2, 2012(ren-chen)",       "Fifth Month 1, 2012(ren-chen)" ),
4231            new MonthPatternItem( "en@calendar=dangi",        DateFormat.SHORT, "3bis/2/2012",                 "4/2/2012",                       "5/1/2012" ),
4232            new MonthPatternItem( "en@calendar=dangi",        -2,               "78x29-3bis-2",                "78x29-4-2",                      "78x29-5-1" ),
4233            new MonthPatternItem( "ko@calendar=dangi",        DateFormat.LONG,  "\uC784\uC9C4\uB144 \uC7243\uC6D4 2\uC77C",
4234                                                                                "\uC784\uC9C4\uB144 4\uC6D4 2\uC77C",
4235                                                                                "\uC784\uC9C4\uB144 5\uC6D4 1\uC77C" ),
4236            new MonthPatternItem( "ko@calendar=dangi",        DateFormat.SHORT, "29. \uC7243. 2.",
4237                                                                                "29. 4. 2.",
4238                                                                                "29. 5. 1." ),
4239        };
4240        //                         style: -1        -2            -3       -4
4241        final String[] customPatterns = { "y-Ml-d", "G'x'y-Ml-d", "U-M-d", "U MMM d" }; // previously G and l for chinese cal only handled by ChineseDateFormat
4242        Calendar rootChineseCalendar = Calendar.getInstance(new ULocale("root@calendar=chinese"));
4243        for (MonthPatternItem item: items) {
4244            ULocale locale = new ULocale(item.locale);
4245            DateFormat dfmt = (item.style >= 0)? DateFormat.getDateInstance(item.style, locale): new SimpleDateFormat(customPatterns[-item.style - 1], locale);
4246            int idate = 0;
4247            for (ChineseCalTestDate date: dates) {
4248                rootChineseCalendar.clear();
4249                rootChineseCalendar.set( Calendar.ERA, date.era );
4250                rootChineseCalendar.set( date.year, date.month-1, date.day );
4251                rootChineseCalendar.set( Calendar.IS_LEAP_MONTH, date.isLeapMonth );
4252                StringBuffer result = new StringBuffer();
4253                FieldPosition fpos = new FieldPosition(0);
4254                dfmt.format(rootChineseCalendar, result, fpos);
4255                if (result.toString().compareTo(item.dateString[idate]) != 0) {
4256                    errln("FAIL: Chinese calendar format for locale " + item.locale +  ", style " + item.style +
4257                            ", expected \"" + item.dateString[idate] + "\", got \"" + result + "\"");
4258                } else {
4259                    // formatted OK, try parse
4260                    ParsePosition ppos = new ParsePosition(0);
4261                    // ensure we are really parsing the fields we should be
4262                    rootChineseCalendar.set( Calendar.YEAR, 1 );
4263                    rootChineseCalendar.set( Calendar.MONTH, 0 );
4264                    rootChineseCalendar.set( Calendar.IS_LEAP_MONTH, 0 );
4265                    rootChineseCalendar.set( Calendar.DATE, 1 );
4266                    //
4267                    dfmt.parse(result.toString(), rootChineseCalendar, ppos);
4268                    int era = rootChineseCalendar.get(Calendar.ERA);
4269                    int year = rootChineseCalendar.get(Calendar.YEAR);
4270                    int month = rootChineseCalendar.get(Calendar.MONTH) + 1;
4271                    int isLeapMonth = rootChineseCalendar.get(Calendar.IS_LEAP_MONTH);
4272                    int day = rootChineseCalendar.get(Calendar.DATE);
4273                    if ( ppos.getIndex() < result.length() || year != date.year || month != date.month || isLeapMonth != date.isLeapMonth || day != date.day) {
4274                        errln("FAIL: Chinese calendar parse for locale " + item.locale +  ", style " + item.style +
4275                                ", string \"" + result + "\", expected " + date.year+"-"+date.month+"("+date.isLeapMonth+")-"+date.day +
4276                                ", got pos " + ppos.getIndex() + " era("+era+")-"+year+"-"+month+"("+isLeapMonth+")-"+day );
4277                    }
4278                }
4279                idate++;
4280            }
4281        }
4282    }
4283
4284    @Test
4285    public void TestNonGregoFmtParse() {
4286        class CalAndFmtTestItem {
4287            public int era;
4288            public int year;
4289            public int month;
4290            public int day;
4291            public int hour;
4292            public int minute;
4293            public String formattedDate;
4294             // Simple constructor
4295            public CalAndFmtTestItem(int er, int yr, int mo, int da, int hr, int mi, String fd) {
4296                era = er;
4297                year = yr;
4298                month = mo;
4299                day = da;
4300                hour = hr;
4301                minute = mi;
4302                formattedDate = fd;
4303            }
4304        };
4305        // test items for he@calendar=hebrew, long date format
4306        final CalAndFmtTestItem[] cafti_he_hebrew_long = {
4307            //                     era    yr  mo  da  hr  mi  formattedDate
4308            new CalAndFmtTestItem(   0, 4999, 12, 29, 12,  0, "\u05DB\u05F4\u05D8 \u05D1\u05D0\u05DC\u05D5\u05DC \u05D3\u05F3\u05EA\u05EA\u05E7\u05E6\u05F4\u05D8" ),
4309            new CalAndFmtTestItem(   0, 5100,  0,  1, 12,  0, "\u05D0\u05F3 \u05D1\u05EA\u05E9\u05E8\u05D9 \u05E7\u05F3" ),
4310            new CalAndFmtTestItem(   0, 5774,  5,  1, 12,  0, "\u05D0\u05F3 \u05D1\u05D0\u05D3\u05E8 \u05D0\u05F3 \u05EA\u05E9\u05E2\u05F4\u05D3" ),
4311            new CalAndFmtTestItem(   0, 5999, 12, 29, 12,  0, "\u05DB\u05F4\u05D8 \u05D1\u05D0\u05DC\u05D5\u05DC \u05EA\u05EA\u05E7\u05E6\u05F4\u05D8" ),
4312            new CalAndFmtTestItem(   0, 6100,  0,  1, 12,  0, "\u05D0\u05F3 \u05D1\u05EA\u05E9\u05E8\u05D9 \u05D5\u05F3\u05E7\u05F3" ),
4313        };
4314        final CalAndFmtTestItem[] cafti_zh_chinese_custU = {
4315            //                     era    yr  mo  da  hr  mi  formattedDate
4316            new CalAndFmtTestItem(  78,   31,  0,  1, 12,  0, "2014\u7532\u5348\u5E74\u6B63\u67081" ),
4317            new CalAndFmtTestItem(  77,   31,  0,  1, 12,  0, "1954\u7532\u5348\u5E74\u6B63\u67081" ),
4318        };
4319        final CalAndFmtTestItem[] cafti_zh_chinese_custNoU = {
4320            //                     era    yr  mo  da  hr  mi  formattedDate
4321            new CalAndFmtTestItem(  78,   31,  0,  1, 12, 0, "2014\u5E74\u6B63\u67081" ),
4322            new CalAndFmtTestItem(  77,   31,  0,  1, 12, 0, "1954\u5E74\u6B63\u67081" ),
4323        };
4324        final CalAndFmtTestItem[] cafti_ja_japanese_custGy = {
4325            //                     era    yr  mo  da  hr  mi  formattedDate
4326            new CalAndFmtTestItem( 235,   26,  2,  5, 12, 0, "2014(\u5E73\u621026)\u5E743\u67085\u65E5" ),
4327            new CalAndFmtTestItem( 234,   60,  2,  5, 12, 0, "1985(\u662D\u548C60)\u5E743\u67085\u65E5" ),
4328        };
4329        final CalAndFmtTestItem[] cafti_ja_japanese_custNoGy = {
4330            //                     era    yr  mo  da  hr  mi  formattedDate
4331            new CalAndFmtTestItem( 235,   26,  2,  5, 12, 0, "2014\u5E743\u67085\u65E5" ),
4332            new CalAndFmtTestItem( 234,   60,  2,  5, 12, 0, "1985\u5E743\u67085\u65E5" ),
4333        };
4334        final CalAndFmtTestItem[] cafti_en_islamic_cust = {
4335            //                     era    yr  mo  da  hr  mi  formattedDate
4336            new CalAndFmtTestItem(   0, 1384,  0,  1, 12, 0, "1 Muh. 1384 AH, 1964" ),
4337            new CalAndFmtTestItem(   0, 1436,  0,  1, 12, 0, "1 Muh. 1436 AH, 2014" ),
4338            new CalAndFmtTestItem(   0, 1487,  0,  1, 12, 0, "1 Muh. 1487 AH, 2064" ),
4339        };
4340        class TestNonGregoItem {
4341            public String locale;
4342            public int style;
4343            public String pattern;  // ignored unless style == DateFormat.NONE
4344            public CalAndFmtTestItem[] caftItems;
4345             // Simple constructor
4346            public TestNonGregoItem(String loc, int styl, String pat, CalAndFmtTestItem[] items) {
4347                locale = loc;
4348                style = styl;
4349                pattern = pat;
4350                caftItems = items;
4351            }
4352        };
4353        final TestNonGregoItem[] items = {
4354            new TestNonGregoItem( "he@calendar=hebrew",   DateFormat.LONG, "",                          cafti_he_hebrew_long ),
4355            new TestNonGregoItem( "zh@calendar=chinese",  DateFormat.NONE, "rU\u5E74MMMd",              cafti_zh_chinese_custU ),
4356            new TestNonGregoItem( "zh@calendar=chinese",  DateFormat.NONE, "r\u5E74MMMd",               cafti_zh_chinese_custNoU ),
4357            new TestNonGregoItem( "ja@calendar=japanese", DateFormat.NONE, "r(Gy)\u5E74M\u6708d\u65E5", cafti_ja_japanese_custGy ),
4358            new TestNonGregoItem( "ja@calendar=japanese", DateFormat.NONE, "r\u5E74M\u6708d\u65E5",     cafti_ja_japanese_custNoGy ),
4359            new TestNonGregoItem( "en@calendar=islamic",  DateFormat.NONE, "d MMM y G, r",              cafti_en_islamic_cust ),
4360        };
4361        for (TestNonGregoItem item: items) {
4362            ULocale locale = new ULocale(item.locale);
4363            DateFormat dfmt = null;
4364            if (item.style != DateFormat.NONE) {
4365                dfmt = DateFormat.getDateInstance(item.style, locale);
4366            } else {
4367                dfmt = new SimpleDateFormat(item.pattern, locale);
4368            }
4369            Calendar cal = dfmt.getCalendar();
4370
4371            for (CalAndFmtTestItem caftItem: item.caftItems) {
4372                cal.clear();
4373                cal.set(Calendar.ERA, caftItem.era);
4374                cal.set(caftItem.year, caftItem.month, caftItem.day, caftItem.hour, caftItem.minute, 0);
4375                StringBuffer result = new StringBuffer();
4376                FieldPosition fpos = new FieldPosition(0);
4377                dfmt.format(cal, result, fpos);
4378                if (result.toString().compareTo(caftItem.formattedDate) != 0) {
4379                    errln("FAIL: date format for locale " + item.locale +  ", style " + item.style +
4380                            ", expected \"" + caftItem.formattedDate + "\", got \"" + result + "\"");
4381                } else {
4382                    // formatted OK, try parse
4383                    ParsePosition ppos = new ParsePosition(0);
4384                    dfmt.parse(result.toString(), cal, ppos);
4385                    int era = cal.get(Calendar.ERA);
4386                    int year = cal.get(Calendar.YEAR);
4387                    int month = cal.get(Calendar.MONTH);
4388                    int day = cal.get(Calendar.DATE);
4389                    if ( ppos.getIndex() < result.length() || era != caftItem.era || year != caftItem.year || month != caftItem.month || day != caftItem.day) {
4390                        errln("FAIL: date parse for locale " + item.locale +  ", style " + item.style +
4391                                ", string \"" + result + "\", expected " + caftItem.era+":" +caftItem.year+"-"+caftItem.month+"-"+caftItem.day +
4392                                ", got pos " + ppos.getIndex() + " "+year+"-"+month+"-"+day );
4393                    }
4394                }
4395            }
4396        }
4397    }
4398
4399    @Test
4400    public void TestFormatsWithNumberSystems() {
4401        TimeZone zone = TimeZone.getFrozenTimeZone("UTC");
4402        long date = 1451556000000L; // for UTC: grego 31-Dec-2015 10 AM, hebrew 19 tevet 5776, chinese yi-wei 11mo 21day
4403        class TestFmtWithNumSysItem {
4404            public String localeID;
4405            public int style;
4406            public String expectPattern;
4407            public String expectFormat;
4408             // Simple constructor
4409            public TestFmtWithNumSysItem(String loc, int styl, String pat, String exp) {
4410                localeID = loc;
4411                style = styl;
4412                expectPattern = pat;
4413                expectFormat = exp;
4414            }
4415        };
4416        final TestFmtWithNumSysItem[] items = {
4417            new TestFmtWithNumSysItem( "haw@calendar=gregorian", DateFormat.SHORT,  "d/M/yy",       "31/xii/15" ),
4418            new TestFmtWithNumSysItem( "he@calendar=hebrew",     DateFormat.LONG, "d \u05D1MMMM y", "\u05D9\u05F4\u05D8 \u05D1\u05D8\u05D1\u05EA \u05EA\u05E9\u05E2\u05F4\u05D5" ),
4419            new TestFmtWithNumSysItem( "zh@calendar=chinese",      DateFormat.LONG, "rU\u5E74MMMd", "2015\u4E59\u672A\u5E74\u5341\u4E00\u6708\u5EFF\u4E00" ), // "2015乙未年十一月廿一"
4420            new TestFmtWithNumSysItem( "zh_Hant@calendar=chinese", DateFormat.LONG, "rU\u5E74MMMd", "2015\u4E59\u672A\u5E74\u51AC\u6708\u5EFF\u4E00" ), // "2015乙未年冬月廿一"
4421            new TestFmtWithNumSysItem( "ja@calendar=chinese", DateFormat.LONG, "U\u5E74MMMd\u65E5", "\u4E59\u672A\u5E74\u5341\u4E00\u6708\u4E8C\u4E00\u65E5" ), // "乙未年十一月二一日"
4422        };
4423        for (TestFmtWithNumSysItem item: items) {
4424            ULocale locale = new ULocale(item.localeID);
4425            Calendar cal = Calendar.getInstance(zone, locale);
4426            cal.setTimeInMillis(date);
4427            SimpleDateFormat sdfmt = (SimpleDateFormat) DateFormat.getDateInstance(item.style, locale);
4428            StringBuffer getFormat = new StringBuffer();
4429            FieldPosition fp = new FieldPosition(0);
4430            sdfmt.format(cal, getFormat, fp);
4431            if (getFormat.toString().compareTo(item.expectFormat) != 0) {
4432                errln("FAIL: date format for locale " + item.localeID + ", expected \"" + item.expectFormat + "\", got \"" + getFormat.toString() + "\"");
4433            }
4434            String getPattern = sdfmt.toPattern();
4435            if (getPattern.compareTo(item.expectPattern) != 0) {
4436                errln("FAIL: date pattern for locale " + item.localeID + ", expected \"" + item.expectPattern + "\", got \"" + getPattern + "\"");
4437            }
4438        }
4439
4440    }
4441
4442    @Test
4443    public void TestTwoDigitWOY() { // See ICU Ticket #8514
4444        String dateText = new String("98MON01");
4445
4446        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYEEEww");
4447        simpleDateFormat.set2DigitYearStart(new GregorianCalendar(1999,0,1).getTime());
4448
4449        Calendar cal = new GregorianCalendar();
4450        cal.clear();
4451        cal.setFirstDayOfWeek(Calendar.SUNDAY);
4452        cal.setMinimalDaysInFirstWeek(4);
4453
4454        ParsePosition pp = new ParsePosition(0);
4455
4456        simpleDateFormat.parse(dateText, cal, pp);
4457
4458        if (pp.getErrorIndex() >= 0) {
4459            errln("FAIL: Error in parsing two digit WOY");
4460        }
4461
4462        simpleDateFormat.applyPattern("Y");
4463
4464        String result = simpleDateFormat.format(cal.getTime());
4465        if ( !result.equals("2098") ) {
4466            errln("FAIL: Unexpected result in two digit WOY parse.  Expected 2098, got " + result);
4467        }
4468    }
4469
4470    @Test
4471    public void TestContext() {
4472        class TestContextItem {
4473            public String locale;
4474            public String pattern;
4475            public DisplayContext capitalizationContext;
4476            public String expectedFormat;
4477             // Simple constructor
4478            public TestContextItem(String loc, String pat, DisplayContext capCtxt, String expFmt) {
4479                locale = loc;
4480                pattern = pat;
4481                capitalizationContext = capCtxt;
4482                expectedFormat = expFmt;
4483            }
4484        };
4485        final TestContextItem[] items = {
4486            new TestContextItem( "fr", "MMMM y", DisplayContext.CAPITALIZATION_NONE,                    "juillet 2008" ),
4487            new TestContextItem( "fr", "MMMM y", DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,  "juillet 2008" ),
4488            new TestContextItem( "fr", "MMMM y", DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, "Juillet 2008" ),
4489            new TestContextItem( "fr", "MMMM y", DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU,     "juillet 2008" ),
4490            new TestContextItem( "fr", "MMMM y", DisplayContext.CAPITALIZATION_FOR_STANDALONE,          "Juillet 2008" ),
4491            new TestContextItem( "cs", "LLLL y", DisplayContext.CAPITALIZATION_NONE,                    "\u010Dervenec 2008" ),
4492            new TestContextItem( "cs", "LLLL y", DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,  "\u010Dervenec 2008" ),
4493            new TestContextItem( "cs", "LLLL y", DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, "\u010Cervenec 2008" ),
4494            new TestContextItem( "cs", "LLLL y", DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU,     "\u010Cervenec 2008" ),
4495            new TestContextItem( "cs", "LLLL y", DisplayContext.CAPITALIZATION_FOR_STANDALONE,          "\u010Dervenec 2008" ),
4496        };
4497        class TestRelativeContextItem {
4498            public String locale;
4499            public DisplayContext capitalizationContext;
4500            public String expectedFormatToday;
4501            public String expectedFormatYesterday;
4502             // Simple constructor
4503            public TestRelativeContextItem(String loc, DisplayContext capCtxt, String expFmtToday, String expFmtYesterday) {
4504                locale = loc;
4505                capitalizationContext = capCtxt;
4506                expectedFormatToday = expFmtToday;
4507                expectedFormatYesterday = expFmtYesterday;
4508            }
4509        };
4510        final TestRelativeContextItem[] relItems = {
4511            new TestRelativeContextItem( "en", DisplayContext.CAPITALIZATION_NONE,                      "today", "yesterday" ),
4512            new TestRelativeContextItem( "en", DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,    "today", "yesterday" ),
4513            new TestRelativeContextItem( "en", DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, "Today", "Yesterday" ),
4514            new TestRelativeContextItem( "en", DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU,       "Today", "Yesterday" ),
4515            new TestRelativeContextItem( "en", DisplayContext.CAPITALIZATION_FOR_STANDALONE,            "Today", "Yesterday" ),
4516            new TestRelativeContextItem( "nb", DisplayContext.CAPITALIZATION_NONE,                      "i dag", "i g\u00E5r" ),
4517            new TestRelativeContextItem( "nb", DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,    "i dag", "i g\u00E5r" ),
4518            new TestRelativeContextItem( "nb", DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, "I dag", "I g\u00E5r" ),
4519            new TestRelativeContextItem( "nb", DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU,       "i dag", "i g\u00E5r" ),
4520            new TestRelativeContextItem( "nb", DisplayContext.CAPITALIZATION_FOR_STANDALONE,            "I dag", "I g\u00E5r" ),
4521        };
4522
4523        Calendar cal = new GregorianCalendar(2008, Calendar.JULY, 2);
4524        for (TestContextItem item: items) {
4525            ULocale locale = new ULocale(item.locale);
4526            SimpleDateFormat sdfmt = new SimpleDateFormat(item.pattern, locale);
4527
4528            // now try context & standard format call
4529            sdfmt.setContext(item.capitalizationContext);
4530            SimpleDateFormat sdfmtClone = (SimpleDateFormat)sdfmt.clone();
4531            if (!sdfmtClone.equals(sdfmt)) {
4532                errln("FAIL: for locale " + item.locale +  ", capitalizationContext " + item.capitalizationContext +
4533                        ", sdfmt.clone() != sdfmt (for SimpleDateFormat)");
4534            }
4535
4536            StringBuffer result2 = new StringBuffer();
4537            FieldPosition fpos2 = new FieldPosition(0);
4538            sdfmt.format(cal, result2, fpos2);
4539            if (result2.toString().compareTo(item.expectedFormat) != 0) {
4540                errln("FAIL: format for locale " + item.locale +  ", capitalizationContext " + item.capitalizationContext +
4541                        ", expected \"" + item.expectedFormat + "\", got \"" + result2 + "\"");
4542            }
4543
4544            // now read back context, make sure it is what we set (testing with DateFormat subclass)
4545            DisplayContext capitalizationContext = sdfmt.getContext(DisplayContext.Type.CAPITALIZATION);
4546            if (capitalizationContext != item.capitalizationContext) {
4547                errln("FAIL: getContext for locale " + item.locale +  ", capitalizationContext " + item.capitalizationContext +
4548                        ", but got context " + capitalizationContext);
4549            }
4550        }
4551        for (TestRelativeContextItem relItem: relItems) {
4552            ULocale locale = new ULocale(relItem.locale);
4553            DateFormat dfmt = DateFormat.getDateInstance(DateFormat.RELATIVE_LONG, locale);
4554            Date today = new Date();
4555
4556            // now try context & standard format call
4557            dfmt.setContext(relItem.capitalizationContext);
4558
4559            // write to stream, then read a copy from stream & compare
4560            boolean serializeTestFail = false;
4561            ByteArrayOutputStream baos = null;
4562            DateFormat dfmtFromStream = null;
4563            try {
4564                baos = new ByteArrayOutputStream();
4565                ObjectOutputStream oos = new ObjectOutputStream(baos);
4566                oos.writeObject(dfmt);
4567                oos.close();
4568            } catch (IOException i) {
4569                errln("FAIL: for locale " + relItem.locale +  ", capitalizationContext " + relItem.capitalizationContext +
4570                        ", serialization of RELATIVE_LONG DateFormat fails with IOException");
4571                serializeTestFail = true;
4572            }
4573            if (!serializeTestFail) {
4574                byte[] buf = baos.toByteArray();
4575                try {
4576                    ByteArrayInputStream bais = new ByteArrayInputStream(buf);
4577                    ObjectInputStream ois = new ObjectInputStream(bais);
4578                    dfmtFromStream = (DateFormat)ois.readObject();
4579                    ois.close();
4580                } catch (IOException i) {
4581                    errln("FAIL: for locale " + relItem.locale +  ", capitalizationContext " + relItem.capitalizationContext +
4582                            ", deserialization of RELATIVE_LONG DateFormat fails with IOException");
4583                    serializeTestFail = true;
4584                } catch (ClassNotFoundException c) {
4585                    errln("FAIL: for locale " + relItem.locale +  ", capitalizationContext " + relItem.capitalizationContext +
4586                            ", deserialization of RELATIVE_LONG DateFormat fails with ClassNotFoundException");
4587                    serializeTestFail = true;
4588                }
4589            }
4590            if (!serializeTestFail && dfmtFromStream==null) {
4591                errln("FAIL: for locale " + relItem.locale +  ", capitalizationContext " + relItem.capitalizationContext +
4592                        ", dfmtFromStream is null (for RELATIVE_LONG)");
4593                serializeTestFail = true;
4594            }
4595            if (!serializeTestFail && !dfmtFromStream.equals(dfmt)) {
4596                errln("FAIL: for locale " + relItem.locale +  ", capitalizationContext " + relItem.capitalizationContext +
4597                        ", dfmtFromStream != dfmt (for RELATIVE_LONG)");
4598                serializeTestFail = true;
4599            }
4600
4601            cal.setTime(today);
4602            StringBuffer result2 = new StringBuffer();
4603            FieldPosition fpos2 = new FieldPosition(0);
4604            dfmt.format(cal, result2, fpos2);
4605            if (result2.toString().compareTo(relItem.expectedFormatToday) != 0) {
4606                errln("FAIL: format today for locale " + relItem.locale +  ", capitalizationContext " + relItem.capitalizationContext +
4607                        ", expected \"" + relItem.expectedFormatToday + "\", got \"" + result2 + "\"");
4608            }
4609            if (!serializeTestFail) {
4610                result2.setLength(0);
4611                dfmtFromStream.format(cal, result2, fpos2);
4612                if (result2.toString().compareTo(relItem.expectedFormatToday) != 0) {
4613                    errln("FAIL: use dfmtFromStream to format today for locale " + relItem.locale +  ", capitalizationContext " +
4614                            relItem.capitalizationContext + ", expected \"" + relItem.expectedFormatToday + "\", got \"" + result2 + "\"");
4615                }
4616            }
4617
4618            cal.add(Calendar.DATE, -1);
4619            result2.setLength(0);
4620            dfmt.format(cal, result2, fpos2);
4621            if (result2.toString().compareTo(relItem.expectedFormatYesterday) != 0) {
4622                errln("FAIL: format yesterday for locale " + relItem.locale +  ", capitalizationContext " + relItem.capitalizationContext +
4623                        ", expected \"" + relItem.expectedFormatYesterday + "\", got \"" + result2 + "\"");
4624            }
4625
4626            // now read back context, make sure it is what we set (testing with DateFormat itself)
4627            DisplayContext capitalizationContext = dfmt.getContext(DisplayContext.Type.CAPITALIZATION);
4628            if (capitalizationContext != relItem.capitalizationContext) {
4629                errln("FAIL: getContext for locale " + relItem.locale +  ", capitalizationContext " + relItem.capitalizationContext +
4630                        ", but got context " + capitalizationContext);
4631            }
4632        }
4633    }
4634
4635    static Date TEST_DATE = new Date(2012-1900, 1-1, 15); // January 15, 2012
4636
4637    @Test
4638    public void TestDotAndAtLeniency() {
4639        for (ULocale locale : Arrays.asList(ULocale.ENGLISH, ULocale.FRENCH)) {
4640            List<Object[]> tests = new ArrayList();
4641
4642            for (int dateStyle = DateFormat.FULL; dateStyle <= DateFormat.SHORT; ++dateStyle) {
4643                DateFormat dateFormat = DateFormat.getDateInstance(dateStyle, locale);
4644
4645                for (int timeStyle = DateFormat.FULL; timeStyle <= DateFormat.SHORT; ++timeStyle) {
4646                    DateFormat format = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
4647                    DateFormat timeFormat = DateFormat.getTimeInstance(timeStyle, locale);
4648                    String formattedString = format.format(TEST_DATE);
4649
4650                    tests.add(new Object[]{format, formattedString});
4651
4652                    formattedString = dateFormat.format(TEST_DATE) + "  " + timeFormat.format(TEST_DATE);
4653                    tests.add(new Object[]{format, formattedString});
4654                    if (formattedString.contains("n ")) { // will add "." after the end of text ending in 'n', like Jan.
4655                        tests.add(new Object[]{format, formattedString.replace("n ", "n. ") + "."});
4656                    }
4657                    if (formattedString.contains(". ")) { // will subtract "." at the end of strings.
4658                        tests.add(new Object[]{format, formattedString.replace(". ", " ")});
4659                    }
4660                }
4661            }
4662            for (Object[] test : tests) {
4663                DateFormat format = (DateFormat) test[0];
4664                String formattedString = (String) test[1];
4665                if (!showParse(format, formattedString)) {
4666                    // showParse(format, formattedString); // for debugging
4667                }
4668            }
4669        }
4670
4671    }
4672
4673    private boolean showParse(DateFormat format, String formattedString) {
4674        ParsePosition parsePosition = new ParsePosition(0);
4675        parsePosition.setIndex(0);
4676        Date parsed = format.parse(formattedString, parsePosition);
4677        boolean ok = TEST_DATE.equals(parsed) && parsePosition.getIndex() == formattedString.length();
4678        if (ok) {
4679            logln(format + "\t" + formattedString);
4680        } else {
4681            errln(format + "\t" + formattedString);
4682        }
4683        return ok;
4684    }
4685
4686    @Test
4687    public void TestDateFormatLeniency() {
4688        // For details see http://bugs.icu-project.org/trac/ticket/10261
4689
4690        class TestDateFormatLeniencyItem {
4691            public ULocale locale;
4692            public boolean leniency;
4693            public String parseString;
4694            public String pattern;
4695            public String expectedResult;   // null indicates expected error
4696             // Simple constructor
4697            public TestDateFormatLeniencyItem(ULocale loc, boolean len, String parString, String patt, String expResult) {
4698                locale = loc;
4699                leniency = len;
4700                pattern = patt;
4701                parseString = parString;
4702                expectedResult = expResult;
4703            }
4704        };
4705
4706        final TestDateFormatLeniencyItem[] items = {
4707            //                             locale               leniency    parse String    pattern             expected result
4708            new TestDateFormatLeniencyItem(ULocale.ENGLISH,     true,       "2008-07 02",   "yyyy-LLLL dd",     "2008-July 02"),
4709            new TestDateFormatLeniencyItem(ULocale.ENGLISH,     false,      "2008-07 02",   "yyyy-LLLL dd",     null),
4710            new TestDateFormatLeniencyItem(ULocale.ENGLISH,     true,       "2008-Jan 02",  "yyyy-LLL. dd",     "2008-Jan. 02"),
4711            new TestDateFormatLeniencyItem(ULocale.ENGLISH,     false,      "2008-Jan 02",  "yyyy-LLL. dd",     null),
4712            new TestDateFormatLeniencyItem(ULocale.ENGLISH,     true,       "2008-Jan--02", "yyyy-MMM' -- 'dd", "2008-Jan -- 02"),
4713            new TestDateFormatLeniencyItem(ULocale.ENGLISH,     false,      "2008-Jan--02", "yyyy-MMM' -- 'dd", null),
4714        };
4715
4716        for (TestDateFormatLeniencyItem item : items) {
4717            SimpleDateFormat sdfmt = new SimpleDateFormat(item.pattern, item.locale);
4718            sdfmt.setBooleanAttribute(BooleanAttribute.PARSE_ALLOW_WHITESPACE, item.leniency)
4719                    .setBooleanAttribute(BooleanAttribute.PARSE_ALLOW_NUMERIC, item.leniency)
4720                    .setBooleanAttribute(BooleanAttribute.PARSE_PARTIAL_LITERAL_MATCH, item.leniency);
4721
4722            ParsePosition p = new ParsePosition(0);
4723            Date d = sdfmt.parse(item.parseString, p);
4724            if (item.expectedResult == null) {
4725                if (p.getErrorIndex() != -1)
4726                    continue;
4727                else
4728                    errln("error: unexpected parse success..." + item.parseString + " w/ lenient=" + item.leniency
4729                            + " should have failed");
4730            }
4731            if (p.getErrorIndex() != -1) {
4732                errln("error: parse error for string " + item.parseString + " -- idx[" + p.getIndex() + "] errIdx["
4733                        + p.getErrorIndex() + "]");
4734                continue;
4735            }
4736
4737            String result = sdfmt.format(d);
4738            if (!result.equalsIgnoreCase(item.expectedResult)) {
4739                errln("error: unexpected format result. expected - " + item.expectedResult + "  but result was - "
4740                        + result);
4741            } else {
4742                logln("formatted results match! - " + result);
4743            }
4744        }
4745    }
4746
4747    // A regression test case for ticket#10632.
4748    // Make sure RELATIVE style works for getInstance overloads taking
4749    // Calendar instance.
4750    @Test
4751    public void Test10632() {
4752        Date[] testDates = new Date[3];
4753        Calendar cal = Calendar.getInstance();
4754
4755        // today
4756        testDates[0] = cal.getTime();
4757
4758        // tomorrow
4759        cal.add(Calendar.DATE, 1);
4760        testDates[1] = cal.getTime();
4761
4762        // yesterday
4763        cal.add(Calendar.DATE, -2);
4764        testDates[2] = cal.getTime();
4765
4766
4767        // Relative styles for testing
4768        int[] dateStylesList = {
4769                DateFormat.RELATIVE_FULL,
4770                DateFormat.RELATIVE_LONG,
4771                DateFormat.RELATIVE_MEDIUM,
4772                DateFormat.RELATIVE_SHORT
4773        };
4774
4775        Calendar fmtCal = DateFormat.getInstance().getCalendar();
4776
4777        for (int i = 0; i < dateStylesList.length; i++) {
4778            DateFormat fmt0 = DateFormat.getDateTimeInstance(dateStylesList[i], DateFormat.DEFAULT);
4779            DateFormat fmt1 = DateFormat.getDateTimeInstance(fmtCal, dateStylesList[i], DateFormat.DEFAULT);
4780
4781            for (int j = 0; j < testDates.length; j++) {
4782                String s0 = fmt0.format(testDates[j]);
4783                String s1 = fmt1.format(testDates[j]);
4784
4785                if (!s0.equals(s1)) {
4786                    errln("FAIL: Different results returned by two equivalent relative formatters: s0="
4787                            + s0 + ", s1=" + s1);
4788                }
4789            }
4790        }
4791    }
4792
4793    @Test
4794    public void TestParseMultiPatternMatch() {
4795        // For details see http://bugs.icu-project.org/trac/ticket/10336
4796
4797        class TestMultiPatternMatchItem {
4798            public boolean leniency;
4799            public String parseString;
4800            public String pattern;
4801            public String expectedResult;   // null indicates expected error
4802             // Simple constructor
4803            public TestMultiPatternMatchItem(boolean len, String parString, String patt, String expResult) {
4804                leniency = len;
4805                pattern = patt;
4806                parseString = parString;
4807                expectedResult = expResult;
4808            }
4809        };
4810
4811        final TestMultiPatternMatchItem[] items = {
4812                //                            leniency    parse String                  pattern                 expected result
4813                new TestMultiPatternMatchItem(true,       "2013-Sep 13",                "yyyy-MMM dd",          "2013-Sep 13"),
4814                new TestMultiPatternMatchItem(true,       "2013-September 14",          "yyyy-MMM dd",          "2013-Sep 14"),
4815                new TestMultiPatternMatchItem(false,      "2013-September 15",          "yyyy-MMM dd",          null),
4816                new TestMultiPatternMatchItem(false,      "2013-September 16",          "yyyy-MMMM dd",         "2013-September 16"),
4817                new TestMultiPatternMatchItem(true,       "2013-Sep 17",                "yyyy-LLL dd",          "2013-Sep 17"),
4818                new TestMultiPatternMatchItem(true,       "2013-September 18",          "yyyy-LLL dd",          "2013-Sep 18"),
4819                new TestMultiPatternMatchItem(false,      "2013-September 19",          "yyyy-LLL dd",          null),
4820                new TestMultiPatternMatchItem(false,      "2013-September 20",          "yyyy-LLLL dd",         "2013-September 20"),
4821                new TestMultiPatternMatchItem(true,       "2013 Sat Sep 21",            "yyyy EEE MMM dd",      "2013 Sat Sep 21"),
4822                new TestMultiPatternMatchItem(true,       "2013 Sunday Sep 22",         "yyyy EEE MMM dd",      "2013 Sun Sep 22"),
4823                new TestMultiPatternMatchItem(false,      "2013 Monday Sep 23",         "yyyy EEE MMM dd",      null),
4824                new TestMultiPatternMatchItem(false,      "2013 Tuesday Sep 24",        "yyyy EEEE MMM dd",     "2013 Tuesday Sep 24"),
4825                new TestMultiPatternMatchItem(true,       "2013 Wed Sep 25",            "yyyy eee MMM dd",      "2013 Wed Sep 25"),
4826                new TestMultiPatternMatchItem(true,       "2013 Thu Sep 26",            "yyyy eee MMM dd",      "2013 Thu Sep 26"),
4827                new TestMultiPatternMatchItem(false,      "2013 Friday Sep 27",         "yyyy eee MMM dd",      null),
4828                new TestMultiPatternMatchItem(false,      "2013 Saturday Sep 28",       "yyyy eeee MMM dd",    "2013 Saturday Sep 28"),
4829                new TestMultiPatternMatchItem(true,       "2013 Sun Sep 29",            "yyyy ccc MMM dd",      "2013 Sun Sep 29"),
4830                new TestMultiPatternMatchItem(true,       "2013 Monday Sep 30",         "yyyy ccc MMM dd",      "2013 Mon Sep 30"),
4831                new TestMultiPatternMatchItem(false,      "2013 Sunday Oct 13",         "yyyy ccc MMM dd",      null),
4832                new TestMultiPatternMatchItem(false,      "2013 Monday Oct 14",         "yyyy cccc MMM dd",     "2013 Monday Oct 14"),
4833                new TestMultiPatternMatchItem(true,       "2013 Oct 15 Q4",             "yyyy MMM dd QQQ",      "2013 Oct 15 Q4"),
4834                new TestMultiPatternMatchItem(true,       "2013 Oct 16 4th quarter",    "yyyy MMM dd QQQ",      "2013 Oct 16 Q4"),
4835                new TestMultiPatternMatchItem(false,      "2013 Oct 17 4th quarter",    "yyyy MMM dd QQQ",      null),
4836                new TestMultiPatternMatchItem(false,      "2013 Oct 18 Q4",             "yyyy MMM dd QQQ",      "2013 Oct 18 Q4"),
4837                new TestMultiPatternMatchItem(true,       "2013 Oct 19 Q4",             "yyyy MMM dd qqqq",      "2013 Oct 19 4th quarter"),
4838                new TestMultiPatternMatchItem(true,       "2013 Oct 20 4th quarter",    "yyyy MMM dd qqqq",      "2013 Oct 20 4th quarter"),
4839                new TestMultiPatternMatchItem(false,      "2013 Oct 21 Q4",             "yyyy MMM dd qqqq",      null),
4840                new TestMultiPatternMatchItem(false,      "2013 Oct 22 4th quarter",    "yyyy MMM dd qqqq",      "2013 Oct 22 4th quarter"),
4841        };
4842
4843        StringBuffer result = new StringBuffer();
4844        Date d = new Date();
4845        GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"), Locale.US);
4846        SimpleDateFormat sdfmt = new SimpleDateFormat();
4847        ParsePosition p = new ParsePosition(0);
4848        for (TestMultiPatternMatchItem item: items) {
4849            cal.clear();
4850            sdfmt.setCalendar(cal);
4851            sdfmt.applyPattern(item.pattern);
4852            sdfmt.setLenient(item.leniency);
4853            sdfmt.setBooleanAttribute(BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH, item.leniency);
4854            result.setLength(0);
4855            p.setIndex(0);
4856            p.setErrorIndex(-1);
4857            d = sdfmt.parse(item.parseString, p);
4858            if(item.expectedResult == null) {
4859                if(p.getErrorIndex() != -1)
4860                    continue;
4861                else
4862                    errln("error: unexpected parse success..."+item.parseString + " w/ lenient="+item.leniency+" should have failed");
4863            }
4864            if(p.getErrorIndex() != -1) {
4865                errln("error: parse error for string " +item.parseString + " -- idx["+p.getIndex()+"] errIdx["+p.getErrorIndex()+"]");
4866                continue;
4867            }
4868            cal.setTime(d);
4869            result = sdfmt.format(cal, result, new FieldPosition(0));
4870            if(!result.toString().equalsIgnoreCase(item.expectedResult)) {
4871                errln("error: unexpected format result. expected - " + item.expectedResult + "  but result was - " + result);
4872            } else {
4873                logln("formatted results match! - " + result.toString());
4874            }
4875        }
4876
4877    }
4878
4879    @Test
4880    public void TestParseLeniencyAPIs() {
4881        DateFormat fmt = DateFormat.getInstance();
4882
4883        assertTrue("isLenient default", fmt.isLenient());
4884        assertTrue("isCalendarLenient default", fmt.isCalendarLenient());
4885        assertTrue("ALLOW_WHITESPACE default", fmt.getBooleanAttribute(BooleanAttribute.PARSE_ALLOW_WHITESPACE));
4886        assertTrue("ALLOW_NUMERIC default", fmt.getBooleanAttribute(BooleanAttribute.PARSE_ALLOW_NUMERIC));
4887        assertTrue("PARTIAL_MATCH default", fmt.getBooleanAttribute(BooleanAttribute.PARSE_PARTIAL_LITERAL_MATCH));
4888        assertTrue("MULTIPLE_PATTERNS default", fmt.getBooleanAttribute(BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH));
4889
4890        // Set calendar to strict
4891        fmt.setCalendarLenient(false);
4892
4893        assertFalse("isLeninent after setCalendarLenient(FALSE)", fmt.isLenient());
4894        assertFalse("isCalendarLenient after setCalendarLenient(FALSE)", fmt.isCalendarLenient());
4895        assertTrue("ALLOW_WHITESPACE after setCalendarLenient(FALSE)", fmt.getBooleanAttribute(BooleanAttribute.PARSE_ALLOW_WHITESPACE));
4896        assertTrue("ALLOW_NUMERIC  after setCalendarLenient(FALSE)", fmt.getBooleanAttribute(BooleanAttribute.PARSE_ALLOW_NUMERIC));
4897
4898        // Set to strict
4899        fmt.setLenient(false);
4900
4901        assertFalse("isLeninent after setLenient(FALSE)", fmt.isLenient());
4902        assertFalse("isCalendarLenient after setLenient(FALSE)", fmt.isCalendarLenient());
4903        assertFalse("ALLOW_WHITESPACE after setLenient(FALSE)", fmt.getBooleanAttribute(BooleanAttribute.PARSE_ALLOW_WHITESPACE));
4904        assertFalse("ALLOW_NUMERIC  after setLenient(FALSE)", fmt.getBooleanAttribute(BooleanAttribute.PARSE_ALLOW_NUMERIC));
4905        // These two boolean attributes are NOT affected according to the API specification
4906        assertTrue("PARTIAL_MATCH after setLenient(FALSE)", fmt.getBooleanAttribute(BooleanAttribute.PARSE_PARTIAL_LITERAL_MATCH));
4907        assertTrue("MULTIPLE_PATTERNS after setLenient(FALSE)", fmt.getBooleanAttribute(BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH));
4908
4909        // Allow white space leniency
4910        fmt.setBooleanAttribute(BooleanAttribute.PARSE_ALLOW_WHITESPACE, true);
4911
4912        assertFalse("isLeninent after ALLOW_WHITESPACE/TRUE", fmt.isLenient());
4913        assertFalse("isCalendarLenient after ALLOW_WHITESPACE/TRUE", fmt.isCalendarLenient());
4914        assertTrue("ALLOW_WHITESPACE after ALLOW_WHITESPACE/TRUE", fmt.getBooleanAttribute(BooleanAttribute.PARSE_ALLOW_WHITESPACE));
4915        assertFalse("ALLOW_NUMERIC  after ALLOW_WHITESPACE/TRUE", fmt.getBooleanAttribute(BooleanAttribute.PARSE_ALLOW_NUMERIC));
4916
4917        // Set to lenient
4918        fmt.setLenient(true);
4919
4920        assertTrue("isLenient after setLenient(TRUE)", fmt.isLenient());
4921        assertTrue("isCalendarLenient after setLenient(TRUE)", fmt.isCalendarLenient());
4922        assertTrue("ALLOW_WHITESPACE after setLenient(TRUE)", fmt.getBooleanAttribute(BooleanAttribute.PARSE_ALLOW_WHITESPACE));
4923        assertTrue("ALLOW_NUMERIC after setLenient(TRUE)", fmt.getBooleanAttribute(BooleanAttribute.PARSE_ALLOW_NUMERIC));
4924
4925    }
4926
4927    @Test
4928    public void TestAmPmMidnightNoon() {
4929        // Some times on 2015-11-13.
4930        long k000000 = 1447372800000L;
4931        long k000030 = 1447372830000L;
4932        long k003000 = 1447374600000L;
4933        long k060000 = 1447394400000L;
4934        long k120000 = 1447416000000L;
4935        long k180000 = 1447437600000L;
4936
4937        // Short.
4938        SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss bbb");
4939        sdf.setTimeZone(TimeZone.GMT_ZONE);
4940
4941        // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
4942        // For ICU 57 output of "midnight" is temporarily suppressed.
4943
4944//        assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000));
4945        assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 AM", sdf.format(k000000));
4946        assertEquals("hh:mm:ss bbbb | 00:00:30", "12:00:30 AM", sdf.format(k000030));
4947        assertEquals("hh:mm:ss bbbb | 00:30:00", "12:30:00 AM", sdf.format(k003000));
4948        assertEquals("hh:mm:ss bbbb | 06:00:00", "06:00:00 AM", sdf.format(k060000));
4949        assertEquals("hh:mm:ss bbbb | 12:00:00", "12:00:00 noon", sdf.format(k120000));
4950        assertEquals("hh:mm:ss bbbb | 18:00:00", "06:00:00 PM", sdf.format(k180000));
4951
4952        sdf.applyPattern("hh:mm bbb");
4953
4954//        assertEquals("hh:mm bbb | 00:00:00", "12:00 midnight", sdf.format(k000000));
4955        assertEquals("hh:mm bbb | 00:00:00", "12:00 AM", sdf.format(k000000));
4956//        assertEquals("hh:mm bbb | 00:00:30", "12:00 midnight", sdf.format(k000030));
4957        assertEquals("hh:mm bbb | 00:00:30", "12:00 AM", sdf.format(k000030));
4958        assertEquals("hh:mm bbb | 00:30:00", "12:30 AM", sdf.format(k003000));
4959
4960        sdf.applyPattern("hh bbb");
4961
4962//        assertEquals("hh bbb | 00:00:00", "12 midnight", sdf.format(k000000));
4963        assertEquals("hh bbb | 00:00:00", "12 AM", sdf.format(k000000));
4964//        assertEquals("hh bbb | 00:00:30", "12 midnight", sdf.format(k000030));
4965        assertEquals("hh bbb | 00:00:30", "12 AM", sdf.format(k000030));
4966//        assertEquals("hh bbb | 00:30:00", "12 midnight", sdf.format(k003000));
4967        assertEquals("hh bbb | 00:30:00", "12 AM", sdf.format(k003000));
4968
4969        // Wide.
4970        sdf.applyPattern("hh:mm:ss bbbb");
4971
4972//        assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000));
4973        assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 AM", sdf.format(k000000));
4974        assertEquals("hh:mm:ss bbbb | 00:00:30", "12:00:30 AM", sdf.format(k000030));
4975        assertEquals("hh:mm:ss bbbb | 00:30:00", "12:30:00 AM", sdf.format(k003000));
4976        assertEquals("hh:mm:ss bbbb | 06:00:00", "06:00:00 AM", sdf.format(k060000));
4977        assertEquals("hh:mm:ss bbbb | 12:00:00", "12:00:00 noon", sdf.format(k120000));
4978        assertEquals("hh:mm:ss bbbb | 18:00:00", "06:00:00 PM", sdf.format(k180000));
4979
4980        sdf.applyPattern("hh:mm bbbb");
4981
4982//        assertEquals("hh:mm bbbb | 00:00:00", "12:00 midnight", sdf.format(k000000));
4983        assertEquals("hh:mm bbbb | 00:00:00", "12:00 AM", sdf.format(k000000));
4984//        assertEquals("hh:mm bbbb | 00:00:30", "12:00 midnight", sdf.format(k000030));
4985        assertEquals("hh:mm bbbb | 00:00:30", "12:00 AM", sdf.format(k000030));
4986        assertEquals("hh:mm bbbb | 00:30:00", "12:30 AM", sdf.format(k003000));
4987
4988        sdf.applyPattern("hh bbbb");
4989//        assertEquals("hh bbbb | 00:00:00", "12 midnight", sdf.format(k000000));
4990        assertEquals("hh bbbb | 00:00:00", "12 AM", sdf.format(k000000));
4991//        assertEquals("hh bbbb | 00:00:30", "12 midnight", sdf.format(k000030));
4992        assertEquals("hh bbbb | 00:00:30", "12 AM", sdf.format(k000030));
4993//        assertEquals("hh bbbb | 00:30:00", "12 midnight", sdf.format(k003000));
4994        assertEquals("hh bbbb | 00:30:00", "12 AM", sdf.format(k003000));
4995
4996        // Narrow.
4997        sdf.applyPattern("hh:mm:ss bbbbb");
4998
4999//        assertEquals("hh:mm:ss bbbbb | 00:00:00", "12:00:00 mi", sdf.format(k000000));
5000        assertEquals("hh:mm:ss bbbbb | 00:00:00", "12:00:00 a", sdf.format(k000000));
5001        assertEquals("hh:mm:ss bbbbb | 00:00:30", "12:00:30 a", sdf.format(k000030));
5002        assertEquals("hh:mm:ss bbbbb | 00:30:00", "12:30:00 a", sdf.format(k003000));
5003        assertEquals("hh:mm:ss bbbbb | 06:00:00", "06:00:00 a", sdf.format(k060000));
5004        assertEquals("hh:mm:ss bbbbb | 12:00:00", "12:00:00 n", sdf.format(k120000));
5005        assertEquals("hh:mm:ss bbbbb | 18:00:00", "06:00:00 p", sdf.format(k180000));
5006
5007        sdf.applyPattern("hh:mm bbbbb");
5008
5009//        assertEquals("hh:mm bbbbb | 00:00:00", "12:00 mi", sdf.format(k000000));
5010        assertEquals("hh:mm bbbbb | 00:00:00", "12:00 a", sdf.format(k000000));
5011//        assertEquals("hh:mm bbbbb | 00:00:30", "12:00 mi", sdf.format(k000030));
5012        assertEquals("hh:mm bbbbb | 00:00:30", "12:00 a", sdf.format(k000030));
5013        assertEquals("hh:mm bbbbb | 00:30:00", "12:30 a", sdf.format(k003000));
5014
5015        sdf.applyPattern("hh bbbbb");
5016
5017//        assertEquals("hh bbbbb | 00:00:00", "12 mi", sdf.format(k000000));
5018        assertEquals("hh bbbbb | 00:00:00", "12 a", sdf.format(k000000));
5019//        assertEquals("hh bbbbb | 00:00:30", "12 mi", sdf.format(k000030));
5020        assertEquals("hh bbbbb | 00:00:30", "12 a", sdf.format(k000030));
5021//        assertEquals("hh bbbbb | 00:30:00", "12 mi", sdf.format(k003000));
5022        assertEquals("hh bbbbb | 00:30:00", "12 a", sdf.format(k003000));
5023    }
5024
5025    public void TestFlexibleDayPeriod() {
5026        // Some times on 2015-11-13.
5027        long k000000 = 1447372800000L;
5028        long k000030 = 1447372830000L;
5029        long k003000 = 1447374600000L;
5030        long k060000 = 1447394400000L;
5031        long k120000 = 1447416000000L;
5032        long k180000 = 1447437600000L;
5033
5034        // Short.
5035        SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss BBB");
5036        sdf.setTimeZone(TimeZone.GMT_ZONE);
5037
5038        // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
5039        // For ICU 57 output of "midnight" is temporarily suppressed.
5040
5041//        assertEquals("hh:mm:ss BBB | 00:00:00", "12:00:00 midnight", sdf.format(k000000));
5042        assertEquals("hh:mm:ss BBB | 00:00:00", "12:00:00 at night", sdf.format(k000000));
5043        assertEquals("hh:mm:ss BBB | 00:00:30", "12:00:30 at night", sdf.format(k000030));
5044        assertEquals("hh:mm:ss BBB | 00:30:00", "12:30:00 at night", sdf.format(k003000));
5045        assertEquals("hh:mm:ss BBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000));
5046        assertEquals("hh:mm:ss BBB | 12:00:00", "12:00:00 noon", sdf.format(k120000));
5047        assertEquals("hh:mm:ss BBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000));
5048
5049        sdf.applyPattern("hh:mm BBB");
5050
5051//        assertEquals("hh:mm BBB | 00:00:00", "12:00 midnight", sdf.format(k000000));
5052        assertEquals("hh:mm BBB | 00:00:00", "12:00 at night", sdf.format(k000000));
5053//        assertEquals("hh:mm BBB | 00:00:30", "12:00 midnight", sdf.format(k000030));
5054        assertEquals("hh:mm BBB | 00:00:30", "12:00 at night", sdf.format(k000030));
5055        assertEquals("hh:mm BBB | 00:30:00", "12:30 at night", sdf.format(k003000));
5056
5057        sdf.applyPattern("hh BBB");
5058
5059//        assertEquals("hh BBB | 00:00:00", "12 midnight", sdf.format(k000000));
5060        assertEquals("hh BBB | 00:00:00", "12 at night", sdf.format(k000000));
5061//        assertEquals("hh BBB | 00:00:30", "12 midnight", sdf.format(k000030));
5062        assertEquals("hh BBB | 00:00:30", "12 at night", sdf.format(k000030));
5063//        assertEquals("hh BBB | 00:30:00", "12 midnight", sdf.format(k003000));
5064        assertEquals("hh BBB | 00:30:00", "12 at night", sdf.format(k003000));
5065
5066        // Wide
5067        sdf.applyPattern("hh:mm:ss BBBB");
5068
5069//        assertEquals("hh:mm:ss BBBB | 00:00:00", "12:00:00 midnight", sdf.format(k000000));
5070        assertEquals("hh:mm:ss BBBB | 00:00:00", "12:00:00 at night", sdf.format(k000000));
5071        assertEquals("hh:mm:ss BBBB | 00:00:30", "12:00:30 at night", sdf.format(k000030));
5072        assertEquals("hh:mm:ss BBBB | 00:30:00", "12:30:00 at night", sdf.format(k003000));
5073        assertEquals("hh:mm:ss BBBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000));
5074        assertEquals("hh:mm:ss BBBB | 12:00:00", "12:00:00 noon", sdf.format(k120000));
5075        assertEquals("hh:mm:ss BBBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000));
5076
5077        sdf.applyPattern("hh:mm BBBB");
5078
5079//        assertEquals("hh:mm BBBB | 00:00:00", "12:00 midnight", sdf.format(k000000));
5080        assertEquals("hh:mm BBBB | 00:00:00", "12:00 at night", sdf.format(k000000));
5081//        assertEquals("hh:mm BBBB | 00:00:30", "12:00 midnight", sdf.format(k000030));
5082        assertEquals("hh:mm BBBB | 00:00:30", "12:00 at night", sdf.format(k000030));
5083        assertEquals("hh:mm BBBB | 00:30:00", "12:30 at night", sdf.format(k003000));
5084
5085        sdf.applyPattern("hh BBBB");
5086
5087//        assertEquals("hh BBBB | 00:00:00", "12 midnight", sdf.format(k000000));
5088        assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000));
5089//        assertEquals("hh BBBB | 00:00:30", "12 midnight", sdf.format(k000030));
5090        assertEquals("hh BBBB | 00:00:30", "12 at night", sdf.format(k000030));
5091//        assertEquals("hh BBBB | 00:30:00", "12 midnight", sdf.format(k003000));
5092        assertEquals("hh BBBB | 00:30:00", "12 at night", sdf.format(k003000));
5093
5094        // Narrow
5095        sdf.applyPattern("hh:mm:ss BBBBB");
5096
5097//        assertEquals("hh:mm:ss BBBBB | 00:00:00", "12:00:00 mi", sdf.format(k000000));
5098        assertEquals("hh:mm:ss BBBBB | 00:00:00", "12:00:00 at night", sdf.format(k000000));
5099        assertEquals("hh:mm:ss BBBBB | 00:00:30", "12:00:30 at night", sdf.format(k000030));
5100        assertEquals("hh:mm:ss BBBBB | 00:30:00", "12:30:00 at night", sdf.format(k003000));
5101        assertEquals("hh:mm:ss BBBBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000));
5102        assertEquals("hh:mm:ss BBBBB | 12:00:00", "12:00:00 n", sdf.format(k120000));
5103        assertEquals("hh:mm:ss BBBBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000));
5104
5105        sdf.applyPattern("hh:mm BBBBB");
5106
5107//        assertEquals("hh:mm BBBBB | 00:00:00", "12:00 mi", sdf.format(k000000));
5108        assertEquals("hh:mm BBBBB | 00:00:00", "12:00 at night", sdf.format(k000000));
5109//        assertEquals("hh:mm BBBBB | 00:00:30", "12:00 mi", sdf.format(k000030));
5110        assertEquals("hh:mm BBBBB | 00:00:30", "12:00 at night", sdf.format(k000030));
5111        assertEquals("hh:mm BBBBB | 00:30:00", "12:30 at night", sdf.format(k003000));
5112
5113        sdf.applyPattern("hh BBBBB");
5114
5115//        assertEquals("hh BBBBB | 00:00:00", "12 mi", sdf.format(k000000));
5116        assertEquals("hh BBBBB | 00:00:00", "12 at night", sdf.format(k000000));
5117//        assertEquals("hh BBBBB | 00:00:30", "12 mi", sdf.format(k000030));
5118        assertEquals("hh BBBBB | 00:00:30", "12 at night", sdf.format(k000030));
5119//        assertEquals("hh BBBBB | 00:30:00", "12 mi", sdf.format(k003000));
5120        assertEquals("hh BBBBB | 00:30:00", "12 at night", sdf.format(k003000));
5121    }
5122
5123    public void TestDayPeriodWithLocales() {
5124        // Some times on 2015-11-13 (UTC+0).
5125        long k000000 = 1447372800000L;
5126        long k010000 = 1447376400000L;
5127        long k120000 = 1447416000000L;
5128        long k220000 = 1447452000000L;
5129
5130        // Locale de has a word for midnight, but not noon.
5131        SimpleDateFormat sdf = new SimpleDateFormat("", ULocale.GERMANY);
5132        sdf.setTimeZone(TimeZone.GMT_ZONE);
5133
5134        // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
5135        // For ICU 57 output of "midnight" and its localized equivalents is temporarily suppressed.
5136
5137        sdf.applyPattern("hh:mm:ss bbbb");
5138
5139//        assertEquals("hh:mm:ss bbbb | 00:00:00 | de", "12:00:00 Mitternacht", sdf.format(k000000));
5140        assertEquals("hh:mm:ss bbbb | 00:00:00 | de", "12:00:00 vorm.", sdf.format(k000000));
5141        assertEquals("hh:mm:ss bbbb | 12:00:00 | de", "12:00:00 nachm.", sdf.format(k120000));
5142
5143        // Locale ee has a rule that wraps around midnight (21h - 4h).
5144        sdf = new SimpleDateFormat("", new ULocale("ee"));
5145        sdf.setTimeZone(TimeZone.GMT_ZONE);
5146
5147        sdf.applyPattern("hh:mm:ss BBBB");
5148
5149        assertEquals("hh:mm:ss BBBB | 22:00:00 | ee", "10:00:00 zã", sdf.format(k220000));
5150        assertEquals("hh:mm:ss BBBB | 00:00:00 | ee", "12:00:00 zã", sdf.format(k000000));
5151        assertEquals("hh:mm:ss BBBB | 01:00:00 | ee", "01:00:00 zã", sdf.format(k010000));
5152
5153        // Locale root has rules for AM/PM only.
5154        sdf = new SimpleDateFormat("", new ULocale("root"));
5155        sdf.setTimeZone(TimeZone.GMT_ZONE);
5156
5157        sdf.applyPattern("hh:mm:ss BBBB");
5158
5159        assertEquals("hh:mm:ss BBBB | 00:00:00 | root", "12:00:00 AM", sdf.format(k000000));
5160        assertEquals("hh:mm:ss BBBB | 12:00:00 | root", "12:00:00 PM", sdf.format(k120000));
5161
5162        // Empty string should behave exactly as root.
5163        sdf = new SimpleDateFormat("", new ULocale(""));
5164        sdf.setTimeZone(TimeZone.GMT_ZONE);
5165
5166        sdf.applyPattern("hh:mm:ss BBBB");
5167
5168        assertEquals("hh:mm:ss BBBB | 00:00:00 | \"\" (root)", "12:00:00 AM", sdf.format(k000000));
5169        assertEquals("hh:mm:ss BBBB | 12:00:00 | \"\" (root)", "12:00:00 PM", sdf.format(k120000));
5170
5171        // Locale en_US should fall back to en.
5172        sdf = new SimpleDateFormat("", new ULocale("en_US"));
5173        sdf.setTimeZone(TimeZone.GMT_ZONE);
5174
5175        sdf.applyPattern("hh:mm:ss BBBB");
5176
5177//        assertEquals("hh:mm:ss BBBB | 00:00:00 | en_US", "12:00:00 midnight", sdf.format(k000000));
5178        assertEquals("hh:mm:ss BBBB | 00:00:00 | en_US", "12:00:00 at night", sdf.format(k000000));
5179        assertEquals("hh:mm:ss BBBB | 01:00:00 | en_US", "01:00:00 at night", sdf.format(k010000));
5180        assertEquals("hh:mm:ss BBBB | 12:00:00 | en_US", "12:00:00 noon", sdf.format(k120000));
5181
5182        // Locale es_CO should not fall back to es and should have a
5183        // different string for 1 in the morning.
5184        // (es_CO: "de la mañana" vs. es: "de la madrugada")
5185        sdf = new SimpleDateFormat("", new ULocale("es_CO"));
5186        sdf.setTimeZone(TimeZone.GMT_ZONE);
5187
5188        sdf.applyPattern("hh:mm:ss BBBB");
5189        assertEquals("hh:mm:ss BBBB | 01:00:00 | es_CO", "01:00:00 de la mañana", sdf.format(k010000));
5190
5191        sdf = new SimpleDateFormat("", new ULocale("es"));
5192        sdf.setTimeZone(TimeZone.GMT_ZONE);
5193
5194        sdf.applyPattern("hh:mm:ss BBBB");
5195        assertEquals("hh:mm:ss BBBB | 01:00:00 | es", "01:00:00 de la madrugada", sdf.format(k010000));
5196    }
5197
5198    public void TestMinuteSecondFieldsInOddPlaces() {
5199        // Some times on 2015-11-13 (UTC+0).
5200        long k000000 = 1447372800000L;
5201        long k000030 = 1447372830000L;
5202        long k003000 = 1447374600000L;
5203        long k060030 = 1447394430000L;
5204        long k063000 = 1447396200000L;
5205
5206        // Apply pattern through constructor to make sure parsePattern() is called during initialization.
5207        SimpleDateFormat sdf = new SimpleDateFormat("hh:mm 'ss' bbbb");
5208        sdf.setTimeZone(TimeZone.GMT_ZONE);
5209
5210        // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
5211        // For ICU 57 output of "midnight" is temporarily suppressed.
5212
5213        // Seconds field is not present.
5214//        assertEquals("hh:mm 'ss' bbbb | 00:00:30", "12:00 ss midnight", sdf.format(k000030));
5215        assertEquals("hh:mm 'ss' bbbb | 00:00:30", "12:00 ss AM", sdf.format(k000030));
5216        assertEquals("hh:mm 'ss' bbbb | 06:00:30", "06:00 ss AM", sdf.format(k060030));
5217
5218        sdf.applyPattern("hh:mm 'ss' BBBB");
5219
5220//        assertEquals("hh:mm 'ss' BBBB | 00:00:30", "12:00 ss midnight", sdf.format(k000030));
5221        assertEquals("hh:mm 'ss' BBBB | 00:00:30", "12:00 ss at night", sdf.format(k000030));
5222        assertEquals("hh:mm 'ss' BBBB | 06:00:30", "06:00 ss in the morning", sdf.format(k060030));
5223
5224        // Minutes field is not present.
5225        sdf.applyPattern("hh 'mm ss' bbbb");
5226
5227//        assertEquals("hh 'mm ss' bbbb | 00:30:00", "12 mm ss midnight", sdf.format(k003000));
5228        assertEquals("hh 'mm ss' bbbb | 00:30:00", "12 mm ss AM", sdf.format(k003000));
5229        assertEquals("hh 'mm ss' bbbb | 06:30:00", "06 mm ss AM", sdf.format(k063000));
5230
5231        sdf.applyPattern("hh 'mm ss' BBBB");
5232
5233//        assertEquals("hh 'mm ss' BBBB | 00:30:00", "12 mm ss midnight", sdf.format(k003000));
5234        assertEquals("hh 'mm ss' BBBB | 00:30:00", "12 mm ss at night", sdf.format(k003000));
5235        assertEquals("hh 'mm ss' BBBB | 06:30:00", "06 mm ss in the morning", sdf.format(k063000));
5236
5237        // Minutes and seconds fields appear after day periods.
5238        sdf.applyPattern("bbbb hh:mm:ss");
5239
5240//        assertEquals("bbbb hh:mm:ss | 00:00:00", "midnight 12:00:00", sdf.format(k000000));
5241        assertEquals("bbbb hh:mm:ss | 00:00:00", "AM 12:00:00", sdf.format(k000000));
5242        assertEquals("bbbb hh:mm:ss | 00:00:30", "AM 12:00:30", sdf.format(k000030));
5243        assertEquals("bbbb hh:mm:ss | 00:30:00", "AM 12:30:00", sdf.format(k003000));
5244
5245        sdf.applyPattern("BBBB hh:mm:ss");
5246
5247//        assertEquals("BBBB hh:mm:ss | 00:00:00", "midnight 12:00:00", sdf.format(k000000));
5248        assertEquals("BBBB hh:mm:ss | 00:00:00", "at night 12:00:00", sdf.format(k000000));
5249        assertEquals("BBBB hh:mm:ss | 00:00:30", "at night 12:00:30", sdf.format(k000030));
5250        assertEquals("BBBB hh:mm:ss | 00:30:00", "at night 12:30:00", sdf.format(k003000));
5251
5252        // Confirm applyPattern() reparses the pattern string.
5253        sdf.applyPattern("BBBB hh");
5254//        assertEquals("BBBB hh | 00:00:30", "midnight 12", sdf.format(k000030));
5255        assertEquals("BBBB hh | 00:00:30", "at night 12", sdf.format(k000030));
5256
5257        sdf.applyPattern("BBBB hh:mm:'ss'");
5258//        assertEquals("BBBB hh:mm:'ss' | 00:00:30", "midnight 12:00:ss", sdf.format(k000030));
5259        assertEquals("BBBB hh:mm:'ss' | 00:00:30", "at night 12:00:ss", sdf.format(k000030));
5260
5261        sdf.applyPattern("BBBB hh:mm:ss");
5262        assertEquals("BBBB hh:mm:ss | 00:00:30", "at night 12:00:30", sdf.format(k000030));
5263    }
5264
5265    public void TestDayPeriodParsing() throws ParseException {
5266        // Some times on 2015-11-13 (UTC+0).
5267        Date k000000 = new Date(1447372800000L);
5268        Date k003700 = new Date(1447375020000L);
5269        Date k010000 = new Date(1447376400000L);
5270        Date k013000 = new Date(1447378200000L);
5271        Date k030000 = new Date(1447383600000L);
5272        Date k090000 = new Date(1447405200000L);
5273        Date k120000 = new Date(1447416000000L);
5274        Date k130000 = new Date(1447419600000L);
5275        Date k133700 = new Date(1447421820000L);
5276        Date k150000 = new Date(1447426800000L);
5277        Date k190000 = new Date(1447441200000L);
5278        Date k193000 = new Date(1447443000000L);
5279        Date k200000 = new Date(1447444800000L);
5280        Date k210000 = new Date(1447448400000L);
5281
5282        SimpleDateFormat sdf = new SimpleDateFormat("");
5283        sdf.setTimeZone(TimeZone.GMT_ZONE);
5284
5285        // 'B' -- flexible day periods
5286        // A day period on its own parses to the center of that period.
5287        sdf.applyPattern("yyyy-MM-dd B");
5288        assertEquals("yyyy-MM-dd B | 2015-11-13 midnight", k000000, sdf.parse("2015-11-13 midnight"));
5289        assertEquals("yyyy-MM-dd B | 2015-11-13 noon", k120000, sdf.parse("2015-11-13 noon"));
5290        assertEquals("yyyy-MM-dd B | 2015-11-13 in the afternoon", k150000, sdf.parse("2015-11-13 in the afternoon"));
5291        assertEquals("yyyy-MM-dd B | 2015-11-13 in the evening", k193000, sdf.parse("2015-11-13 in the evening"));
5292        assertEquals("yyyy-MM-dd B | 2015-11-13 at night", k013000, sdf.parse("2015-11-13 at night"));
5293
5294        // If time and day period are consistent with each other then time is parsed accordingly.
5295        sdf.applyPattern("yyyy-MM-dd hh:mm B");
5296        assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 12:00 midnight", k000000, sdf.parse("2015-11-13 12:00 midnight"));
5297        assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 12:00 noon", k120000, sdf.parse("2015-11-13 12:00 noon"));
5298        assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 01:00 at night", k010000, sdf.parse("2015-11-13 01:00 at night"));
5299        assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 01:00 in the afternoon", k130000, sdf.parse("2015-11-13 01:00 in the afternoon"));
5300        assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 09:00 in the morning", k090000, sdf.parse("2015-11-13 09:00 in the morning"));
5301        assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 09:00 at night", k210000, sdf.parse("2015-11-13 09:00 at night"));
5302
5303        // If the hour is 13 thru 23 then day period has no effect on time (since time is assumed
5304        // to be in 24-hour format).
5305        // TODO: failing!
5306        sdf.applyPattern("yyyy-MM-dd HH:mm B");
5307        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 midnight", k133700, sdf.parse("2015-11-13 13:37 midnight"));
5308        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 noon", k133700, sdf.parse("2015-11-13 13:37 noon"));
5309        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 at night", k133700, sdf.parse("2015-11-13 13:37 at night"));
5310        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 in the afternoon", k133700, sdf.parse("2015-11-13 13:37 in the afternoon"));
5311        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 in the morning", k133700, sdf.parse("2015-11-13 13:37 in the morning"));
5312        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 at night", k133700, sdf.parse("2015-11-13 13:37 at night"));
5313
5314        // Hour 0 is synonymous with hour 12 when parsed with 'h'.
5315        // This unfortunately means we have to tolerate "0 noon" as it's synonymous with "12 noon".
5316        sdf.applyPattern("yyyy-MM-dd hh:mm B");
5317        assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 00:00 midnight", k000000, sdf.parse("2015-11-13 00:00 midnight"));
5318        assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 00:00 noon", k120000, sdf.parse("2015-11-13 00:00 noon"));
5319
5320        // But when parsed with 'H', 0 indicates a 24-hour time, therefore we disregard the day period.
5321        sdf.applyPattern("yyyy-MM-dd HH:mm B");
5322        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 midnight", k003700, sdf.parse("2015-11-13 00:37 midnight"));
5323        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 noon", k003700, sdf.parse("2015-11-13 00:37 noon"));
5324        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 at night", k003700, sdf.parse("2015-11-13 00:37 at night"));
5325        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 in the afternoon", k003700, sdf.parse("2015-11-13 00:37 in the afternoon"));
5326        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 in the morning", k003700, sdf.parse("2015-11-13 00:37 in the morning"));
5327        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 at night", k003700, sdf.parse("2015-11-13 00:37 at night"));
5328
5329        // Even when parsed with 'H', hours 1 thru 12 are considered 12-hour time and takes
5330        // day period into account in parsing.
5331        sdf.applyPattern("yyyy-MM-dd HH:mm B");
5332        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 12:00 midnight", k000000, sdf.parse("2015-11-13 12:00 midnight"));
5333        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 12:00 noon", k120000, sdf.parse("2015-11-13 12:00 noon"));
5334        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 01:00 at night", k010000, sdf.parse("2015-11-13 01:00 at night"));
5335        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 01:00 in the afternoon", k130000, sdf.parse("2015-11-13 01:00 in the afternoon"));
5336        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 09:00 in the morning", k090000, sdf.parse("2015-11-13 09:00 in the morning"));
5337        assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 09:00 at night", k210000, sdf.parse("2015-11-13 09:00 at night"));
5338
5339        // If a 12-hour time and the day period don't agree with each other, time is parsed as close
5340        // to the given day period as possible.
5341        sdf.applyPattern("yyyy-MM-dd hh:mm B");
5342
5343        // AFTERNOON1 is [12, 18), but "7 in the afternoon" parses to 19:00.
5344        assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 07:00 in the afternoon", k190000, sdf.parse("2015-11-13 07:00 in the afternoon"));
5345        // NIGHT1 is [21, 6), but "8 at night" parses to 20:00.
5346        assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 08:00 at night", k200000, sdf.parse("2015-11-13 08:00 at night"));
5347
5348        // 'b' -- fixed day periods (AM, PM, midnight, noon)
5349        // On their own, "midnight" parses to 00:00 and "noon" parses to 12:00.
5350        // AM and PM are handled by the 'a' parser (which doesn't handle this case well).
5351        sdf.applyPattern("yyyy-MM-dd b");
5352        assertEquals("yyyy-MM-dd b | 2015-11-13 midnight", k000000, sdf.parse("2015-11-13 midnight"));
5353        assertEquals("yyyy-MM-dd b | 2015-11-13 noon", k120000, sdf.parse("2015-11-13 noon"));
5354
5355        // For 12-hour times, AM and PM should be parsed as if with pattern character 'a'.
5356        sdf.applyPattern("yyyy-MM-dd hh:mm b");
5357        assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 01:00 AM", k010000, sdf.parse("2015-11-13 01:00 AM"));
5358        assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 01:00 PM", k130000, sdf.parse("2015-11-13 01:00 PM"));
5359
5360        // 12 midnight parses to 00:00, and 12 noon parses to 12:00.
5361        assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 12:00 midnight", k000000, sdf.parse("2015-11-13 12:00 midnight"));
5362        assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 12:00 noon", k120000, sdf.parse("2015-11-13 12:00 noon"));
5363
5364        // Hours 13-23 indicate 24-hour time so we disregard "midnight" or "noon".
5365        // Again, AM and PM are handled by the 'a' parser which doesn't handle this case well.
5366        sdf.applyPattern("yyyy-MM-dd HH:mm b");
5367        assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 13:37 midnight", k133700, sdf.parse("2015-11-13 13:37 midnight"));
5368        assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 13:37 noon", k133700, sdf.parse("2015-11-13 13:37 noon"));
5369
5370        // Hour 0 is synonymous with hour 12 when parsed with 'h'.
5371        // Again, this means we have to tolerate "0 noon" as it's synonymous with "12 noon".
5372        sdf.applyPattern("yyyy-MM-dd hh:mm b");
5373        assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 00:00 midnight", k000000, sdf.parse("2015-11-13 00:00 midnight"));
5374        assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 00:00 noon", k120000, sdf.parse("2015-11-13 00:00 noon"));
5375
5376        // With 'H' though 0 indicates a 24-hour time, therefore we disregard the day period.
5377        sdf.applyPattern("yyyy-MM-dd HH:mm b");
5378        assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 00:37 midnight", k003700, sdf.parse("2015-11-13 00:37 midnight"));
5379        assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 00:37 noon", k003700, sdf.parse("2015-11-13 00:37 noon"));
5380
5381        // If "midnight" or "noon" is parsed with a 12-hour time other than 12:00, choose
5382        // the version that's closer to the period given.
5383        sdf.applyPattern("yyyy-MM-dd hh:mm b");
5384        assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 03:00 midnight", k030000, sdf.parse("2015-11-13 03:00 midnight"));
5385        assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 03:00 noon", k150000, sdf.parse("2015-11-13 03:00 noon"));
5386    }
5387}
5388