Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.text.format.cts;
     18 
     19 import android.content.res.Configuration;
     20 import android.content.res.Resources;
     21 import android.test.AndroidTestCase;
     22 import android.text.format.Time;
     23 import android.util.Log;
     24 import android.util.TimeFormatException;
     25 
     26 import java.util.ArrayList;
     27 import java.util.Arrays;
     28 import java.util.Calendar;
     29 import java.util.List;
     30 import java.util.Locale;
     31 import java.util.Objects;
     32 import java.util.TimeZone;
     33 
     34 public class TimeTest extends AndroidTestCase {
     35     private static final String TAG = "TimeTest";
     36 
     37     private Locale originalLocale;
     38 
     39     @Override
     40     protected void setUp() throws Exception {
     41         super.setUp();
     42         originalLocale = Locale.getDefault();
     43     }
     44 
     45     @Override
     46     public void tearDown() throws Exception {
     47         // The Locale may be changed by tests. Revert to the original.
     48         changeJavaAndAndroidLocale(originalLocale);
     49         super.tearDown();
     50     }
     51 
     52     public void testConstructor() {
     53         Time time = new Time();
     54         new Time(Time.getCurrentTimezone());
     55         time.set(System.currentTimeMillis());
     56         Time anotherTime = new Time(time);
     57         assertTime(time, anotherTime);
     58     }
     59 
     60     public void testNormalize() {
     61         final int expectedMonth = 3;
     62         final int expectedDate = 1;
     63         Time time = new Time();
     64         // set date to March 32.
     65         time.year = 2008;
     66         time.month = 2;
     67         time.monthDay = 32;
     68         long timeMilliseconds = time.normalize(false);
     69         Calendar cal = Calendar.getInstance();
     70         cal.setTimeInMillis(timeMilliseconds);
     71         assertEquals(2008, cal.get(Calendar.YEAR));
     72         assertEquals(3, cal.get(Calendar.MONTH));
     73         assertEquals(1, cal.get(Calendar.DAY_OF_MONTH));
     74         assertEquals(expectedMonth, time.month);
     75         assertEquals(expectedDate, time.monthDay);
     76 
     77         // reset date to March 32.
     78         time.month = 2;
     79         time.monthDay = 32;
     80         assertEquals(timeMilliseconds, time.normalize(true));
     81         assertEquals(expectedMonth, time.month);
     82         assertEquals(expectedDate, time.monthDay);
     83     }
     84 
     85     public void testSwitchTimezone() {
     86         String timeZone = "US/Pacific";
     87         String anotherTimeZone = "Asia/Chongqing";
     88         Time time = new Time(timeZone);
     89         assertEquals(timeZone, time.timezone);
     90         time.switchTimezone(anotherTimeZone);
     91         assertEquals(anotherTimeZone, time.timezone);
     92     }
     93 
     94     public void testSet() {
     95         final int year = 2008;
     96         final int month = 5;
     97         final int date = 10;
     98         Time time = new Time();
     99         time.set(date, month, year);
    100         assertEquals(year, time.year);
    101         assertEquals(month, time.month);
    102         assertEquals(date, time.monthDay);
    103 
    104         Time anotherTime = new Time();
    105         anotherTime.set(time);
    106         assertTime(time, anotherTime);
    107     }
    108 
    109     private void assertTime(Time time, Time anotherTime) {
    110         assertEquals(time.timezone, anotherTime.timezone);
    111         assertEquals(time.allDay, anotherTime.allDay);
    112         assertEquals(time.second, anotherTime.second);
    113         assertEquals(time.minute, anotherTime.minute);
    114         assertEquals(time.hour, anotherTime.hour);
    115         assertEquals(time.monthDay, anotherTime.monthDay);
    116         assertEquals(time.month, anotherTime.month);
    117         assertEquals(time.year, anotherTime.year);
    118         assertEquals(time.weekDay, anotherTime.weekDay);
    119         assertEquals(time.yearDay, anotherTime.yearDay);
    120         assertEquals(time.isDst, anotherTime.isDst);
    121         assertEquals(time.gmtoff, anotherTime.gmtoff);
    122     }
    123 
    124     public void testGetWeekNumber() {
    125         Time time = new Time();
    126         time.normalize(false);
    127         time.set(12, 10, 2008);
    128         assertEquals(45, time.getWeekNumber());
    129 
    130         assertEquals("20081112", time.format2445());
    131 
    132         assertEquals("2008-11-12", time.format3339(true));
    133         assertEquals("2008-11-12T00:00:00.000+00:00", time.format3339(false));
    134 
    135         Time anotherTime = new Time();
    136         assertTrue(anotherTime.parse3339("2008-11-12T00:00:00.000+00:00"));
    137         assertEquals(time.year, anotherTime.year);
    138         assertEquals(time.month, anotherTime.month);
    139         assertEquals(time.monthDay, anotherTime.monthDay);
    140         assertEquals(Time.TIMEZONE_UTC, anotherTime.timezone);
    141 
    142         try {
    143             anotherTime.parse3339("2008-111-12T00:00:00.000+00:00");
    144             fail("should throw exception");
    145         } catch (TimeFormatException e) {
    146             // expected
    147         }
    148     }
    149 
    150     public void testParseNull() {
    151         Time t = new Time();
    152         try {
    153             t.parse(null);
    154             fail();
    155         } catch (NullPointerException expected) {
    156         }
    157 
    158         try {
    159             t.parse3339(null);
    160             fail();
    161         } catch (NullPointerException expected) {
    162         }
    163     }
    164 
    165     // http://code.google.com/p/android/issues/detail?id=16002
    166     // We'd leak one JNI global reference each time parsing failed.
    167     // This would cause a crash when we filled the global reference table.
    168     public void testBug16002() {
    169         Time t = new Time();
    170         for (int i = 0; i < 8192; ++i) {
    171             try {
    172                 t.parse3339("xxx");
    173                 fail();
    174             } catch (TimeFormatException expected) {
    175             }
    176         }
    177     }
    178 
    179     // http://code.google.com/p/android/issues/detail?id=22225
    180     // We'd leak one JNI global reference each time parsing failed.
    181     // This would cause a crash when we filled the global reference table.
    182     public void testBug22225() {
    183         Time t = new Time();
    184         for (int i = 0; i < 8192; ++i) {
    185             try {
    186                 t.parse("xxx");
    187                 fail();
    188             } catch (TimeFormatException expected) {
    189             }
    190         }
    191     }
    192 
    193     public void testIsEpoch() {
    194         Time time = new Time();
    195         assertTrue(Time.isEpoch(time));
    196         time.set(1, 2, 1970);
    197         time.normalize(false);
    198         assertFalse(Time.isEpoch(time));
    199     }
    200 
    201     public void testAfterBefore() {
    202         Time a = new Time(Time.TIMEZONE_UTC);
    203         Time b = new Time("America/Los_Angeles");
    204         assertFalse(a.after(b));
    205         assertTrue(b.after(a));
    206         assertFalse(b.before(a));
    207         assertTrue(a.before(b));
    208     }
    209 
    210     // Below are tests merged from Google
    211     private static class DateTest {
    212         public int year1;
    213         public int month1;
    214         public int day1;
    215         public int hour1;
    216         public int minute1;
    217         public int dst1;
    218 
    219         public int delta;
    220 
    221         public int year2;
    222         public int month2;
    223         public int day2;
    224         public int hour2;
    225         public int minute2;
    226         public int dst2;
    227 
    228         public DateTest(int year1, int month1, int day1, int hour1, int minute1, int dst1,
    229                 int delta, int year2, int month2, int day2, int hour2, int minute2,
    230                 int dst2) {
    231             this.year1 = year1;
    232             this.month1 = month1;
    233             this.day1 = day1;
    234             this.hour1 = hour1;
    235             this.minute1 = minute1;
    236             this.dst1 = dst1;
    237             this.delta = delta;
    238             this.year2 = year2;
    239             this.month2 = month2;
    240             this.day2 = day2;
    241             this.hour2 = hour2;
    242             this.minute2 = minute2;
    243             this.dst2 = dst2;
    244         }
    245 
    246         public DateTest(int year1, int month1, int day1, int hour1, int minute1,
    247                 int delta, int year2, int month2, int day2, int hour2, int minute2) {
    248             this.year1 = year1;
    249             this.month1 = month1;
    250             this.day1 = day1;
    251             this.hour1 = hour1;
    252             this.minute1 = minute1;
    253             this.dst1 = -1;
    254             this.delta = delta;
    255             this.year2 = year2;
    256             this.month2 = month2;
    257             this.day2 = day2;
    258             this.hour2 = hour2;
    259             this.minute2 = minute2;
    260             this.dst2 = -1;
    261         }
    262     }
    263 
    264     // These tests assume that DST changes on Nov 4, 2007 at 2am (to 1am).
    265 
    266     // The "offset" field in "dayTests" represents days.
    267     // Use normalize(true) with these tests to change the date by 1 day.
    268     private DateTest[] dayTests = {
    269             // The month numbers are 0-relative, so Jan=0, Feb=1,...Dec=11
    270 
    271             // Nov 4, 12am + 0 day = Nov 4, 12am
    272             // Nov 5, 12am + 0 day = Nov 5, 12am
    273             new DateTest(2007, 10, 4, 0, 0, 0, 2007, 10, 4, 0, 0),
    274             new DateTest(2007, 10, 5, 0, 0, 0, 2007, 10, 5, 0, 0),
    275 
    276             // Nov 3, 12am + 1 day = Nov 4, 12am
    277             // Nov 4, 12am + 1 day = Nov 5, 12am
    278             // Nov 5, 12am + 1 day = Nov 6, 12am
    279             new DateTest(2007, 10, 3, 0, 0, 1, 2007, 10, 4, 0, 0),
    280             new DateTest(2007, 10, 4, 0, 0, 1, 2007, 10, 5, 0, 0),
    281             new DateTest(2007, 10, 5, 0, 0, 1, 2007, 10, 6, 0, 0),
    282 
    283             // Nov 3, 1am + 1 day = Nov 4, 1am
    284             // Nov 4, 1am + 1 day = Nov 5, 1am
    285             // Nov 5, 1am + 1 day = Nov 6, 1am
    286             new DateTest(2007, 10, 3, 1, 0, 1, 2007, 10, 4, 1, 0),
    287             new DateTest(2007, 10, 4, 1, 0, 1, 2007, 10, 5, 1, 0),
    288             new DateTest(2007, 10, 5, 1, 0, 1, 2007, 10, 6, 1, 0),
    289 
    290             // Nov 3, 2am + 1 day = Nov 4, 2am
    291             // Nov 4, 2am + 1 day = Nov 5, 2am
    292             // Nov 5, 2am + 1 day = Nov 6, 2am
    293             new DateTest(2007, 10, 3, 2, 0, 1, 2007, 10, 4, 2, 0),
    294             new DateTest(2007, 10, 4, 2, 0, 1, 2007, 10, 5, 2, 0),
    295             new DateTest(2007, 10, 5, 2, 0, 1, 2007, 10, 6, 2, 0),
    296     };
    297 
    298     // The "offset" field in "minuteTests" represents minutes.
    299     // Use normalize(false) with these tests.
    300     private DateTest[] minuteTests = {
    301             // The month numbers are 0-relative, so Jan=0, Feb=1,...Dec=11
    302 
    303             // Nov 4, 12am + 0 minutes = Nov 4, 12am
    304             // Nov 5, 12am + 0 minutes = Nov 5, 12am
    305             new DateTest(2007, 10, 4, 0, 0, 0, 2007, 10, 4, 0, 0),
    306             new DateTest(2007, 10, 5, 0, 0, 0, 2007, 10, 5, 0, 0),
    307 
    308             // Nov 3, 12am + 60 minutes = Nov 3, 1am
    309             // Nov 4, 12am + 60 minutes = Nov 4, 1am
    310             // Nov 5, 12am + 60 minutes = Nov 5, 1am
    311             new DateTest(2007, 10, 3, 0, 0, 60, 2007, 10, 3, 1, 0),
    312             new DateTest(2007, 10, 4, 0, 0, 60, 2007, 10, 4, 1, 0),
    313             new DateTest(2007, 10, 5, 0, 0, 60, 2007, 10, 5, 1, 0),
    314 
    315             // Nov 3, 1am + 60 minutes = Nov 3, 2am
    316             // Nov 4, 1am (PDT) + 30 minutes = Nov 4, 1:30am (PDT)
    317             // Nov 4, 1am (PDT) + 60 minutes = Nov 4, 1am (PST)
    318             new DateTest(2007, 10, 3, 1, 0, 60, 2007, 10, 3, 2, 0),
    319             new DateTest(2007, 10, 4, 1, 0, 1, 30, 2007, 10, 4, 1, 30, 1),
    320             new DateTest(2007, 10, 4, 1, 0, 1, 60, 2007, 10, 4, 1, 0, 0),
    321 
    322             // Nov 4, 1:30am (PDT) + 15 minutes = Nov 4, 1:45am (PDT)
    323             // Nov 4, 1:30am (PDT) + 30 minutes = Nov 4, 1:00am (PST)
    324             // Nov 4, 1:30am (PDT) + 60 minutes = Nov 4, 1:30am (PST)
    325             new DateTest(2007, 10, 4, 1, 30, 1, 15, 2007, 10, 4, 1, 45, 1),
    326             new DateTest(2007, 10, 4, 1, 30, 1, 30, 2007, 10, 4, 1, 0, 0),
    327             new DateTest(2007, 10, 4, 1, 30, 1, 60, 2007, 10, 4, 1, 30, 0),
    328 
    329             // Nov 4, 1:30am (PST) + 15 minutes = Nov 4, 1:45am (PST)
    330             // Nov 4, 1:30am (PST) + 30 minutes = Nov 4, 2:00am (PST)
    331             // Nov 5, 1am + 60 minutes = Nov 5, 2am
    332             new DateTest(2007, 10, 4, 1, 30, 0, 15, 2007, 10, 4, 1, 45, 0),
    333             new DateTest(2007, 10, 4, 1, 30, 0, 30, 2007, 10, 4, 2, 0, 0),
    334             new DateTest(2007, 10, 5, 1, 0, 60, 2007, 10, 5, 2, 0),
    335 
    336             // Nov 3, 2am + 60 minutes = Nov 3, 3am
    337             // Nov 4, 2am + 30 minutes = Nov 4, 2:30am
    338             // Nov 4, 2am + 60 minutes = Nov 4, 3am
    339             // Nov 5, 2am + 60 minutes = Nov 5, 3am
    340             new DateTest(2007, 10, 3, 2, 0, 60, 2007, 10, 3, 3, 0),
    341             new DateTest(2007, 10, 4, 2, 0, 30, 2007, 10, 4, 2, 30),
    342             new DateTest(2007, 10, 4, 2, 0, 60, 2007, 10, 4, 3, 0),
    343             new DateTest(2007, 10, 5, 2, 0, 60, 2007, 10, 5, 3, 0),
    344     };
    345 
    346     public void testNormalize1() throws Exception {
    347         String tz = "America/Los_Angeles";
    348         Time local = new Time(tz);
    349 
    350         int len = dayTests.length;
    351         for (int index = 0; index < len; index++) {
    352             DateTest test = dayTests[index];
    353             local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1);
    354             // call normalize() to make sure that isDst is set
    355             local.normalize(false /* use isDst */);
    356             local.monthDay += test.delta;
    357             local.normalize(true /* ignore isDst */);
    358 
    359             Time expected = new Time(tz);
    360             Fields.setDateTime(expected, test.year2, test.month2, test.day2, test.hour2,
    361                     test.minute2, 0);
    362             Fields.assertTimeEquals("day test index " + index + ", normalize():",
    363                     Fields.MAIN_DATE_TIME, expected, local);
    364 
    365             local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1);
    366             // call normalize() to make sure that isDst is set
    367             local.normalize(false /* use isDst */);
    368             local.monthDay += test.delta;
    369             long millis = local.toMillis(true /* ignore isDst */);
    370             local.set(millis);
    371 
    372             expected = new Time(tz);
    373             Fields.setDateTime(expected, test.year2, test.month2, test.day2, test.hour2,
    374                     test.minute2, 0);
    375             Fields.assertTimeEquals("day test index " + index + ", toMillis():",
    376                     Fields.MAIN_DATE_TIME, expected, local);
    377         }
    378 
    379         len = minuteTests.length;
    380         for (int index = 0; index < len; index++) {
    381             DateTest test = minuteTests[index];
    382             local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1);
    383             local.isDst = test.dst1;
    384             // call normalize() to make sure that isDst is set
    385             local.normalize(false /* use isDst */);
    386             if (test.dst2 == -1) test.dst2 = local.isDst;
    387             local.minute += test.delta;
    388             local.normalize(false /* use isDst */);
    389 
    390             Time expected = new Time(tz);
    391             Fields.setDateTime(expected, test.year2, test.month2, test.day2, test.hour2,
    392                     test.minute2, 0);
    393             Fields.setDst(expected, test.dst2 /* isDst */, PstPdt.getUtcOffsetSeconds(test.dst2));
    394             Fields.assertTimeEquals("minute test index " + index + ", normalize():",
    395                     Fields.MAIN_DATE_TIME | Fields.DST_FIELDS, expected, local);
    396 
    397             local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1);
    398             local.isDst = test.dst1;
    399             // call normalize() to make sure that isDst is set
    400             local.normalize(false /* use isDst */);
    401             if (test.dst2 == -1) test.dst2 = local.isDst;
    402             local.minute += test.delta;
    403             long millis = local.toMillis(false /* use isDst */);
    404             local.set(millis);
    405 
    406             expected = new Time(tz);
    407             Fields.setDateTime(expected, test.year2, test.month2, test.day2, test.hour2,
    408                     test.minute2, 0);
    409             Fields.setDst(expected, test.dst2 /* isDst */, PstPdt.getUtcOffsetSeconds(test.dst2));
    410             Fields.assertTimeEquals("minute test index " + index + ", toMillis():",
    411                     Fields.MAIN_DATE_TIME | Fields.DST_FIELDS, expected, local);
    412         }
    413     }
    414 
    415     public void testSwitchTimezone_simpleUtc() throws Exception {
    416         String originalTz = Time.TIMEZONE_UTC;
    417         Time t = new Time(originalTz);
    418         Fields.set(t, 2006, 9, 5, 12, 0, 0, -1 /* isDst */, 0, 0, 0);
    419 
    420         String newTz = "America/Los_Angeles";
    421         t.switchTimezone(newTz);
    422 
    423         Time expected1 = new Time(newTz);
    424         Fields.set(expected1, 2006, 9, 5, 5, 0, 0, 1 /* isDst */, -25200, 277, 4);
    425         Fields.assertTimeEquals(expected1, t);
    426 
    427         t.switchTimezone(originalTz);
    428 
    429         Time expected2 = new Time(originalTz);
    430         Fields.set(expected2, 2006, 9, 5, 12, 0, 0, 0 /* isDst */, 0, 277, 4);
    431         Fields.assertTimeEquals(expected2, t);
    432     }
    433 
    434     public void testSwitchTimezone_standardToStandardTime() throws Exception {
    435         String zone1 = "Europe/London";
    436         String zone2 = "America/Los_Angeles";
    437 
    438         // A time unambiguously in standard time in both zones.
    439         Time t = new Time(zone1);
    440         Fields.set(t, 2007, 2, 10, 12, 0, 0, -1 /* isDst */, 0, 0, 0);
    441 
    442         t.switchTimezone(zone2);
    443 
    444         Time expected1 = new Time(zone2);
    445         Fields.set(expected1, 2007, 2, 10, 4, 0, 0, 0 /* isDst */, -28800, 68, 6);
    446         Fields.assertTimeEquals(expected1, t);
    447 
    448         t.switchTimezone(zone1);
    449 
    450         Time expected2 = new Time(zone1);
    451         Fields.set(expected2, 2007, 2, 10, 12, 0, 0, 0 /* isDst */, 0, 68, 6);
    452         Fields.assertTimeEquals(expected2, t);
    453     }
    454 
    455     public void testSwitchTimezone_dstToDstTime() throws Exception {
    456         String zone1 = "Europe/London";
    457         String zone2 = "America/Los_Angeles";
    458 
    459         // A time unambiguously in DST in both zones.
    460         Time t = new Time(zone1);
    461         Fields.set(t, 2007, 2, 26, 12, 0, 0, -1 /* isDst */, 0, 0, 0);
    462 
    463         t.switchTimezone(zone2);
    464 
    465         Time expected1 = new Time(zone2);
    466         Fields.set(expected1, 2007, 2, 26, 4, 0, 0, 1 /* isDst */, -25200, 84, 1);
    467         Fields.assertTimeEquals(expected1, t);
    468 
    469         t.switchTimezone(zone1);
    470 
    471         Time expected2 = new Time(zone1);
    472         Fields.set(expected2, 2007, 2, 26, 12, 0, 0, 1 /* isDst */, 3600, 84, 1);
    473         Fields.assertTimeEquals(expected2, t);
    474     }
    475 
    476     public void testSwitchTimezone_standardToDstTime() throws Exception {
    477         String zone1 = "Europe/London";
    478         String zone2 = "America/Los_Angeles";
    479 
    480         // A time that is in standard time in zone1, but in DST in zone2.
    481         Time t = new Time(zone1);
    482         Fields.set(t, 2007, 2, 24, 12, 0, 0, -1 /* isDst */, 0, 0, 0);
    483 
    484         t.switchTimezone(zone2);
    485 
    486         Time expected1 = new Time(zone2);
    487         Fields.set(expected1, 2007, 2, 24, 5, 0, 0, 1 /* isDst */, -25200, 82, 6);
    488         Fields.assertTimeEquals(expected1, t);
    489 
    490         t.switchTimezone(zone1);
    491 
    492         Time expected2 = new Time(zone1);
    493         Fields.set(expected2, 2007, 2, 24, 12, 0, 0, 0 /* isDst */, 0, 82, 6);
    494         Fields.assertTimeEquals(expected2, t);
    495     }
    496 
    497     public void testSwitchTimezone_sourceDateInvalid() throws Exception {
    498         String zone1 = "Europe/London";
    499         String zone2 = "America/Los_Angeles";
    500 
    501         // A source wall time known not to normalize because it doesn't "exist" locally.
    502         Time t = new Time(zone1);
    503         Fields.set(t, 2007, 2, 25, 1, 30, 0, -1 /* isDst */, 0, 0, 0);
    504         assertEquals(-1, t.toMillis(false));
    505 
    506         t.switchTimezone(zone2);
    507 
    508         // It is assumed a sad trombone noise is also emitted from the device at this point.
    509         // This illustrates why using -1 to indicate a problem, when -1 is in range, is a poor idea.
    510         Time expected1 = new Time(zone2);
    511         Fields.set(expected1, 1969, 11, 31, 15, 59, 59, 0 /* isDst */, -28800, 364, 3);
    512         Fields.assertTimeEquals(expected1, t);
    513     }
    514 
    515     public void testSwitchTimezone_dstToStandardTime() throws Exception {
    516         String zone1 = "America/Los_Angeles";
    517         String zone2 = "Europe/London";
    518 
    519         // A time that is in DST in zone1, but in standard in zone2.
    520         Time t = new Time(zone1);
    521         Fields.set(t, 2007, 2, 12, 12, 0, 0, -1 /* isDst */, 0, 0, 0);
    522 
    523         t.switchTimezone(zone2);
    524 
    525         Time expected1 = new Time(zone2);
    526         Fields.set(expected1, 2007, 2, 12, 19, 0, 0, 0 /* isDst */, 0, 70, 1);
    527         Fields.assertTimeEquals(expected1, t);
    528 
    529         t.switchTimezone(zone1);
    530 
    531         Time expected2 = new Time(zone1);
    532         Fields.set(expected2, 2007, 2, 12, 12, 0, 0, 1 /* isDst */, -25200, 70, 1);
    533         Fields.assertTimeEquals(expected2, t);
    534     }
    535 
    536     public void testCtor() throws Exception {
    537         String tz = Time.TIMEZONE_UTC;
    538         Time t = new Time(tz);
    539         assertEquals(tz, t.timezone);
    540 
    541         Time expected = new Time(tz);
    542         Fields.set(expected, 1970, 0, 1, 0, 0, 0, -1 /* isDst */, 0, 0, 0);
    543         Fields.assertTimeEquals(expected, t);
    544     }
    545 
    546     public void testGetActualMaximum() throws Exception {
    547         Time t = new Time(Time.TIMEZONE_UTC);
    548         assertEquals(59, t.getActualMaximum(Time.SECOND));
    549         assertEquals(59, t.getActualMaximum(Time.MINUTE));
    550         assertEquals(23, t.getActualMaximum(Time.HOUR));
    551         assertEquals(11, t.getActualMaximum(Time.MONTH));
    552         assertEquals(2037, t.getActualMaximum(Time.YEAR));
    553         assertEquals(6, t.getActualMaximum(Time.WEEK_DAY));
    554         assertEquals(364, t.getActualMaximum(Time.YEAR_DAY));
    555         t.year = 2000;
    556         assertEquals(365, t.getActualMaximum(Time.YEAR_DAY));
    557 
    558         try {
    559             t.getActualMaximum(Time.WEEK_NUM);
    560             fail("should throw runtime exception");
    561         } catch (Exception e) {
    562             // expected
    563         }
    564         final int noExistField = -1;
    565         try {
    566             t.getActualMaximum(noExistField);
    567         } catch (Exception e) {
    568             // expected
    569         }
    570 
    571         t.year = 2001;
    572         final int[] DAYS_PER_MONTH = {
    573                 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
    574         };
    575         assertMonth(t, DAYS_PER_MONTH);
    576 
    577         t.year = 2000;
    578         DAYS_PER_MONTH[1] = 29;
    579         assertMonth(t, DAYS_PER_MONTH);
    580     }
    581 
    582     private void assertMonth(Time t, final int[] DAYS_PER_MONTH) {
    583         for (int i = 0; i < t.getActualMaximum(Time.MONTH); i++) {
    584             t.month = i;
    585             assertEquals(DAYS_PER_MONTH[i], t.getActualMaximum(Time.MONTH_DAY));
    586         }
    587     }
    588 
    589     public void testClear0() throws Exception {
    590         Time t = new Time(Time.getCurrentTimezone());
    591         t.clear(Time.TIMEZONE_UTC);
    592         assertEquals(Time.TIMEZONE_UTC, t.timezone);
    593         assertFalse(t.allDay);
    594         assertEquals(0, t.second);
    595         assertEquals(0, t.minute);
    596         assertEquals(0, t.hour);
    597         assertEquals(0, t.monthDay);
    598         assertEquals(0, t.month);
    599         assertEquals(0, t.year);
    600         assertEquals(0, t.weekDay);
    601         assertEquals(0, t.yearDay);
    602         assertEquals(0, t.gmtoff);
    603         assertEquals(-1, t.isDst);
    604     }
    605 
    606     public void testClear() throws Exception {
    607         Time t = new Time("America/Los_Angeles");
    608         Fields.set(t, 1, 2, 3, 4, 5, 6, 7 /* isDst */, 8, 9, 10);
    609 
    610         t.clear(Time.TIMEZONE_UTC);
    611 
    612         Time expected = new Time(Time.TIMEZONE_UTC);
    613         Fields.set(expected, 0, 0, 0, 0, 0, 0, -1 /* isDst */, 0, 0, 0);
    614         Fields.assertTimeEquals(expected, t);
    615     }
    616 
    617     public void testCompare() throws Exception {
    618         String timezone = "America/New_York";
    619         int[] aDateTimeFields = new int[] { 2005, 2, 3, 4, 5, 6 };
    620 
    621         Time a = new Time(timezone);
    622         Fields.setDateTime(a, aDateTimeFields);
    623         Fields.setDst(a, 7, 8);
    624         Fields.setDerivedDateTime(a, 9, 10);
    625 
    626         int[] bDateTimeFields = new int[aDateTimeFields.length];
    627         System.arraycopy(aDateTimeFields, 0, bDateTimeFields, 0, aDateTimeFields.length);
    628         Time b = new Time(timezone);
    629         Fields.setDateTime(b, bDateTimeFields);
    630         Fields.setDst(b, 7, 8);
    631         Fields.setDerivedDateTime(b, 9, 10);
    632 
    633         // Confirm timezone behavior: When timezones differ the result depends on the millis time.
    634         // This means that all date/time and the isDst field can impact compare() when timezones
    635         // are different. The result is always -1, 0 or 1.
    636 
    637         // East of New York. Millis goes down for a given wall time.
    638         b.timezone = "Europe/London";
    639         assertEquals(1, Time.compare(a, b));
    640         assertEquals(-1, Time.compare(b, a));
    641 
    642         // West of New York. Millis goes up for a given wall time.
    643         b.timezone = "America/Los_Angeles";
    644         assertEquals(-1, Time.compare(a, b));
    645         assertEquals(1, Time.compare(b, a));
    646 
    647         b.timezone = timezone;
    648         assertEquals(0, Time.compare(a, b));
    649         assertEquals(0, Time.compare(b, a));
    650 
    651         // Now confirm behavior when timezones are the same: Only the date/time fields are checked
    652         // and the result depends on the difference between the fields and the order in which they
    653         // are checked.
    654 
    655         // Check date/time fields
    656         for (int i = 0; i < aDateTimeFields.length; i++) {
    657             bDateTimeFields[i] = 99999;
    658             Fields.setDateTime(b, bDateTimeFields);
    659 
    660             assertEquals(aDateTimeFields[i] - bDateTimeFields[i], Time.compare(a, b));
    661             assertEquals(bDateTimeFields[i] - aDateTimeFields[i], Time.compare(b, a));
    662 
    663             bDateTimeFields[i] = -99999;
    664             Fields.setDateTime(b, bDateTimeFields);
    665 
    666             assertEquals(aDateTimeFields[i] - bDateTimeFields[i], Time.compare(a, b));
    667             assertEquals(bDateTimeFields[i] - aDateTimeFields[i], Time.compare(b, a));
    668 
    669             bDateTimeFields[i] = aDateTimeFields[i];
    670             Fields.setDateTime(b, bDateTimeFields);
    671 
    672             assertEquals(0, Time.compare(a, b));
    673             assertEquals(0, Time.compare(b, a));
    674         }
    675 
    676         // Show that the derived fields have no effect on compare when timezones are the same.
    677         Fields.setDst(b, 999, 999);
    678         Fields.setDerivedDateTime(b, 999, 999);
    679         assertEquals(0, Time.compare(a, b));
    680         assertEquals(0, Time.compare(b, a));
    681     }
    682 
    683     public void testCompareNullFailure() throws Exception {
    684         Time a = new Time(Time.TIMEZONE_UTC);
    685 
    686         try {
    687             Time.compare(a, null);
    688             fail("Should throw NullPointerException on second argument");
    689         } catch (NullPointerException e) {
    690             // pass
    691         }
    692 
    693         try {
    694             Time.compare(null, a);
    695             fail("Should throw NullPointerException on first argument");
    696         } catch (NullPointerException e) {
    697             // pass
    698         }
    699 
    700         try {
    701             Time.compare(null, null);
    702             fail("Should throw NullPointerException because both args are null");
    703         } catch (NullPointerException e) {
    704             // pass
    705         }
    706     }
    707 
    708     public void testCompare_invalidDatesAreEqualIfTimezoneDiffers() throws Exception {
    709         String timezone = "America/New_York";
    710         // This date is outside of the valid set of dates that can be calculated so toMillis()
    711         // returns -1.
    712         int[] dateTimeFields = new int[] { 1, 2, 3, 4, 5, 6 };
    713 
    714         Time a = new Time(timezone);
    715         Fields.setDateTime(a, dateTimeFields);
    716         Fields.setDst(a, 7, 8);
    717         Fields.setDerivedDateTime(a, 9, 10);
    718         assertEquals(-1, a.toMillis(false));
    719 
    720         Time b = new Time(timezone);
    721         Fields.setDateTime(b, dateTimeFields);
    722         Fields.setDst(b, 11, 12);
    723         Fields.setDerivedDateTime(b, 13, 14);
    724         assertEquals(-1, b.toMillis(false));
    725 
    726         // DST and derived-date time fields are always ignored.
    727         assertEquals(0, Time.compare(a, b));
    728 
    729         // Set a different invalid set of date fields.
    730         Fields.setDateTime(b, new int[] { 6, 5, 4, 3, 2, 1 });
    731         assertEquals(-5, Time.compare(a, b));
    732 
    733         // Now change the timezone
    734         b.timezone = Time.TIMEZONE_UTC;
    735 
    736         // >:-(
    737         assertEquals(0, Time.compare(a, b));
    738     }
    739 
    740     public void testFormat() throws Exception {
    741         Time t = new Time(Time.TIMEZONE_UTC);
    742         String r = t.format("%Y%m%dT%H%M%S");
    743         assertEquals("19700101T000000", r);
    744     }
    745 
    746     public void testFormat_null() {
    747         Time t = new Time(Time.TIMEZONE_UTC);
    748         assertEquals(t.format("%c"), t.format(null));
    749     }
    750 
    751     public void testFormat_badPatterns() throws Exception {
    752         Time t = new Time(Time.TIMEZONE_UTC);
    753         assertFormatEquals(t, "%~Y", "~Y");
    754         assertFormatEquals(t, "%", "%");
    755     }
    756 
    757     public void testFormat_doesNotNormalize() throws Exception {
    758         Time t = new Time(Time.TIMEZONE_UTC);
    759         Fields.set(t, 2005, 13, 32, -1, -1, -1, -2, -2, -2, -2);
    760 
    761         Time tCopy = new Time(t);
    762         Fields.assertTimeEquals(t, tCopy);
    763 
    764         assertFormatEquals(t, "%Y%m%dT%H%M%S", "20051432T-1-1-1");
    765 
    766         Fields.assertTimeEquals(t, tCopy);
    767     }
    768 
    769     private static void assertFormatEquals(Time t, String formatArg, String expected) {
    770         assertEquals(expected, t.format(formatArg));
    771     }
    772 
    773     public void testFormat_tokensUkLocale() throws Exception {
    774         changeJavaAndAndroidLocale(Locale.UK);
    775 
    776         Time t = new Time("Europe/London");
    777         Fields.setDateTime(t, 2005, 5, 1, 12, 30, 15);
    778 
    779         // Prove the un-normalized fields are used.
    780         assertFormatEquals(t, "%A", "Sunday");
    781 
    782         // Set fields like weekday.
    783         t.normalize(true);
    784 
    785         assertFormatEquals(t, "%A", "Wednesday");
    786         assertFormatEquals(t, "%a", "Wed");
    787         assertFormatEquals(t, "%B", "June");
    788         assertFormatEquals(t, "%b", "Jun");
    789         assertFormatEquals(t, "%C", "20");
    790         assertFormatEquals(t, "%c", "1 Jun 2005, 12:30:15");
    791         assertFormatEquals(t, "%D", "06/01/05");
    792         assertFormatEquals(t, "%d", "01");
    793         assertFormatEquals(t, "%E", "E");
    794         assertFormatEquals(t, "%e", " 1");
    795         assertFormatEquals(t, "%F", "2005-06-01");
    796         assertFormatEquals(t, "%G", "2005");
    797         assertFormatEquals(t, "%g", "05");
    798         assertFormatEquals(t, "%H", "12");
    799         assertFormatEquals(t, "%h", "Jun");
    800         assertFormatEquals(t, "%I", "12");
    801         assertFormatEquals(t, "%j", "152");
    802         assertFormatEquals(t, "%K", "K");
    803         assertFormatEquals(t, "%k", "12");
    804         assertFormatEquals(t, "%l", "12");
    805         assertFormatEquals(t, "%M", "30");
    806         assertFormatEquals(t, "%m", "06");
    807         assertFormatEquals(t, "%n", "\n");
    808         assertFormatEquals(t, "%O", "O");
    809         assertFormatEquals(t, "%p", "pm");
    810         assertFormatEquals(t, "%P", "pm");
    811         assertFormatEquals(t, "%R", "12:30");
    812         assertFormatEquals(t, "%r", "12:30:15 pm");
    813         assertFormatEquals(t, "%S", "15");
    814         // The original C implementation uses the (native) system default TZ, not the timezone of
    815         // the Time to calculate this and was therefore not stable. This changed to use the Time's
    816         // timezone when the Time class was re-written in Java.
    817         assertFormatEquals(t, "%s", "1117625415");
    818         assertFormatEquals(t, "%T", "12:30:15");
    819         assertFormatEquals(t, "%t", "\t");
    820         assertFormatEquals(t, "%U", "22");
    821         assertFormatEquals(t, "%u", "3");
    822         assertFormatEquals(t, "%V", "22");
    823         assertFormatEquals(t, "%v", " 1-Jun-2005");
    824         assertFormatEquals(t, "%W", "22");
    825         assertFormatEquals(t, "%w", "3");
    826         assertFormatEquals(t, "%X", "12:30:15");
    827         assertFormatEquals(t, "%x", "1 June 2005");
    828         assertFormatEquals(t, "%y", "05");
    829         assertFormatEquals(t, "%Y", "2005");
    830         assertFormatEquals(t, "%Z", "BST");
    831         assertFormatEquals(t, "%z", "+0100");
    832         assertFormatEquals(t, "%+", "Wed Jun  1 12:30:15 BST 2005");
    833         assertFormatEquals(t, "%%", "%");
    834 
    835         // Modifiers
    836 
    837         assertFormatEquals(t, "%EC", "20");
    838         assertFormatEquals(t, "%OC", "20");
    839 
    840         assertFormatEquals(t, "%_+", "Wed Jun  1 12:30:15 BST 2005");
    841         assertFormatEquals(t, "%-+", "Wed Jun  1 12:30:15 BST 2005");
    842         assertFormatEquals(t, "%0+", "Wed Jun  1 12:30:15 BST 2005");
    843         assertFormatEquals(t, "%^+", "Wed Jun  1 12:30:15 BST 2005");
    844         assertFormatEquals(t, "%#+", "Wed Jun  1 12:30:15 BST 2005");
    845 
    846         assertFormatEquals(t, "%_A", "Wednesday");
    847         assertFormatEquals(t, "%-A", "Wednesday");
    848         assertFormatEquals(t, "%0A", "Wednesday");
    849         assertFormatEquals(t, "%^A", "WEDNESDAY");
    850         assertFormatEquals(t, "%#A", "wEDNESDAY");
    851 
    852         assertFormatEquals(t, "%_Y", "20 5");
    853         assertFormatEquals(t, "%-Y", "205");
    854         assertFormatEquals(t, "%0Y", "2005");
    855         assertFormatEquals(t, "%^Y", "2005");
    856         assertFormatEquals(t, "%#Y", "2005");
    857 
    858         assertFormatEquals(t, "%_d", " 1");
    859         assertFormatEquals(t, "%-d", "1");
    860         assertFormatEquals(t, "%0d", "01");
    861         assertFormatEquals(t, "%^d", "01");
    862         assertFormatEquals(t, "%#d", "01");
    863     }
    864 
    865     public void testFormat_tokensUsLocale() throws Exception {
    866         changeJavaAndAndroidLocale(Locale.US);
    867 
    868         Time t = new Time("America/New_York");
    869         Fields.setDateTime(t, 2005, 5, 1, 12, 30, 15);
    870 
    871         // Prove the un-normalized fields are used.
    872         assertFormatEquals(t, "%A", "Sunday");
    873 
    874         // Set fields like weekday.
    875         t.normalize(true);
    876 
    877         assertFormatEquals(t, "%A", "Wednesday");
    878         assertFormatEquals(t, "%a", "Wed");
    879         assertFormatEquals(t, "%B", "June");
    880         assertFormatEquals(t, "%b", "Jun");
    881         assertFormatEquals(t, "%C", "20");
    882         assertFormatEquals(t, "%c", "Jun 1, 2005, 12:30:15 PM");
    883         assertFormatEquals(t, "%D", "06/01/05");
    884         assertFormatEquals(t, "%d", "01");
    885         assertFormatEquals(t, "%E", "E");
    886         assertFormatEquals(t, "%e", " 1");
    887         assertFormatEquals(t, "%F", "2005-06-01");
    888         assertFormatEquals(t, "%G", "2005");
    889         assertFormatEquals(t, "%g", "05");
    890         assertFormatEquals(t, "%H", "12");
    891         assertFormatEquals(t, "%h", "Jun");
    892         assertFormatEquals(t, "%I", "12");
    893         assertFormatEquals(t, "%j", "152");
    894         assertFormatEquals(t, "%K", "K");
    895         assertFormatEquals(t, "%k", "12");
    896         assertFormatEquals(t, "%l", "12");
    897         assertFormatEquals(t, "%M", "30");
    898         assertFormatEquals(t, "%m", "06");
    899         assertFormatEquals(t, "%n", "\n");
    900         assertFormatEquals(t, "%O", "O");
    901         assertFormatEquals(t, "%p", "PM");
    902         assertFormatEquals(t, "%P", "pm");
    903         assertFormatEquals(t, "%R", "12:30");
    904         assertFormatEquals(t, "%r", "12:30:15 PM");
    905         assertFormatEquals(t, "%S", "15");
    906         // The original C implementation uses the (native) system default TZ, not the timezone of
    907         // the Time to calculate this and was therefore not stable. This changed to use the Time's
    908         // timezone when the Time class was re-written in Java.
    909         assertFormatEquals(t, "%s", "1117643415");
    910         assertFormatEquals(t, "%T", "12:30:15");
    911         assertFormatEquals(t, "%t", "\t");
    912         assertFormatEquals(t, "%U", "22");
    913         assertFormatEquals(t, "%u", "3");
    914         assertFormatEquals(t, "%V", "22");
    915         assertFormatEquals(t, "%v", " 1-Jun-2005");
    916         assertFormatEquals(t, "%W", "22");
    917         assertFormatEquals(t, "%w", "3");
    918         assertFormatEquals(t, "%X", "12:30:15 PM");
    919         assertFormatEquals(t, "%x", "June 1, 2005");
    920         assertFormatEquals(t, "%y", "05");
    921         assertFormatEquals(t, "%Y", "2005");
    922         assertFormatEquals(t, "%Z", "EDT");
    923         assertFormatEquals(t, "%z", "-0400");
    924         assertFormatEquals(t, "%+", "Wed Jun  1 12:30:15 EDT 2005");
    925         assertFormatEquals(t, "%%", "%");
    926 
    927         // Modifiers
    928 
    929         assertFormatEquals(t, "%EC", "20");
    930         assertFormatEquals(t, "%OC", "20");
    931 
    932         assertFormatEquals(t, "%_+", "Wed Jun  1 12:30:15 EDT 2005");
    933         assertFormatEquals(t, "%-+", "Wed Jun  1 12:30:15 EDT 2005");
    934         assertFormatEquals(t, "%0+", "Wed Jun  1 12:30:15 EDT 2005");
    935         assertFormatEquals(t, "%^+", "Wed Jun  1 12:30:15 EDT 2005");
    936         assertFormatEquals(t, "%#+", "Wed Jun  1 12:30:15 EDT 2005");
    937 
    938         assertFormatEquals(t, "%_A", "Wednesday");
    939         assertFormatEquals(t, "%-A", "Wednesday");
    940         assertFormatEquals(t, "%0A", "Wednesday");
    941         assertFormatEquals(t, "%^A", "WEDNESDAY");
    942         assertFormatEquals(t, "%#A", "wEDNESDAY");
    943 
    944         assertFormatEquals(t, "%_Y", "20 5");
    945         assertFormatEquals(t, "%-Y", "205");
    946         assertFormatEquals(t, "%0Y", "2005");
    947         assertFormatEquals(t, "%^Y", "2005");
    948         assertFormatEquals(t, "%#Y", "2005");
    949 
    950         assertFormatEquals(t, "%_d", " 1");
    951         assertFormatEquals(t, "%-d", "1");
    952         assertFormatEquals(t, "%0d", "01");
    953         assertFormatEquals(t, "%^d", "01");
    954         assertFormatEquals(t, "%#d", "01");
    955     }
    956 
    957     public void testFormat_tokensFranceLocale() throws Exception {
    958         changeJavaAndAndroidLocale(Locale.FRANCE);
    959 
    960         Time t = new Time("Europe/Paris");
    961         Fields.setDateTime(t, 2005, 5, 1, 12, 30, 15);
    962 
    963         // Prove the un-normalized fields are used.
    964         assertFormatEquals(t, "%A", "dimanche");
    965 
    966         // Set fields like weekday.
    967         t.normalize(true);
    968 
    969         assertFormatEquals(t, "%A", "mercredi");
    970         assertFormatEquals(t, "%a", "mer.");
    971         assertFormatEquals(t, "%B", "juin");
    972         assertFormatEquals(t, "%b", "juin");
    973         assertFormatEquals(t, "%C", "20");
    974         assertFormatEquals(t, "%c", "1 juin 2005  12:30:15");
    975         assertFormatEquals(t, "%D", "06/01/05");
    976         assertFormatEquals(t, "%d", "01");
    977         assertFormatEquals(t, "%E", "E");
    978         assertFormatEquals(t, "%e", " 1");
    979         assertFormatEquals(t, "%F", "2005-06-01");
    980         assertFormatEquals(t, "%G", "2005");
    981         assertFormatEquals(t, "%g", "05");
    982         assertFormatEquals(t, "%H", "12");
    983         assertFormatEquals(t, "%h", "juin");
    984         assertFormatEquals(t, "%I", "12");
    985         assertFormatEquals(t, "%j", "152");
    986         assertFormatEquals(t, "%K", "K");
    987         assertFormatEquals(t, "%k", "12");
    988         assertFormatEquals(t, "%l", "12");
    989         assertFormatEquals(t, "%M", "30");
    990         assertFormatEquals(t, "%m", "06");
    991         assertFormatEquals(t, "%n", "\n");
    992         assertFormatEquals(t, "%O", "O");
    993         assertFormatEquals(t, "%p", "PM");
    994         assertFormatEquals(t, "%P", "pm");
    995         assertFormatEquals(t, "%R", "12:30");
    996         assertFormatEquals(t, "%r", "12:30:15 PM");
    997         assertFormatEquals(t, "%S", "15");
    998         // The original C implementation uses the (native) system default TZ, not the timezone of
    999         // the Time to calculate this and was therefore not stable. This changed to use the Time's
   1000         // timezone when the Time class was re-written in Java.
   1001         assertFormatEquals(t, "%s", "1117621815");
   1002         assertFormatEquals(t, "%T", "12:30:15");
   1003         assertFormatEquals(t, "%t", "\t");
   1004         assertFormatEquals(t, "%U", "22");
   1005         assertFormatEquals(t, "%u", "3");
   1006         assertFormatEquals(t, "%V", "22");
   1007         assertFormatEquals(t, "%v", " 1-juin-2005");
   1008         assertFormatEquals(t, "%W", "22");
   1009         assertFormatEquals(t, "%w", "3");
   1010         assertFormatEquals(t, "%X", "12:30:15");
   1011         assertFormatEquals(t, "%x", "1 juin 2005");
   1012         assertFormatEquals(t, "%y", "05");
   1013         assertFormatEquals(t, "%Y", "2005");
   1014         assertFormatEquals(t, "%Z", "GMT+02:00");
   1015         assertFormatEquals(t, "%z", "+0200");
   1016         assertFormatEquals(t, "%+", "mer. juin  1 12:30:15 GMT+02:00 2005");
   1017         assertFormatEquals(t, "%%", "%");
   1018 
   1019         // Modifiers
   1020 
   1021         assertFormatEquals(t, "%EC", "20");
   1022         assertFormatEquals(t, "%OC", "20");
   1023 
   1024         assertFormatEquals(t, "%_+", "mer. juin  1 12:30:15 GMT+02:00 2005");
   1025         assertFormatEquals(t, "%-+", "mer. juin  1 12:30:15 GMT+02:00 2005");
   1026         assertFormatEquals(t, "%0+", "mer. juin  1 12:30:15 GMT+02:00 2005");
   1027         assertFormatEquals(t, "%^+", "mer. juin  1 12:30:15 GMT+02:00 2005");
   1028         assertFormatEquals(t, "%#+", "mer. juin  1 12:30:15 GMT+02:00 2005");
   1029 
   1030         assertFormatEquals(t, "%_A", "mercredi");
   1031         assertFormatEquals(t, "%-A", "mercredi");
   1032         assertFormatEquals(t, "%0A", "mercredi");
   1033         assertFormatEquals(t, "%^A", "MERCREDI");
   1034         assertFormatEquals(t, "%#A", "MERCREDI");
   1035 
   1036         assertFormatEquals(t, "%_Y", "20 5");
   1037         assertFormatEquals(t, "%-Y", "205");
   1038         assertFormatEquals(t, "%0Y", "2005");
   1039         assertFormatEquals(t, "%^Y", "2005");
   1040         assertFormatEquals(t, "%#Y", "2005");
   1041 
   1042         assertFormatEquals(t, "%_d", " 1");
   1043         assertFormatEquals(t, "%-d", "1");
   1044         assertFormatEquals(t, "%0d", "01");
   1045         assertFormatEquals(t, "%^d", "01");
   1046         assertFormatEquals(t, "%#d", "01");
   1047     }
   1048 
   1049     public void testFormat_tokensJapanLocale() throws Exception {
   1050         changeJavaAndAndroidLocale(Locale.JAPAN);
   1051 
   1052         Time t = new Time("Asia/Tokyo");
   1053         Fields.setDateTime(t, 2005, 5, 1, 12, 30, 15);
   1054 
   1055         // Prove the un-normalized fields are used.
   1056         assertFormatEquals(t, "%A", "");
   1057 
   1058         // Set fields like weekday.
   1059         t.normalize(true);
   1060 
   1061         assertFormatEquals(t, "%A", "");
   1062         assertFormatEquals(t, "%a", "");
   1063         assertFormatEquals(t, "%B", "6");
   1064         assertFormatEquals(t, "%b", "6");
   1065         assertFormatEquals(t, "%C", "20");
   1066         assertFormatEquals(t, "%c", "2005/06/01 12:30:15");
   1067         assertFormatEquals(t, "%D", "06/01/05");
   1068         assertFormatEquals(t, "%d", "01");
   1069         assertFormatEquals(t, "%E", "E");
   1070         assertFormatEquals(t, "%e", " 1");
   1071         assertFormatEquals(t, "%F", "2005-06-01");
   1072         assertFormatEquals(t, "%G", "2005");
   1073         assertFormatEquals(t, "%g", "05");
   1074         assertFormatEquals(t, "%H", "12");
   1075         assertFormatEquals(t, "%h", "6");
   1076         assertFormatEquals(t, "%I", "12");
   1077         assertFormatEquals(t, "%j", "152");
   1078         assertFormatEquals(t, "%k", "12");
   1079         assertFormatEquals(t, "%l", "12");
   1080         assertFormatEquals(t, "%M", "30");
   1081         assertFormatEquals(t, "%m", "06");
   1082         assertFormatEquals(t, "%n", "\n");
   1083         assertFormatEquals(t, "%O", "O");
   1084         assertFormatEquals(t, "%p", "");
   1085         assertFormatEquals(t, "%P", "");
   1086         assertFormatEquals(t, "%R", "12:30");
   1087         assertFormatEquals(t, "%r", "12:30:15 ");
   1088         assertFormatEquals(t, "%S", "15");
   1089         // The original C implementation uses the (native) system default TZ, not the timezone of
   1090         // the Time to calculate this and was therefore not stable. This changed to use the Time's
   1091         // timezone when the Time class was re-written in Java.
   1092         assertFormatEquals(t, "%s", "1117596615");
   1093         assertFormatEquals(t, "%T", "12:30:15");
   1094         assertFormatEquals(t, "%t", "\t");
   1095         assertFormatEquals(t, "%U", "22");
   1096         assertFormatEquals(t, "%u", "3");
   1097         assertFormatEquals(t, "%V", "22");
   1098         assertFormatEquals(t, "%v", " 1-6-2005");
   1099         assertFormatEquals(t, "%W", "22");
   1100         assertFormatEquals(t, "%w", "3");
   1101         assertFormatEquals(t, "%X", "12:30:15");
   1102         assertFormatEquals(t, "%x", "200561");
   1103         assertFormatEquals(t, "%y", "05");
   1104         assertFormatEquals(t, "%Y", "2005");
   1105         assertFormatEquals(t, "%Z", "JST");
   1106         assertFormatEquals(t, "%z", "+0900");
   1107         assertFormatEquals(t, "%+", " 6  1 12:30:15 JST 2005");
   1108         assertFormatEquals(t, "%%", "%");
   1109 
   1110         // Modifiers
   1111 
   1112         assertFormatEquals(t, "%EC", "20");
   1113         assertFormatEquals(t, "%OC", "20");
   1114 
   1115         assertFormatEquals(t, "%_+", " 6  1 12:30:15 JST 2005");
   1116         assertFormatEquals(t, "%-+", " 6  1 12:30:15 JST 2005");
   1117         assertFormatEquals(t, "%0+", " 6  1 12:30:15 JST 2005");
   1118         assertFormatEquals(t, "%^+", " 6  1 12:30:15 JST 2005");
   1119         assertFormatEquals(t, "%#+", " 6  1 12:30:15 JST 2005");
   1120 
   1121         assertFormatEquals(t, "%_A", "");
   1122         assertFormatEquals(t, "%-A", "");
   1123         assertFormatEquals(t, "%0A", "");
   1124         assertFormatEquals(t, "%^A", "");
   1125         assertFormatEquals(t, "%#A", "");
   1126 
   1127         assertFormatEquals(t, "%_Y", "20 5");
   1128         assertFormatEquals(t, "%-Y", "205");
   1129         assertFormatEquals(t, "%0Y", "2005");
   1130         assertFormatEquals(t, "%^Y", "2005");
   1131         assertFormatEquals(t, "%#Y", "2005");
   1132 
   1133         assertFormatEquals(t, "%_d", " 1");
   1134         assertFormatEquals(t, "%-d", "1");
   1135         assertFormatEquals(t, "%0d", "01");
   1136         assertFormatEquals(t, "%^d", "01");
   1137         assertFormatEquals(t, "%#d", "01");
   1138     }
   1139 
   1140     public void testFormat2445() throws Exception {
   1141         Time t = new Time(Time.TIMEZONE_UTC);
   1142         Fields.setDateTime(t, 2005, 5, 1, 12, 30, 15);
   1143 
   1144         // UTC behavior is to add a trailing Z.
   1145         String expected = t.format("%Y%m%dT%H%M%SZ");
   1146         assertEquals(expected, t.format2445());
   1147 
   1148         // Only UTC includes the Z.
   1149         t.timezone = "America/Los_Angeles";
   1150         expected = t.format("%Y%m%dT%H%M%S");
   1151         assertEquals(expected, t.format2445());
   1152 
   1153         // There is odd behavior around negative values.
   1154         Fields.setDateTime(t, 2005, -1, -1, -1, -1, -1);
   1155         assertEquals("2005000 T0 0 0 ", t.format2445());
   1156     }
   1157 
   1158     public void testFormat2445_doesNotNormalize() throws Exception {
   1159         Time t = new Time(Time.TIMEZONE_UTC);
   1160         Fields.set(t, 2005, 13, 32, 25, 61, 61, -2, -2, -2, -2);
   1161 
   1162         Time tCopy = new Time(t);
   1163         Fields.assertTimeEquals(t, tCopy);
   1164 
   1165         assertEquals("20051432T256161Z", t.format2445());
   1166         Fields.assertTimeEquals(t, tCopy);
   1167 
   1168         t.timezone = tCopy.timezone = "America/Los_Angeles";
   1169         assertEquals("20051432T256161", t.format2445());
   1170         Fields.assertTimeEquals(t, tCopy);
   1171     }
   1172 
   1173     public void testToString() throws Exception {
   1174         Time t = new Time(Time.TIMEZONE_UTC);
   1175         assertEquals("19700101T000000UTC(0,0,0,-1,0)", t.toString());
   1176 
   1177         t.timezone = "America/Los_Angeles";
   1178         assertEquals("19700101T000000America/Los_Angeles(0,0,0,-1,28800)", t.toString());
   1179     }
   1180 
   1181     public void testToString_doesNotNormalize() throws Exception {
   1182         Time t = new Time(Time.TIMEZONE_UTC);
   1183         Fields.set(t, 2005, 13, 32, -1, -1, -1, -2, -2, -2, -2);
   1184 
   1185         Time tCopy = new Time(t);
   1186         Fields.assertTimeEquals(t, tCopy);
   1187 
   1188         String r = t.toString();
   1189         assertEquals("20051432T-1-1-1UTC(-2,-2,-2,-2,1141426739)", r);
   1190 
   1191         Fields.assertTimeEquals(t, tCopy);
   1192     }
   1193 
   1194     public void testGetCurrentTimezone() throws Exception {
   1195         String r = Time.getCurrentTimezone();
   1196         assertEquals(TimeZone.getDefault().getID(), r);
   1197     }
   1198 
   1199     public void testSetToNow() throws Exception {
   1200         Time t = new Time(Time.TIMEZONE_UTC);
   1201 
   1202         // Time works in seconds so all millis values have to be divided by 1000, otherwise
   1203         // the greater accuracy of System.currentTimeMillis() causes the test to fail.
   1204 
   1205         long lowerBound = System.currentTimeMillis() / 1000;
   1206 
   1207         t.setToNow();
   1208 
   1209         long upperBound = System.currentTimeMillis() / 1000;
   1210 
   1211         long actual = t.toMillis(true /* ignore isDst */) / 1000;
   1212         assertTrue(lowerBound <= actual && actual <= upperBound);
   1213     }
   1214 
   1215     public void testToMillis_utc() throws Exception {
   1216         Time t = new Time(Time.TIMEZONE_UTC);
   1217 
   1218         long winterTimeUtcMillis = 1167613323000L;
   1219 
   1220         Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 1, 9, 9);
   1221         long r = t.toMillis(true /* ignore isDst */);
   1222         assertEquals(winterTimeUtcMillis, r);
   1223 
   1224         Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 1, 9, 9);
   1225         r = t.toMillis(true /* ignore isDst */);
   1226         assertEquals(winterTimeUtcMillis, r);
   1227 
   1228         Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 1, 9, 9);
   1229         r = t.toMillis(true /* ignore isDst */);
   1230         assertEquals(winterTimeUtcMillis, r);
   1231 
   1232         Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 1, 9, 9);
   1233         r = t.toMillis(false /* ignore isDst */);
   1234         assertEquals(winterTimeUtcMillis, r);
   1235 
   1236         Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 1, 9, 9);
   1237         r = t.toMillis(false /* ignore isDst */);
   1238         assertEquals(-1, r);
   1239 
   1240         Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 1, 9, 9);
   1241         r = t.toMillis(false /* ignore isDst */);
   1242         assertEquals(winterTimeUtcMillis, r);
   1243 
   1244         long summerTimeUtcMillis = 1180659723000L;
   1245 
   1246         Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 1, 9, 9);
   1247         r = t.toMillis(true /* ignore isDst */);
   1248         assertEquals(summerTimeUtcMillis, r);
   1249 
   1250         Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 1, 9, 9);
   1251         r = t.toMillis(true /* ignore isDst */);
   1252         assertEquals(summerTimeUtcMillis, r);
   1253 
   1254         Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 1, 9, 9);
   1255         r = t.toMillis(true /* ignore isDst */);
   1256         assertEquals(summerTimeUtcMillis, r);
   1257 
   1258         Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 1, 9, 9);
   1259         r = t.toMillis(false /* ignore isDst */);
   1260         assertEquals(summerTimeUtcMillis, r);
   1261 
   1262         Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 1, 9, 9);
   1263         r = t.toMillis(false /* ignore isDst */);
   1264         assertEquals(-1, r);
   1265 
   1266         Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 1, 9, 9);
   1267         r = t.toMillis(false /* ignore isDst */);
   1268         assertEquals(summerTimeUtcMillis, r);
   1269     }
   1270 
   1271     public void testToMillis_dstTz() throws Exception {
   1272         Time t = new Time(PstPdt.ID);
   1273 
   1274         // A STD time
   1275         long stdTimeUtcMillis = 1167613323000L;
   1276         long stdTimeMillis = stdTimeUtcMillis - PstPdt.getUtcOffsetMillis(false);
   1277 
   1278         Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
   1279         long r = t.toMillis(true /* ignore isDst */);
   1280         assertEquals(stdTimeMillis, r);
   1281 
   1282         Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
   1283         assertToMillisResult(true, t, stdTimeMillis);
   1284 
   1285         Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
   1286         assertToMillisResult(true, t, stdTimeMillis);
   1287 
   1288         long dstToStdCorrectionMillis =
   1289                 PstPdt.getUtcOffsetMillis(false) - PstPdt.getUtcOffsetMillis(true);
   1290 
   1291         Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
   1292         assertToMillisResult(false, t, stdTimeMillis);
   1293 
   1294         Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
   1295         assertToMillisResult(false, t, stdTimeMillis + dstToStdCorrectionMillis);
   1296 
   1297         Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
   1298         assertToMillisResult(false, t, stdTimeMillis);
   1299 
   1300         // A DST time
   1301         long dstTimeUtcMillis = 1180659723000L;
   1302         long dstTimeMillis = dstTimeUtcMillis - PstPdt.getUtcOffsetMillis(true);
   1303 
   1304         Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
   1305         assertToMillisResult(true, t, dstTimeMillis);
   1306 
   1307         Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
   1308         assertToMillisResult(true, t, dstTimeMillis);
   1309 
   1310         Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
   1311         assertToMillisResult(true, t, dstTimeMillis);
   1312 
   1313         long stdToDstCorrectionMillis = -dstToStdCorrectionMillis;
   1314 
   1315         Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
   1316         assertToMillisResult(false, t, dstTimeMillis + stdToDstCorrectionMillis);
   1317 
   1318         Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
   1319         assertToMillisResult(false, t, dstTimeMillis);
   1320 
   1321         Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
   1322         assertToMillisResult(false, t, dstTimeMillis);
   1323     }
   1324 
   1325     private static void assertToMillisResult(boolean toMillisArgument, Time t, long expectedResult) {
   1326         long r = t.toMillis(toMillisArgument /* ignore isDst */);
   1327         assertEquals(expectedResult, r);
   1328     }
   1329 
   1330     public void testToMillis_doesNotNormalize() {
   1331         Time t = new Time(Time.TIMEZONE_UTC);
   1332 
   1333         Fields.set(t, 2007, 13, 32, 25, 60, 60, -2 /* isDst */, Integer.MAX_VALUE, 367, 7);
   1334 
   1335         Time originalTime = new Time(t);
   1336         Fields.assertTimeEquals(t, originalTime);
   1337 
   1338         t.toMillis(true);
   1339         Fields.assertTimeEquals(originalTime, t);
   1340 
   1341         t.toMillis(false);
   1342         Fields.assertTimeEquals(originalTime, t);
   1343     }
   1344 
   1345     public void testToMillis_skippedTime() {
   1346         // Tests behavior around a transition from STD to DST that introduces an hour of "skipped"
   1347         // time from 01:00 to 01:59.
   1348         String timezone = PstPdt.ID;
   1349         long stdBaseTimeMillis = 1173607200000L;
   1350         long dstBaseTimeMillis = 1173603600000L;
   1351 
   1352         // Try each minute from one minute before the skipped hour until one after.
   1353         for (int i = -1; i <= 60; i++) {
   1354             int minutesInMillis = i * 60000;
   1355             int[] timeFields = new int[] { 2007, 2, 11, 2, i, 0, -999 /* not used */, 9, 9, 9 };
   1356 
   1357             Time time = new Time(timezone);
   1358 
   1359             // isDst = 0, toMillis(true)
   1360             Fields.set(time, timeFields);
   1361             time.isDst = 0;
   1362             long expectedTimeMillis;
   1363             if (i == -1) {
   1364                 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis;
   1365             } else if (i == 60) {
   1366                 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis;
   1367             } else {
   1368                 expectedTimeMillis = -1;
   1369             }
   1370             assertToMillisResult(true, time, expectedTimeMillis);
   1371 
   1372             // isDst = 0, toMillis(false)
   1373             Fields.set(time, timeFields);
   1374             time.isDst = 0;
   1375             expectedTimeMillis = stdBaseTimeMillis + minutesInMillis;
   1376             assertToMillisResult(false, time, expectedTimeMillis);
   1377 
   1378             // isDst = 1, toMillis(true)
   1379             Fields.set(time, timeFields);
   1380             time.isDst = 1;
   1381             if (i == -1) {
   1382                 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis;
   1383             } else if (i == 60) {
   1384                 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis;
   1385             } else {
   1386                 expectedTimeMillis = -1;
   1387             }
   1388             assertToMillisResult(true, time, expectedTimeMillis);
   1389 
   1390             // isDst = 1, toMillis(false)
   1391             Fields.set(time, timeFields);
   1392             time.isDst = 1;
   1393             expectedTimeMillis = dstBaseTimeMillis + minutesInMillis;
   1394             assertToMillisResult(false, time, expectedTimeMillis);
   1395 
   1396             // isDst = -1, toMillis(true)
   1397             Fields.set(time, timeFields);
   1398             time.isDst = -1;
   1399 
   1400             if (i == -1) {
   1401                 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis;
   1402             } else if (i == 60) {
   1403                 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis;
   1404             } else {
   1405                 expectedTimeMillis = -1;
   1406             }
   1407             assertToMillisResult(false, time, expectedTimeMillis);
   1408 
   1409             // isDst = -1, toMillis(false)
   1410             Fields.set(time, timeFields);
   1411             time.isDst = -1;
   1412             assertToMillisResult(false, time, expectedTimeMillis);
   1413         }
   1414     }
   1415 
   1416     public void testToMillis_duplicateWallTime() {
   1417         // 1:00 in standard / 2:00 in DST
   1418         long timeBaseMillis = 1194163200000L;
   1419         long dstCorrectionMillis = 3600000;
   1420 
   1421         // Try each minute from one minute before the duplicated hour until one after.
   1422         for (int i = -1; i <= 60; i++) {
   1423             int minutesInMillis = i * 60000;
   1424 
   1425             Time time = new Time(PstPdt.ID);
   1426             int[] timeFields = new int[] { 2007, 10, 4, 1, i, 0, -999 /* not used */, 9, 9, 9};
   1427 
   1428             // isDst = 0, toMillis(true)
   1429             Fields.set(time, timeFields);
   1430             time.isDst = 0;
   1431             long timeMillis = time.toMillis(true);
   1432             if (i == -1) {
   1433                 assertEquals("i = " + i, timeBaseMillis + minutesInMillis, timeMillis);
   1434             } else if (i == 60) {
   1435                 assertEquals("i = " + i, timeBaseMillis + minutesInMillis + dstCorrectionMillis,
   1436                         timeMillis);
   1437             } else {
   1438                 // When ignoreDst the choice between DST and STD is arbitrary when both are
   1439                 // possible.
   1440                 assertTrue("i = " + i, timeMillis == timeBaseMillis + minutesInMillis
   1441                         || timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis);
   1442             }
   1443 
   1444             // isDst = 0, toMillis(false)
   1445             Fields.set(time, timeFields);
   1446             time.isDst = 0;
   1447             assertToMillisResult(false, time,
   1448                     timeBaseMillis + minutesInMillis + dstCorrectionMillis);
   1449 
   1450             // isDst = 1, toMillis(true)
   1451             Fields.set(time, timeFields);
   1452             time.isDst = 1;
   1453             if (i == -1) {
   1454                 assertEquals("i = " + i, timeBaseMillis + minutesInMillis, timeMillis);
   1455             } else if (i == 60) {
   1456                 assertEquals("i = " + i, timeBaseMillis + minutesInMillis + dstCorrectionMillis,
   1457                         timeMillis);
   1458             } else {
   1459                 // When ignoreDst or isDst == -1 the choice between DST and STD is arbitrary when
   1460                 // both are possible.
   1461                 assertTrue("i = " + i, timeMillis == timeBaseMillis + minutesInMillis
   1462                         || timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis);
   1463             }
   1464 
   1465             // isDst = 1, toMillis(false)
   1466             Fields.set(time, timeFields);
   1467             time.isDst = 1;
   1468             assertToMillisResult(false, time, timeBaseMillis + minutesInMillis);
   1469 
   1470             // isDst = -1, toMillis(true)
   1471             Fields.set(time, timeFields);
   1472             time.isDst = -1;
   1473             timeMillis = time.toMillis(true);
   1474             if (i == -1) {
   1475                 assertEquals("i = " + i, timeBaseMillis + minutesInMillis, timeMillis);
   1476             } else if (i == 60) {
   1477                 assertEquals("i = " + i, timeBaseMillis + minutesInMillis + dstCorrectionMillis,
   1478                         timeMillis);
   1479             } else {
   1480                 // When ignoreDst or isDst == -1 the choice between DST and STD is arbitrary when
   1481                 // both are possible.
   1482                 assertTrue("i = " + i, timeMillis == timeBaseMillis + minutesInMillis
   1483                         || timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis);
   1484             }
   1485 
   1486             // isDst = -1, toMillis(false)
   1487             Fields.set(time, timeFields);
   1488             time.isDst = -1;
   1489             timeMillis = time.toMillis(false);
   1490             if (i == -1) {
   1491                 assertEquals("i = " + i, timeBaseMillis + minutesInMillis, timeMillis);
   1492             } else if (i == 60) {
   1493                 assertEquals("i = " + i, timeBaseMillis + minutesInMillis + dstCorrectionMillis,
   1494                         timeMillis);
   1495             } else {
   1496                 // When ignoreDst or isDst == -1 the choice between DST and STD is arbitrary when
   1497                 // both are possible.
   1498                 assertTrue("i = " + i, timeMillis == timeBaseMillis + minutesInMillis
   1499                         || timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis);
   1500             }
   1501         }
   1502     }
   1503 
   1504     public void testToMillis_beforeTzRecords() {
   1505         int[] timeFields = new int[] { 1900, 0, 1, 2, 3, 4, -999 /* not used */, 9, 9, 9 };
   1506         assertToMillisInvalid(timeFields, PstPdt.ID);
   1507         assertToMillisInvalid(timeFields, Time.TIMEZONE_UTC);
   1508     }
   1509 
   1510     private static void assertToMillisInvalid(int[] timeFields, String timezone) {
   1511         Time time = new Time(timezone);
   1512 
   1513         // isDst = 0, toMillis(true)
   1514         Fields.set(time, timeFields);
   1515         time.isDst = 0;
   1516         assertToMillisResult(true, time, -1);
   1517 
   1518         // isDst = 0, toMillis(false)
   1519         Fields.set(time, timeFields);
   1520         time.isDst = 0;
   1521         assertToMillisResult(false, time, -1);
   1522 
   1523         // isDst = 1, toMillis(true)
   1524         Fields.set(time, timeFields);
   1525         time.isDst = 1;
   1526         assertToMillisResult(true, time, -1);
   1527 
   1528         // isDst = 1, toMillis(false)
   1529         Fields.set(time, timeFields);
   1530         time.isDst = 1;
   1531         assertToMillisResult(false, time, -1);
   1532 
   1533         // isDst = -1, toMillis(true)
   1534         Fields.set(time, timeFields);
   1535         time.isDst = -1;
   1536         assertToMillisResult(true, time, -1);
   1537 
   1538         // isDst = -1, toMillis(false)
   1539         Fields.set(time, timeFields);
   1540         time.isDst = -1;
   1541         assertToMillisResult(false, time, -1);
   1542     }
   1543 
   1544     public void testToMillis_afterTzRecords() {
   1545         int[] timeFields = new int[] { 2039, 0, 1, 2, 3, 4, -999 /* not used */, 9, 9, 9 };
   1546         assertToMillisInvalid(timeFields, PstPdt.ID);
   1547         assertToMillisInvalid(timeFields, Time.TIMEZONE_UTC);
   1548     }
   1549 
   1550     public void testToMillis_invalid() {
   1551         int[] timeFields = new int[] { 0, 0, 0, 0, 0, 0, -999 /* not used */, 9, 9, 9 };
   1552         assertToMillisInvalid(timeFields, PstPdt.ID);
   1553         assertToMillisInvalid(timeFields, Time.TIMEZONE_UTC);
   1554     }
   1555 
   1556     public void testParse_date() throws Exception {
   1557         String nonUtcTz = PstPdt.ID;
   1558         Time t = new Time(nonUtcTz);
   1559         assertFalse(t.parse("12345678"));
   1560         Time expected = new Time(nonUtcTz);
   1561         Fields.setAllDayDate(expected, 1234, 55, 78);
   1562         Fields.setDst(expected, -1 /* isDst */, 0);
   1563         Fields.setDerivedDateTime(expected, 0, 0);
   1564         Fields.assertTimeEquals(expected, t);
   1565     }
   1566 
   1567     public void testParse_null() throws Exception {
   1568         Time t = new Time(Time.TIMEZONE_UTC);
   1569         try {
   1570             t.parse(null);
   1571             fail();
   1572         } catch (NullPointerException e) {
   1573         }
   1574     }
   1575 
   1576     public void testParse() throws Exception {
   1577         Time t = new Time(Time.TIMEZONE_UTC);
   1578         t.parse("20061005T120000");
   1579 
   1580         Time expected = new Time(Time.TIMEZONE_UTC);
   1581         Fields.set(expected, 2006, 9, 5, 12, 0, 0, -1 /* isDst */, 0, 0, 0);
   1582         Fields.assertTimeEquals(expected, t);
   1583     }
   1584 
   1585     public void testParse_dateTime() throws Exception {
   1586         String nonUtcTz = PstPdt.ID;
   1587         Time t = new Time(nonUtcTz);
   1588         assertFalse(t.parse("12345678T901234"));
   1589         Time expected = new Time(nonUtcTz);
   1590         Fields.set(expected, 1234, 55, 78, 90, 12, 34, -1 /* isDst */, 0, 0, 0);
   1591         Fields.assertTimeEquals(expected, t);
   1592 
   1593         Time t2 = new Time(nonUtcTz);
   1594         assertTrue(t2.parse("12345678T901234Z"));
   1595         Time utcExpected = new Time(Time.TIMEZONE_UTC);
   1596         Fields.set(utcExpected, 1234, 55, 78, 90, 12, 34, -1 /* isDst */, 0, 0, 0);
   1597         Fields.assertTimeEquals(utcExpected, t2);
   1598     }
   1599 
   1600     public void testParse_errors() throws Exception {
   1601         String nonUtcTz = PstPdt.ID;
   1602         try {
   1603             Time t = new Time(nonUtcTz);
   1604             t.parse(null);
   1605             fail();
   1606         } catch (NullPointerException e) {
   1607         }
   1608 
   1609         // Too short
   1610         assertParseError("");
   1611         assertParseError("1");
   1612         assertParseError("12");
   1613         assertParseError("123");
   1614         assertParseError("1234");
   1615         assertParseError("12345");
   1616         assertParseError("123456");
   1617         assertParseError("1234567");
   1618 
   1619         // No "T" in the expected place
   1620         assertParseError("12345678S");
   1621 
   1622         // Invalid character in the first 8 characters.
   1623         assertParseError("12X45678");
   1624 
   1625         // Too short for a date/time (15 or 16 characters allowed)
   1626         assertParseError("12345678T");
   1627         assertParseError("12345678T0");
   1628         assertParseError("12345678T01");
   1629         assertParseError("12345678T012");
   1630         assertParseError("12345678T0123");
   1631         assertParseError("12345678T01234");
   1632 
   1633         // Invalid character
   1634         assertParseError("12345678T0X2345");
   1635     }
   1636 
   1637     private static void assertParseError(String s) {
   1638         Time t = new Time(Time.TIMEZONE_UTC);
   1639         try {
   1640             t.parse(s);
   1641             fail();
   1642         } catch (TimeFormatException expected) {
   1643         }
   1644     }
   1645 
   1646     public void testParse3339() throws Exception {
   1647         String tz = Time.TIMEZONE_UTC;
   1648         Time expected = new Time(tz);
   1649         Fields.setAllDayDate(expected, 1980, 4, 23);
   1650         Fields.setDst(expected, -1 /* isDst */, 0);
   1651         Fields.setDerivedDateTime(expected, 0, 0);
   1652         assertParse3339Succeeds(tz, "1980-05-23", expected);
   1653 
   1654         Fields.setDateTime(expected, 1980, 4, 23, 9, 50, 50);
   1655         Fields.setDst(expected, -1 /* isDst */, 0);
   1656         Fields.setDerivedDateTime(expected, 0, 0);
   1657         assertParse3339Succeeds(tz, "1980-05-23T09:50:50", expected);
   1658 
   1659         Fields.setDateTime(expected, 1980, 4, 23, 9, 50, 50);
   1660         Fields.setDst(expected, -1 /* isDst */, 0);
   1661         Fields.setDerivedDateTime(expected, 0, 0);
   1662         assertParse3339Succeeds(tz, "1980-05-23T09:50:50Z", expected);
   1663 
   1664         Fields.setDateTime(expected, 1980, 4, 23, 9, 50, 50);
   1665         Fields.setDst(expected, -1 /* isDst */, 0);
   1666         Fields.setDerivedDateTime(expected, 0, 0);
   1667         assertParse3339Succeeds(tz, "1980-05-23T09:50:50.0Z", expected);
   1668 
   1669         Fields.setDateTime(expected, 1980, 4, 23, 9, 50, 50);
   1670         Fields.setDst(expected, -1 /* isDst */, 0);
   1671         Fields.setDerivedDateTime(expected, 0, 0);
   1672         assertParse3339Succeeds(tz, "1980-05-23T09:50:50.12Z", expected);
   1673 
   1674         Fields.setDateTime(expected, 1980, 4, 23, 9, 50, 50);
   1675         Fields.setDst(expected, -1 /* isDst */, 0);
   1676         Fields.setDerivedDateTime(expected, 0, 0);
   1677         assertParse3339Succeeds(tz, "1980-05-23T09:50:50.123Z", expected);
   1678 
   1679         // The time should be normalized to UTC
   1680         Fields.setDateTime(expected, 1980, 4, 23, 10, 55, 50);
   1681         Fields.setDst(expected, -1 /* isDst */, 0);
   1682         Fields.setDerivedDateTime(expected, 0, 0);
   1683         assertParse3339Succeeds(tz, "1980-05-23T09:50:50-01:05", expected);
   1684 
   1685         // The time should be normalized to UTC
   1686         Fields.setDateTime(expected, 1980, 4, 23, 10, 55, 50);
   1687         Fields.setDst(expected, -1 /* isDst */, 0);
   1688         Fields.setDerivedDateTime(expected, 0, 0);
   1689         assertParse3339Succeeds(tz, "1980-05-23T09:50:50.123-01:05", expected);
   1690     }
   1691 
   1692     private static void assertParse3339Succeeds(String timeZone, String toParse, Time expected) {
   1693         Time t = new Time(timeZone);
   1694         t.parse3339(toParse);
   1695         Fields.assertTimeEquals(expected, t);
   1696     }
   1697 
   1698     public void testParse3339_parseErrors() {
   1699         // Too short
   1700         assertParse3339Error("1980");
   1701 
   1702         // Timezone too short
   1703         assertParse3339Error("1980-05-23T09:50:50.123+");
   1704         assertParse3339Error("1980-05-23T09:50:50.123+05:0");
   1705     }
   1706 
   1707     public void testParse3339_null() {
   1708         Time t = new Time(Time.TIMEZONE_UTC);
   1709         try {
   1710             t.parse3339(null);
   1711             fail();
   1712         } catch (NullPointerException e) {
   1713         }
   1714     }
   1715 
   1716     private void assertParse3339Error(String s) {
   1717         String tz = Time.TIMEZONE_UTC;
   1718         Time t = new Time(tz);
   1719         try {
   1720             t.parse3339(s);
   1721             fail();
   1722         } catch (TimeFormatException expected) {
   1723         }
   1724     }
   1725 
   1726     public void testSetMillis_utc() throws Exception {
   1727         String tz = Time.TIMEZONE_UTC;
   1728         Time t = new Time(tz);
   1729         t.set(1000L);
   1730 
   1731         Time expected = new Time(tz);
   1732         Fields.set(expected, 1970, 0, 1, 0, 0, 1, 0 /* isDst */, 0, 0, 4);
   1733         Fields.assertTimeEquals(expected, t);
   1734 
   1735         t.set(2000L);
   1736         Fields.set(expected, 1970, 0, 1, 0, 0, 2, 0 /* isDst */, 0, 0, 4);
   1737         Fields.assertTimeEquals(expected, t);
   1738 
   1739         t.set(1000L * 60);
   1740         Fields.set(expected, 1970, 0, 1, 0, 1, 0, 0 /* isDst */, 0, 0, 4);
   1741         Fields.assertTimeEquals(expected, t);
   1742 
   1743         t.set((1000L * 60 * 60 * 24) + 1000L);
   1744         Fields.set(expected, 1970, 0, 2, 0, 0, 1, 0 /* isDst */, 0, 1, 5);
   1745         Fields.assertTimeEquals(expected, t);
   1746     }
   1747 
   1748     public void testSetMillis_utc_edgeCases() throws Exception {
   1749         String tz = Time.TIMEZONE_UTC;
   1750         Time t = new Time(tz);
   1751         t.set(Integer.MAX_VALUE + 1L);
   1752 
   1753         Time expected = new Time(tz);
   1754         // This a 32-bit int overflow bug.
   1755         Fields.set(expected, 1970, 0, 25, 20, 31, 23, 0 /* isDst */, 0, 24, 0);
   1756         Fields.assertTimeEquals(expected, t);
   1757 
   1758         t = new Time(tz);
   1759         t.set(Integer.MIN_VALUE - 1L);
   1760         // This a 32-bit int underflow bug.
   1761         Fields.set(expected, 1969, 11, 7, 3, 28, 37, 0 /* isDst */, 0, 340, 0);
   1762         Fields.assertTimeEquals(expected, t);
   1763     }
   1764 
   1765     public void testSetFields() throws Exception {
   1766         String tz = Time.TIMEZONE_UTC;
   1767         Time t = new Time(tz);
   1768         Fields.set(t, 9, 9, 9, 9, 9, 9, 9 /* isDst */, 9, 9, 9);
   1769 
   1770         t.set(1, 2, 3, 4, 5, 6);
   1771 
   1772         Time expected = new Time(tz);
   1773         Fields.set(expected, 6, 5, 4, 3, 2, 1, -1 /* isDst */, 0, 0, 0);
   1774         Fields.assertTimeEquals(expected, t);
   1775     }
   1776 
   1777     // Timezones that cover the world.  Some GMT offsets occur more than
   1778     // once in case some cities decide to change their GMT offset.
   1779     private static final String[] mTimeZones = {
   1780         "UTC",
   1781         "Pacific/Kiritimati",
   1782         "Pacific/Enderbury",
   1783         "Pacific/Fiji",
   1784         "Antarctica/South_Pole",
   1785         "Pacific/Norfolk",
   1786         "Pacific/Ponape",
   1787         "Asia/Magadan",
   1788         "Australia/Lord_Howe",
   1789         "Australia/Sydney",
   1790         "Australia/Adelaide",
   1791         "Asia/Tokyo",
   1792         "Asia/Seoul",
   1793         "Asia/Taipei",
   1794         "Asia/Singapore",
   1795         "Asia/Hong_Kong",
   1796         "Asia/Saigon",
   1797         "Asia/Bangkok",
   1798         "Indian/Cocos",
   1799         "Asia/Rangoon",
   1800         "Asia/Omsk",
   1801         "Antarctica/Mawson",
   1802         "Asia/Colombo",
   1803         "Asia/Calcutta",
   1804         "Asia/Oral",
   1805         "Asia/Kabul",
   1806         "Asia/Dubai",
   1807         "Asia/Tehran",
   1808         "Europe/Moscow",
   1809         "Asia/Baghdad",
   1810         "Africa/Mogadishu",
   1811         "Europe/Athens",
   1812         "Africa/Cairo",
   1813         "Europe/Rome",
   1814         "Europe/Berlin",
   1815         "Europe/Amsterdam",
   1816         "Africa/Tunis",
   1817         "Europe/London",
   1818         "Europe/Dublin",
   1819         "Atlantic/St_Helena",
   1820         "Africa/Monrovia",
   1821         "Africa/Accra",
   1822         "Atlantic/Azores",
   1823         "Atlantic/South_Georgia",
   1824         "America/Noronha",
   1825         "America/Sao_Paulo",
   1826         "America/Cayenne",
   1827         "America/St_Johns",
   1828         "America/Puerto_Rico",
   1829         "America/Aruba",
   1830         "America/New_York",
   1831         "America/Chicago",
   1832         "America/Denver",
   1833         "America/Los_Angeles",
   1834         "America/Anchorage",
   1835         "Pacific/Marquesas",
   1836         "America/Adak",
   1837         "Pacific/Honolulu",
   1838         "Pacific/Midway",
   1839     };
   1840 
   1841     public void testGetJulianDay() throws Exception {
   1842         Time time = new Time();
   1843 
   1844         // For every 15th day of 2008, and for each of the timezones listed above,
   1845         // get the Julian day for 12am and then check that if we change the time we get the
   1846         // same Julian day. Note that one of the many problems with the Time class
   1847         // is its lack of error handling. If we accidentally hit a time that doesn't
   1848         // exist (because it was skipped by a daylight savings transition), rather than
   1849         // an error, you'll silently get 1970-01-01. We should @deprecate Time.
   1850         for (int monthDay = 1; monthDay <= 366; monthDay += 15) {
   1851             for (int zoneIndex = 0; zoneIndex < mTimeZones.length; zoneIndex++) {
   1852                 // We leave the "month" as zero because we are changing the
   1853                 // "monthDay" from 1 to 366. The call to normalize() will
   1854                 // then change the "month" (but we don't really care).
   1855                 time.set(0, 0, 12, monthDay, 0, 2008);
   1856                 time.timezone = mTimeZones[zoneIndex];
   1857                 long millis = time.normalize(true);
   1858                 if (zoneIndex == 0) {
   1859                     Log.i(TAG, time.format("%B %d, %Y"));
   1860                 }
   1861 
   1862                 // This is the Julian day for 12pm for this day of the year
   1863                 int julianDay = Time.getJulianDay(millis, time.gmtoff);
   1864 
   1865                 // Change the time during the day and check that we get the same
   1866                 // Julian day.
   1867                 for (int hour = 0; hour < 24; hour++) {
   1868                     for (int minute = 0; minute < 60; minute += 15) {
   1869                         time.set(0, minute, hour, monthDay, 0, 2008);
   1870                         millis = time.normalize(true);
   1871                         if (millis == -1) {
   1872                             // millis == -1 means the wall time does not exist in the chosen
   1873                             // timezone due to a DST change. We cannot calculate a JulianDay for -1.
   1874                             continue;
   1875                         }
   1876 
   1877                         int day = Time.getJulianDay(millis, time.gmtoff);
   1878                         assertEquals("Julian day: " + day + " at time "
   1879                                 + time.hour + ":" + time.minute
   1880                                 + " != today's Julian day: " + julianDay
   1881                                 + " timezone: " + time.timezone, day, julianDay);
   1882                     }
   1883                 }
   1884             }
   1885         }
   1886     }
   1887 
   1888     public void testSetJulianDay() throws Exception {
   1889         Time time = new Time();
   1890 
   1891         // For each day of the year in 2008, and for each timezone,
   1892         // test that we can set the Julian day correctly.
   1893         for (int monthDay = 1; monthDay <= 366; monthDay += 20) {
   1894             for (int zoneIndex = 0; zoneIndex < mTimeZones.length; zoneIndex++) {
   1895                 // We leave the "month" as zero because we are changing the
   1896                 // "monthDay" from 1 to 366. The call to normalize() will
   1897                 // then change the "month" (but we don't really care).
   1898                 time.set(0, 0, 12, monthDay, 0, 2008);
   1899                 time.timezone = mTimeZones[zoneIndex];
   1900                 long millis = time.normalize(true);
   1901                 if (zoneIndex == 0) {
   1902                     Log.i(TAG, time.format("%B %d, %Y"));
   1903                 }
   1904                 // This is the Julian day for 12pm for this day of the year
   1905                 int julianDay = Time.getJulianDay(millis, time.gmtoff);
   1906 
   1907                 time.setJulianDay(julianDay);
   1908 
   1909                 // Some places change daylight saving time at 12am and so there
   1910                 // is no 12am on some days in some timezones. In those cases,
   1911                 // the time is set to 1am.
   1912                 // Examples: Africa/Cairo on April 25, 2008
   1913                 // America/Sao_Paulo on October 12, 2008
   1914                 // Atlantic/Azores on March 30, 2008
   1915                 assertTrue(time.hour == 0 || time.hour == 1);
   1916                 assertEquals(0, time.minute);
   1917                 assertEquals(0, time.second);
   1918 
   1919                 millis = time.toMillis(false);
   1920                 if (millis == -1) {
   1921                     // millis == -1 means the wall time does not exist in the chosen
   1922                     // timezone due to a DST change. We cannot calculate a JulianDay for -1.
   1923                     continue;
   1924                 }
   1925                 int day = Time.getJulianDay(millis, time.gmtoff);
   1926                 assertEquals("Error: gmtoff " + (time.gmtoff / 3600.0) + " day " + julianDay
   1927                                 + " millis " + millis+ " " + time.format("%B %d, %Y")
   1928                                 + " " + time.timezone,
   1929                         day, julianDay);
   1930             }
   1931         }
   1932     }
   1933 
   1934     public void testNormalize_utc() throws Exception {
   1935         Time t = new Time(Time.TIMEZONE_UTC);
   1936         Time expected = new Time(Time.TIMEZONE_UTC);
   1937 
   1938         long winterTimeUtcMillis = 1167613323000L;
   1939 
   1940         Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
   1941         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 0, 0, 1);
   1942         assertNormalizeResult(true, t, expected, winterTimeUtcMillis);
   1943 
   1944         Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
   1945         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 0, 0, 1);
   1946         assertNormalizeResult(true, t, expected, winterTimeUtcMillis);
   1947 
   1948         Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
   1949         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 0, 0, 1);
   1950         assertNormalizeResult(true, t, expected, winterTimeUtcMillis);
   1951 
   1952         Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
   1953         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 0, 0, 1);
   1954         assertNormalizeResult(false, t, expected, winterTimeUtcMillis);
   1955 
   1956         Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
   1957         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
   1958         assertNormalizeResult(false, t, expected, -1);
   1959 
   1960         Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
   1961         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 0, 0, 1);
   1962         assertNormalizeResult(false, t, expected, winterTimeUtcMillis);
   1963 
   1964         long summerTimeUtcMillis = 1180659723000L;
   1965 
   1966         Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
   1967         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5);
   1968         assertNormalizeResult(true, t, expected, summerTimeUtcMillis);
   1969 
   1970         Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
   1971         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5);
   1972         assertNormalizeResult(true, t, expected, summerTimeUtcMillis);
   1973 
   1974         Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
   1975         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5);
   1976         assertNormalizeResult(true, t, expected, summerTimeUtcMillis);
   1977 
   1978         Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
   1979         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5);
   1980         assertNormalizeResult(false, t, expected, summerTimeUtcMillis);
   1981 
   1982         Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
   1983         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
   1984         assertNormalizeResult(false, t, expected, -1);
   1985 
   1986         Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 1, 9, 9);
   1987         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5);
   1988         assertNormalizeResult(false, t, expected, summerTimeUtcMillis);
   1989     }
   1990 
   1991     public void testNormalize_dstTz() throws Exception {
   1992         Time t = new Time(PstPdt.ID);
   1993         Time expected = new Time(PstPdt.ID);
   1994 
   1995         // A STD time
   1996         long stdTimeUtcMillis = 1167613323000L;
   1997         long stdTimeMillis = stdTimeUtcMillis - PstPdt.getUtcOffsetMillis(false);
   1998 
   1999         Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
   2000         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, -28800, 0, 1);
   2001         assertNormalizeResult(true, t, expected, stdTimeMillis);
   2002 
   2003         Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
   2004         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, -28800, 0, 1);
   2005         assertNormalizeResult(true, t, expected, stdTimeMillis);
   2006 
   2007         Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
   2008         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, -28800, 0, 1);
   2009         assertNormalizeResult(true, t, expected, stdTimeMillis);
   2010 
   2011         long dstToStdCorrectionMillis =
   2012                 PstPdt.getUtcOffsetMillis(false) - PstPdt.getUtcOffsetMillis(true);
   2013 
   2014         Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
   2015         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, -28800, 0, 1);
   2016         assertNormalizeResult(false, t, expected, stdTimeMillis);
   2017 
   2018         Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
   2019         Fields.set(expected, 2007, 0, 1, 0, 2, 3, 0 /* isDst */, -28800, 0, 1);
   2020         assertNormalizeResult(false, t, expected, stdTimeMillis + dstToStdCorrectionMillis);
   2021 
   2022         Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
   2023         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, -28800, 0, 1);
   2024         assertNormalizeResult(false, t, expected, stdTimeMillis);
   2025 
   2026         // A DST time
   2027         long dstTimeUtcMillis = 1180659723000L;
   2028         long dstTimeMillis = dstTimeUtcMillis - PstPdt.getUtcOffsetMillis(true);
   2029 
   2030         Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
   2031         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5);
   2032         assertNormalizeResult(true, t, expected, dstTimeMillis);
   2033 
   2034         Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
   2035         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5);
   2036         assertNormalizeResult(true, t, expected, dstTimeMillis);
   2037 
   2038         Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
   2039         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5);
   2040         assertNormalizeResult(true, t, expected, dstTimeMillis);
   2041 
   2042         long stdToDstCorrectionMillis = -dstToStdCorrectionMillis;
   2043 
   2044         Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
   2045         Fields.set(expected, 2007, 5, 1, 2, 2, 3, 1 /* isDst */, -25200, 151, 5);
   2046         assertNormalizeResult(false, t, expected, dstTimeMillis + stdToDstCorrectionMillis);
   2047 
   2048         Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5);
   2049         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5);
   2050         assertNormalizeResult(false, t, expected, dstTimeMillis);
   2051 
   2052         Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, -25200, 151, 5);
   2053         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5);
   2054         assertNormalizeResult(false, t, expected, dstTimeMillis);
   2055     }
   2056 
   2057     public void testNormalize_skippedTime() {
   2058         // Tests behavior around a transition from STD to DST that introduces an hour of "skipped"
   2059         // time from 01:00 to 01:59.
   2060         String timezone = PstPdt.ID;
   2061         long stdBaseTimeMillis = 1173607200000L;
   2062         long dstBaseTimeMillis = 1173603600000L;
   2063 
   2064         // Try each minute from one minute before the skipped hour until one after.
   2065         for (int i = -1; i <= 60; i++) {
   2066             int minutesInMillis = i * 60000;
   2067             int[] dateTimeArgs = new int[] { 2007, 2, 11, 2, i, 0 };
   2068 
   2069             int[] normalizedAdjustedBackwardDateTimeArgs;
   2070             int[] normalizedDateTimeArgs;
   2071             int[] normalizedAdjustedForwardDateTimeArgs;
   2072             if (i == -1) {
   2073                 normalizedAdjustedBackwardDateTimeArgs = new int[] { 2007, 2, 11, 0, 59, 0 };
   2074                 normalizedDateTimeArgs = new int[] { 2007, 2, 11, 1, 59, 0 };
   2075                 normalizedAdjustedForwardDateTimeArgs = null;
   2076             } else if (i == 60) {
   2077                 normalizedAdjustedBackwardDateTimeArgs = null;
   2078                 normalizedDateTimeArgs = new int[] { 2007, 2, 11, 3, 0, 0 };
   2079                 normalizedAdjustedForwardDateTimeArgs = new int[] { 2007, 2, 11, 4, 0, 0 };
   2080             } else {
   2081                 normalizedAdjustedBackwardDateTimeArgs = new int[] { 2007, 2, 11, 1, i, 0 };
   2082                 normalizedDateTimeArgs = null;
   2083                 normalizedAdjustedForwardDateTimeArgs =  new int[] { 2007, 2, 11, 3, i, 0 };
   2084             }
   2085 
   2086             Time time = new Time(timezone);
   2087             Time expected = new Time(timezone);
   2088 
   2089             // isDst = 0, normalize(true)
   2090             Fields.setDateTime(time, dateTimeArgs);
   2091             Fields.setDst(time, 0 /* isDst */, 9);
   2092             Fields.setDerivedDateTime(time, 9, 9);
   2093 
   2094             long timeMillis = time.normalize(true);
   2095             long expectedTimeMillis;
   2096             if (i == -1) {
   2097                 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis;
   2098                 Fields.setDateTime(expected, normalizedDateTimeArgs);
   2099                 Fields.setDst(expected, 0, PstPdt.getUtcOffsetSeconds(0));
   2100                 Fields.setDerivedDateTime(expected, 69, 0);
   2101             } else if (i == 60) {
   2102                 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis;
   2103                 Fields.setDateTime(expected, normalizedDateTimeArgs);
   2104                 Fields.setDst(expected, 1, PstPdt.getUtcOffsetSeconds(1));
   2105                 Fields.setDerivedDateTime(expected, 69, 0);
   2106             } else {
   2107                 expectedTimeMillis = -1;
   2108                 Fields.setDateTime(expected, dateTimeArgs);
   2109                 Fields.setDst(expected, -1, 9);
   2110                 Fields.setDerivedDateTime(expected, 9, 9);
   2111             }
   2112             assertEquals("i = " + i, expectedTimeMillis, timeMillis);
   2113             Fields.assertTimeEquals("i = " + i, expected, time);
   2114 
   2115             // isDst = 0, normalize(false)
   2116             Fields.setDateTime(time, dateTimeArgs);
   2117             Fields.setDst(time, 0 /* isDst */, 9);
   2118             Fields.setDerivedDateTime(time, 9, 9);
   2119 
   2120             timeMillis = time.normalize(false);
   2121             expectedTimeMillis = stdBaseTimeMillis + minutesInMillis;
   2122             assertEquals("i = " + i, expectedTimeMillis, timeMillis);
   2123             if (i == -1) {
   2124                 Fields.setDateTime(expected, normalizedDateTimeArgs);
   2125                 Fields.setDst(expected, 0, PstPdt.getUtcOffsetSeconds(0));
   2126             } else {
   2127                 Fields.setDateTime(expected, normalizedAdjustedForwardDateTimeArgs);
   2128                 Fields.setDst(expected, 1, PstPdt.getUtcOffsetSeconds(1));
   2129             }
   2130             Fields.setDerivedDateTime(expected, 69, 0);
   2131             Fields.assertTimeEquals("i = " + i, expected, time);
   2132 
   2133             // isDst = 1, normalize(true)
   2134             Fields.setDateTime(time, dateTimeArgs);
   2135             Fields.setDst(time, 1 /* isDst */, 9);
   2136             Fields.setDerivedDateTime(time, 9, 9);
   2137 
   2138             timeMillis = time.normalize(true);
   2139             if (i == -1) {
   2140                 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis;
   2141                 Fields.setDateTime(expected, normalizedDateTimeArgs);
   2142                 Fields.setDst(expected, 0, PstPdt.getUtcOffsetSeconds(0));
   2143                 Fields.setDerivedDateTime(expected, 69, 0);
   2144             } else if (i == 60) {
   2145                 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis;
   2146                 Fields.setDateTime(expected, normalizedDateTimeArgs);
   2147                 Fields.setDst(expected, 1, PstPdt.getUtcOffsetSeconds(1));
   2148                 Fields.setDerivedDateTime(expected, 69, 0);
   2149             } else {
   2150                 expectedTimeMillis = -1;
   2151                 Fields.setDateTime(expected, dateTimeArgs);
   2152                 Fields.setDst(expected, -1, 9);
   2153                 Fields.setDerivedDateTime(expected, 9, 9);
   2154             }
   2155             assertEquals("i = " + i, expectedTimeMillis, timeMillis);
   2156             Fields.assertTimeEquals("i = " + i, expected, time);
   2157 
   2158             // isDst = 1, normalize(false)
   2159             Fields.setDateTime(time, dateTimeArgs);
   2160             Fields.setDst(time, 1 /* isDst */, 9);
   2161             Fields.setDerivedDateTime(time, 9, 9);
   2162 
   2163             timeMillis = time.normalize(false);
   2164             expectedTimeMillis = dstBaseTimeMillis + minutesInMillis;
   2165             assertEquals("i = " + i, expectedTimeMillis, timeMillis);
   2166             if (i == 60) {
   2167                 Fields.setDateTime(expected, normalizedDateTimeArgs);
   2168                 Fields.setDst(expected, 1, PstPdt.getUtcOffsetSeconds(1));
   2169             } else {
   2170                 Fields.setDateTime(expected, normalizedAdjustedBackwardDateTimeArgs);
   2171                 Fields.setDst(expected, 0, PstPdt.getUtcOffsetSeconds(0));
   2172             }
   2173             Fields.setDerivedDateTime(expected, 69, 0);
   2174             Fields.assertTimeEquals("i = " + i, expected, time);
   2175 
   2176             // isDst = -1, normalize(true)
   2177             Fields.setDateTime(time, dateTimeArgs);
   2178             Fields.setDst(time, -1 /* isDst */, 9);
   2179             Fields.setDerivedDateTime(time, 9, 9);
   2180 
   2181             timeMillis = time.normalize(true);
   2182             if (i == -1) {
   2183                 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis;
   2184                 Fields.setDateTime(expected, normalizedDateTimeArgs);
   2185                 Fields.setDst(expected, 0, PstPdt.getUtcOffsetSeconds(0));
   2186                 Fields.setDerivedDateTime(expected, 69, 0);
   2187             } else if (i == 60) {
   2188                 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis;
   2189                 Fields.setDateTime(expected, normalizedDateTimeArgs);
   2190                 Fields.setDst(expected, 1, PstPdt.getUtcOffsetSeconds(1));
   2191                 Fields.setDerivedDateTime(expected, 69, 0);
   2192             } else {
   2193                 expectedTimeMillis = -1;
   2194                 Fields.setDateTime(expected, dateTimeArgs);
   2195                 Fields.setDst(expected, -1, 9);
   2196                 Fields.setDerivedDateTime(expected, 9, 9);
   2197             }
   2198             assertEquals("i = " + i, expectedTimeMillis, timeMillis);
   2199             Fields.assertTimeEquals("i = " + i, expected, time);
   2200 
   2201             // isDst = -1, normalize(false)
   2202             Fields.setDateTime(time, dateTimeArgs);
   2203             Fields.setDst(time, -1 /* isDst */, 9);
   2204             Fields.setDerivedDateTime(time, 9, 9);
   2205 
   2206             timeMillis = time.normalize(false);
   2207             if (i == -1) {
   2208                 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis;
   2209                 Fields.setDateTime(expected, normalizedDateTimeArgs);
   2210                 Fields.setDst(expected, 0, PstPdt.getUtcOffsetSeconds(0));
   2211                 Fields.setDerivedDateTime(expected, 69, 0);
   2212             } else if (i == 60) {
   2213                 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis;
   2214                 Fields.setDateTime(expected, normalizedDateTimeArgs);
   2215                 Fields.setDst(expected, 1, PstPdt.getUtcOffsetSeconds(1));
   2216                 Fields.setDerivedDateTime(expected, 69, 0);
   2217             } else {
   2218                 expectedTimeMillis = -1;
   2219                 Fields.setDateTime(expected, dateTimeArgs);
   2220                 Fields.setDst(expected, -1, 9);
   2221                 Fields.setDerivedDateTime(expected, 9, 9);
   2222             }
   2223             assertEquals("i = " + i, expectedTimeMillis, timeMillis);
   2224             Fields.assertTimeEquals("i = " + i, expected, time);
   2225         }
   2226     }
   2227 
   2228     public void testNormalize_duplicateWallTime() {
   2229         // 1:00 in standard / 2:00 in DST
   2230         long timeBaseMillis = 1194163200000L;
   2231         long dstCorrectionMillis = 3600000;
   2232 
   2233         // Try each minute from one minute before the duplicated hour until one after.
   2234         for (int i = -1; i <= 60; i++) {
   2235             Time time = new Time(PstPdt.ID);
   2236             Time expected = new Time(PstPdt.ID);
   2237 
   2238             int[] dateTimeArgs = new int[] { 2007, 10, 4, 1, i, 0 };
   2239             int[] normalizedAdjustedBackwardDateTimeArgs;
   2240             int[] normalizedDateTimeArgs;
   2241             int[] normalizedAdjustedForwardDateTimeArgs;
   2242             if (i == -1) {
   2243                 normalizedAdjustedBackwardDateTimeArgs = null;
   2244                 normalizedDateTimeArgs = new int[] { 2007, 10, 4, 0, 59, 0 };
   2245                 normalizedAdjustedForwardDateTimeArgs = new int[] { 2007, 10, 4, 1, 59, 0 };
   2246             } else if (i == 60) {
   2247                 normalizedAdjustedBackwardDateTimeArgs = new int[] { 2007, 10, 4, 1, 0, 0 };
   2248                 normalizedDateTimeArgs = new int[] { 2007, 10, 4, 2, 0, 0 };
   2249                 normalizedAdjustedForwardDateTimeArgs = null;
   2250             } else {
   2251                 normalizedAdjustedBackwardDateTimeArgs = null;
   2252                 normalizedDateTimeArgs = dateTimeArgs;
   2253                 normalizedAdjustedForwardDateTimeArgs =  null;
   2254             }
   2255 
   2256             int minutesInMillis = i * 60000;
   2257 
   2258             // isDst = 0, normalize(true)
   2259             Fields.setDateTime(time, dateTimeArgs);
   2260             Fields.setDst(time, 0 /* isDst */, 9);
   2261             Fields.setDerivedDateTime(time, 9, 9);
   2262 
   2263             long timeMillis = time.normalize(true);
   2264 
   2265             Fields.setDateTime(expected, normalizedDateTimeArgs);
   2266             // When ignoreDst == true the choice between DST and STD is arbitrary when both answers
   2267             // are possible.
   2268             if (timeMillis == timeBaseMillis + minutesInMillis) {
   2269                 // i == 60 is unambiguous
   2270                 assertTrue("i =" + i, i < 60);
   2271                 Fields.setDst(expected, 1 /* isDst */, PstPdt.getUtcOffsetSeconds(1));
   2272             } else if (timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis) {
   2273                 // i == -1 is unambiguous
   2274                 assertTrue("i =" + i, i > -1);
   2275                 Fields.setDst(expected, 0 /* isDst */, PstPdt.getUtcOffsetSeconds(0));
   2276             } else {
   2277                 fail("i =" + i);
   2278             }
   2279             Fields.setDerivedDateTime(expected, 307, 0);
   2280             Fields.assertTimeEquals("i = " + i, expected, time);
   2281 
   2282             // isDst = 0, normalize(false)
   2283             Fields.setDateTime(time, dateTimeArgs);
   2284             Fields.setDst(time, 0 /* isDst */, 9);
   2285             Fields.setDerivedDateTime(time, 9, 9);
   2286 
   2287             timeMillis = time.normalize(false);
   2288             long expectedTimeMillis = timeBaseMillis + minutesInMillis + dstCorrectionMillis;
   2289             assertEquals("i = " + i, expectedTimeMillis, timeMillis);
   2290             if (i == -1) {
   2291                 Fields.setDateTime(expected, normalizedAdjustedForwardDateTimeArgs);
   2292                 Fields.setDst(expected, 1 /* isDst */, PstPdt.getUtcOffsetSeconds(1));
   2293             } else {
   2294                 Fields.setDateTime(expected, normalizedDateTimeArgs);
   2295                 Fields.setDst(expected, 0 /* isDst */, PstPdt.getUtcOffsetSeconds(0));
   2296             }
   2297             Fields.setDerivedDateTime(expected, 307, 0);
   2298             Fields.assertTimeEquals("i = " + i, expected, time);
   2299 
   2300             // isDst = 1, normalize(true)
   2301             Fields.setDateTime(time, dateTimeArgs);
   2302             Fields.setDst(time, 1 /* isDst */, 9);
   2303             Fields.setDerivedDateTime(time, 9, 9);
   2304 
   2305             timeMillis = time.normalize(true);
   2306             Fields.setDateTime(expected, normalizedDateTimeArgs);
   2307             // When ignoreDst == true the choice between DST and STD is arbitrary when both answers
   2308             // are possible.
   2309             if (timeMillis == timeBaseMillis + minutesInMillis) {
   2310                 // i == 60 is unambiguous
   2311                 assertTrue("i =" + i, i < 60);
   2312                 Fields.setDst(expected, 1 /* isDst */, PstPdt.getUtcOffsetSeconds(1));
   2313             } else if (timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis) {
   2314                 // i == -1 is unambiguous
   2315                 assertTrue("i =" + i, i > -1);
   2316                 Fields.setDst(expected, 0 /* isDst */, PstPdt.getUtcOffsetSeconds(0));
   2317             } else {
   2318                 fail("i =" + i);
   2319             }
   2320             Fields.setDerivedDateTime(expected, 307, 0);
   2321             Fields.assertTimeEquals("i = " + i, expected, time);
   2322 
   2323             // isDst = 1, normalize(false)
   2324             Fields.setDateTime(time, dateTimeArgs);
   2325             Fields.setDst(time, 1 /* isDst */, 9);
   2326             Fields.setDerivedDateTime(time, 9, 9);
   2327 
   2328             timeMillis = time.normalize(false);
   2329             expectedTimeMillis = timeBaseMillis + minutesInMillis;
   2330             if (i == 60) {
   2331                 Fields.setDateTime(expected, normalizedAdjustedBackwardDateTimeArgs);
   2332                 Fields.setDst(expected, 0 /* isDst */, PstPdt.getUtcOffsetSeconds(0));
   2333             } else {
   2334                 Fields.setDateTime(expected, normalizedDateTimeArgs);
   2335                 Fields.setDst(expected, 1 /* isDst */, PstPdt.getUtcOffsetSeconds(1));
   2336             }
   2337             Fields.setDerivedDateTime(expected, 307, 0);
   2338             assertEquals("i = " + i, expectedTimeMillis, timeMillis);
   2339             Fields.assertTimeEquals("i = " + i, expected, time);
   2340 
   2341             // isDst = -1, normalize(true)
   2342             Fields.setDateTime(time, dateTimeArgs);
   2343             Fields.setDst(time, -1 /* isDst */, 9);
   2344             Fields.setDerivedDateTime(time, 9, 9);
   2345 
   2346             timeMillis = time.normalize(true);
   2347             Fields.setDateTime(expected, normalizedDateTimeArgs);
   2348             // When isDst == -1 the choice between DST and STD is arbitrary when both answers
   2349             // are possible.
   2350             if (timeMillis == timeBaseMillis + minutesInMillis) {
   2351                 // i == 60 is unambiguous
   2352                 assertTrue("i =" + i, i < 60);
   2353                 Fields.setDst(expected, 1 /* isDst */, PstPdt.getUtcOffsetSeconds(1));
   2354             } else if (timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis) {
   2355                 // i == -1 is unambiguous
   2356                 assertTrue("i =" + i, i > -1);
   2357                 Fields.setDst(expected, 0 /* isDst */, PstPdt.getUtcOffsetSeconds(0));
   2358             } else {
   2359                 fail("i =" + i);
   2360             }
   2361             Fields.setDerivedDateTime(expected, 307, 0);
   2362             Fields.assertTimeEquals("i = " + i, expected, time);
   2363 
   2364             // isDst = -1, normalize(false)
   2365             Fields.setDateTime(time, dateTimeArgs);
   2366             Fields.setDst(time, -1 /* isDst */, 9);
   2367             Fields.setDerivedDateTime(time, 9, 9);
   2368 
   2369             timeMillis = time.normalize(false);
   2370             // When isDst == -1 the choice between DST and STD is arbitrary when both answers
   2371             // are possible.
   2372             if (timeMillis == timeBaseMillis + minutesInMillis) {
   2373                 // i == 60 is unambiguous
   2374                 assertTrue("i =" + i, i < 60);
   2375                 Fields.setDst(expected, 1 /* isDst */, PstPdt.getUtcOffsetSeconds(1));
   2376             } else if (timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis) {
   2377                 // i == -1 is unambiguous
   2378                 assertTrue("i =" + i, i > -1);
   2379                 Fields.setDst(expected, 0 /* isDst */, PstPdt.getUtcOffsetSeconds(0));
   2380             } else {
   2381                 fail("i =" + i);
   2382             }
   2383             Fields.setDerivedDateTime(expected, 307, 0);
   2384             Fields.assertTimeEquals("i = " + i, expected, time);
   2385         }
   2386     }
   2387 
   2388     public void testNormalize_beforeTzRecords() {
   2389         int[] timeFields = new int[] { 1900, 0, 1, 2, 3, 4, -999 /* not used */, 9, 9, 9 };
   2390         assertNormalizeInvalid(timeFields, PstPdt.ID);
   2391         assertNormalizeInvalid(timeFields, Time.TIMEZONE_UTC);
   2392     }
   2393 
   2394     private static void assertNormalizeInvalid(int[] timeFields, String timezone) {
   2395         Time time = new Time(timezone);
   2396         Time expected = new Time(timezone);
   2397 
   2398         // isDst = 0, normalize(true)
   2399         Fields.set(time, timeFields);
   2400         time.isDst = 0;
   2401         Fields.set(expected, timeFields);
   2402         expected.isDst = -1;
   2403         assertNormalizeResult(true, time, expected, -1);
   2404 
   2405         // isDst = 0, normalize(false)
   2406         Fields.set(time, timeFields);
   2407         time.isDst = 0;
   2408         Fields.set(expected, timeFields);
   2409         expected.isDst = 0;
   2410         assertNormalizeResult(false, time, expected, -1);
   2411 
   2412         // isDst = 1, normalize(true)
   2413         Fields.set(time, timeFields);
   2414         time.isDst = 1;
   2415         Fields.set(expected, timeFields);
   2416         expected.isDst = -1;
   2417         assertNormalizeResult(true, time, expected, -1);
   2418 
   2419         // isDst = 1, normalize(false)
   2420         Fields.set(time, timeFields);
   2421         time.isDst = 1;
   2422         Fields.set(expected, timeFields);
   2423         expected.isDst = 1;
   2424         assertNormalizeResult(false, time, expected, -1);
   2425 
   2426         // isDst = -1, normalize(true)
   2427         Fields.set(time, timeFields);
   2428         time.isDst = -1;
   2429         Fields.set(expected, timeFields);
   2430         expected.isDst = -1;
   2431         assertNormalizeResult(true, time, expected, -1);
   2432 
   2433         // isDst = -1, normalize(false)
   2434         Fields.set(time, timeFields);
   2435         time.isDst = -1;
   2436         Fields.set(expected, timeFields);
   2437         expected.isDst = -1;
   2438         assertNormalizeResult(false, time, expected, -1);
   2439     }
   2440 
   2441     public void testNormalize_afterTzRecords() {
   2442         int[] timeFields = new int[] { 2039, 0, 1, 2, 3, 4, -999 /* not used */, 9, 9, 9 };
   2443         assertNormalizeInvalid(timeFields, PstPdt.ID);
   2444         assertNormalizeInvalid(timeFields, Time.TIMEZONE_UTC);
   2445     }
   2446 
   2447     public void testNormalize_invalid() {
   2448         int[] timeFields = new int[] { 0, 0, 0, 0, 0, 0, -999 /* not used */, 9, 9, 9 };
   2449         assertNormalizeInvalid(timeFields, PstPdt.ID);
   2450         assertNormalizeInvalid(timeFields, Time.TIMEZONE_UTC);
   2451     }
   2452 
   2453     public void testNormalize_dstToDstSkip() {
   2454         // In London, 4th May 1941 02:00 - 03:00 was a skip from DST -> DST (+1 hour -> +2 hours)
   2455         String timezone = "Europe/London";
   2456         Time t = new Time(timezone);
   2457         Time expected = new Time(timezone);
   2458 
   2459         // Demonstrate the data we expect either side of the skipped interval: 01:59
   2460         Fields.set(t, 1941, 4, 4, 1, 59, 0, -1 /* isDst */, 9, 9, 9);
   2461         Fields.set(expected, 1941, 4, 4, 1, 59, 0, 1 /* isDst */, 3600, 123, 0);
   2462         assertNormalizeResult(true, t, expected, -904518060000L);
   2463 
   2464         // Demonstrate the data we expect either side of the skipped interval: 03:00
   2465         Fields.set(t, 1941, 4, 4, 3, 0, 0, -1 /* isDst */, 9, 9, 9);
   2466         Fields.set(expected, 1941, 4, 4, 3, 0, 0, 1 /* isDst */, 7200, 123, 0);
   2467         assertNormalizeResult(true, t, expected, -904518000000L);
   2468 
   2469         // isDst = 1, normalize(false)
   2470         Fields.set(t, 1941, 4, 4, 2, 30, 0, 1 /* isDst */, 9, 9, 9);
   2471         Fields.set(expected, 1941, 4, 4, 2, 30, 0, 1 /* isDst */, 9, 9, 9);
   2472         assertNormalizeResult(false, t, expected, -1);
   2473 
   2474         // isDst = -1, normalize(false)
   2475         Fields.set(t, 1941, 4, 4, 2, 30, 0, -1 /* isDst */, 9, 9, 9);
   2476         Fields.set(expected, 1941, 4, 4, 2, 30, 0, -1 /* isDst */, 9, 9, 9);
   2477         assertNormalizeResult(false, t, expected, -1);
   2478 
   2479         // The results below are potentially arbitrary: 01:30 and 02:30 are not a valid standard
   2480         // times so normalize() must apply one of the possible STD -> DST adjustments to arrive at a
   2481         // date / time.
   2482 
   2483         // isDst = 0, normalize(false) @ 01:30
   2484         Fields.set(t, 1941, 4, 4, 1, 30, 0, 0 /* isDst */, 9, 9, 9);
   2485         Fields.set(expected, 1941, 4, 4, 3, 30, 0, 1 /* isDst */, 7200, 123, 0);
   2486         assertNormalizeResult(false, t, expected, -904516200000L);
   2487 
   2488         // isDst = 0, normalize(false) @ 02:30
   2489         Fields.set(t, 1941, 4, 4, 2, 30, 0, 0 /* isDst */, 9, 9, 9);
   2490         long timeMillis = t.normalize(false);
   2491 
   2492         if (timeMillis == -904516200000L) {
   2493             // The original C implementation chooses this one.
   2494             Fields.set(expected, 1941, 4, 4, 3, 30, 0, 1 /* isDst */, 7200, 123, 0);
   2495         } else if (timeMillis == -904512600000L) {
   2496             Fields.set(expected, 1941, 4, 4, 4, 30, 0, 1 /* isDst */, 7200, 123, 0);
   2497         } else {
   2498             fail();
   2499         }
   2500         Fields.assertTimeEquals(expected, t);
   2501     }
   2502 
   2503     public void testNormalize_dstToDstRepeat() {
   2504         // In London, 10th August 1941 02:00 - 03:00 was a repeat from DST -> DST
   2505         // (+2 hour -> +1 hour)
   2506         String timezone = "Europe/London";
   2507         Time t = new Time(timezone);
   2508         Time expected = new Time(timezone);
   2509 
   2510         // Demonstrate the data we expect during the repeated interval: 02:30 (first)
   2511         t.set(-896052600000L);
   2512         Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 7200, 221, 0);
   2513         Fields.assertTimeEquals(expected, t);
   2514 
   2515         // Demonstrate the data we expect during the repeated interval: 02:30 (second)
   2516         t.set(-896049000000L);
   2517         Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 3600, 221, 0);
   2518         Fields.assertTimeEquals(expected, t);
   2519 
   2520         // Now check times in the repeated hour with different isDst assertions...
   2521 
   2522         // isDst = 1, normalize(false) @ 02:30
   2523         Fields.set(t, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 9, 9, 9);
   2524         Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 3600, 221, 0);
   2525         assertNormalizeResult(false, t, expected, -896049000000L);
   2526 
   2527         // isDst = -1, normalize(false) @ 02:30
   2528         Fields.set(t, 1941, 7, 10, 2, 30, 0, -1 /* isDst */, 9, 9, 9);
   2529         Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 3600, 221, 0);
   2530         assertNormalizeResult(false, t, expected, -896049000000L);
   2531 
   2532         // The results below are potentially arbitrary: 01:30 and 02:30 are not a valid standard
   2533         // times so normalize() must apply one of the possible STD -> DST adjustments to arrive at a
   2534         // date / time.
   2535 
   2536         // isDst = 0, normalize(false) @ 01:30
   2537         Fields.set(t, 1941, 7, 10, 1, 30, 0, 0 /* isDst */, 9, 9, 9);
   2538         long timeMillis = t.normalize(false);
   2539         if (timeMillis == -896052600000L) {
   2540             // The original C implementation chooses this one.
   2541             Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 7200, 221, 0);
   2542         } else if (timeMillis == -896049000000L) {
   2543             Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 3600, 221, 0);
   2544         } else {
   2545             fail();
   2546         }
   2547         Fields.assertTimeEquals(expected, t);
   2548 
   2549         // isDst = 0, normalize(false) @ 02:30
   2550         Fields.set(t, 1941, 7, 10, 2, 30, 0, 0 /* isDst */, 9, 9, 9);
   2551         Fields.set(expected, 1941, 7, 10, 3, 30, 0, 1 /* isDst */, 3600, 221, 0);
   2552         assertNormalizeResult(false, t, expected, -896045400000L);
   2553     }
   2554 
   2555     public void testNormalize_stdToStdRepeat() {
   2556         // In London, 31st October 1971 02:00 - 03:00 was a repeat from STD -> STD
   2557         String timezone = "Europe/London";
   2558         Time t = new Time(timezone);
   2559         Time expected = new Time(timezone);
   2560 
   2561         // Demonstrate the data we expect during the repeated interval: 02:30 (first)
   2562         t.set(57720600000L);
   2563         Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 3600, 303, 0);
   2564         Fields.assertTimeEquals(expected, t);
   2565 
   2566         // Demonstrate the data we expect during the repeated interval: 02:30 (second)
   2567         t.set(57724200000L);
   2568         Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 0, 303, 0);
   2569         Fields.assertTimeEquals(expected, t);
   2570 
   2571         // isDst = 0, normalize(false) @ 02:30
   2572         Fields.set(t, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 9, 9, 9);
   2573 
   2574         long timeMillis = t.normalize(false);
   2575 
   2576         // Either answer is valid: the choice is arbitrary.
   2577         if (57720600000L == timeMillis) {
   2578             // The original C implementation chooses this one.
   2579             Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 3600, 303, 0);
   2580         } else if (57724200000L == timeMillis) {
   2581             Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 0, 303, 0);
   2582         } else {
   2583             fail();
   2584         }
   2585         Fields.assertTimeEquals(expected, t);
   2586 
   2587         // isDst = -1, normalize(false) @ 02:30
   2588         Fields.set(t, 1971, 9, 31, 2, 30, 0, -1 /* isDst */, 9, 9, 9);
   2589 
   2590         timeMillis = t.normalize(false);
   2591 
   2592         Fields.setDateTime(expected, 1971, 9, 31, 2, 30, 0);
   2593         // Either answer is valid: the choice is arbitrary.
   2594         if (57720600000L == timeMillis) {
   2595             // The original C implementation chooses this one.
   2596             Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 3600, 303, 0);
   2597         } else if (57724200000L == timeMillis) {
   2598             Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 0, 303, 0);
   2599         } else {
   2600             fail();
   2601         }
   2602         Fields.assertTimeEquals(expected, t);
   2603 
   2604         // The results below are potentially arbitrary: 01:30 and 02:30 are not a valid DST
   2605         // so normalize() must apply one of the possible STD -> DST adjustments to arrive at a
   2606         // date / time.
   2607 
   2608         // isDst = 1, normalize(false) @ 01:30
   2609         Fields.set(t, 1971, 9, 31, 1, 30, 0, 1 /* isDst */, 9, 9, 9);
   2610 
   2611         timeMillis = t.normalize(false);
   2612 
   2613         if (timeMillis == 57713400000L) {
   2614             // Original C implementation chooses this one.
   2615             Fields.set(expected, 1971, 9, 31, 0, 30, 0, 0 /* isDst */, 3600, 303, 0);
   2616         } else if (timeMillis == 57717000000L) {
   2617             Fields.set(expected, 1971, 9, 31, 1, 30, 0, 0 /* isDst */, 3600, 303, 0);
   2618         } else {
   2619             fail();
   2620         }
   2621         Fields.assertTimeEquals(expected, t);
   2622 
   2623         // isDst = 1, normalize(false) @ 02:30
   2624         Fields.set(t, 1971, 9, 31, 2, 30, 0, 1 /* isDst */, 9, 9, 9);
   2625         timeMillis = t.normalize(false);
   2626         if (timeMillis == 57717000000L) {
   2627             // The original C implementation chooses this one.
   2628             Fields.set(expected, 1971, 9, 31, 1, 30, 0, 0 /* isDst */, 3600, 303, 0);
   2629         } else if (timeMillis == 57720600000L) {
   2630             Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 3600, 303, 0);
   2631         } else {
   2632             fail();
   2633         }
   2634         Fields.assertTimeEquals(expected, t);
   2635 
   2636         // isDst = 1, normalize(false) @ 03:30
   2637         Fields.set(t, 1971, 9, 31, 3, 30, 0, 1 /* isDst */, 9, 9, 9);
   2638         Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 0, 303, 0);
   2639         assertNormalizeResult(false, t, expected, 57724200000L);
   2640     }
   2641 
   2642     public void testNormalize_stdToStdSkip() {
   2643         // In Kiritimati, 1st Jan 1995 10:00 - 10:40 was a skip from STD -> STD (plus they do not
   2644         // observe DST).
   2645         String timezone = "Pacific/Kiritimati";
   2646         Time t = new Time(timezone);
   2647         Time expected = new Time(timezone);
   2648 
   2649         // isDst = 0, normalize(false)
   2650         Fields.set(t, 1995, 0, 1, 10, 20, 0, 0 /* isDst */, 9, 9, 9);
   2651         Fields.set(expected, 1995, 0, 1, 10, 20, 0, 0 /* isDst */, 9, 9, 9);
   2652         assertNormalizeResult(false, t, expected, -1);
   2653 
   2654         // isDst = 1, normalize(false)
   2655         Fields.set(t, 1995, 0, 1, 10, 20, 0, 1 /* isDst */, 9, 9, 9);
   2656         Fields.set(expected, 1995, 0, 1, 10, 20, 0, 1 /* isDst */, 9, 9, 9);
   2657         assertNormalizeResult(false, t, expected, -1);
   2658 
   2659         // isDst = -1, normalize(false)
   2660         Fields.set(t, 1995, 0, 1, 10, 20, 0, -1 /* isDst */, 9, 9, 9);
   2661         Fields.set(expected, 1995, 0, 1, 10, 20, 0, -1 /* isDst */, 9, 9, 9);
   2662         assertNormalizeResult(false, t, expected, -1);
   2663     }
   2664 
   2665     public void testNormalize_utcWithDst() {
   2666         // In UTC (or other zone without DST), what happens when a DST time is specified and there
   2667         // is no DST offset available in the timezone data.
   2668         Time t = new Time(Time.TIMEZONE_UTC);
   2669         Time expected = new Time(Time.TIMEZONE_UTC);
   2670 
   2671         // isDst = 1, normalize(false)
   2672         Fields.set(t, 2005, 6, 22, 1, 30, 0, 1 /* isDst */, 9, 9, 9);
   2673         Fields.set(expected, 2005, 6, 22, 1, 30, 0, 1 /* isDst */, 9, 9, 9);
   2674         assertNormalizeResult(false, t, expected, -1);
   2675 
   2676         // isDst = -1, normalize(false)
   2677         Fields.set(t, 2005, 6, 22, 1, 30, 0, -1 /* isDst */, 9, 9, 9);
   2678         Fields.set(expected, 2005, 6, 22, 1, 30, 0, 0 /* isDst */, 0, 202, 5);
   2679         assertNormalizeResult(false, t, expected, 1121995800000L);
   2680     }
   2681 
   2682     public void testUnknownTz() {
   2683         // Historically the code used UTC if the timezone is unrecognized.
   2684 
   2685         String unknownTimezoneId = "THIS_ID_IS_NOT_A_VALID_TZ";
   2686         Time t = new Time(unknownTimezoneId);
   2687         assertEquals(unknownTimezoneId, t.timezone);
   2688         Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
   2689 
   2690         // We can't know for sure which time zone is being used, but we assume it is UTC if the date
   2691         // normalizes to isDst == 0 and with an offset of 0 during the summer months.
   2692 
   2693         long timeMillis = t.normalize(true);
   2694         assertEquals(unknownTimezoneId, t.timezone);
   2695         assertEquals(1180659723000L, timeMillis);
   2696 
   2697         Time expected = new Time(unknownTimezoneId);
   2698         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5);
   2699         Fields.assertTimeEquals(expected, t);
   2700     }
   2701 
   2702     private static void assertNormalizeResult(boolean normalizeArgument, Time toNormalize,
   2703             Time expectedTime, long expectedTimeMillis) {
   2704         long actualTimeMillis = toNormalize.normalize(normalizeArgument /* ignore isDst */);
   2705         assertEquals(expectedTimeMillis, actualTimeMillis);
   2706         Fields.assertTimeEquals(expectedTime, toNormalize);
   2707     }
   2708 
   2709     /** A helper class for manipulating / testing fields on Time objects. */
   2710     private static class Fields {
   2711         final static int MAIN_DATE_TIME = 1;
   2712         final static int DST_FIELDS = 2;
   2713         final static int DERIVED_DATE_TIME = 4;
   2714 
   2715         final static int ALL = MAIN_DATE_TIME | DST_FIELDS | DERIVED_DATE_TIME;
   2716 
   2717         public static void assertTimeEquals(Time expected, Time actual) {
   2718             assertTimeEquals("", ALL, expected, actual);
   2719         }
   2720 
   2721         public static void assertTimeEquals(int fields, Time expected, Time actual) {
   2722             assertTimeEquals("", fields, expected, actual);
   2723         }
   2724 
   2725         public static void assertTimeEquals(String message, Time expected, Time actual) {
   2726             assertTimeEquals(message, Fields.ALL, expected, actual);
   2727         }
   2728 
   2729         public static void assertTimeEquals(String message, int fields, Time expected,
   2730                 Time actual) {
   2731             boolean mainDateTimeOk = (fields & Fields.MAIN_DATE_TIME) == 0
   2732                     || (Objects.equals(expected.timezone, actual.timezone)
   2733                     && expected.year == actual.year
   2734                     && expected.month == actual.month
   2735                     && expected.monthDay == actual.monthDay
   2736                     && expected.hour == actual.hour
   2737                     && expected.minute == actual.minute
   2738                     && expected.second == actual.second
   2739                     && expected.allDay == actual.allDay);
   2740 
   2741             boolean dstFieldsOk = (fields & Fields.DST_FIELDS) == 0
   2742                     || (expected.isDst == actual.isDst && expected.gmtoff == actual.gmtoff);
   2743 
   2744             boolean derivedDateTimeOk = (fields & Fields.DERIVED_DATE_TIME) == 0
   2745                     || (expected.yearDay == actual.yearDay && expected.weekDay == actual.weekDay);
   2746 
   2747             if (!mainDateTimeOk || !dstFieldsOk || !derivedDateTimeOk) {
   2748                 String expectedTime = timeToString(fields, expected);
   2749                 String actualTime = timeToString(fields, actual);
   2750                 fail(message + " [Time fields differed. Expected: " + expectedTime + "Actual: "
   2751                         + actualTime + "]");
   2752             }
   2753         }
   2754 
   2755         private static String timeToString(int fields, Time time) {
   2756             List<Object> values = new ArrayList<Object>();
   2757             StringBuilder format = new StringBuilder();
   2758             if ((fields & Fields.MAIN_DATE_TIME) > 0) {
   2759                 format.append("%d-%02d-%02d %02d:%02d:%02d allDay=%b timezone=%s ");
   2760                 values.addAll(
   2761                         Arrays.asList(time.year, time.month, time.monthDay, time.hour, time.minute,
   2762                                 time.second, time.allDay, time.timezone));
   2763             }
   2764             if ((fields & Fields.DST_FIELDS) > 0) {
   2765                 format.append("isDst=%d, gmtoff=%d ");
   2766                 values.add(time.isDst);
   2767                 values.add(time.gmtoff);
   2768             }
   2769             if ((fields & Fields.DERIVED_DATE_TIME) > 0) {
   2770                 format.append("yearDay=%d, weekDay=%d ");
   2771                 values.add(time.yearDay);
   2772                 values.add(time.weekDay);
   2773 
   2774             }
   2775             return String.format(format.toString(), values.toArray());
   2776         }
   2777 
   2778         public static void setDateTime(Time t, int year, int month, int monthDay, int hour,
   2779                 int minute, int second) {
   2780             t.year = year;
   2781             t.month = month;
   2782             t.monthDay = monthDay;
   2783             t.hour = hour;
   2784             t.minute = minute;
   2785             t.second = second;
   2786             t.allDay = false;
   2787         }
   2788 
   2789         public static void setDateTime(Time t, int[] args) {
   2790             assertEquals(6, args.length);
   2791             setDateTime(t, args[0], args[1], args[2], args[3], args[4], args[5]);
   2792         }
   2793 
   2794         public static void setDst(Time t, int isDst, int gmtoff) {
   2795             t.isDst = isDst;
   2796             t.gmtoff = gmtoff;
   2797         }
   2798 
   2799         public static void setDerivedDateTime(Time t, int yearDay, int weekDay) {
   2800             t.yearDay = yearDay;
   2801             t.weekDay = weekDay;
   2802         }
   2803 
   2804         public static void setAllDayDate(Time t, int year, int month, int monthDay) {
   2805             t.year = year;
   2806             t.month = month;
   2807             t.monthDay = monthDay;
   2808             t.allDay = true;
   2809         }
   2810 
   2811         public static void set(Time t, int[] args) {
   2812             assertEquals(10, args.length);
   2813             set(t, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8],
   2814                     args[9]);
   2815         }
   2816 
   2817         public static void set(Time t, int year, int month, int monthDay, int hour, int minute,
   2818                 int second, int isDst, int gmtoff, int yearDay, int weekDay) {
   2819             setDateTime(t, year, month, monthDay, hour, minute, second);
   2820             setDst(t, isDst, gmtoff);
   2821             setDerivedDateTime(t, yearDay, weekDay);
   2822         }
   2823     }
   2824 
   2825     private static class PstPdt {
   2826         public static final String ID = "America/Los_Angeles";
   2827 
   2828         public static int getUtcOffsetSeconds(int isDst) {
   2829             if (isDst == 0) {
   2830                 return -28800;
   2831             } else if (isDst == 1) {
   2832                 return -25200;
   2833             }
   2834             throw new IllegalArgumentException();
   2835         }
   2836 
   2837         public static int getUtcOffsetSeconds(boolean isDst) {
   2838             return getUtcOffsetSeconds(isDst ? 1 : 0);
   2839         }
   2840 
   2841         public static int getUtcOffsetMillis(boolean isDst) {
   2842             return getUtcOffsetSeconds(isDst) * 1000;
   2843         }
   2844     }
   2845 
   2846     private static void changeJavaAndAndroidLocale(Locale locale) {
   2847         // The Time class uses the Android-managed locale for string resources containing format
   2848         // patterns and the Java-managed locale for other things (e.g. month names, week days names)
   2849         // that are placed into those patterns. For example the format "%c" expands to include
   2850         // a pattern that includes month names.
   2851         // Changing the Java-managed Locale does not affect the Android-managed locale.
   2852         // Changing the Android-managed locale does not affect the Java-managed locale.
   2853         //
   2854         // In order to ensure consistent behavior in the tests the device Locale must not be
   2855         // assumed. To simulate the most common behavior (i.e. when the Java and the Android-managed
   2856         // locales agree), when the Java-managed locale is changed during this test the locale in
   2857         // the runtime-local copy of the system resources is modified as well.
   2858 
   2859         // Change the Java-managed locale.
   2860         Locale.setDefault(locale);
   2861 
   2862         // Change the local copy of the Android system configuration: this simulates the device
   2863         // being set to the locale and forces a reload of the string resources.
   2864         Configuration configuration = Resources.getSystem().getConfiguration();
   2865         configuration.locale = locale;
   2866         Resources.getSystem().updateConfiguration(configuration, null);
   2867     }
   2868 }
   2869