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 */
60package tck.java.time.zone;
61
62import static org.testng.Assert.assertEquals;
63import static org.testng.Assert.assertFalse;
64import static org.testng.Assert.assertNotNull;
65import static org.testng.Assert.assertTrue;
66
67import java.io.ByteArrayInputStream;
68import java.io.ByteArrayOutputStream;
69import java.io.ObjectInputStream;
70import java.io.ObjectOutputStream;
71import java.time.DayOfWeek;
72import java.time.Duration;
73import java.time.Instant;
74import java.time.LocalDate;
75import java.time.LocalDateTime;
76import java.time.LocalTime;
77import java.time.Month;
78import java.time.OffsetDateTime;
79import java.time.Year;
80import java.time.ZoneId;
81import java.time.ZoneOffset;
82import java.time.ZonedDateTime;
83import java.time.zone.ZoneOffsetTransition;
84import java.time.zone.ZoneOffsetTransitionRule;
85import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition;
86import java.time.zone.ZoneRules;
87import java.util.ArrayList;
88import java.util.Iterator;
89import java.util.List;
90
91import org.testng.annotations.Test;
92
93/**
94 * Test ZoneRules.
95 */
96@Test
97public class TCKZoneRules {
98
99    private static final ZoneOffset OFFSET_ZERO = ZoneOffset.ofHours(0);
100    private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
101    private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
102    public static final String LATEST_TZDB = "2009b";
103    private static final int OVERLAP = 2;
104    private static final int GAP = 0;
105
106
107
108    //-----------------------------------------------------------------------
109    // Europe/London
110    //-----------------------------------------------------------------------
111    private ZoneRules europeLondon() {
112        return ZoneId.of("Europe/London").getRules();
113    }
114
115    public void test_London() {
116        ZoneRules test = europeLondon();
117        assertEquals(test.isFixedOffset(), false);
118    }
119
120    public void test_London_preTimeZones() {
121        ZoneRules test = europeLondon();
122        ZonedDateTime old = createZDT(1800, 1, 1, ZoneOffset.UTC);
123        Instant instant = old.toInstant();
124        ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(0, -1, -15);
125        assertEquals(test.getOffset(instant), offset);
126        checkOffset(test, old.toLocalDateTime(), offset, 1);
127        assertEquals(test.getStandardOffset(instant), offset);
128        assertEquals(test.getDaylightSavings(instant), Duration.ZERO);
129        assertEquals(test.isDaylightSavings(instant), false);
130    }
131
132    public void test_London_getOffset() {
133        ZoneRules test = europeLondon();
134        assertEquals(test.getOffset(createInstant(2008, 1, 1, ZoneOffset.UTC)), OFFSET_ZERO);
135        assertEquals(test.getOffset(createInstant(2008, 2, 1, ZoneOffset.UTC)), OFFSET_ZERO);
136        assertEquals(test.getOffset(createInstant(2008, 3, 1, ZoneOffset.UTC)), OFFSET_ZERO);
137        assertEquals(test.getOffset(createInstant(2008, 4, 1, ZoneOffset.UTC)), OFFSET_PONE);
138        assertEquals(test.getOffset(createInstant(2008, 5, 1, ZoneOffset.UTC)), OFFSET_PONE);
139        assertEquals(test.getOffset(createInstant(2008, 6, 1, ZoneOffset.UTC)), OFFSET_PONE);
140        assertEquals(test.getOffset(createInstant(2008, 7, 1, ZoneOffset.UTC)), OFFSET_PONE);
141        assertEquals(test.getOffset(createInstant(2008, 8, 1, ZoneOffset.UTC)), OFFSET_PONE);
142        assertEquals(test.getOffset(createInstant(2008, 9, 1, ZoneOffset.UTC)), OFFSET_PONE);
143        assertEquals(test.getOffset(createInstant(2008, 10, 1, ZoneOffset.UTC)), OFFSET_PONE);
144        assertEquals(test.getOffset(createInstant(2008, 11, 1, ZoneOffset.UTC)), OFFSET_ZERO);
145        assertEquals(test.getOffset(createInstant(2008, 12, 1, ZoneOffset.UTC)), OFFSET_ZERO);
146    }
147
148    public void test_London_getOffset_toDST() {
149        ZoneRules test = europeLondon();
150        assertEquals(test.getOffset(createInstant(2008, 3, 24, ZoneOffset.UTC)), OFFSET_ZERO);
151        assertEquals(test.getOffset(createInstant(2008, 3, 25, ZoneOffset.UTC)), OFFSET_ZERO);
152        assertEquals(test.getOffset(createInstant(2008, 3, 26, ZoneOffset.UTC)), OFFSET_ZERO);
153        assertEquals(test.getOffset(createInstant(2008, 3, 27, ZoneOffset.UTC)), OFFSET_ZERO);
154        assertEquals(test.getOffset(createInstant(2008, 3, 28, ZoneOffset.UTC)), OFFSET_ZERO);
155        assertEquals(test.getOffset(createInstant(2008, 3, 29, ZoneOffset.UTC)), OFFSET_ZERO);
156        assertEquals(test.getOffset(createInstant(2008, 3, 30, ZoneOffset.UTC)), OFFSET_ZERO);
157        assertEquals(test.getOffset(createInstant(2008, 3, 31, ZoneOffset.UTC)), OFFSET_PONE);
158        // cutover at 01:00Z
159        assertEquals(test.getOffset(createInstant(2008, 3, 30, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_ZERO);
160        assertEquals(test.getOffset(createInstant(2008, 3, 30, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_PONE);
161    }
162
163    public void test_London_getOffset_fromDST() {
164        ZoneRules test = europeLondon();
165        assertEquals(test.getOffset(createInstant(2008, 10, 24, ZoneOffset.UTC)), OFFSET_PONE);
166        assertEquals(test.getOffset(createInstant(2008, 10, 25, ZoneOffset.UTC)), OFFSET_PONE);
167        assertEquals(test.getOffset(createInstant(2008, 10, 26, ZoneOffset.UTC)), OFFSET_PONE);
168        assertEquals(test.getOffset(createInstant(2008, 10, 27, ZoneOffset.UTC)), OFFSET_ZERO);
169        assertEquals(test.getOffset(createInstant(2008, 10, 28, ZoneOffset.UTC)), OFFSET_ZERO);
170        assertEquals(test.getOffset(createInstant(2008, 10, 29, ZoneOffset.UTC)), OFFSET_ZERO);
171        assertEquals(test.getOffset(createInstant(2008, 10, 30, ZoneOffset.UTC)), OFFSET_ZERO);
172        assertEquals(test.getOffset(createInstant(2008, 10, 31, ZoneOffset.UTC)), OFFSET_ZERO);
173        // cutover at 01:00Z
174        assertEquals(test.getOffset(createInstant(2008, 10, 26, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_PONE);
175        assertEquals(test.getOffset(createInstant(2008, 10, 26, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_ZERO);
176    }
177
178    public void test_London_getOffsetInfo() {
179        ZoneRules test = europeLondon();
180        checkOffset(test, createLDT(2008, 1, 1), OFFSET_ZERO, 1);
181        checkOffset(test, createLDT(2008, 2, 1), OFFSET_ZERO, 1);
182        checkOffset(test, createLDT(2008, 3, 1), OFFSET_ZERO, 1);
183        checkOffset(test, createLDT(2008, 4, 1), OFFSET_PONE, 1);
184        checkOffset(test, createLDT(2008, 5, 1), OFFSET_PONE, 1);
185        checkOffset(test, createLDT(2008, 6, 1), OFFSET_PONE, 1);
186        checkOffset(test, createLDT(2008, 7, 1), OFFSET_PONE, 1);
187        checkOffset(test, createLDT(2008, 8, 1), OFFSET_PONE, 1);
188        checkOffset(test, createLDT(2008, 9, 1), OFFSET_PONE, 1);
189        checkOffset(test, createLDT(2008, 10, 1), OFFSET_PONE, 1);
190        checkOffset(test, createLDT(2008, 11, 1), OFFSET_ZERO, 1);
191        checkOffset(test, createLDT(2008, 12, 1), OFFSET_ZERO, 1);
192    }
193
194    public void test_London_getOffsetInfo_toDST() {
195        ZoneRules test = europeLondon();
196        checkOffset(test, createLDT(2008, 3, 24), OFFSET_ZERO, 1);
197        checkOffset(test, createLDT(2008, 3, 25), OFFSET_ZERO, 1);
198        checkOffset(test, createLDT(2008, 3, 26), OFFSET_ZERO, 1);
199        checkOffset(test, createLDT(2008, 3, 27), OFFSET_ZERO, 1);
200        checkOffset(test, createLDT(2008, 3, 28), OFFSET_ZERO, 1);
201        checkOffset(test, createLDT(2008, 3, 29), OFFSET_ZERO, 1);
202        checkOffset(test, createLDT(2008, 3, 30), OFFSET_ZERO, 1);
203        checkOffset(test, createLDT(2008, 3, 31), OFFSET_PONE, 1);
204        // cutover at 01:00Z
205        checkOffset(test, LocalDateTime.of(2008, 3, 30, 0, 59, 59, 999999999), OFFSET_ZERO, 1);
206        checkOffset(test, LocalDateTime.of(2008, 3, 30, 2, 0, 0, 0), OFFSET_PONE, 1);
207    }
208
209    public void test_London_getOffsetInfo_fromDST() {
210        ZoneRules test = europeLondon();
211        checkOffset(test, createLDT(2008, 10, 24), OFFSET_PONE, 1);
212        checkOffset(test, createLDT(2008, 10, 25), OFFSET_PONE, 1);
213        checkOffset(test, createLDT(2008, 10, 26), OFFSET_PONE, 1);
214        checkOffset(test, createLDT(2008, 10, 27), OFFSET_ZERO, 1);
215        checkOffset(test, createLDT(2008, 10, 28), OFFSET_ZERO, 1);
216        checkOffset(test, createLDT(2008, 10, 29), OFFSET_ZERO, 1);
217        checkOffset(test, createLDT(2008, 10, 30), OFFSET_ZERO, 1);
218        checkOffset(test, createLDT(2008, 10, 31), OFFSET_ZERO, 1);
219        // cutover at 01:00Z
220        checkOffset(test, LocalDateTime.of(2008, 10, 26, 0, 59, 59, 999999999), OFFSET_PONE, 1);
221        checkOffset(test, LocalDateTime.of(2008, 10, 26, 2, 0, 0, 0), OFFSET_ZERO, 1);
222    }
223
224    public void test_London_getOffsetInfo_gap() {
225        ZoneRules test = europeLondon();
226        final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 30, 1, 0, 0, 0);
227        ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_ZERO, GAP);
228        assertEquals(trans.isGap(), true);
229        assertEquals(trans.isOverlap(), false);
230        assertEquals(trans.getOffsetBefore(), OFFSET_ZERO);
231        assertEquals(trans.getOffsetAfter(), OFFSET_PONE);
232        assertEquals(trans.getInstant(), createInstant(2008, 3, 30, 1, 0, ZoneOffset.UTC));
233        assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(2008, 3, 30, 1, 0));
234        assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(2008, 3, 30, 2, 0));
235        assertEquals(trans.isValidOffset(OFFSET_ZERO), false);
236        assertEquals(trans.isValidOffset(OFFSET_PONE), false);
237        assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
238        assertEquals(trans.toString(), "Transition[Gap at 2008-03-30T01:00Z to +01:00]");
239
240        assertFalse(trans.equals(null));
241        assertFalse(trans.equals(OFFSET_ZERO));
242        assertTrue(trans.equals(trans));
243
244        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
245        assertTrue(trans.equals(otherTrans));
246        assertEquals(trans.hashCode(), otherTrans.hashCode());
247    }
248
249    public void test_London_getOffsetInfo_overlap() {
250        ZoneRules test = europeLondon();
251        final LocalDateTime dateTime = LocalDateTime.of(2008, 10, 26, 1, 0, 0, 0);
252        ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_PONE, OVERLAP);
253        assertEquals(trans.isGap(), false);
254        assertEquals(trans.isOverlap(), true);
255        assertEquals(trans.getOffsetBefore(), OFFSET_PONE);
256        assertEquals(trans.getOffsetAfter(), OFFSET_ZERO);
257        assertEquals(trans.getInstant(), createInstant(2008, 10, 26, 1, 0, ZoneOffset.UTC));
258        assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(2008, 10, 26, 2, 0));
259        assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(2008, 10, 26, 1, 0));
260        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-1)), false);
261        assertEquals(trans.isValidOffset(OFFSET_ZERO), true);
262        assertEquals(trans.isValidOffset(OFFSET_PONE), true);
263        assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
264        assertEquals(trans.toString(), "Transition[Overlap at 2008-10-26T02:00+01:00 to Z]");
265
266        assertFalse(trans.equals(null));
267        assertFalse(trans.equals(OFFSET_PONE));
268        assertTrue(trans.equals(trans));
269
270        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
271        assertTrue(trans.equals(otherTrans));
272        assertEquals(trans.hashCode(), otherTrans.hashCode());
273    }
274
275    public void test_London_getStandardOffset() {
276        ZoneRules test = europeLondon();
277        ZonedDateTime zdt = createZDT(1840, 1, 1, ZoneOffset.UTC);
278        while (zdt.getYear() < 2010) {
279            Instant instant = zdt.toInstant();
280            if (zdt.getYear() < 1848) {
281                assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHoursMinutesSeconds(0, -1, -15));
282            } else if (zdt.getYear() >= 1969 && zdt.getYear() < 1972) {
283                assertEquals(test.getStandardOffset(instant), OFFSET_PONE);
284            } else {
285                assertEquals(test.getStandardOffset(instant), OFFSET_ZERO);
286            }
287            zdt = zdt.plusMonths(6);
288        }
289    }
290
291    public void test_London_getTransitions() {
292        ZoneRules test = europeLondon();
293        List<ZoneOffsetTransition> trans = test.getTransitions();
294
295        ZoneOffsetTransition first = trans.get(0);
296        assertEquals(first.getDateTimeBefore(), LocalDateTime.of(1847, 12, 1, 0, 0));
297        assertEquals(first.getOffsetBefore(), ZoneOffset.ofHoursMinutesSeconds(0, -1, -15));
298        assertEquals(first.getOffsetAfter(), OFFSET_ZERO);
299
300        ZoneOffsetTransition spring1916 = trans.get(1);
301        assertEquals(spring1916.getDateTimeBefore(), LocalDateTime.of(1916, 5, 21, 2, 0));
302        assertEquals(spring1916.getOffsetBefore(), OFFSET_ZERO);
303        assertEquals(spring1916.getOffsetAfter(), OFFSET_PONE);
304
305        ZoneOffsetTransition autumn1916 = trans.get(2);
306        assertEquals(autumn1916.getDateTimeBefore(), LocalDateTime.of(1916, 10, 1, 3, 0));
307        assertEquals(autumn1916.getOffsetBefore(), OFFSET_PONE);
308        assertEquals(autumn1916.getOffsetAfter(), OFFSET_ZERO);
309
310        ZoneOffsetTransition zot = null;
311        Iterator<ZoneOffsetTransition> it = trans.iterator();
312        while (it.hasNext()) {
313            zot = it.next();
314            if (zot.getDateTimeBefore().getYear() == 1990) {
315                break;
316            }
317        }
318        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1990, 3, 25, 1, 0));
319        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
320        zot = it.next();
321        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1990, 10, 28, 2, 0));
322        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
323        zot = it.next();
324        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1991, 3, 31, 1, 0));
325        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
326        zot = it.next();
327        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1991, 10, 27, 2, 0));
328        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
329        zot = it.next();
330        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1992, 3, 29, 1, 0));
331        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
332        zot = it.next();
333        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1992, 10, 25, 2, 0));
334        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
335        zot = it.next();
336        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1993, 3, 28, 1, 0));
337        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
338        zot = it.next();
339        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1993, 10, 24, 2, 0));
340        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
341        zot = it.next();
342        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1994, 3, 27, 1, 0));
343        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
344        zot = it.next();
345        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1994, 10, 23, 2, 0));
346        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
347        zot = it.next();
348        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1995, 3, 26, 1, 0));
349        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
350        zot = it.next();
351        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1995, 10, 22, 2, 0));
352        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
353        zot = it.next();
354        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1996, 3, 31, 1, 0));
355        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
356        zot = it.next();
357        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1996, 10, 27, 2, 0));
358        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
359        zot = it.next();
360        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1997, 3, 30, 1, 0));
361        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
362        zot = it.next();
363        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1997, 10, 26, 2, 0));
364        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
365        assertEquals(it.hasNext(), false);
366    }
367
368    public void test_London_getTransitionRules() {
369        ZoneRules test = europeLondon();
370        List<ZoneOffsetTransitionRule> rules = test.getTransitionRules();
371        assertEquals(rules.size(), 2);
372
373        ZoneOffsetTransitionRule in = rules.get(0);
374        assertEquals(in.getMonth(), Month.MARCH);
375        assertEquals(in.getDayOfMonthIndicator(), 25);  // optimized from -1
376        assertEquals(in.getDayOfWeek(), DayOfWeek.SUNDAY);
377        assertEquals(in.getLocalTime(), LocalTime.of(1, 0));
378        assertEquals(in.getTimeDefinition(), TimeDefinition.UTC);
379        assertEquals(in.getStandardOffset(), OFFSET_ZERO);
380        assertEquals(in.getOffsetBefore(), OFFSET_ZERO);
381        assertEquals(in.getOffsetAfter(), OFFSET_PONE);
382
383        ZoneOffsetTransitionRule out = rules.get(1);
384        assertEquals(out.getMonth(), Month.OCTOBER);
385        assertEquals(out.getDayOfMonthIndicator(), 25);  // optimized from -1
386        assertEquals(out.getDayOfWeek(), DayOfWeek.SUNDAY);
387        assertEquals(out.getLocalTime(), LocalTime.of(1, 0));
388        assertEquals(out.getTimeDefinition(), TimeDefinition.UTC);
389        assertEquals(out.getStandardOffset(), OFFSET_ZERO);
390        assertEquals(out.getOffsetBefore(), OFFSET_PONE);
391        assertEquals(out.getOffsetAfter(), OFFSET_ZERO);
392    }
393
394    //-----------------------------------------------------------------------
395    public void test_London_nextTransition_historic() {
396        ZoneRules test = europeLondon();
397        List<ZoneOffsetTransition> trans = test.getTransitions();
398
399        ZoneOffsetTransition first = trans.get(0);
400        assertEquals(test.nextTransition(first.getInstant().minusNanos(1)), first);
401
402        for (int i = 0; i < trans.size() - 1; i++) {
403            ZoneOffsetTransition cur = trans.get(i);
404            ZoneOffsetTransition next = trans.get(i + 1);
405
406            assertEquals(test.nextTransition(cur.getInstant()), next);
407            assertEquals(test.nextTransition(next.getInstant().minusNanos(1)), next);
408        }
409    }
410
411    public void test_London_nextTransition_rulesBased() {
412        ZoneRules test = europeLondon();
413        List<ZoneOffsetTransitionRule> rules = test.getTransitionRules();
414        List<ZoneOffsetTransition> trans = test.getTransitions();
415
416        ZoneOffsetTransition last = trans.get(trans.size() - 1);
417        assertEquals(test.nextTransition(last.getInstant()), rules.get(0).createTransition(1998));
418
419        for (int year = 1998; year < 2010; year++) {
420            ZoneOffsetTransition a = rules.get(0).createTransition(year);
421            ZoneOffsetTransition b = rules.get(1).createTransition(year);
422            ZoneOffsetTransition c = rules.get(0).createTransition(year + 1);
423
424            assertEquals(test.nextTransition(a.getInstant()), b);
425            assertEquals(test.nextTransition(b.getInstant().minusNanos(1)), b);
426
427            assertEquals(test.nextTransition(b.getInstant()), c);
428            assertEquals(test.nextTransition(c.getInstant().minusNanos(1)), c);
429        }
430    }
431
432    public void test_London_nextTransition_lastYear() {
433        ZoneRules test = europeLondon();
434        List<ZoneOffsetTransitionRule> rules = test.getTransitionRules();
435        ZoneOffsetTransition zot = rules.get(1).createTransition(Year.MAX_VALUE);
436        assertEquals(test.nextTransition(zot.getInstant()), null);
437    }
438
439    //-----------------------------------------------------------------------
440    public void test_London_previousTransition_historic() {
441        ZoneRules test = europeLondon();
442        List<ZoneOffsetTransition> trans = test.getTransitions();
443
444        ZoneOffsetTransition first = trans.get(0);
445        assertEquals(test.previousTransition(first.getInstant()), null);
446        assertEquals(test.previousTransition(first.getInstant().minusNanos(1)), null);
447
448        for (int i = 0; i < trans.size() - 1; i++) {
449            ZoneOffsetTransition prev = trans.get(i);
450            ZoneOffsetTransition cur = trans.get(i + 1);
451
452            assertEquals(test.previousTransition(cur.getInstant()), prev);
453            assertEquals(test.previousTransition(prev.getInstant().plusSeconds(1)), prev);
454            assertEquals(test.previousTransition(prev.getInstant().plusNanos(1)), prev);
455        }
456    }
457
458    public void test_London_previousTransition_rulesBased() {
459        ZoneRules test = europeLondon();
460        List<ZoneOffsetTransitionRule> rules = test.getTransitionRules();
461        List<ZoneOffsetTransition> trans = test.getTransitions();
462
463        ZoneOffsetTransition last = trans.get(trans.size() - 1);
464        assertEquals(test.previousTransition(last.getInstant().plusSeconds(1)), last);
465        assertEquals(test.previousTransition(last.getInstant().plusNanos(1)), last);
466
467        // Jan 1st of year between transitions and rules
468        ZonedDateTime odt = ZonedDateTime.ofInstant(last.getInstant(), last.getOffsetAfter());
469        odt = odt.withDayOfYear(1).plusYears(1).with(LocalTime.MIDNIGHT);
470        assertEquals(test.previousTransition(odt.toInstant()), last);
471
472        // later years
473        for (int year = 1998; year < 2010; year++) {
474            ZoneOffsetTransition a = rules.get(0).createTransition(year);
475            ZoneOffsetTransition b = rules.get(1).createTransition(year);
476            ZoneOffsetTransition c = rules.get(0).createTransition(year + 1);
477
478            assertEquals(test.previousTransition(c.getInstant()), b);
479            assertEquals(test.previousTransition(b.getInstant().plusSeconds(1)), b);
480            assertEquals(test.previousTransition(b.getInstant().plusNanos(1)), b);
481
482            assertEquals(test.previousTransition(b.getInstant()), a);
483            assertEquals(test.previousTransition(a.getInstant().plusSeconds(1)), a);
484            assertEquals(test.previousTransition(a.getInstant().plusNanos(1)), a);
485        }
486    }
487
488    //-----------------------------------------------------------------------
489    // Europe/Paris
490    //-----------------------------------------------------------------------
491    private ZoneRules europeParis() {
492        return ZoneId.of("Europe/Paris").getRules();
493    }
494
495    public void test_Paris() {
496        ZoneRules test = europeParis();
497        assertEquals(test.isFixedOffset(), false);
498    }
499
500    public void test_Paris_preTimeZones() {
501        ZoneRules test = europeParis();
502        ZonedDateTime old = createZDT(1800, 1, 1, ZoneOffset.UTC);
503        Instant instant = old.toInstant();
504        ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(0, 9, 21);
505        assertEquals(test.getOffset(instant), offset);
506        checkOffset(test, old.toLocalDateTime(), offset, 1);
507        assertEquals(test.getStandardOffset(instant), offset);
508        assertEquals(test.getDaylightSavings(instant), Duration.ZERO);
509        assertEquals(test.isDaylightSavings(instant), false);
510    }
511
512    public void test_Paris_getOffset() {
513        ZoneRules test = europeParis();
514        assertEquals(test.getOffset(createInstant(2008, 1, 1, ZoneOffset.UTC)), OFFSET_PONE);
515        assertEquals(test.getOffset(createInstant(2008, 2, 1, ZoneOffset.UTC)), OFFSET_PONE);
516        assertEquals(test.getOffset(createInstant(2008, 3, 1, ZoneOffset.UTC)), OFFSET_PONE);
517        assertEquals(test.getOffset(createInstant(2008, 4, 1, ZoneOffset.UTC)), OFFSET_PTWO);
518        assertEquals(test.getOffset(createInstant(2008, 5, 1, ZoneOffset.UTC)), OFFSET_PTWO);
519        assertEquals(test.getOffset(createInstant(2008, 6, 1, ZoneOffset.UTC)), OFFSET_PTWO);
520        assertEquals(test.getOffset(createInstant(2008, 7, 1, ZoneOffset.UTC)), OFFSET_PTWO);
521        assertEquals(test.getOffset(createInstant(2008, 8, 1, ZoneOffset.UTC)), OFFSET_PTWO);
522        assertEquals(test.getOffset(createInstant(2008, 9, 1, ZoneOffset.UTC)), OFFSET_PTWO);
523        assertEquals(test.getOffset(createInstant(2008, 10, 1, ZoneOffset.UTC)), OFFSET_PTWO);
524        assertEquals(test.getOffset(createInstant(2008, 11, 1, ZoneOffset.UTC)), OFFSET_PONE);
525        assertEquals(test.getOffset(createInstant(2008, 12, 1, ZoneOffset.UTC)), OFFSET_PONE);
526    }
527
528    public void test_Paris_getOffset_toDST() {
529        ZoneRules test = europeParis();
530        assertEquals(test.getOffset(createInstant(2008, 3, 24, ZoneOffset.UTC)), OFFSET_PONE);
531        assertEquals(test.getOffset(createInstant(2008, 3, 25, ZoneOffset.UTC)), OFFSET_PONE);
532        assertEquals(test.getOffset(createInstant(2008, 3, 26, ZoneOffset.UTC)), OFFSET_PONE);
533        assertEquals(test.getOffset(createInstant(2008, 3, 27, ZoneOffset.UTC)), OFFSET_PONE);
534        assertEquals(test.getOffset(createInstant(2008, 3, 28, ZoneOffset.UTC)), OFFSET_PONE);
535        assertEquals(test.getOffset(createInstant(2008, 3, 29, ZoneOffset.UTC)), OFFSET_PONE);
536        assertEquals(test.getOffset(createInstant(2008, 3, 30, ZoneOffset.UTC)), OFFSET_PONE);
537        assertEquals(test.getOffset(createInstant(2008, 3, 31, ZoneOffset.UTC)), OFFSET_PTWO);
538        // cutover at 01:00Z
539        assertEquals(test.getOffset(createInstant(2008, 3, 30, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_PONE);
540        assertEquals(test.getOffset(createInstant(2008, 3, 30, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_PTWO);
541    }
542
543    public void test_Paris_getOffset_fromDST() {
544        ZoneRules test = europeParis();
545        assertEquals(test.getOffset(createInstant(2008, 10, 24, ZoneOffset.UTC)), OFFSET_PTWO);
546        assertEquals(test.getOffset(createInstant(2008, 10, 25, ZoneOffset.UTC)), OFFSET_PTWO);
547        assertEquals(test.getOffset(createInstant(2008, 10, 26, ZoneOffset.UTC)), OFFSET_PTWO);
548        assertEquals(test.getOffset(createInstant(2008, 10, 27, ZoneOffset.UTC)), OFFSET_PONE);
549        assertEquals(test.getOffset(createInstant(2008, 10, 28, ZoneOffset.UTC)), OFFSET_PONE);
550        assertEquals(test.getOffset(createInstant(2008, 10, 29, ZoneOffset.UTC)), OFFSET_PONE);
551        assertEquals(test.getOffset(createInstant(2008, 10, 30, ZoneOffset.UTC)), OFFSET_PONE);
552        assertEquals(test.getOffset(createInstant(2008, 10, 31, ZoneOffset.UTC)), OFFSET_PONE);
553        // cutover at 01:00Z
554        assertEquals(test.getOffset(createInstant(2008, 10, 26, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_PTWO);
555        assertEquals(test.getOffset(createInstant(2008, 10, 26, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_PONE);
556    }
557
558    public void test_Paris_getOffsetInfo() {
559        ZoneRules test = europeParis();
560        checkOffset(test, createLDT(2008, 1, 1), OFFSET_PONE, 1);
561        checkOffset(test, createLDT(2008, 2, 1), OFFSET_PONE, 1);
562        checkOffset(test, createLDT(2008, 3, 1), OFFSET_PONE, 1);
563        checkOffset(test, createLDT(2008, 4, 1), OFFSET_PTWO, 1);
564        checkOffset(test, createLDT(2008, 5, 1), OFFSET_PTWO, 1);
565        checkOffset(test, createLDT(2008, 6, 1), OFFSET_PTWO, 1);
566        checkOffset(test, createLDT(2008, 7, 1), OFFSET_PTWO, 1);
567        checkOffset(test, createLDT(2008, 8, 1), OFFSET_PTWO, 1);
568        checkOffset(test, createLDT(2008, 9, 1), OFFSET_PTWO, 1);
569        checkOffset(test, createLDT(2008, 10, 1), OFFSET_PTWO, 1);
570        checkOffset(test, createLDT(2008, 11, 1), OFFSET_PONE, 1);
571        checkOffset(test, createLDT(2008, 12, 1), OFFSET_PONE, 1);
572    }
573
574    public void test_Paris_getOffsetInfo_toDST() {
575        ZoneRules test = europeParis();
576        checkOffset(test, createLDT(2008, 3, 24), OFFSET_PONE, 1);
577        checkOffset(test, createLDT(2008, 3, 25), OFFSET_PONE, 1);
578        checkOffset(test, createLDT(2008, 3, 26), OFFSET_PONE, 1);
579        checkOffset(test, createLDT(2008, 3, 27), OFFSET_PONE, 1);
580        checkOffset(test, createLDT(2008, 3, 28), OFFSET_PONE, 1);
581        checkOffset(test, createLDT(2008, 3, 29), OFFSET_PONE, 1);
582        checkOffset(test, createLDT(2008, 3, 30), OFFSET_PONE, 1);
583        checkOffset(test, createLDT(2008, 3, 31), OFFSET_PTWO, 1);
584        // cutover at 01:00Z which is 02:00+01:00(local Paris time)
585        checkOffset(test, LocalDateTime.of(2008, 3, 30, 1, 59, 59, 999999999), OFFSET_PONE, 1);
586        checkOffset(test, LocalDateTime.of(2008, 3, 30, 3, 0, 0, 0), OFFSET_PTWO, 1);
587    }
588
589    public void test_Paris_getOffsetInfo_fromDST() {
590        ZoneRules test = europeParis();
591        checkOffset(test, createLDT(2008, 10, 24), OFFSET_PTWO, 1);
592        checkOffset(test, createLDT(2008, 10, 25), OFFSET_PTWO, 1);
593        checkOffset(test, createLDT(2008, 10, 26), OFFSET_PTWO, 1);
594        checkOffset(test, createLDT(2008, 10, 27), OFFSET_PONE, 1);
595        checkOffset(test, createLDT(2008, 10, 28), OFFSET_PONE, 1);
596        checkOffset(test, createLDT(2008, 10, 29), OFFSET_PONE, 1);
597        checkOffset(test, createLDT(2008, 10, 30), OFFSET_PONE, 1);
598        checkOffset(test, createLDT(2008, 10, 31), OFFSET_PONE, 1);
599        // cutover at 01:00Z which is 02:00+01:00(local Paris time)
600        checkOffset(test, LocalDateTime.of(2008, 10, 26, 1, 59, 59, 999999999), OFFSET_PTWO, 1);
601        checkOffset(test, LocalDateTime.of(2008, 10, 26, 3, 0, 0, 0), OFFSET_PONE, 1);
602    }
603
604    public void test_Paris_getOffsetInfo_gap() {
605        ZoneRules test = europeParis();
606        final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 30, 2, 0, 0, 0);
607        ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_PONE, GAP);
608        assertEquals(trans.isGap(), true);
609        assertEquals(trans.isOverlap(), false);
610        assertEquals(trans.getOffsetBefore(), OFFSET_PONE);
611        assertEquals(trans.getOffsetAfter(), OFFSET_PTWO);
612        assertEquals(trans.getInstant(), createInstant(2008, 3, 30, 1, 0, ZoneOffset.UTC));
613        assertEquals(trans.isValidOffset(OFFSET_ZERO), false);
614        assertEquals(trans.isValidOffset(OFFSET_PONE), false);
615        assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
616        assertEquals(trans.toString(), "Transition[Gap at 2008-03-30T02:00+01:00 to +02:00]");
617
618        assertFalse(trans.equals(null));
619        assertFalse(trans.equals(OFFSET_PONE));
620        assertTrue(trans.equals(trans));
621
622        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
623        assertTrue(trans.equals(otherTrans));
624        assertEquals(trans.hashCode(), otherTrans.hashCode());
625    }
626
627    public void test_Paris_getOffsetInfo_overlap() {
628        ZoneRules test = europeParis();
629        final LocalDateTime dateTime = LocalDateTime.of(2008, 10, 26, 2, 0, 0, 0);
630        ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_PTWO, OVERLAP);
631        assertEquals(trans.isGap(), false);
632        assertEquals(trans.isOverlap(), true);
633        assertEquals(trans.getOffsetBefore(), OFFSET_PTWO);
634        assertEquals(trans.getOffsetAfter(), OFFSET_PONE);
635        assertEquals(trans.getInstant(), createInstant(2008, 10, 26, 1, 0, ZoneOffset.UTC));
636        assertEquals(trans.isValidOffset(OFFSET_ZERO), false);
637        assertEquals(trans.isValidOffset(OFFSET_PONE), true);
638        assertEquals(trans.isValidOffset(OFFSET_PTWO), true);
639        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(3)), false);
640        assertEquals(trans.toString(), "Transition[Overlap at 2008-10-26T03:00+02:00 to +01:00]");
641
642        assertFalse(trans.equals(null));
643        assertFalse(trans.equals(OFFSET_PTWO));
644        assertTrue(trans.equals(trans));
645
646        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
647        assertTrue(trans.equals(otherTrans));
648        assertEquals(trans.hashCode(), otherTrans.hashCode());
649    }
650
651    public void test_Paris_getStandardOffset() {
652        ZoneRules test = europeParis();
653        ZonedDateTime zdt = createZDT(1840, 1, 1, ZoneOffset.UTC);
654        while (zdt.getYear() < 2010) {
655            Instant instant = zdt.toInstant();
656            if (zdt.toLocalDate().isBefore(LocalDate.of(1911, 3, 11))) {
657                assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHoursMinutesSeconds(0, 9, 21));
658            } else if (zdt.toLocalDate().isBefore(LocalDate.of(1940, 6, 14))) {
659                assertEquals(test.getStandardOffset(instant), OFFSET_ZERO);
660            } else if (zdt.toLocalDate().isBefore(LocalDate.of(1944, 8, 25))) {
661                assertEquals(test.getStandardOffset(instant), OFFSET_PONE);
662            } else if (zdt.toLocalDate().isBefore(LocalDate.of(1945, 9, 16))) {
663                assertEquals(test.getStandardOffset(instant), OFFSET_ZERO);
664            } else {
665                assertEquals(test.getStandardOffset(instant), OFFSET_PONE);
666            }
667            zdt = zdt.plusMonths(6);
668        }
669    }
670
671    //-----------------------------------------------------------------------
672    // America/New_York
673    //-----------------------------------------------------------------------
674    private ZoneRules americaNewYork() {
675        return ZoneId.of("America/New_York").getRules();
676    }
677
678    public void test_NewYork() {
679        ZoneRules test = americaNewYork();
680        assertEquals(test.isFixedOffset(), false);
681    }
682
683    public void test_NewYork_preTimeZones() {
684        ZoneRules test = americaNewYork();
685        ZonedDateTime old = createZDT(1800, 1, 1, ZoneOffset.UTC);
686        Instant instant = old.toInstant();
687        ZoneOffset offset = ZoneOffset.of("-04:56:02");
688        assertEquals(test.getOffset(instant), offset);
689        checkOffset(test, old.toLocalDateTime(), offset, 1);
690        assertEquals(test.getStandardOffset(instant), offset);
691        assertEquals(test.getDaylightSavings(instant), Duration.ZERO);
692        assertEquals(test.isDaylightSavings(instant), false);
693    }
694
695    public void test_NewYork_getOffset() {
696        ZoneRules test = americaNewYork();
697        ZoneOffset offset = ZoneOffset.ofHours(-5);
698        assertEquals(test.getOffset(createInstant(2008, 1, 1, offset)), ZoneOffset.ofHours(-5));
699        assertEquals(test.getOffset(createInstant(2008, 2, 1, offset)), ZoneOffset.ofHours(-5));
700        assertEquals(test.getOffset(createInstant(2008, 3, 1, offset)), ZoneOffset.ofHours(-5));
701        assertEquals(test.getOffset(createInstant(2008, 4, 1, offset)), ZoneOffset.ofHours(-4));
702        assertEquals(test.getOffset(createInstant(2008, 5, 1, offset)), ZoneOffset.ofHours(-4));
703        assertEquals(test.getOffset(createInstant(2008, 6, 1, offset)), ZoneOffset.ofHours(-4));
704        assertEquals(test.getOffset(createInstant(2008, 7, 1, offset)), ZoneOffset.ofHours(-4));
705        assertEquals(test.getOffset(createInstant(2008, 8, 1, offset)), ZoneOffset.ofHours(-4));
706        assertEquals(test.getOffset(createInstant(2008, 9, 1, offset)), ZoneOffset.ofHours(-4));
707        assertEquals(test.getOffset(createInstant(2008, 10, 1, offset)), ZoneOffset.ofHours(-4));
708        assertEquals(test.getOffset(createInstant(2008, 11, 1, offset)), ZoneOffset.ofHours(-4));
709        assertEquals(test.getOffset(createInstant(2008, 12, 1, offset)), ZoneOffset.ofHours(-5));
710        assertEquals(test.getOffset(createInstant(2008, 1, 28, offset)), ZoneOffset.ofHours(-5));
711        assertEquals(test.getOffset(createInstant(2008, 2, 28, offset)), ZoneOffset.ofHours(-5));
712        assertEquals(test.getOffset(createInstant(2008, 3, 28, offset)), ZoneOffset.ofHours(-4));
713        assertEquals(test.getOffset(createInstant(2008, 4, 28, offset)), ZoneOffset.ofHours(-4));
714        assertEquals(test.getOffset(createInstant(2008, 5, 28, offset)), ZoneOffset.ofHours(-4));
715        assertEquals(test.getOffset(createInstant(2008, 6, 28, offset)), ZoneOffset.ofHours(-4));
716        assertEquals(test.getOffset(createInstant(2008, 7, 28, offset)), ZoneOffset.ofHours(-4));
717        assertEquals(test.getOffset(createInstant(2008, 8, 28, offset)), ZoneOffset.ofHours(-4));
718        assertEquals(test.getOffset(createInstant(2008, 9, 28, offset)), ZoneOffset.ofHours(-4));
719        assertEquals(test.getOffset(createInstant(2008, 10, 28, offset)), ZoneOffset.ofHours(-4));
720        assertEquals(test.getOffset(createInstant(2008, 11, 28, offset)), ZoneOffset.ofHours(-5));
721        assertEquals(test.getOffset(createInstant(2008, 12, 28, offset)), ZoneOffset.ofHours(-5));
722    }
723
724    public void test_NewYork_getOffset_toDST() {
725        ZoneRules test = americaNewYork();
726        ZoneOffset offset = ZoneOffset.ofHours(-5);
727        assertEquals(test.getOffset(createInstant(2008, 3, 8, offset)), ZoneOffset.ofHours(-5));
728        assertEquals(test.getOffset(createInstant(2008, 3, 9, offset)), ZoneOffset.ofHours(-5));
729        assertEquals(test.getOffset(createInstant(2008, 3, 10, offset)), ZoneOffset.ofHours(-4));
730        assertEquals(test.getOffset(createInstant(2008, 3, 11, offset)), ZoneOffset.ofHours(-4));
731        assertEquals(test.getOffset(createInstant(2008, 3, 12, offset)), ZoneOffset.ofHours(-4));
732        assertEquals(test.getOffset(createInstant(2008, 3, 13, offset)), ZoneOffset.ofHours(-4));
733        assertEquals(test.getOffset(createInstant(2008, 3, 14, offset)), ZoneOffset.ofHours(-4));
734        // cutover at 02:00 local
735        assertEquals(test.getOffset(createInstant(2008, 3, 9, 1, 59, 59, 999999999, offset)), ZoneOffset.ofHours(-5));
736        assertEquals(test.getOffset(createInstant(2008, 3, 9, 2, 0, 0, 0, offset)), ZoneOffset.ofHours(-4));
737    }
738
739    public void test_NewYork_getOffset_fromDST() {
740        ZoneRules test = americaNewYork();
741        ZoneOffset offset = ZoneOffset.ofHours(-4);
742        assertEquals(test.getOffset(createInstant(2008, 11, 1, offset)), ZoneOffset.ofHours(-4));
743        assertEquals(test.getOffset(createInstant(2008, 11, 2, offset)), ZoneOffset.ofHours(-4));
744        assertEquals(test.getOffset(createInstant(2008, 11, 3, offset)), ZoneOffset.ofHours(-5));
745        assertEquals(test.getOffset(createInstant(2008, 11, 4, offset)), ZoneOffset.ofHours(-5));
746        assertEquals(test.getOffset(createInstant(2008, 11, 5, offset)), ZoneOffset.ofHours(-5));
747        assertEquals(test.getOffset(createInstant(2008, 11, 6, offset)), ZoneOffset.ofHours(-5));
748        assertEquals(test.getOffset(createInstant(2008, 11, 7, offset)), ZoneOffset.ofHours(-5));
749        // cutover at 02:00 local
750        assertEquals(test.getOffset(createInstant(2008, 11, 2, 1, 59, 59, 999999999, offset)), ZoneOffset.ofHours(-4));
751        assertEquals(test.getOffset(createInstant(2008, 11, 2, 2, 0, 0, 0, offset)), ZoneOffset.ofHours(-5));
752    }
753
754    public void test_NewYork_getOffsetInfo() {
755        ZoneRules test = americaNewYork();
756        checkOffset(test, createLDT(2008, 1, 1), ZoneOffset.ofHours(-5), 1);
757        checkOffset(test, createLDT(2008, 2, 1), ZoneOffset.ofHours(-5), 1);
758        checkOffset(test, createLDT(2008, 3, 1), ZoneOffset.ofHours(-5), 1);
759        checkOffset(test, createLDT(2008, 4, 1), ZoneOffset.ofHours(-4), 1);
760        checkOffset(test, createLDT(2008, 5, 1), ZoneOffset.ofHours(-4), 1);
761        checkOffset(test, createLDT(2008, 6, 1), ZoneOffset.ofHours(-4), 1);
762        checkOffset(test, createLDT(2008, 7, 1), ZoneOffset.ofHours(-4), 1);
763        checkOffset(test, createLDT(2008, 8, 1), ZoneOffset.ofHours(-4), 1);
764        checkOffset(test, createLDT(2008, 9, 1), ZoneOffset.ofHours(-4), 1);
765        checkOffset(test, createLDT(2008, 10, 1), ZoneOffset.ofHours(-4), 1);
766        checkOffset(test, createLDT(2008, 11, 1), ZoneOffset.ofHours(-4), 1);
767        checkOffset(test, createLDT(2008, 12, 1), ZoneOffset.ofHours(-5), 1);
768        checkOffset(test, createLDT(2008, 1, 28), ZoneOffset.ofHours(-5), 1);
769        checkOffset(test, createLDT(2008, 2, 28), ZoneOffset.ofHours(-5), 1);
770        checkOffset(test, createLDT(2008, 3, 28), ZoneOffset.ofHours(-4), 1);
771        checkOffset(test, createLDT(2008, 4, 28), ZoneOffset.ofHours(-4), 1);
772        checkOffset(test, createLDT(2008, 5, 28), ZoneOffset.ofHours(-4), 1);
773        checkOffset(test, createLDT(2008, 6, 28), ZoneOffset.ofHours(-4), 1);
774        checkOffset(test, createLDT(2008, 7, 28), ZoneOffset.ofHours(-4), 1);
775        checkOffset(test, createLDT(2008, 8, 28), ZoneOffset.ofHours(-4), 1);
776        checkOffset(test, createLDT(2008, 9, 28), ZoneOffset.ofHours(-4), 1);
777        checkOffset(test, createLDT(2008, 10, 28), ZoneOffset.ofHours(-4), 1);
778        checkOffset(test, createLDT(2008, 11, 28), ZoneOffset.ofHours(-5), 1);
779        checkOffset(test, createLDT(2008, 12, 28), ZoneOffset.ofHours(-5), 1);
780    }
781
782    public void test_NewYork_getOffsetInfo_toDST() {
783        ZoneRules test = americaNewYork();
784        checkOffset(test, createLDT(2008, 3, 8), ZoneOffset.ofHours(-5), 1);
785        checkOffset(test, createLDT(2008, 3, 9), ZoneOffset.ofHours(-5), 1);
786        checkOffset(test, createLDT(2008, 3, 10), ZoneOffset.ofHours(-4), 1);
787        checkOffset(test, createLDT(2008, 3, 11), ZoneOffset.ofHours(-4), 1);
788        checkOffset(test, createLDT(2008, 3, 12), ZoneOffset.ofHours(-4), 1);
789        checkOffset(test, createLDT(2008, 3, 13), ZoneOffset.ofHours(-4), 1);
790        checkOffset(test, createLDT(2008, 3, 14), ZoneOffset.ofHours(-4), 1);
791        // cutover at 02:00 local
792        checkOffset(test, LocalDateTime.of(2008, 3, 9, 1, 59, 59, 999999999), ZoneOffset.ofHours(-5), 1);
793        checkOffset(test, LocalDateTime.of(2008, 3, 9, 3, 0, 0, 0), ZoneOffset.ofHours(-4), 1);
794    }
795
796    public void test_NewYork_getOffsetInfo_fromDST() {
797        ZoneRules test = americaNewYork();
798        checkOffset(test, createLDT(2008, 11, 1), ZoneOffset.ofHours(-4), 1);
799        checkOffset(test, createLDT(2008, 11, 2), ZoneOffset.ofHours(-4), 1);
800        checkOffset(test, createLDT(2008, 11, 3), ZoneOffset.ofHours(-5), 1);
801        checkOffset(test, createLDT(2008, 11, 4), ZoneOffset.ofHours(-5), 1);
802        checkOffset(test, createLDT(2008, 11, 5), ZoneOffset.ofHours(-5), 1);
803        checkOffset(test, createLDT(2008, 11, 6), ZoneOffset.ofHours(-5), 1);
804        checkOffset(test, createLDT(2008, 11, 7), ZoneOffset.ofHours(-5), 1);
805        // cutover at 02:00 local
806        checkOffset(test, LocalDateTime.of(2008, 11, 2, 0, 59, 59, 999999999), ZoneOffset.ofHours(-4), 1);
807        checkOffset(test, LocalDateTime.of(2008, 11, 2, 2, 0, 0, 0), ZoneOffset.ofHours(-5), 1);
808    }
809
810    public void test_NewYork_getOffsetInfo_gap() {
811        ZoneRules test = americaNewYork();
812        final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 9, 2, 0, 0, 0);
813        ZoneOffsetTransition trans = checkOffset(test, dateTime, ZoneOffset.ofHours(-5), GAP);
814        assertEquals(trans.isGap(), true);
815        assertEquals(trans.isOverlap(), false);
816        assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(-5));
817        assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(-4));
818        assertEquals(trans.getInstant(), createInstant(2008, 3, 9, 2, 0, ZoneOffset.ofHours(-5)));
819        assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
820        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-5)), false);
821        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-4)), false);
822        assertEquals(trans.toString(), "Transition[Gap at 2008-03-09T02:00-05:00 to -04:00]");
823
824        assertFalse(trans.equals(null));
825        assertFalse(trans.equals(ZoneOffset.ofHours(-5)));
826        assertTrue(trans.equals(trans));
827
828        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
829        assertTrue(trans.equals(otherTrans));
830        assertEquals(trans.hashCode(), otherTrans.hashCode());
831    }
832
833    public void test_NewYork_getOffsetInfo_overlap() {
834        ZoneRules test = americaNewYork();
835        final LocalDateTime dateTime = LocalDateTime.of(2008, 11, 2, 1, 0, 0, 0);
836        ZoneOffsetTransition trans = checkOffset(test, dateTime, ZoneOffset.ofHours(-4), OVERLAP);
837        assertEquals(trans.isGap(), false);
838        assertEquals(trans.isOverlap(), true);
839        assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(-4));
840        assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(-5));
841        assertEquals(trans.getInstant(), createInstant(2008, 11, 2, 2, 0, ZoneOffset.ofHours(-4)));
842        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-1)), false);
843        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-5)), true);
844        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-4)), true);
845        assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
846        assertEquals(trans.toString(), "Transition[Overlap at 2008-11-02T02:00-04:00 to -05:00]");
847
848        assertFalse(trans.equals(null));
849        assertFalse(trans.equals(ZoneOffset.ofHours(-4)));
850        assertTrue(trans.equals(trans));
851
852        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
853        assertTrue(trans.equals(otherTrans));
854        assertEquals(trans.hashCode(), otherTrans.hashCode());
855    }
856
857    public void test_NewYork_getStandardOffset() {
858        ZoneRules test = americaNewYork();
859        ZonedDateTime dateTime = createZDT(1860, 1, 1, ZoneOffset.UTC);
860        while (dateTime.getYear() < 2010) {
861            Instant instant = dateTime.toInstant();
862            if (dateTime.toLocalDate().isBefore(LocalDate.of(1883, 11, 18))) {
863                assertEquals(test.getStandardOffset(instant), ZoneOffset.of("-04:56:02"));
864            } else {
865                assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHours(-5));
866            }
867            dateTime = dateTime.plusMonths(6);
868        }
869    }
870
871    //-----------------------------------------------------------------------
872    // Kathmandu
873    //-----------------------------------------------------------------------
874    private ZoneRules asiaKathmandu() {
875        return ZoneId.of("Asia/Kathmandu").getRules();
876    }
877
878    public void test_Kathmandu_nextTransition_historic() {
879        ZoneRules test = asiaKathmandu();
880        List<ZoneOffsetTransition> trans = test.getTransitions();
881
882        ZoneOffsetTransition first = trans.get(0);
883        assertEquals(test.nextTransition(first.getInstant().minusNanos(1)), first);
884
885        for (int i = 0; i < trans.size() - 1; i++) {
886            ZoneOffsetTransition cur = trans.get(i);
887            ZoneOffsetTransition next = trans.get(i + 1);
888
889            assertEquals(test.nextTransition(cur.getInstant()), next);
890            assertEquals(test.nextTransition(next.getInstant().minusNanos(1)), next);
891        }
892    }
893
894    public void test_Kathmandu_nextTransition_noRules() {
895        ZoneRules test = asiaKathmandu();
896        List<ZoneOffsetTransition> trans = test.getTransitions();
897
898        ZoneOffsetTransition last = trans.get(trans.size() - 1);
899        assertEquals(test.nextTransition(last.getInstant()), null);
900    }
901
902    //-----------------------------------------------------------------------
903    // Apia
904    //-----------------------------------------------------------------------
905    private ZoneRules pacificApia() {
906        return ZoneId.of("Pacific/Apia").getRules();
907    }
908
909    public void test_Apia_nextTransition_historic() {
910        ZoneRules test = pacificApia();
911        List<ZoneOffsetTransition> trans = test.getTransitions();
912
913        ZoneOffsetTransition first = trans.get(0);
914        assertEquals(test.nextTransition(first.getInstant().minusNanos(1)), first);
915
916        for (int i = 0; i < trans.size() - 1; i++) {
917            ZoneOffsetTransition cur = trans.get(i);
918            ZoneOffsetTransition next = trans.get(i + 1);
919
920            assertEquals(test.nextTransition(cur.getInstant()), next);
921            assertEquals(test.nextTransition(next.getInstant().minusNanos(1)), next);
922        }
923    }
924
925    public void test_Apia_jumpOverInternationalDateLine_M10_to_P14() {
926        // transition occurred at 2011-12-30T00:00-10:00
927        ZoneRules test = pacificApia();
928        Instant instantBefore = LocalDate.of(2011, 12, 27).atStartOfDay(ZoneOffset.UTC).toInstant();
929        ZoneOffsetTransition trans = test.nextTransition(instantBefore);
930        assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(2011, 12, 30, 0, 0));
931        assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(2011, 12, 31, 0, 0));
932        assertEquals(trans.isGap(), true);
933        assertEquals(trans.isOverlap(), false);
934        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-10)), false);
935        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(+14)), false);
936        assertEquals(trans.getDuration(), Duration.ofHours(24));
937        assertEquals(trans.getInstant(), LocalDateTime.of(2011, 12, 31, 0, 0).toInstant(ZoneOffset.ofHours(+14)));
938
939        ZonedDateTime zdt = ZonedDateTime.of(2011, 12, 29, 23, 0, 0, 0, ZoneId.of("Pacific/Apia"));
940        assertEquals(zdt.plusHours(2).toLocalDateTime(), LocalDateTime.of(2011, 12, 31, 1, 0));
941    }
942
943    public void test_Apia_jumpForwardOverInternationalDateLine_P12_to_M12() {
944        // transition occurred at 1879-07-04T00:00+12:33:04
945        ZoneRules test = pacificApia();
946        Instant instantBefore = LocalDate.of(1879, 7, 2).atStartOfDay(ZoneOffset.UTC).toInstant();
947        ZoneOffsetTransition trans = test.nextTransition(instantBefore);
948        assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(1879, 7, 5, 0, 0));
949        assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(1879, 7, 4, 0, 0));
950        assertEquals(trans.isGap(), false);
951        assertEquals(trans.isOverlap(), true);
952        assertEquals(trans.isValidOffset(ZoneOffset.ofHoursMinutesSeconds(+12, 33, 4)), true);
953        assertEquals(trans.isValidOffset(ZoneOffset.ofHoursMinutesSeconds(-11, -26, -56)), true);
954        assertEquals(trans.getDuration(), Duration.ofHours(-24));
955        assertEquals(trans.getInstant(), LocalDateTime.of(1879, 7, 4, 0, 0).toInstant(ZoneOffset.ofHoursMinutesSeconds(-11, -26, -56)));
956
957        ZonedDateTime zdt = ZonedDateTime.of(1879, 7, 4, 23, 0, 0, 0, ZoneId.of("Pacific/Apia"));
958        assertEquals(zdt.plusHours(2).toLocalDateTime(), LocalDateTime.of(1879, 7, 4, 1, 0, 0));
959    }
960
961    //-------------------------------------------------------------------------
962    @Test(expectedExceptions=UnsupportedOperationException.class)
963    public void test_getTransitions_immutable() {
964        ZoneRules test = europeParis();
965        test.getTransitions().clear();
966    }
967
968    @Test(expectedExceptions=UnsupportedOperationException.class)
969    public void test_getTransitionRules_immutable() {
970        ZoneRules test = europeParis();
971        test.getTransitionRules().clear();
972    }
973
974    //-----------------------------------------------------------------------
975    // of()
976    //-----------------------------------------------------------------------
977    public void test_of(){
978        //used for standard offset
979        ZoneOffset stdOffset1 = ZoneOffset.UTC;
980        ZoneOffset stdOffset2 = ZoneOffset.ofHours(1);
981        LocalDateTime time_of_stdOffsetTransition1 = LocalDateTime.of(2013, 1, 5, 1, 0);
982        ZoneOffsetTransition  stdOffsetTransition1 = ZoneOffsetTransition.of(time_of_stdOffsetTransition1, stdOffset1, stdOffset2);
983        List<ZoneOffsetTransition> stdOffsetTransition_list = new ArrayList<ZoneOffsetTransition>();
984        stdOffsetTransition_list.add(stdOffsetTransition1);
985
986        //used for wall offset
987        ZoneOffset wallOffset1 = ZoneOffset.ofHours(2);
988        ZoneOffset wallOffset2 = ZoneOffset.ofHours(4);
989        ZoneOffset wallOffset3 = ZoneOffset.ofHours(7);
990
991        LocalDateTime time_of_wallOffsetTransition1 = LocalDateTime.of(2013, 2, 5, 1, 0);
992        LocalDateTime time_of_wallOffsetTransition2 = LocalDateTime.of(2013, 3, 5, 1, 0);
993        LocalDateTime time_of_wallOffsetTransition3 = LocalDateTime.of(2013, 10, 5, 1, 0);
994
995        ZoneOffsetTransition  wallOffsetTransition1 = ZoneOffsetTransition.of(time_of_wallOffsetTransition1, wallOffset1, wallOffset2);
996        ZoneOffsetTransition  wallOffsetTransition2 = ZoneOffsetTransition.of(time_of_wallOffsetTransition2, wallOffset2, wallOffset3);
997        ZoneOffsetTransition  wallOffsetTransition3 = ZoneOffsetTransition.of(time_of_wallOffsetTransition3, wallOffset3, wallOffset1);
998
999        List<ZoneOffsetTransition> wallOffsetTransition_list = new ArrayList<ZoneOffsetTransition>();
1000        wallOffsetTransition_list.add(wallOffsetTransition1);
1001        wallOffsetTransition_list.add(wallOffsetTransition2);
1002        wallOffsetTransition_list.add(wallOffsetTransition3);
1003
1004        //used for ZoneOffsetTransitionRule
1005        ZoneOffset ruleOffset = ZoneOffset.ofHours(3);
1006        ZoneOffsetTransitionRule.TimeDefinition timeDefinition = ZoneOffsetTransitionRule.TimeDefinition.valueOf("WALL");
1007        ZoneOffsetTransitionRule rule1 = ZoneOffsetTransitionRule.of(Month.FEBRUARY,
1008                                                                     2,
1009                                                                     DayOfWeek.MONDAY,
1010                                                                     LocalTime.of(1, 0),
1011                                                                     false,
1012                                                                     timeDefinition,
1013                                                                     ZoneOffset.UTC,
1014                                                                     ZoneOffset.UTC,
1015                                                                     ruleOffset
1016                                                                     );
1017         List<ZoneOffsetTransitionRule> rule_list = new ArrayList<ZoneOffsetTransitionRule>();
1018         rule_list.add(rule1);
1019
1020         //Begin verification
1021         ZoneRules zoneRule = ZoneRules.of(stdOffset1,
1022                                           wallOffset1,
1023                                           stdOffsetTransition_list,
1024                                           wallOffsetTransition_list,
1025                                           rule_list
1026                                           );
1027
1028         OffsetDateTime before_time_of_stdOffsetTransition1 = OffsetDateTime.of(time_of_stdOffsetTransition1, stdOffset1).minusSeconds(1);
1029         OffsetDateTime after_time_of_stdOffsetTransition1 = OffsetDateTime.of(time_of_stdOffsetTransition1, stdOffset1).plusSeconds(1);;
1030         assertEquals(zoneRule.getStandardOffset(before_time_of_stdOffsetTransition1.toInstant()), stdOffset1);
1031         assertEquals(zoneRule.getStandardOffset(after_time_of_stdOffsetTransition1.toInstant()), stdOffset2);
1032
1033         OffsetDateTime  before_time_of_wallOffsetTransition1 = OffsetDateTime.of(time_of_wallOffsetTransition1, wallOffset1).minusSeconds(1);
1034         OffsetDateTime  after_time_of_wallOffsetTransition1 = OffsetDateTime.of(time_of_wallOffsetTransition1, wallOffset1).plusSeconds(1);
1035         assertEquals(zoneRule.nextTransition(before_time_of_wallOffsetTransition1.toInstant()), wallOffsetTransition1);
1036         assertEquals(zoneRule.nextTransition(after_time_of_wallOffsetTransition1.toInstant()), wallOffsetTransition2);
1037
1038         OffsetDateTime  before_time_of_wallOffsetTransition2 = OffsetDateTime.of(time_of_wallOffsetTransition2, wallOffset2).minusSeconds(1);
1039         OffsetDateTime  after_time_of_wallOffsetTransition2 = OffsetDateTime.of(time_of_wallOffsetTransition2, wallOffset2).plusSeconds(1);
1040         assertEquals(zoneRule.nextTransition(before_time_of_wallOffsetTransition2.toInstant()), wallOffsetTransition2);
1041         assertEquals(zoneRule.nextTransition(after_time_of_wallOffsetTransition2.toInstant()), wallOffsetTransition3);
1042
1043         OffsetDateTime  before_time_of_wallOffsetTransition3 = OffsetDateTime.of(time_of_wallOffsetTransition3, wallOffset3).minusSeconds(1);
1044         OffsetDateTime  after_time_of_wallOffsetTransition3 = OffsetDateTime.of(time_of_wallOffsetTransition3, wallOffset3).plusSeconds(1);
1045         assertEquals(zoneRule.nextTransition(before_time_of_wallOffsetTransition3.toInstant()), wallOffsetTransition3);
1046         assertEquals(zoneRule.nextTransition(after_time_of_wallOffsetTransition3.toInstant()), rule1.createTransition(2014));
1047    }
1048
1049    //-----------------------------------------------------------------------
1050    // equals() / hashCode()
1051    //-----------------------------------------------------------------------
1052    public void test_equals() {
1053        ZoneRules test1 = europeLondon();
1054        ZoneRules test2 = europeParis();
1055        ZoneRules test2b = europeParis();
1056        assertEquals(test1.equals(test2), false);
1057        assertEquals(test2.equals(test1), false);
1058
1059        assertEquals(test1.equals(test1), true);
1060        assertEquals(test2.equals(test2), true);
1061        assertEquals(test2.equals(test2b), true);
1062
1063        assertEquals(test1.hashCode() == test1.hashCode(), true);
1064        assertEquals(test2.hashCode() == test2.hashCode(), true);
1065        assertEquals(test2.hashCode() == test2b.hashCode(), true);
1066    }
1067
1068    public void test_equals_null() {
1069        assertEquals(europeLondon().equals(null), false);
1070    }
1071
1072    public void test_equals_notZoneRules() {
1073        assertEquals(europeLondon().equals("Europe/London"), false);
1074    }
1075
1076    public void test_toString() {
1077        assertEquals(europeLondon().toString().contains("ZoneRules"), true);
1078    }
1079
1080    //-----------------------------------------------------------------------
1081    //-----------------------------------------------------------------------
1082    //-----------------------------------------------------------------------
1083    private Instant createInstant(int year, int month, int day, ZoneOffset offset) {
1084        return LocalDateTime.of(year, month, day, 0, 0).toInstant(offset);
1085    }
1086
1087    private Instant createInstant(int year, int month, int day, int hour, int min, ZoneOffset offset) {
1088        return LocalDateTime.of(year, month, day, hour, min).toInstant(offset);
1089    }
1090
1091    private Instant createInstant(int year, int month, int day, int hour, int min, int sec, int nano, ZoneOffset offset) {
1092        return LocalDateTime.of(year, month, day, hour, min, sec, nano).toInstant(offset);
1093    }
1094
1095    private ZonedDateTime createZDT(int year, int month, int day, ZoneId zone) {
1096        return LocalDateTime.of(year, month, day, 0, 0).atZone(zone);
1097    }
1098
1099    private LocalDateTime createLDT(int year, int month, int day) {
1100        return LocalDateTime.of(year, month, day, 0, 0);
1101    }
1102
1103    private ZoneOffsetTransition checkOffset(ZoneRules rules, LocalDateTime dateTime, ZoneOffset offset, int type) {
1104        List<ZoneOffset> validOffsets = rules.getValidOffsets(dateTime);
1105        assertEquals(validOffsets.size(), type);
1106        assertEquals(rules.getOffset(dateTime), offset);
1107        if (type == 1) {
1108            assertEquals(validOffsets.get(0), offset);
1109            return null;
1110        } else {
1111            ZoneOffsetTransition zot = rules.getTransition(dateTime);
1112            assertNotNull(zot);
1113            assertEquals(zot.isOverlap(), type == 2);
1114            assertEquals(zot.isGap(), type == 0);
1115            assertEquals(zot.isValidOffset(offset), type == 2);
1116            return zot;
1117        }
1118    }
1119
1120}
1121