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