1 /*
   2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * This file is available under and governed by the GNU General Public
  26  * License version 2 only, as published by the Free Software Foundation.
  27  * However, the following notice accompanied the original version of this
  28  * file:
  29  *
  30  * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
  31  *
  32  * All rights reserved.
  33  *
  34  * Redistribution and use in source and binary forms, with or without
  35  * modification, are permitted provided that the following conditions are met:
  36  *
  37  *  * Redistributions of source code must retain the above copyright notice,
  38  *    this list of conditions and the following disclaimer.
  39  *
  40  *  * Redistributions in binary form must reproduce the above copyright notice,
  41  *    this list of conditions and the following disclaimer in the documentation
  42  *    and/or other materials provided with the distribution.
  43  *
  44  *  * Neither the name of JSR-310 nor the names of its contributors
  45  *    may be used to endorse or promote products derived from this software
  46  *    without specific prior written permission.
  47  *
  48  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  49  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  50  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  51  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  52  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  53  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  54  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  55  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  56  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  57  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  58  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  59  */
  60 package tck.java.time.zone;
  61 
  62 import java.time.temporal.Year;
  63 import java.time.zone.*;
  64 
  65 import static org.testng.Assert.assertEquals;
  66 import static org.testng.Assert.assertFalse;
  67 import static org.testng.Assert.assertNotNull;
  68 import static org.testng.Assert.assertTrue;
  69 
  70 import java.io.ByteArrayInputStream;
  71 import java.io.ByteArrayOutputStream;
  72 import java.io.ObjectInputStream;
  73 import java.io.ObjectOutputStream;
  74 import java.util.Iterator;
  75 import java.util.List;
  76 
  77 import java.time.DayOfWeek;
  78 import java.time.Duration;
  79 import java.time.Instant;
  80 import java.time.LocalDate;
  81 import java.time.LocalDateTime;
  82 import java.time.LocalTime;
  83 import java.time.Month;
  84 import java.time.ZoneId;
  85 import java.time.ZoneOffset;
  86 import java.time.ZonedDateTime;
  87 import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition;
  88 
  89 import org.testng.annotations.Test;
  90 
  91 /**
  92  * Test ZoneRules.
  93  */
  94 @Test
  95 public class TCKZoneRules {
  96 
  97     private static final ZoneOffset OFFSET_ZERO = ZoneOffset.ofHours(0);
  98     private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
  99     private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
 100     public static final String LATEST_TZDB = "2009b";
 101     private static final int OVERLAP = 2;
 102     private static final int GAP = 0;
 103 
 104     //-----------------------------------------------------------------------
 105     // Basics
 106     //-----------------------------------------------------------------------
 107     public void test_serialization_loaded() throws Exception {
 108         assertSerialization(europeLondon());
 109         assertSerialization(europeParis());
 110         assertSerialization(americaNewYork());
 111     }
 112 
 113     private void assertSerialization(ZoneRules test) throws Exception {
 114         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 115         ObjectOutputStream out = new ObjectOutputStream(baos);
 116         out.writeObject(test);
 117         baos.close();
 118         byte[] bytes = baos.toByteArray();
 119 
 120         ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
 121         ObjectInputStream in = new ObjectInputStream(bais);
 122         ZoneRules result = (ZoneRules) in.readObject();
 123 
 124         assertEquals(result, test);
 125     }
 126 
 127     //-----------------------------------------------------------------------
 128     // Europe/London
 129     //-----------------------------------------------------------------------
 130     private ZoneRules europeLondon() {
 131         return ZoneId.of("Europe/London").getRules();
 132     }
 133 
 134     public void test_London() {
 135         ZoneRules test = europeLondon();
 136         assertEquals(test.isFixedOffset(), false);
 137     }
 138 
 139     public void test_London_preTimeZones() {
 140         ZoneRules test = europeLondon();
 141         ZonedDateTime old = createZDT(1800, 1, 1, ZoneOffset.UTC);
 142         Instant instant = old.toInstant();
 143         ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(0, -1, -15);
 144         assertEquals(test.getOffset(instant), offset);
 145         checkOffset(test, old.getDateTime(), offset, 1);
 146         assertEquals(test.getStandardOffset(instant), offset);
 147         assertEquals(test.getDaylightSavings(instant), Duration.ZERO);
 148         assertEquals(test.isDaylightSavings(instant), false);
 149     }
 150 
 151     public void test_London_getOffset() {
 152         ZoneRules test = europeLondon();
 153         assertEquals(test.getOffset(createInstant(2008, 1, 1, ZoneOffset.UTC)), OFFSET_ZERO);
 154         assertEquals(test.getOffset(createInstant(2008, 2, 1, ZoneOffset.UTC)), OFFSET_ZERO);
 155         assertEquals(test.getOffset(createInstant(2008, 3, 1, ZoneOffset.UTC)), OFFSET_ZERO);
 156         assertEquals(test.getOffset(createInstant(2008, 4, 1, ZoneOffset.UTC)), OFFSET_PONE);
 157         assertEquals(test.getOffset(createInstant(2008, 5, 1, ZoneOffset.UTC)), OFFSET_PONE);
 158         assertEquals(test.getOffset(createInstant(2008, 6, 1, ZoneOffset.UTC)), OFFSET_PONE);
 159         assertEquals(test.getOffset(createInstant(2008, 7, 1, ZoneOffset.UTC)), OFFSET_PONE);
 160         assertEquals(test.getOffset(createInstant(2008, 8, 1, ZoneOffset.UTC)), OFFSET_PONE);
 161         assertEquals(test.getOffset(createInstant(2008, 9, 1, ZoneOffset.UTC)), OFFSET_PONE);
 162         assertEquals(test.getOffset(createInstant(2008, 10, 1, ZoneOffset.UTC)), OFFSET_PONE);
 163         assertEquals(test.getOffset(createInstant(2008, 11, 1, ZoneOffset.UTC)), OFFSET_ZERO);
 164         assertEquals(test.getOffset(createInstant(2008, 12, 1, ZoneOffset.UTC)), OFFSET_ZERO);
 165     }
 166 
 167     public void test_London_getOffset_toDST() {
 168         ZoneRules test = europeLondon();
 169         assertEquals(test.getOffset(createInstant(2008, 3, 24, ZoneOffset.UTC)), OFFSET_ZERO);
 170         assertEquals(test.getOffset(createInstant(2008, 3, 25, ZoneOffset.UTC)), OFFSET_ZERO);
 171         assertEquals(test.getOffset(createInstant(2008, 3, 26, ZoneOffset.UTC)), OFFSET_ZERO);
 172         assertEquals(test.getOffset(createInstant(2008, 3, 27, ZoneOffset.UTC)), OFFSET_ZERO);
 173         assertEquals(test.getOffset(createInstant(2008, 3, 28, ZoneOffset.UTC)), OFFSET_ZERO);
 174         assertEquals(test.getOffset(createInstant(2008, 3, 29, ZoneOffset.UTC)), OFFSET_ZERO);
 175         assertEquals(test.getOffset(createInstant(2008, 3, 30, ZoneOffset.UTC)), OFFSET_ZERO);
 176         assertEquals(test.getOffset(createInstant(2008, 3, 31, ZoneOffset.UTC)), OFFSET_PONE);
 177         // cutover at 01:00Z
 178         assertEquals(test.getOffset(createInstant(2008, 3, 30, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_ZERO);
 179         assertEquals(test.getOffset(createInstant(2008, 3, 30, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_PONE);
 180     }
 181 
 182     public void test_London_getOffset_fromDST() {
 183         ZoneRules test = europeLondon();
 184         assertEquals(test.getOffset(createInstant(2008, 10, 24, ZoneOffset.UTC)), OFFSET_PONE);
 185         assertEquals(test.getOffset(createInstant(2008, 10, 25, ZoneOffset.UTC)), OFFSET_PONE);
 186         assertEquals(test.getOffset(createInstant(2008, 10, 26, ZoneOffset.UTC)), OFFSET_PONE);
 187         assertEquals(test.getOffset(createInstant(2008, 10, 27, ZoneOffset.UTC)), OFFSET_ZERO);
 188         assertEquals(test.getOffset(createInstant(2008, 10, 28, ZoneOffset.UTC)), OFFSET_ZERO);
 189         assertEquals(test.getOffset(createInstant(2008, 10, 29, ZoneOffset.UTC)), OFFSET_ZERO);
 190         assertEquals(test.getOffset(createInstant(2008, 10, 30, ZoneOffset.UTC)), OFFSET_ZERO);
 191         assertEquals(test.getOffset(createInstant(2008, 10, 31, ZoneOffset.UTC)), OFFSET_ZERO);
 192         // cutover at 01:00Z
 193         assertEquals(test.getOffset(createInstant(2008, 10, 26, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_PONE);
 194         assertEquals(test.getOffset(createInstant(2008, 10, 26, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_ZERO);
 195     }
 196 
 197     public void test_London_getOffsetInfo() {
 198         ZoneRules test = europeLondon();
 199         checkOffset(test, createLDT(2008, 1, 1), OFFSET_ZERO, 1);
 200         checkOffset(test, createLDT(2008, 2, 1), OFFSET_ZERO, 1);
 201         checkOffset(test, createLDT(2008, 3, 1), OFFSET_ZERO, 1);
 202         checkOffset(test, createLDT(2008, 4, 1), OFFSET_PONE, 1);
 203         checkOffset(test, createLDT(2008, 5, 1), OFFSET_PONE, 1);
 204         checkOffset(test, createLDT(2008, 6, 1), OFFSET_PONE, 1);
 205         checkOffset(test, createLDT(2008, 7, 1), OFFSET_PONE, 1);
 206         checkOffset(test, createLDT(2008, 8, 1), OFFSET_PONE, 1);
 207         checkOffset(test, createLDT(2008, 9, 1), OFFSET_PONE, 1);
 208         checkOffset(test, createLDT(2008, 10, 1), OFFSET_PONE, 1);
 209         checkOffset(test, createLDT(2008, 11, 1), OFFSET_ZERO, 1);
 210         checkOffset(test, createLDT(2008, 12, 1), OFFSET_ZERO, 1);
 211     }
 212 
 213     public void test_London_getOffsetInfo_toDST() {
 214         ZoneRules test = europeLondon();
 215         checkOffset(test, createLDT(2008, 3, 24), OFFSET_ZERO, 1);
 216         checkOffset(test, createLDT(2008, 3, 25), OFFSET_ZERO, 1);
 217         checkOffset(test, createLDT(2008, 3, 26), OFFSET_ZERO, 1);
 218         checkOffset(test, createLDT(2008, 3, 27), OFFSET_ZERO, 1);
 219         checkOffset(test, createLDT(2008, 3, 28), OFFSET_ZERO, 1);
 220         checkOffset(test, createLDT(2008, 3, 29), OFFSET_ZERO, 1);
 221         checkOffset(test, createLDT(2008, 3, 30), OFFSET_ZERO, 1);
 222         checkOffset(test, createLDT(2008, 3, 31), OFFSET_PONE, 1);
 223         // cutover at 01:00Z
 224         checkOffset(test, LocalDateTime.of(2008, 3, 30, 0, 59, 59, 999999999), OFFSET_ZERO, 1);
 225         checkOffset(test, LocalDateTime.of(2008, 3, 30, 2, 0, 0, 0), OFFSET_PONE, 1);
 226     }
 227 
 228     public void test_London_getOffsetInfo_fromDST() {
 229         ZoneRules test = europeLondon();
 230         checkOffset(test, createLDT(2008, 10, 24), OFFSET_PONE, 1);
 231         checkOffset(test, createLDT(2008, 10, 25), OFFSET_PONE, 1);
 232         checkOffset(test, createLDT(2008, 10, 26), OFFSET_PONE, 1);
 233         checkOffset(test, createLDT(2008, 10, 27), OFFSET_ZERO, 1);
 234         checkOffset(test, createLDT(2008, 10, 28), OFFSET_ZERO, 1);
 235         checkOffset(test, createLDT(2008, 10, 29), OFFSET_ZERO, 1);
 236         checkOffset(test, createLDT(2008, 10, 30), OFFSET_ZERO, 1);
 237         checkOffset(test, createLDT(2008, 10, 31), OFFSET_ZERO, 1);
 238         // cutover at 01:00Z
 239         checkOffset(test, LocalDateTime.of(2008, 10, 26, 0, 59, 59, 999999999), OFFSET_PONE, 1);
 240         checkOffset(test, LocalDateTime.of(2008, 10, 26, 2, 0, 0, 0), OFFSET_ZERO, 1);
 241     }
 242 
 243     public void test_London_getOffsetInfo_gap() {
 244         ZoneRules test = europeLondon();
 245         final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 30, 1, 0, 0, 0);
 246         ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_ZERO, GAP);
 247         assertEquals(trans.isGap(), true);
 248         assertEquals(trans.isOverlap(), false);
 249         assertEquals(trans.getOffsetBefore(), OFFSET_ZERO);
 250         assertEquals(trans.getOffsetAfter(), OFFSET_PONE);
 251         assertEquals(trans.getInstant(), createInstant(2008, 3, 30, 1, 0, ZoneOffset.UTC));
 252         assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(2008, 3, 30, 1, 0));
 253         assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(2008, 3, 30, 2, 0));
 254         assertEquals(trans.isValidOffset(OFFSET_ZERO), false);
 255         assertEquals(trans.isValidOffset(OFFSET_PONE), false);
 256         assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
 257         assertEquals(trans.toString(), "Transition[Gap at 2008-03-30T01:00Z to +01:00]");
 258 
 259         assertFalse(trans.equals(null));
 260         assertFalse(trans.equals(OFFSET_ZERO));
 261         assertTrue(trans.equals(trans));
 262 
 263         final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
 264         assertTrue(trans.equals(otherTrans));
 265         assertEquals(trans.hashCode(), otherTrans.hashCode());
 266     }
 267 
 268     public void test_London_getOffsetInfo_overlap() {
 269         ZoneRules test = europeLondon();
 270         final LocalDateTime dateTime = LocalDateTime.of(2008, 10, 26, 1, 0, 0, 0);
 271         ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_PONE, OVERLAP);
 272         assertEquals(trans.isGap(), false);
 273         assertEquals(trans.isOverlap(), true);
 274         assertEquals(trans.getOffsetBefore(), OFFSET_PONE);
 275         assertEquals(trans.getOffsetAfter(), OFFSET_ZERO);
 276         assertEquals(trans.getInstant(), createInstant(2008, 10, 26, 1, 0, ZoneOffset.UTC));
 277         assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(2008, 10, 26, 2, 0));
 278         assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(2008, 10, 26, 1, 0));
 279         assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-1)), false);
 280         assertEquals(trans.isValidOffset(OFFSET_ZERO), true);
 281         assertEquals(trans.isValidOffset(OFFSET_PONE), true);
 282         assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
 283         assertEquals(trans.toString(), "Transition[Overlap at 2008-10-26T02:00+01:00 to Z]");
 284 
 285         assertFalse(trans.equals(null));
 286         assertFalse(trans.equals(OFFSET_PONE));
 287         assertTrue(trans.equals(trans));
 288 
 289         final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
 290         assertTrue(trans.equals(otherTrans));
 291         assertEquals(trans.hashCode(), otherTrans.hashCode());
 292     }
 293 
 294     public void test_London_getStandardOffset() {
 295         ZoneRules test = europeLondon();
 296         ZonedDateTime zdt = createZDT(1840, 1, 1, ZoneOffset.UTC);
 297         while (zdt.getYear() < 2010) {
 298             Instant instant = zdt.toInstant();
 299             if (zdt.getYear() < 1848) {
 300                 assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHoursMinutesSeconds(0, -1, -15));
 301             } else if (zdt.getYear() >= 1969 && zdt.getYear() < 1972) {
 302                 assertEquals(test.getStandardOffset(instant), OFFSET_PONE);
 303             } else {
 304                 assertEquals(test.getStandardOffset(instant), OFFSET_ZERO);
 305             }
 306             zdt = zdt.plusMonths(6);
 307         }
 308     }
 309 
 310     public void test_London_getTransitions() {
 311         ZoneRules test = europeLondon();
 312         List<ZoneOffsetTransition> trans = test.getTransitions();
 313 
 314         ZoneOffsetTransition first = trans.get(0);
 315         assertEquals(first.getDateTimeBefore(), LocalDateTime.of(1847, 12, 1, 0, 0));
 316         assertEquals(first.getOffsetBefore(), ZoneOffset.ofHoursMinutesSeconds(0, -1, -15));
 317         assertEquals(first.getOffsetAfter(), OFFSET_ZERO);
 318 
 319         ZoneOffsetTransition spring1916 = trans.get(1);
 320         assertEquals(spring1916.getDateTimeBefore(), LocalDateTime.of(1916, 5, 21, 2, 0));
 321         assertEquals(spring1916.getOffsetBefore(), OFFSET_ZERO);
 322         assertEquals(spring1916.getOffsetAfter(), OFFSET_PONE);
 323 
 324         ZoneOffsetTransition autumn1916 = trans.get(2);
 325         assertEquals(autumn1916.getDateTimeBefore(), LocalDateTime.of(1916, 10, 1, 3, 0));
 326         assertEquals(autumn1916.getOffsetBefore(), OFFSET_PONE);
 327         assertEquals(autumn1916.getOffsetAfter(), OFFSET_ZERO);
 328 
 329         ZoneOffsetTransition zot = null;
 330         Iterator<ZoneOffsetTransition> it = trans.iterator();
 331         while (it.hasNext()) {
 332             zot = it.next();
 333             if (zot.getDateTimeBefore().getYear() == 1990) {
 334                 break;
 335             }
 336         }
 337         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1990, 3, 25, 1, 0));
 338         assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
 339         zot = it.next();
 340         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1990, 10, 28, 2, 0));
 341         assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
 342         zot = it.next();
 343         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1991, 3, 31, 1, 0));
 344         assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
 345         zot = it.next();
 346         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1991, 10, 27, 2, 0));
 347         assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
 348         zot = it.next();
 349         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1992, 3, 29, 1, 0));
 350         assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
 351         zot = it.next();
 352         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1992, 10, 25, 2, 0));
 353         assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
 354         zot = it.next();
 355         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1993, 3, 28, 1, 0));
 356         assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
 357         zot = it.next();
 358         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1993, 10, 24, 2, 0));
 359         assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
 360         zot = it.next();
 361         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1994, 3, 27, 1, 0));
 362         assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
 363         zot = it.next();
 364         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1994, 10, 23, 2, 0));
 365         assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
 366         zot = it.next();
 367         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1995, 3, 26, 1, 0));
 368         assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
 369         zot = it.next();
 370         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1995, 10, 22, 2, 0));
 371         assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
 372         zot = it.next();
 373         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1996, 3, 31, 1, 0));
 374         assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
 375         zot = it.next();
 376         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1996, 10, 27, 2, 0));
 377         assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
 378         zot = it.next();
 379         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1997, 3, 30, 1, 0));
 380         assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
 381         zot = it.next();
 382         assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1997, 10, 26, 2, 0));
 383         assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
 384         assertEquals(it.hasNext(), false);
 385     }
 386 
 387     public void test_London_getTransitionRules() {
 388         ZoneRules test = europeLondon();
 389         List<ZoneOffsetTransitionRule> rules = test.getTransitionRules();
 390         assertEquals(rules.size(), 2);
 391 
 392         ZoneOffsetTransitionRule in = rules.get(0);
 393         assertEquals(in.getMonth(), Month.MARCH);
 394         assertEquals(in.getDayOfMonthIndicator(), 25);  // optimized from -1
 395         assertEquals(in.getDayOfWeek(), DayOfWeek.SUNDAY);
 396         assertEquals(in.getLocalTime(), LocalTime.of(1, 0));
 397         assertEquals(in.getTimeDefinition(), TimeDefinition.UTC);
 398         assertEquals(in.getStandardOffset(), OFFSET_ZERO);
 399         assertEquals(in.getOffsetBefore(), OFFSET_ZERO);
 400         assertEquals(in.getOffsetAfter(), OFFSET_PONE);
 401 
 402         ZoneOffsetTransitionRule out = rules.get(1);
 403         assertEquals(out.getMonth(), Month.OCTOBER);
 404         assertEquals(out.getDayOfMonthIndicator(), 25);  // optimized from -1
 405         assertEquals(out.getDayOfWeek(), DayOfWeek.SUNDAY);
 406         assertEquals(out.getLocalTime(), LocalTime.of(1, 0));
 407         assertEquals(out.getTimeDefinition(), TimeDefinition.UTC);
 408         assertEquals(out.getStandardOffset(), OFFSET_ZERO);
 409         assertEquals(out.getOffsetBefore(), OFFSET_PONE);
 410         assertEquals(out.getOffsetAfter(), OFFSET_ZERO);
 411     }
 412 
 413     //-----------------------------------------------------------------------
 414     public void test_London_nextTransition_historic() {
 415         ZoneRules test = europeLondon();
 416         List<ZoneOffsetTransition> trans = test.getTransitions();
 417 
 418         ZoneOffsetTransition first = trans.get(0);
 419         assertEquals(test.nextTransition(first.getInstant().minusNanos(1)), first);
 420 
 421         for (int i = 0; i < trans.size() - 1; i++) {
 422             ZoneOffsetTransition cur = trans.get(i);
 423             ZoneOffsetTransition next = trans.get(i + 1);
 424 
 425             assertEquals(test.nextTransition(cur.getInstant()), next);
 426             assertEquals(test.nextTransition(next.getInstant().minusNanos(1)), next);
 427         }
 428     }
 429 
 430     public void test_London_nextTransition_rulesBased() {
 431         ZoneRules test = europeLondon();
 432         List<ZoneOffsetTransitionRule> rules = test.getTransitionRules();
 433         List<ZoneOffsetTransition> trans = test.getTransitions();
 434 
 435         ZoneOffsetTransition last = trans.get(trans.size() - 1);
 436         assertEquals(test.nextTransition(last.getInstant()), rules.get(0).createTransition(1998));
 437 
 438         for (int year = 1998; year < 2010; year++) {
 439             ZoneOffsetTransition a = rules.get(0).createTransition(year);
 440             ZoneOffsetTransition b = rules.get(1).createTransition(year);
 441             ZoneOffsetTransition c = rules.get(0).createTransition(year + 1);
 442 
 443             assertEquals(test.nextTransition(a.getInstant()), b);
 444             assertEquals(test.nextTransition(b.getInstant().minusNanos(1)), b);
 445 
 446             assertEquals(test.nextTransition(b.getInstant()), c);
 447             assertEquals(test.nextTransition(c.getInstant().minusNanos(1)), c);
 448         }
 449     }
 450 
 451     public void test_London_nextTransition_lastYear() {
 452         ZoneRules test = europeLondon();
 453         List<ZoneOffsetTransitionRule> rules = test.getTransitionRules();
 454         ZoneOffsetTransition zot = rules.get(1).createTransition(Year.MAX_VALUE);
 455         assertEquals(test.nextTransition(zot.getInstant()), null);
 456     }
 457 
 458     //-----------------------------------------------------------------------
 459     public void test_London_previousTransition_historic() {
 460         ZoneRules test = europeLondon();
 461         List<ZoneOffsetTransition> trans = test.getTransitions();
 462 
 463         ZoneOffsetTransition first = trans.get(0);
 464         assertEquals(test.previousTransition(first.getInstant()), null);
 465         assertEquals(test.previousTransition(first.getInstant().minusNanos(1)), null);
 466 
 467         for (int i = 0; i < trans.size() - 1; i++) {
 468             ZoneOffsetTransition prev = trans.get(i);
 469             ZoneOffsetTransition cur = trans.get(i + 1);
 470 
 471             assertEquals(test.previousTransition(cur.getInstant()), prev);
 472             assertEquals(test.previousTransition(prev.getInstant().plusSeconds(1)), prev);
 473             assertEquals(test.previousTransition(prev.getInstant().plusNanos(1)), prev);
 474         }
 475     }
 476 
 477     public void test_London_previousTransition_rulesBased() {
 478         ZoneRules test = europeLondon();
 479         List<ZoneOffsetTransitionRule> rules = test.getTransitionRules();
 480         List<ZoneOffsetTransition> trans = test.getTransitions();
 481 
 482         ZoneOffsetTransition last = trans.get(trans.size() - 1);
 483         assertEquals(test.previousTransition(last.getInstant().plusSeconds(1)), last);
 484         assertEquals(test.previousTransition(last.getInstant().plusNanos(1)), last);
 485 
 486         // Jan 1st of year between transitions and rules
 487         ZonedDateTime odt = ZonedDateTime.ofInstant(last.getInstant(), last.getOffsetAfter());
 488         odt = odt.withDayOfYear(1).plusYears(1).with(LocalTime.MIDNIGHT);
 489         assertEquals(test.previousTransition(odt.toInstant()), last);
 490 
 491         // later years
 492         for (int year = 1998; year < 2010; year++) {
 493             ZoneOffsetTransition a = rules.get(0).createTransition(year);
 494             ZoneOffsetTransition b = rules.get(1).createTransition(year);
 495             ZoneOffsetTransition c = rules.get(0).createTransition(year + 1);
 496 
 497             assertEquals(test.previousTransition(c.getInstant()), b);
 498             assertEquals(test.previousTransition(b.getInstant().plusSeconds(1)), b);
 499             assertEquals(test.previousTransition(b.getInstant().plusNanos(1)), b);
 500 
 501             assertEquals(test.previousTransition(b.getInstant()), a);
 502             assertEquals(test.previousTransition(a.getInstant().plusSeconds(1)), a);
 503             assertEquals(test.previousTransition(a.getInstant().plusNanos(1)), a);
 504         }
 505     }
 506 
 507     //-----------------------------------------------------------------------
 508     // Europe/Paris
 509     //-----------------------------------------------------------------------
 510     private ZoneRules europeParis() {
 511         return ZoneId.of("Europe/Paris").getRules();
 512     }
 513 
 514     public void test_Paris() {
 515         ZoneRules test = europeParis();
 516         assertEquals(test.isFixedOffset(), false);
 517     }
 518 
 519     public void test_Paris_preTimeZones() {
 520         ZoneRules test = europeParis();
 521         ZonedDateTime old = createZDT(1800, 1, 1, ZoneOffset.UTC);
 522         Instant instant = old.toInstant();
 523         ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(0, 9, 21);
 524         assertEquals(test.getOffset(instant), offset);
 525         checkOffset(test, old.getDateTime(), offset, 1);
 526         assertEquals(test.getStandardOffset(instant), offset);
 527         assertEquals(test.getDaylightSavings(instant), Duration.ZERO);
 528         assertEquals(test.isDaylightSavings(instant), false);
 529     }
 530 
 531     public void test_Paris_getOffset() {
 532         ZoneRules test = europeParis();
 533         assertEquals(test.getOffset(createInstant(2008, 1, 1, ZoneOffset.UTC)), OFFSET_PONE);
 534         assertEquals(test.getOffset(createInstant(2008, 2, 1, ZoneOffset.UTC)), OFFSET_PONE);
 535         assertEquals(test.getOffset(createInstant(2008, 3, 1, ZoneOffset.UTC)), OFFSET_PONE);
 536         assertEquals(test.getOffset(createInstant(2008, 4, 1, ZoneOffset.UTC)), OFFSET_PTWO);
 537         assertEquals(test.getOffset(createInstant(2008, 5, 1, ZoneOffset.UTC)), OFFSET_PTWO);
 538         assertEquals(test.getOffset(createInstant(2008, 6, 1, ZoneOffset.UTC)), OFFSET_PTWO);
 539         assertEquals(test.getOffset(createInstant(2008, 7, 1, ZoneOffset.UTC)), OFFSET_PTWO);
 540         assertEquals(test.getOffset(createInstant(2008, 8, 1, ZoneOffset.UTC)), OFFSET_PTWO);
 541         assertEquals(test.getOffset(createInstant(2008, 9, 1, ZoneOffset.UTC)), OFFSET_PTWO);
 542         assertEquals(test.getOffset(createInstant(2008, 10, 1, ZoneOffset.UTC)), OFFSET_PTWO);
 543         assertEquals(test.getOffset(createInstant(2008, 11, 1, ZoneOffset.UTC)), OFFSET_PONE);
 544         assertEquals(test.getOffset(createInstant(2008, 12, 1, ZoneOffset.UTC)), OFFSET_PONE);
 545     }
 546 
 547     public void test_Paris_getOffset_toDST() {
 548         ZoneRules test = europeParis();
 549         assertEquals(test.getOffset(createInstant(2008, 3, 24, ZoneOffset.UTC)), OFFSET_PONE);
 550         assertEquals(test.getOffset(createInstant(2008, 3, 25, ZoneOffset.UTC)), OFFSET_PONE);
 551         assertEquals(test.getOffset(createInstant(2008, 3, 26, ZoneOffset.UTC)), OFFSET_PONE);
 552         assertEquals(test.getOffset(createInstant(2008, 3, 27, ZoneOffset.UTC)), OFFSET_PONE);
 553         assertEquals(test.getOffset(createInstant(2008, 3, 28, ZoneOffset.UTC)), OFFSET_PONE);
 554         assertEquals(test.getOffset(createInstant(2008, 3, 29, ZoneOffset.UTC)), OFFSET_PONE);
 555         assertEquals(test.getOffset(createInstant(2008, 3, 30, ZoneOffset.UTC)), OFFSET_PONE);
 556         assertEquals(test.getOffset(createInstant(2008, 3, 31, ZoneOffset.UTC)), OFFSET_PTWO);
 557         // cutover at 01:00Z
 558         assertEquals(test.getOffset(createInstant(2008, 3, 30, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_PONE);
 559         assertEquals(test.getOffset(createInstant(2008, 3, 30, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_PTWO);
 560     }
 561 
 562     public void test_Paris_getOffset_fromDST() {
 563         ZoneRules test = europeParis();
 564         assertEquals(test.getOffset(createInstant(2008, 10, 24, ZoneOffset.UTC)), OFFSET_PTWO);
 565         assertEquals(test.getOffset(createInstant(2008, 10, 25, ZoneOffset.UTC)), OFFSET_PTWO);
 566         assertEquals(test.getOffset(createInstant(2008, 10, 26, ZoneOffset.UTC)), OFFSET_PTWO);
 567         assertEquals(test.getOffset(createInstant(2008, 10, 27, ZoneOffset.UTC)), OFFSET_PONE);
 568         assertEquals(test.getOffset(createInstant(2008, 10, 28, ZoneOffset.UTC)), OFFSET_PONE);
 569         assertEquals(test.getOffset(createInstant(2008, 10, 29, ZoneOffset.UTC)), OFFSET_PONE);
 570         assertEquals(test.getOffset(createInstant(2008, 10, 30, ZoneOffset.UTC)), OFFSET_PONE);
 571         assertEquals(test.getOffset(createInstant(2008, 10, 31, ZoneOffset.UTC)), OFFSET_PONE);
 572         // cutover at 01:00Z
 573         assertEquals(test.getOffset(createInstant(2008, 10, 26, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_PTWO);
 574         assertEquals(test.getOffset(createInstant(2008, 10, 26, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_PONE);
 575     }
 576 
 577     public void test_Paris_getOffsetInfo() {
 578         ZoneRules test = europeParis();
 579         checkOffset(test, createLDT(2008, 1, 1), OFFSET_PONE, 1);
 580         checkOffset(test, createLDT(2008, 2, 1), OFFSET_PONE, 1);
 581         checkOffset(test, createLDT(2008, 3, 1), OFFSET_PONE, 1);
 582         checkOffset(test, createLDT(2008, 4, 1), OFFSET_PTWO, 1);
 583         checkOffset(test, createLDT(2008, 5, 1), OFFSET_PTWO, 1);
 584         checkOffset(test, createLDT(2008, 6, 1), OFFSET_PTWO, 1);
 585         checkOffset(test, createLDT(2008, 7, 1), OFFSET_PTWO, 1);
 586         checkOffset(test, createLDT(2008, 8, 1), OFFSET_PTWO, 1);
 587         checkOffset(test, createLDT(2008, 9, 1), OFFSET_PTWO, 1);
 588         checkOffset(test, createLDT(2008, 10, 1), OFFSET_PTWO, 1);
 589         checkOffset(test, createLDT(2008, 11, 1), OFFSET_PONE, 1);
 590         checkOffset(test, createLDT(2008, 12, 1), OFFSET_PONE, 1);
 591     }
 592 
 593     public void test_Paris_getOffsetInfo_toDST() {
 594         ZoneRules test = europeParis();
 595         checkOffset(test, createLDT(2008, 3, 24), OFFSET_PONE, 1);
 596         checkOffset(test, createLDT(2008, 3, 25), OFFSET_PONE, 1);
 597         checkOffset(test, createLDT(2008, 3, 26), OFFSET_PONE, 1);
 598         checkOffset(test, createLDT(2008, 3, 27), OFFSET_PONE, 1);
 599         checkOffset(test, createLDT(2008, 3, 28), OFFSET_PONE, 1);
 600         checkOffset(test, createLDT(2008, 3, 29), OFFSET_PONE, 1);
 601         checkOffset(test, createLDT(2008, 3, 30), OFFSET_PONE, 1);
 602         checkOffset(test, createLDT(2008, 3, 31), OFFSET_PTWO, 1);
 603         // cutover at 01:00Z which is 02:00+01:00(local Paris time)
 604         checkOffset(test, LocalDateTime.of(2008, 3, 30, 1, 59, 59, 999999999), OFFSET_PONE, 1);
 605         checkOffset(test, LocalDateTime.of(2008, 3, 30, 3, 0, 0, 0), OFFSET_PTWO, 1);
 606     }
 607 
 608     public void test_Paris_getOffsetInfo_fromDST() {
 609         ZoneRules test = europeParis();
 610         checkOffset(test, createLDT(2008, 10, 24), OFFSET_PTWO, 1);
 611         checkOffset(test, createLDT(2008, 10, 25), OFFSET_PTWO, 1);
 612         checkOffset(test, createLDT(2008, 10, 26), OFFSET_PTWO, 1);
 613         checkOffset(test, createLDT(2008, 10, 27), OFFSET_PONE, 1);
 614         checkOffset(test, createLDT(2008, 10, 28), OFFSET_PONE, 1);
 615         checkOffset(test, createLDT(2008, 10, 29), OFFSET_PONE, 1);
 616         checkOffset(test, createLDT(2008, 10, 30), OFFSET_PONE, 1);
 617         checkOffset(test, createLDT(2008, 10, 31), OFFSET_PONE, 1);
 618         // cutover at 01:00Z which is 02:00+01:00(local Paris time)
 619         checkOffset(test, LocalDateTime.of(2008, 10, 26, 1, 59, 59, 999999999), OFFSET_PTWO, 1);
 620         checkOffset(test, LocalDateTime.of(2008, 10, 26, 3, 0, 0, 0), OFFSET_PONE, 1);
 621     }
 622 
 623     public void test_Paris_getOffsetInfo_gap() {
 624         ZoneRules test = europeParis();
 625         final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 30, 2, 0, 0, 0);
 626         ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_PONE, GAP);
 627         assertEquals(trans.isGap(), true);
 628         assertEquals(trans.isOverlap(), false);
 629         assertEquals(trans.getOffsetBefore(), OFFSET_PONE);
 630         assertEquals(trans.getOffsetAfter(), OFFSET_PTWO);
 631         assertEquals(trans.getInstant(), createInstant(2008, 3, 30, 1, 0, ZoneOffset.UTC));
 632         assertEquals(trans.isValidOffset(OFFSET_ZERO), false);
 633         assertEquals(trans.isValidOffset(OFFSET_PONE), false);
 634         assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
 635         assertEquals(trans.toString(), "Transition[Gap at 2008-03-30T02:00+01:00 to +02:00]");
 636 
 637         assertFalse(trans.equals(null));
 638         assertFalse(trans.equals(OFFSET_PONE));
 639         assertTrue(trans.equals(trans));
 640 
 641         final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
 642         assertTrue(trans.equals(otherTrans));
 643         assertEquals(trans.hashCode(), otherTrans.hashCode());
 644     }
 645 
 646     public void test_Paris_getOffsetInfo_overlap() {
 647         ZoneRules test = europeParis();
 648         final LocalDateTime dateTime = LocalDateTime.of(2008, 10, 26, 2, 0, 0, 0);
 649         ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_PTWO, OVERLAP);
 650         assertEquals(trans.isGap(), false);
 651         assertEquals(trans.isOverlap(), true);
 652         assertEquals(trans.getOffsetBefore(), OFFSET_PTWO);
 653         assertEquals(trans.getOffsetAfter(), OFFSET_PONE);
 654         assertEquals(trans.getInstant(), createInstant(2008, 10, 26, 1, 0, ZoneOffset.UTC));
 655         assertEquals(trans.isValidOffset(OFFSET_ZERO), false);
 656         assertEquals(trans.isValidOffset(OFFSET_PONE), true);
 657         assertEquals(trans.isValidOffset(OFFSET_PTWO), true);
 658         assertEquals(trans.isValidOffset(ZoneOffset.ofHours(3)), false);
 659         assertEquals(trans.toString(), "Transition[Overlap at 2008-10-26T03:00+02:00 to +01:00]");
 660 
 661         assertFalse(trans.equals(null));
 662         assertFalse(trans.equals(OFFSET_PTWO));
 663         assertTrue(trans.equals(trans));
 664 
 665         final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
 666         assertTrue(trans.equals(otherTrans));
 667         assertEquals(trans.hashCode(), otherTrans.hashCode());
 668     }
 669 
 670     public void test_Paris_getStandardOffset() {
 671         ZoneRules test = europeParis();
 672         ZonedDateTime zdt = createZDT(1840, 1, 1, ZoneOffset.UTC);
 673         while (zdt.getYear() < 2010) {
 674             Instant instant = zdt.toInstant();
 675             if (zdt.getDate().isBefore(LocalDate.of(1911, 3, 11))) {
 676                 assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHoursMinutesSeconds(0, 9, 21));
 677             } else if (zdt.getDate().isBefore(LocalDate.of(1940, 6, 14))) {
 678                 assertEquals(test.getStandardOffset(instant), OFFSET_ZERO);
 679             } else if (zdt.getDate().isBefore(LocalDate.of(1944, 8, 25))) {
 680                 assertEquals(test.getStandardOffset(instant), OFFSET_PONE);
 681             } else if (zdt.getDate().isBefore(LocalDate.of(1945, 9, 16))) {
 682                 assertEquals(test.getStandardOffset(instant), OFFSET_ZERO);
 683             } else {
 684                 assertEquals(test.getStandardOffset(instant), OFFSET_PONE);
 685             }
 686             zdt = zdt.plusMonths(6);
 687         }
 688     }
 689 
 690     //-----------------------------------------------------------------------
 691     // America/New_York
 692     //-----------------------------------------------------------------------
 693     private ZoneRules americaNewYork() {
 694         return ZoneId.of("America/New_York").getRules();
 695     }
 696 
 697     public void test_NewYork() {
 698         ZoneRules test = americaNewYork();
 699         assertEquals(test.isFixedOffset(), false);
 700     }
 701 
 702     public void test_NewYork_preTimeZones() {
 703         ZoneRules test = americaNewYork();
 704         ZonedDateTime old = createZDT(1800, 1, 1, ZoneOffset.UTC);
 705         Instant instant = old.toInstant();
 706         ZoneOffset offset = ZoneOffset.of("-04:56:02");
 707         assertEquals(test.getOffset(instant), offset);
 708         checkOffset(test, old.getDateTime(), offset, 1);
 709         assertEquals(test.getStandardOffset(instant), offset);
 710         assertEquals(test.getDaylightSavings(instant), Duration.ZERO);
 711         assertEquals(test.isDaylightSavings(instant), false);
 712     }
 713 
 714     public void test_NewYork_getOffset() {
 715         ZoneRules test = americaNewYork();
 716         ZoneOffset offset = ZoneOffset.ofHours(-5);
 717         assertEquals(test.getOffset(createInstant(2008, 1, 1, offset)), ZoneOffset.ofHours(-5));
 718         assertEquals(test.getOffset(createInstant(2008, 2, 1, offset)), ZoneOffset.ofHours(-5));
 719         assertEquals(test.getOffset(createInstant(2008, 3, 1, offset)), ZoneOffset.ofHours(-5));
 720         assertEquals(test.getOffset(createInstant(2008, 4, 1, offset)), ZoneOffset.ofHours(-4));
 721         assertEquals(test.getOffset(createInstant(2008, 5, 1, offset)), ZoneOffset.ofHours(-4));
 722         assertEquals(test.getOffset(createInstant(2008, 6, 1, offset)), ZoneOffset.ofHours(-4));
 723         assertEquals(test.getOffset(createInstant(2008, 7, 1, offset)), ZoneOffset.ofHours(-4));
 724         assertEquals(test.getOffset(createInstant(2008, 8, 1, offset)), ZoneOffset.ofHours(-4));
 725         assertEquals(test.getOffset(createInstant(2008, 9, 1, offset)), ZoneOffset.ofHours(-4));
 726         assertEquals(test.getOffset(createInstant(2008, 10, 1, offset)), ZoneOffset.ofHours(-4));
 727         assertEquals(test.getOffset(createInstant(2008, 11, 1, offset)), ZoneOffset.ofHours(-4));
 728         assertEquals(test.getOffset(createInstant(2008, 12, 1, offset)), ZoneOffset.ofHours(-5));
 729         assertEquals(test.getOffset(createInstant(2008, 1, 28, offset)), ZoneOffset.ofHours(-5));
 730         assertEquals(test.getOffset(createInstant(2008, 2, 28, offset)), ZoneOffset.ofHours(-5));
 731         assertEquals(test.getOffset(createInstant(2008, 3, 28, offset)), ZoneOffset.ofHours(-4));
 732         assertEquals(test.getOffset(createInstant(2008, 4, 28, offset)), ZoneOffset.ofHours(-4));
 733         assertEquals(test.getOffset(createInstant(2008, 5, 28, offset)), ZoneOffset.ofHours(-4));
 734         assertEquals(test.getOffset(createInstant(2008, 6, 28, offset)), ZoneOffset.ofHours(-4));
 735         assertEquals(test.getOffset(createInstant(2008, 7, 28, offset)), ZoneOffset.ofHours(-4));
 736         assertEquals(test.getOffset(createInstant(2008, 8, 28, offset)), ZoneOffset.ofHours(-4));
 737         assertEquals(test.getOffset(createInstant(2008, 9, 28, offset)), ZoneOffset.ofHours(-4));
 738         assertEquals(test.getOffset(createInstant(2008, 10, 28, offset)), ZoneOffset.ofHours(-4));
 739         assertEquals(test.getOffset(createInstant(2008, 11, 28, offset)), ZoneOffset.ofHours(-5));
 740         assertEquals(test.getOffset(createInstant(2008, 12, 28, offset)), ZoneOffset.ofHours(-5));
 741     }
 742 
 743     public void test_NewYork_getOffset_toDST() {
 744         ZoneRules test = americaNewYork();
 745         ZoneOffset offset = ZoneOffset.ofHours(-5);
 746         assertEquals(test.getOffset(createInstant(2008, 3, 8, offset)), ZoneOffset.ofHours(-5));
 747         assertEquals(test.getOffset(createInstant(2008, 3, 9, offset)), ZoneOffset.ofHours(-5));
 748         assertEquals(test.getOffset(createInstant(2008, 3, 10, offset)), ZoneOffset.ofHours(-4));
 749         assertEquals(test.getOffset(createInstant(2008, 3, 11, offset)), ZoneOffset.ofHours(-4));
 750         assertEquals(test.getOffset(createInstant(2008, 3, 12, offset)), ZoneOffset.ofHours(-4));
 751         assertEquals(test.getOffset(createInstant(2008, 3, 13, offset)), ZoneOffset.ofHours(-4));
 752         assertEquals(test.getOffset(createInstant(2008, 3, 14, offset)), ZoneOffset.ofHours(-4));
 753         // cutover at 02:00 local
 754         assertEquals(test.getOffset(createInstant(2008, 3, 9, 1, 59, 59, 999999999, offset)), ZoneOffset.ofHours(-5));
 755         assertEquals(test.getOffset(createInstant(2008, 3, 9, 2, 0, 0, 0, offset)), ZoneOffset.ofHours(-4));
 756     }
 757 
 758     public void test_NewYork_getOffset_fromDST() {
 759         ZoneRules test = americaNewYork();
 760         ZoneOffset offset = ZoneOffset.ofHours(-4);
 761         assertEquals(test.getOffset(createInstant(2008, 11, 1, offset)), ZoneOffset.ofHours(-4));
 762         assertEquals(test.getOffset(createInstant(2008, 11, 2, offset)), ZoneOffset.ofHours(-4));
 763         assertEquals(test.getOffset(createInstant(2008, 11, 3, offset)), ZoneOffset.ofHours(-5));
 764         assertEquals(test.getOffset(createInstant(2008, 11, 4, offset)), ZoneOffset.ofHours(-5));
 765         assertEquals(test.getOffset(createInstant(2008, 11, 5, offset)), ZoneOffset.ofHours(-5));
 766         assertEquals(test.getOffset(createInstant(2008, 11, 6, offset)), ZoneOffset.ofHours(-5));
 767         assertEquals(test.getOffset(createInstant(2008, 11, 7, offset)), ZoneOffset.ofHours(-5));
 768         // cutover at 02:00 local
 769         assertEquals(test.getOffset(createInstant(2008, 11, 2, 1, 59, 59, 999999999, offset)), ZoneOffset.ofHours(-4));
 770         assertEquals(test.getOffset(createInstant(2008, 11, 2, 2, 0, 0, 0, offset)), ZoneOffset.ofHours(-5));
 771     }
 772 
 773     public void test_NewYork_getOffsetInfo() {
 774         ZoneRules test = americaNewYork();
 775         checkOffset(test, createLDT(2008, 1, 1), ZoneOffset.ofHours(-5), 1);
 776         checkOffset(test, createLDT(2008, 2, 1), ZoneOffset.ofHours(-5), 1);
 777         checkOffset(test, createLDT(2008, 3, 1), ZoneOffset.ofHours(-5), 1);
 778         checkOffset(test, createLDT(2008, 4, 1), ZoneOffset.ofHours(-4), 1);
 779         checkOffset(test, createLDT(2008, 5, 1), ZoneOffset.ofHours(-4), 1);
 780         checkOffset(test, createLDT(2008, 6, 1), ZoneOffset.ofHours(-4), 1);
 781         checkOffset(test, createLDT(2008, 7, 1), ZoneOffset.ofHours(-4), 1);
 782         checkOffset(test, createLDT(2008, 8, 1), ZoneOffset.ofHours(-4), 1);
 783         checkOffset(test, createLDT(2008, 9, 1), ZoneOffset.ofHours(-4), 1);
 784         checkOffset(test, createLDT(2008, 10, 1), ZoneOffset.ofHours(-4), 1);
 785         checkOffset(test, createLDT(2008, 11, 1), ZoneOffset.ofHours(-4), 1);
 786         checkOffset(test, createLDT(2008, 12, 1), ZoneOffset.ofHours(-5), 1);
 787         checkOffset(test, createLDT(2008, 1, 28), ZoneOffset.ofHours(-5), 1);
 788         checkOffset(test, createLDT(2008, 2, 28), ZoneOffset.ofHours(-5), 1);
 789         checkOffset(test, createLDT(2008, 3, 28), ZoneOffset.ofHours(-4), 1);
 790         checkOffset(test, createLDT(2008, 4, 28), ZoneOffset.ofHours(-4), 1);
 791         checkOffset(test, createLDT(2008, 5, 28), ZoneOffset.ofHours(-4), 1);
 792         checkOffset(test, createLDT(2008, 6, 28), ZoneOffset.ofHours(-4), 1);
 793         checkOffset(test, createLDT(2008, 7, 28), ZoneOffset.ofHours(-4), 1);
 794         checkOffset(test, createLDT(2008, 8, 28), ZoneOffset.ofHours(-4), 1);
 795         checkOffset(test, createLDT(2008, 9, 28), ZoneOffset.ofHours(-4), 1);
 796         checkOffset(test, createLDT(2008, 10, 28), ZoneOffset.ofHours(-4), 1);
 797         checkOffset(test, createLDT(2008, 11, 28), ZoneOffset.ofHours(-5), 1);
 798         checkOffset(test, createLDT(2008, 12, 28), ZoneOffset.ofHours(-5), 1);
 799     }
 800 
 801     public void test_NewYork_getOffsetInfo_toDST() {
 802         ZoneRules test = americaNewYork();
 803         checkOffset(test, createLDT(2008, 3, 8), ZoneOffset.ofHours(-5), 1);
 804         checkOffset(test, createLDT(2008, 3, 9), ZoneOffset.ofHours(-5), 1);
 805         checkOffset(test, createLDT(2008, 3, 10), ZoneOffset.ofHours(-4), 1);
 806         checkOffset(test, createLDT(2008, 3, 11), ZoneOffset.ofHours(-4), 1);
 807         checkOffset(test, createLDT(2008, 3, 12), ZoneOffset.ofHours(-4), 1);
 808         checkOffset(test, createLDT(2008, 3, 13), ZoneOffset.ofHours(-4), 1);
 809         checkOffset(test, createLDT(2008, 3, 14), ZoneOffset.ofHours(-4), 1);
 810         // cutover at 02:00 local
 811         checkOffset(test, LocalDateTime.of(2008, 3, 9, 1, 59, 59, 999999999), ZoneOffset.ofHours(-5), 1);
 812         checkOffset(test, LocalDateTime.of(2008, 3, 9, 3, 0, 0, 0), ZoneOffset.ofHours(-4), 1);
 813     }
 814 
 815     public void test_NewYork_getOffsetInfo_fromDST() {
 816         ZoneRules test = americaNewYork();
 817         checkOffset(test, createLDT(2008, 11, 1), ZoneOffset.ofHours(-4), 1);
 818         checkOffset(test, createLDT(2008, 11, 2), ZoneOffset.ofHours(-4), 1);
 819         checkOffset(test, createLDT(2008, 11, 3), ZoneOffset.ofHours(-5), 1);
 820         checkOffset(test, createLDT(2008, 11, 4), ZoneOffset.ofHours(-5), 1);
 821         checkOffset(test, createLDT(2008, 11, 5), ZoneOffset.ofHours(-5), 1);
 822         checkOffset(test, createLDT(2008, 11, 6), ZoneOffset.ofHours(-5), 1);
 823         checkOffset(test, createLDT(2008, 11, 7), ZoneOffset.ofHours(-5), 1);
 824         // cutover at 02:00 local
 825         checkOffset(test, LocalDateTime.of(2008, 11, 2, 0, 59, 59, 999999999), ZoneOffset.ofHours(-4), 1);
 826         checkOffset(test, LocalDateTime.of(2008, 11, 2, 2, 0, 0, 0), ZoneOffset.ofHours(-5), 1);
 827     }
 828 
 829     public void test_NewYork_getOffsetInfo_gap() {
 830         ZoneRules test = americaNewYork();
 831         final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 9, 2, 0, 0, 0);
 832         ZoneOffsetTransition trans = checkOffset(test, dateTime, ZoneOffset.ofHours(-5), GAP);
 833         assertEquals(trans.isGap(), true);
 834         assertEquals(trans.isOverlap(), false);
 835         assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(-5));
 836         assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(-4));
 837         assertEquals(trans.getInstant(), createInstant(2008, 3, 9, 2, 0, ZoneOffset.ofHours(-5)));
 838         assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
 839         assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-5)), false);
 840         assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-4)), false);
 841         assertEquals(trans.toString(), "Transition[Gap at 2008-03-09T02:00-05:00 to -04:00]");
 842 
 843         assertFalse(trans.equals(null));
 844         assertFalse(trans.equals(ZoneOffset.ofHours(-5)));
 845         assertTrue(trans.equals(trans));
 846 
 847         final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
 848         assertTrue(trans.equals(otherTrans));
 849         assertEquals(trans.hashCode(), otherTrans.hashCode());
 850     }
 851 
 852     public void test_NewYork_getOffsetInfo_overlap() {
 853         ZoneRules test = americaNewYork();
 854         final LocalDateTime dateTime = LocalDateTime.of(2008, 11, 2, 1, 0, 0, 0);
 855         ZoneOffsetTransition trans = checkOffset(test, dateTime, ZoneOffset.ofHours(-4), OVERLAP);
 856         assertEquals(trans.isGap(), false);
 857         assertEquals(trans.isOverlap(), true);
 858         assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(-4));
 859         assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(-5));
 860         assertEquals(trans.getInstant(), createInstant(2008, 11, 2, 2, 0, ZoneOffset.ofHours(-4)));
 861         assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-1)), false);
 862         assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-5)), true);
 863         assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-4)), true);
 864         assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
 865         assertEquals(trans.toString(), "Transition[Overlap at 2008-11-02T02:00-04:00 to -05:00]");
 866 
 867         assertFalse(trans.equals(null));
 868         assertFalse(trans.equals(ZoneOffset.ofHours(-4)));
 869         assertTrue(trans.equals(trans));
 870 
 871         final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
 872         assertTrue(trans.equals(otherTrans));
 873         assertEquals(trans.hashCode(), otherTrans.hashCode());
 874     }
 875 
 876     public void test_NewYork_getStandardOffset() {
 877         ZoneRules test = americaNewYork();
 878         ZonedDateTime dateTime = createZDT(1860, 1, 1, ZoneOffset.UTC);
 879         while (dateTime.getYear() < 2010) {
 880             Instant instant = dateTime.toInstant();
 881             if (dateTime.getDate().isBefore(LocalDate.of(1883, 11, 18))) {
 882                 assertEquals(test.getStandardOffset(instant), ZoneOffset.of("-04:56:02"));
 883             } else {
 884                 assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHours(-5));
 885             }
 886             dateTime = dateTime.plusMonths(6);
 887         }
 888     }
 889 
 890     //-----------------------------------------------------------------------
 891     // Kathmandu
 892     //-----------------------------------------------------------------------
 893     private ZoneRules asiaKathmandu() {
 894         return ZoneId.of("Asia/Kathmandu").getRules();
 895     }
 896 
 897     public void test_Kathmandu_nextTransition_historic() {
 898         ZoneRules test = asiaKathmandu();
 899         List<ZoneOffsetTransition> trans = test.getTransitions();
 900 
 901         ZoneOffsetTransition first = trans.get(0);
 902         assertEquals(test.nextTransition(first.getInstant().minusNanos(1)), first);
 903 
 904         for (int i = 0; i < trans.size() - 1; i++) {
 905             ZoneOffsetTransition cur = trans.get(i);
 906             ZoneOffsetTransition next = trans.get(i + 1);
 907 
 908             assertEquals(test.nextTransition(cur.getInstant()), next);
 909             assertEquals(test.nextTransition(next.getInstant().minusNanos(1)), next);
 910         }
 911     }
 912 
 913     public void test_Kathmandu_nextTransition_noRules() {
 914         ZoneRules test = asiaKathmandu();
 915         List<ZoneOffsetTransition> trans = test.getTransitions();
 916 
 917         ZoneOffsetTransition last = trans.get(trans.size() - 1);
 918         assertEquals(test.nextTransition(last.getInstant()), null);
 919     }
 920 
 921     //-------------------------------------------------------------------------
 922     @Test(expectedExceptions=UnsupportedOperationException.class)
 923     public void test_getTransitions_immutable() {
 924         ZoneRules test = europeParis();
 925         test.getTransitions().clear();
 926     }
 927 
 928     @Test(expectedExceptions=UnsupportedOperationException.class)
 929     public void test_getTransitionRules_immutable() {
 930         ZoneRules test = europeParis();
 931         test.getTransitionRules().clear();
 932     }
 933 
 934     //-----------------------------------------------------------------------
 935     // equals() / hashCode()
 936     //-----------------------------------------------------------------------
 937     public void test_equals() {
 938         ZoneRules test1 = europeLondon();
 939         ZoneRules test2 = europeParis();
 940         ZoneRules test2b = europeParis();
 941         assertEquals(test1.equals(test2), false);
 942         assertEquals(test2.equals(test1), false);
 943 
 944         assertEquals(test1.equals(test1), true);
 945         assertEquals(test2.equals(test2), true);
 946         assertEquals(test2.equals(test2b), true);
 947 
 948         assertEquals(test1.hashCode() == test1.hashCode(), true);
 949         assertEquals(test2.hashCode() == test2.hashCode(), true);
 950         assertEquals(test2.hashCode() == test2b.hashCode(), true);
 951     }
 952 
 953     public void test_equals_null() {
 954         assertEquals(europeLondon().equals(null), false);
 955     }
 956 
 957     public void test_equals_notZoneRules() {
 958         assertEquals(europeLondon().equals("Europe/London"), false);
 959     }
 960 
 961     public void test_toString() {
 962         assertEquals(europeLondon().toString().contains("ZoneRules"), true);
 963     }
 964 
 965     //-----------------------------------------------------------------------
 966     //-----------------------------------------------------------------------
 967     //-----------------------------------------------------------------------
 968     private Instant createInstant(int year, int month, int day, ZoneOffset offset) {
 969         return LocalDateTime.of(year, month, day, 0, 0).toInstant(offset);
 970     }
 971 
 972     private Instant createInstant(int year, int month, int day, int hour, int min, ZoneOffset offset) {
 973         return LocalDateTime.of(year, month, day, hour, min).toInstant(offset);
 974     }
 975 
 976     private Instant createInstant(int year, int month, int day, int hour, int min, int sec, int nano, ZoneOffset offset) {
 977         return LocalDateTime.of(year, month, day, hour, min, sec, nano).toInstant(offset);
 978     }
 979 
 980     private ZonedDateTime createZDT(int year, int month, int day, ZoneId zone) {
 981         return LocalDateTime.of(year, month, day, 0, 0).atZone(zone);
 982     }
 983 
 984     private LocalDateTime createLDT(int year, int month, int day) {
 985         return LocalDateTime.of(year, month, day, 0, 0);
 986     }
 987 
 988     private ZoneOffsetTransition checkOffset(ZoneRules rules, LocalDateTime dateTime, ZoneOffset offset, int type) {
 989         List<ZoneOffset> validOffsets = rules.getValidOffsets(dateTime);
 990         assertEquals(validOffsets.size(), type);
 991         assertEquals(rules.getOffset(dateTime), offset);
 992         if (type == 1) {
 993             assertEquals(validOffsets.get(0), offset);
 994             return null;
 995         } else {
 996             ZoneOffsetTransition zot = rules.getTransition(dateTime);
 997             assertNotNull(zot);
 998             assertEquals(zot.isOverlap(), type == 2);
 999             assertEquals(zot.isGap(), type == 0);
1000             assertEquals(zot.isValidOffset(offset), type == 2);
1001             return zot;
1002         }
1003     }
1004 
1005 }