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        // Android-changed: check for -1, which matches the data, we don't do the "optimization"
376        assertEquals(in.getDayOfMonthIndicator(), -1);  // optimized from -1
377        assertEquals(in.getDayOfWeek(), DayOfWeek.SUNDAY);
378        assertEquals(in.getLocalTime(), LocalTime.of(1, 0));
379        assertEquals(in.getTimeDefinition(), TimeDefinition.UTC);
380        assertEquals(in.getStandardOffset(), OFFSET_ZERO);
381        assertEquals(in.getOffsetBefore(), OFFSET_ZERO);
382        assertEquals(in.getOffsetAfter(), OFFSET_PONE);
383
384        ZoneOffsetTransitionRule out = rules.get(1);
385        assertEquals(out.getMonth(), Month.OCTOBER);
386        // Android-changed: check for -1, which matches the data, we don't do the "optimization"
387        assertEquals(out.getDayOfMonthIndicator(), -1);  // optimized from -1
388        assertEquals(out.getDayOfWeek(), DayOfWeek.SUNDAY);
389        assertEquals(out.getLocalTime(), LocalTime.of(1, 0));
390        assertEquals(out.getTimeDefinition(), TimeDefinition.UTC);
391        assertEquals(out.getStandardOffset(), OFFSET_ZERO);
392        assertEquals(out.getOffsetBefore(), OFFSET_PONE);
393        assertEquals(out.getOffsetAfter(), OFFSET_ZERO);
394    }
395
396    //-----------------------------------------------------------------------
397    public void test_London_nextTransition_historic() {
398        ZoneRules test = europeLondon();
399        List<ZoneOffsetTransition> trans = test.getTransitions();
400
401        ZoneOffsetTransition first = trans.get(0);
402        assertEquals(test.nextTransition(first.getInstant().minusNanos(1)), first);
403
404        for (int i = 0; i < trans.size() - 1; i++) {
405            ZoneOffsetTransition cur = trans.get(i);
406            ZoneOffsetTransition next = trans.get(i + 1);
407
408            assertEquals(test.nextTransition(cur.getInstant()), next);
409            assertEquals(test.nextTransition(next.getInstant().minusNanos(1)), next);
410        }
411    }
412
413    public void test_London_nextTransition_rulesBased() {
414        ZoneRules test = europeLondon();
415        List<ZoneOffsetTransitionRule> rules = test.getTransitionRules();
416        List<ZoneOffsetTransition> trans = test.getTransitions();
417
418        ZoneOffsetTransition last = trans.get(trans.size() - 1);
419        assertEquals(test.nextTransition(last.getInstant()), rules.get(0).createTransition(1998));
420
421        for (int year = 1998; year < 2010; year++) {
422            ZoneOffsetTransition a = rules.get(0).createTransition(year);
423            ZoneOffsetTransition b = rules.get(1).createTransition(year);
424            ZoneOffsetTransition c = rules.get(0).createTransition(year + 1);
425
426            assertEquals(test.nextTransition(a.getInstant()), b);
427            assertEquals(test.nextTransition(b.getInstant().minusNanos(1)), b);
428
429            assertEquals(test.nextTransition(b.getInstant()), c);
430            assertEquals(test.nextTransition(c.getInstant().minusNanos(1)), c);
431        }
432    }
433
434    public void test_London_nextTransition_lastYear() {
435        ZoneRules test = europeLondon();
436        List<ZoneOffsetTransitionRule> rules = test.getTransitionRules();
437        ZoneOffsetTransition zot = rules.get(1).createTransition(Year.MAX_VALUE);
438        assertEquals(test.nextTransition(zot.getInstant()), null);
439    }
440
441    //-----------------------------------------------------------------------
442    public void test_London_previousTransition_historic() {
443        ZoneRules test = europeLondon();
444        List<ZoneOffsetTransition> trans = test.getTransitions();
445
446        ZoneOffsetTransition first = trans.get(0);
447        assertEquals(test.previousTransition(first.getInstant()), null);
448        assertEquals(test.previousTransition(first.getInstant().minusNanos(1)), null);
449
450        for (int i = 0; i < trans.size() - 1; i++) {
451            ZoneOffsetTransition prev = trans.get(i);
452            ZoneOffsetTransition cur = trans.get(i + 1);
453
454            assertEquals(test.previousTransition(cur.getInstant()), prev);
455            assertEquals(test.previousTransition(prev.getInstant().plusSeconds(1)), prev);
456            assertEquals(test.previousTransition(prev.getInstant().plusNanos(1)), prev);
457        }
458    }
459
460    public void test_London_previousTransition_rulesBased() {
461        ZoneRules test = europeLondon();
462        List<ZoneOffsetTransitionRule> rules = test.getTransitionRules();
463        List<ZoneOffsetTransition> trans = test.getTransitions();
464
465        ZoneOffsetTransition last = trans.get(trans.size() - 1);
466        assertEquals(test.previousTransition(last.getInstant().plusSeconds(1)), last);
467        assertEquals(test.previousTransition(last.getInstant().plusNanos(1)), last);
468
469        // Jan 1st of year between transitions and rules
470        ZonedDateTime odt = ZonedDateTime.ofInstant(last.getInstant(), last.getOffsetAfter());
471        odt = odt.withDayOfYear(1).plusYears(1).with(LocalTime.MIDNIGHT);
472        assertEquals(test.previousTransition(odt.toInstant()), last);
473
474        // later years
475        for (int year = 1998; year < 2010; year++) {
476            ZoneOffsetTransition a = rules.get(0).createTransition(year);
477            ZoneOffsetTransition b = rules.get(1).createTransition(year);
478            ZoneOffsetTransition c = rules.get(0).createTransition(year + 1);
479
480            assertEquals(test.previousTransition(c.getInstant()), b);
481            assertEquals(test.previousTransition(b.getInstant().plusSeconds(1)), b);
482            assertEquals(test.previousTransition(b.getInstant().plusNanos(1)), b);
483
484            assertEquals(test.previousTransition(b.getInstant()), a);
485            assertEquals(test.previousTransition(a.getInstant().plusSeconds(1)), a);
486            assertEquals(test.previousTransition(a.getInstant().plusNanos(1)), a);
487        }
488    }
489
490    //-----------------------------------------------------------------------
491    // Europe/Paris
492    //-----------------------------------------------------------------------
493    private ZoneRules europeParis() {
494        return ZoneId.of("Europe/Paris").getRules();
495    }
496
497    public void test_Paris() {
498        ZoneRules test = europeParis();
499        assertEquals(test.isFixedOffset(), false);
500    }
501
502    public void test_Paris_preTimeZones() {
503        ZoneRules test = europeParis();
504        ZonedDateTime old = createZDT(1800, 1, 1, ZoneOffset.UTC);
505        Instant instant = old.toInstant();
506        ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(0, 9, 21);
507        assertEquals(test.getOffset(instant), offset);
508        checkOffset(test, old.toLocalDateTime(), offset, 1);
509        assertEquals(test.getStandardOffset(instant), offset);
510        assertEquals(test.getDaylightSavings(instant), Duration.ZERO);
511        assertEquals(test.isDaylightSavings(instant), false);
512    }
513
514    public void test_Paris_getOffset() {
515        ZoneRules test = europeParis();
516        assertEquals(test.getOffset(createInstant(2008, 1, 1, ZoneOffset.UTC)), OFFSET_PONE);
517        assertEquals(test.getOffset(createInstant(2008, 2, 1, ZoneOffset.UTC)), OFFSET_PONE);
518        assertEquals(test.getOffset(createInstant(2008, 3, 1, ZoneOffset.UTC)), OFFSET_PONE);
519        assertEquals(test.getOffset(createInstant(2008, 4, 1, ZoneOffset.UTC)), OFFSET_PTWO);
520        assertEquals(test.getOffset(createInstant(2008, 5, 1, ZoneOffset.UTC)), OFFSET_PTWO);
521        assertEquals(test.getOffset(createInstant(2008, 6, 1, ZoneOffset.UTC)), OFFSET_PTWO);
522        assertEquals(test.getOffset(createInstant(2008, 7, 1, ZoneOffset.UTC)), OFFSET_PTWO);
523        assertEquals(test.getOffset(createInstant(2008, 8, 1, ZoneOffset.UTC)), OFFSET_PTWO);
524        assertEquals(test.getOffset(createInstant(2008, 9, 1, ZoneOffset.UTC)), OFFSET_PTWO);
525        assertEquals(test.getOffset(createInstant(2008, 10, 1, ZoneOffset.UTC)), OFFSET_PTWO);
526        assertEquals(test.getOffset(createInstant(2008, 11, 1, ZoneOffset.UTC)), OFFSET_PONE);
527        assertEquals(test.getOffset(createInstant(2008, 12, 1, ZoneOffset.UTC)), OFFSET_PONE);
528    }
529
530    public void test_Paris_getOffset_toDST() {
531        ZoneRules test = europeParis();
532        assertEquals(test.getOffset(createInstant(2008, 3, 24, ZoneOffset.UTC)), OFFSET_PONE);
533        assertEquals(test.getOffset(createInstant(2008, 3, 25, ZoneOffset.UTC)), OFFSET_PONE);
534        assertEquals(test.getOffset(createInstant(2008, 3, 26, ZoneOffset.UTC)), OFFSET_PONE);
535        assertEquals(test.getOffset(createInstant(2008, 3, 27, ZoneOffset.UTC)), OFFSET_PONE);
536        assertEquals(test.getOffset(createInstant(2008, 3, 28, ZoneOffset.UTC)), OFFSET_PONE);
537        assertEquals(test.getOffset(createInstant(2008, 3, 29, ZoneOffset.UTC)), OFFSET_PONE);
538        assertEquals(test.getOffset(createInstant(2008, 3, 30, ZoneOffset.UTC)), OFFSET_PONE);
539        assertEquals(test.getOffset(createInstant(2008, 3, 31, ZoneOffset.UTC)), OFFSET_PTWO);
540        // cutover at 01:00Z
541        assertEquals(test.getOffset(createInstant(2008, 3, 30, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_PONE);
542        assertEquals(test.getOffset(createInstant(2008, 3, 30, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_PTWO);
543    }
544
545    public void test_Paris_getOffset_fromDST() {
546        ZoneRules test = europeParis();
547        assertEquals(test.getOffset(createInstant(2008, 10, 24, ZoneOffset.UTC)), OFFSET_PTWO);
548        assertEquals(test.getOffset(createInstant(2008, 10, 25, ZoneOffset.UTC)), OFFSET_PTWO);
549        assertEquals(test.getOffset(createInstant(2008, 10, 26, ZoneOffset.UTC)), OFFSET_PTWO);
550        assertEquals(test.getOffset(createInstant(2008, 10, 27, ZoneOffset.UTC)), OFFSET_PONE);
551        assertEquals(test.getOffset(createInstant(2008, 10, 28, ZoneOffset.UTC)), OFFSET_PONE);
552        assertEquals(test.getOffset(createInstant(2008, 10, 29, ZoneOffset.UTC)), OFFSET_PONE);
553        assertEquals(test.getOffset(createInstant(2008, 10, 30, ZoneOffset.UTC)), OFFSET_PONE);
554        assertEquals(test.getOffset(createInstant(2008, 10, 31, ZoneOffset.UTC)), OFFSET_PONE);
555        // cutover at 01:00Z
556        assertEquals(test.getOffset(createInstant(2008, 10, 26, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_PTWO);
557        assertEquals(test.getOffset(createInstant(2008, 10, 26, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_PONE);
558    }
559
560    public void test_Paris_getOffsetInfo() {
561        ZoneRules test = europeParis();
562        checkOffset(test, createLDT(2008, 1, 1), OFFSET_PONE, 1);
563        checkOffset(test, createLDT(2008, 2, 1), OFFSET_PONE, 1);
564        checkOffset(test, createLDT(2008, 3, 1), OFFSET_PONE, 1);
565        checkOffset(test, createLDT(2008, 4, 1), OFFSET_PTWO, 1);
566        checkOffset(test, createLDT(2008, 5, 1), OFFSET_PTWO, 1);
567        checkOffset(test, createLDT(2008, 6, 1), OFFSET_PTWO, 1);
568        checkOffset(test, createLDT(2008, 7, 1), OFFSET_PTWO, 1);
569        checkOffset(test, createLDT(2008, 8, 1), OFFSET_PTWO, 1);
570        checkOffset(test, createLDT(2008, 9, 1), OFFSET_PTWO, 1);
571        checkOffset(test, createLDT(2008, 10, 1), OFFSET_PTWO, 1);
572        checkOffset(test, createLDT(2008, 11, 1), OFFSET_PONE, 1);
573        checkOffset(test, createLDT(2008, 12, 1), OFFSET_PONE, 1);
574    }
575
576    public void test_Paris_getOffsetInfo_toDST() {
577        ZoneRules test = europeParis();
578        checkOffset(test, createLDT(2008, 3, 24), OFFSET_PONE, 1);
579        checkOffset(test, createLDT(2008, 3, 25), OFFSET_PONE, 1);
580        checkOffset(test, createLDT(2008, 3, 26), OFFSET_PONE, 1);
581        checkOffset(test, createLDT(2008, 3, 27), OFFSET_PONE, 1);
582        checkOffset(test, createLDT(2008, 3, 28), OFFSET_PONE, 1);
583        checkOffset(test, createLDT(2008, 3, 29), OFFSET_PONE, 1);
584        checkOffset(test, createLDT(2008, 3, 30), OFFSET_PONE, 1);
585        checkOffset(test, createLDT(2008, 3, 31), OFFSET_PTWO, 1);
586        // cutover at 01:00Z which is 02:00+01:00(local Paris time)
587        checkOffset(test, LocalDateTime.of(2008, 3, 30, 1, 59, 59, 999999999), OFFSET_PONE, 1);
588        checkOffset(test, LocalDateTime.of(2008, 3, 30, 3, 0, 0, 0), OFFSET_PTWO, 1);
589    }
590
591    public void test_Paris_getOffsetInfo_fromDST() {
592        ZoneRules test = europeParis();
593        checkOffset(test, createLDT(2008, 10, 24), OFFSET_PTWO, 1);
594        checkOffset(test, createLDT(2008, 10, 25), OFFSET_PTWO, 1);
595        checkOffset(test, createLDT(2008, 10, 26), OFFSET_PTWO, 1);
596        checkOffset(test, createLDT(2008, 10, 27), OFFSET_PONE, 1);
597        checkOffset(test, createLDT(2008, 10, 28), OFFSET_PONE, 1);
598        checkOffset(test, createLDT(2008, 10, 29), OFFSET_PONE, 1);
599        checkOffset(test, createLDT(2008, 10, 30), OFFSET_PONE, 1);
600        checkOffset(test, createLDT(2008, 10, 31), OFFSET_PONE, 1);
601        // cutover at 01:00Z which is 02:00+01:00(local Paris time)
602        checkOffset(test, LocalDateTime.of(2008, 10, 26, 1, 59, 59, 999999999), OFFSET_PTWO, 1);
603        checkOffset(test, LocalDateTime.of(2008, 10, 26, 3, 0, 0, 0), OFFSET_PONE, 1);
604    }
605
606    public void test_Paris_getOffsetInfo_gap() {
607        ZoneRules test = europeParis();
608        final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 30, 2, 0, 0, 0);
609        ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_PONE, GAP);
610        assertEquals(trans.isGap(), true);
611        assertEquals(trans.isOverlap(), false);
612        assertEquals(trans.getOffsetBefore(), OFFSET_PONE);
613        assertEquals(trans.getOffsetAfter(), OFFSET_PTWO);
614        assertEquals(trans.getInstant(), createInstant(2008, 3, 30, 1, 0, ZoneOffset.UTC));
615        assertEquals(trans.isValidOffset(OFFSET_ZERO), false);
616        assertEquals(trans.isValidOffset(OFFSET_PONE), false);
617        assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
618        assertEquals(trans.toString(), "Transition[Gap at 2008-03-30T02:00+01:00 to +02:00]");
619
620        assertFalse(trans.equals(null));
621        assertFalse(trans.equals(OFFSET_PONE));
622        assertTrue(trans.equals(trans));
623
624        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
625        assertTrue(trans.equals(otherTrans));
626        assertEquals(trans.hashCode(), otherTrans.hashCode());
627    }
628
629    public void test_Paris_getOffsetInfo_overlap() {
630        ZoneRules test = europeParis();
631        final LocalDateTime dateTime = LocalDateTime.of(2008, 10, 26, 2, 0, 0, 0);
632        ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_PTWO, OVERLAP);
633        assertEquals(trans.isGap(), false);
634        assertEquals(trans.isOverlap(), true);
635        assertEquals(trans.getOffsetBefore(), OFFSET_PTWO);
636        assertEquals(trans.getOffsetAfter(), OFFSET_PONE);
637        assertEquals(trans.getInstant(), createInstant(2008, 10, 26, 1, 0, ZoneOffset.UTC));
638        assertEquals(trans.isValidOffset(OFFSET_ZERO), false);
639        assertEquals(trans.isValidOffset(OFFSET_PONE), true);
640        assertEquals(trans.isValidOffset(OFFSET_PTWO), true);
641        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(3)), false);
642        assertEquals(trans.toString(), "Transition[Overlap at 2008-10-26T03:00+02:00 to +01:00]");
643
644        assertFalse(trans.equals(null));
645        assertFalse(trans.equals(OFFSET_PTWO));
646        assertTrue(trans.equals(trans));
647
648        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
649        assertTrue(trans.equals(otherTrans));
650        assertEquals(trans.hashCode(), otherTrans.hashCode());
651    }
652
653    public void test_Paris_getStandardOffset() {
654        ZoneRules test = europeParis();
655        ZonedDateTime zdt = createZDT(1840, 1, 1, ZoneOffset.UTC);
656        while (zdt.getYear() < 2010) {
657            Instant instant = zdt.toInstant();
658            if (zdt.toLocalDate().isBefore(LocalDate.of(1911, 3, 11))) {
659                assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHoursMinutesSeconds(0, 9, 21));
660            } else if (zdt.toLocalDate().isBefore(LocalDate.of(1940, 6, 14))) {
661                assertEquals(test.getStandardOffset(instant), OFFSET_ZERO);
662            } else if (zdt.toLocalDate().isBefore(LocalDate.of(1944, 8, 25))) {
663                assertEquals(test.getStandardOffset(instant), OFFSET_PONE);
664            } else if (zdt.toLocalDate().isBefore(LocalDate.of(1945, 9, 16))) {
665                assertEquals(test.getStandardOffset(instant), OFFSET_ZERO);
666            } else {
667                assertEquals(test.getStandardOffset(instant), OFFSET_PONE);
668            }
669            zdt = zdt.plusMonths(6);
670        }
671    }
672
673    //-----------------------------------------------------------------------
674    // America/New_York
675    //-----------------------------------------------------------------------
676    private ZoneRules americaNewYork() {
677        return ZoneId.of("America/New_York").getRules();
678    }
679
680    public void test_NewYork() {
681        ZoneRules test = americaNewYork();
682        assertEquals(test.isFixedOffset(), false);
683    }
684
685    public void test_NewYork_preTimeZones() {
686        ZoneRules test = americaNewYork();
687        ZonedDateTime old = createZDT(1800, 1, 1, ZoneOffset.UTC);
688        Instant instant = old.toInstant();
689        ZoneOffset offset = ZoneOffset.of("-04:56:02");
690        assertEquals(test.getOffset(instant), offset);
691        checkOffset(test, old.toLocalDateTime(), offset, 1);
692        assertEquals(test.getStandardOffset(instant), offset);
693        assertEquals(test.getDaylightSavings(instant), Duration.ZERO);
694        assertEquals(test.isDaylightSavings(instant), false);
695    }
696
697    public void test_NewYork_getOffset() {
698        ZoneRules test = americaNewYork();
699        ZoneOffset offset = ZoneOffset.ofHours(-5);
700        assertEquals(test.getOffset(createInstant(2008, 1, 1, offset)), ZoneOffset.ofHours(-5));
701        assertEquals(test.getOffset(createInstant(2008, 2, 1, offset)), ZoneOffset.ofHours(-5));
702        assertEquals(test.getOffset(createInstant(2008, 3, 1, offset)), ZoneOffset.ofHours(-5));
703        assertEquals(test.getOffset(createInstant(2008, 4, 1, offset)), ZoneOffset.ofHours(-4));
704        assertEquals(test.getOffset(createInstant(2008, 5, 1, offset)), ZoneOffset.ofHours(-4));
705        assertEquals(test.getOffset(createInstant(2008, 6, 1, offset)), ZoneOffset.ofHours(-4));
706        assertEquals(test.getOffset(createInstant(2008, 7, 1, offset)), ZoneOffset.ofHours(-4));
707        assertEquals(test.getOffset(createInstant(2008, 8, 1, offset)), ZoneOffset.ofHours(-4));
708        assertEquals(test.getOffset(createInstant(2008, 9, 1, offset)), ZoneOffset.ofHours(-4));
709        assertEquals(test.getOffset(createInstant(2008, 10, 1, offset)), ZoneOffset.ofHours(-4));
710        assertEquals(test.getOffset(createInstant(2008, 11, 1, offset)), ZoneOffset.ofHours(-4));
711        assertEquals(test.getOffset(createInstant(2008, 12, 1, offset)), ZoneOffset.ofHours(-5));
712        assertEquals(test.getOffset(createInstant(2008, 1, 28, offset)), ZoneOffset.ofHours(-5));
713        assertEquals(test.getOffset(createInstant(2008, 2, 28, offset)), ZoneOffset.ofHours(-5));
714        assertEquals(test.getOffset(createInstant(2008, 3, 28, offset)), ZoneOffset.ofHours(-4));
715        assertEquals(test.getOffset(createInstant(2008, 4, 28, offset)), ZoneOffset.ofHours(-4));
716        assertEquals(test.getOffset(createInstant(2008, 5, 28, offset)), ZoneOffset.ofHours(-4));
717        assertEquals(test.getOffset(createInstant(2008, 6, 28, offset)), ZoneOffset.ofHours(-4));
718        assertEquals(test.getOffset(createInstant(2008, 7, 28, offset)), ZoneOffset.ofHours(-4));
719        assertEquals(test.getOffset(createInstant(2008, 8, 28, offset)), ZoneOffset.ofHours(-4));
720        assertEquals(test.getOffset(createInstant(2008, 9, 28, offset)), ZoneOffset.ofHours(-4));
721        assertEquals(test.getOffset(createInstant(2008, 10, 28, offset)), ZoneOffset.ofHours(-4));
722        assertEquals(test.getOffset(createInstant(2008, 11, 28, offset)), ZoneOffset.ofHours(-5));
723        assertEquals(test.getOffset(createInstant(2008, 12, 28, offset)), ZoneOffset.ofHours(-5));
724    }
725
726    public void test_NewYork_getOffset_toDST() {
727        ZoneRules test = americaNewYork();
728        ZoneOffset offset = ZoneOffset.ofHours(-5);
729        assertEquals(test.getOffset(createInstant(2008, 3, 8, offset)), ZoneOffset.ofHours(-5));
730        assertEquals(test.getOffset(createInstant(2008, 3, 9, offset)), ZoneOffset.ofHours(-5));
731        assertEquals(test.getOffset(createInstant(2008, 3, 10, offset)), ZoneOffset.ofHours(-4));
732        assertEquals(test.getOffset(createInstant(2008, 3, 11, offset)), ZoneOffset.ofHours(-4));
733        assertEquals(test.getOffset(createInstant(2008, 3, 12, offset)), ZoneOffset.ofHours(-4));
734        assertEquals(test.getOffset(createInstant(2008, 3, 13, offset)), ZoneOffset.ofHours(-4));
735        assertEquals(test.getOffset(createInstant(2008, 3, 14, offset)), ZoneOffset.ofHours(-4));
736        // cutover at 02:00 local
737        assertEquals(test.getOffset(createInstant(2008, 3, 9, 1, 59, 59, 999999999, offset)), ZoneOffset.ofHours(-5));
738        assertEquals(test.getOffset(createInstant(2008, 3, 9, 2, 0, 0, 0, offset)), ZoneOffset.ofHours(-4));
739    }
740
741    public void test_NewYork_getOffset_fromDST() {
742        ZoneRules test = americaNewYork();
743        ZoneOffset offset = ZoneOffset.ofHours(-4);
744        assertEquals(test.getOffset(createInstant(2008, 11, 1, offset)), ZoneOffset.ofHours(-4));
745        assertEquals(test.getOffset(createInstant(2008, 11, 2, offset)), ZoneOffset.ofHours(-4));
746        assertEquals(test.getOffset(createInstant(2008, 11, 3, offset)), ZoneOffset.ofHours(-5));
747        assertEquals(test.getOffset(createInstant(2008, 11, 4, offset)), ZoneOffset.ofHours(-5));
748        assertEquals(test.getOffset(createInstant(2008, 11, 5, offset)), ZoneOffset.ofHours(-5));
749        assertEquals(test.getOffset(createInstant(2008, 11, 6, offset)), ZoneOffset.ofHours(-5));
750        assertEquals(test.getOffset(createInstant(2008, 11, 7, offset)), ZoneOffset.ofHours(-5));
751        // cutover at 02:00 local
752        assertEquals(test.getOffset(createInstant(2008, 11, 2, 1, 59, 59, 999999999, offset)), ZoneOffset.ofHours(-4));
753        assertEquals(test.getOffset(createInstant(2008, 11, 2, 2, 0, 0, 0, offset)), ZoneOffset.ofHours(-5));
754    }
755
756    public void test_NewYork_getOffsetInfo() {
757        ZoneRules test = americaNewYork();
758        checkOffset(test, createLDT(2008, 1, 1), ZoneOffset.ofHours(-5), 1);
759        checkOffset(test, createLDT(2008, 2, 1), ZoneOffset.ofHours(-5), 1);
760        checkOffset(test, createLDT(2008, 3, 1), ZoneOffset.ofHours(-5), 1);
761        checkOffset(test, createLDT(2008, 4, 1), ZoneOffset.ofHours(-4), 1);
762        checkOffset(test, createLDT(2008, 5, 1), ZoneOffset.ofHours(-4), 1);
763        checkOffset(test, createLDT(2008, 6, 1), ZoneOffset.ofHours(-4), 1);
764        checkOffset(test, createLDT(2008, 7, 1), ZoneOffset.ofHours(-4), 1);
765        checkOffset(test, createLDT(2008, 8, 1), ZoneOffset.ofHours(-4), 1);
766        checkOffset(test, createLDT(2008, 9, 1), ZoneOffset.ofHours(-4), 1);
767        checkOffset(test, createLDT(2008, 10, 1), ZoneOffset.ofHours(-4), 1);
768        checkOffset(test, createLDT(2008, 11, 1), ZoneOffset.ofHours(-4), 1);
769        checkOffset(test, createLDT(2008, 12, 1), ZoneOffset.ofHours(-5), 1);
770        checkOffset(test, createLDT(2008, 1, 28), ZoneOffset.ofHours(-5), 1);
771        checkOffset(test, createLDT(2008, 2, 28), ZoneOffset.ofHours(-5), 1);
772        checkOffset(test, createLDT(2008, 3, 28), ZoneOffset.ofHours(-4), 1);
773        checkOffset(test, createLDT(2008, 4, 28), ZoneOffset.ofHours(-4), 1);
774        checkOffset(test, createLDT(2008, 5, 28), ZoneOffset.ofHours(-4), 1);
775        checkOffset(test, createLDT(2008, 6, 28), ZoneOffset.ofHours(-4), 1);
776        checkOffset(test, createLDT(2008, 7, 28), ZoneOffset.ofHours(-4), 1);
777        checkOffset(test, createLDT(2008, 8, 28), ZoneOffset.ofHours(-4), 1);
778        checkOffset(test, createLDT(2008, 9, 28), ZoneOffset.ofHours(-4), 1);
779        checkOffset(test, createLDT(2008, 10, 28), ZoneOffset.ofHours(-4), 1);
780        checkOffset(test, createLDT(2008, 11, 28), ZoneOffset.ofHours(-5), 1);
781        checkOffset(test, createLDT(2008, 12, 28), ZoneOffset.ofHours(-5), 1);
782    }
783
784    public void test_NewYork_getOffsetInfo_toDST() {
785        ZoneRules test = americaNewYork();
786        checkOffset(test, createLDT(2008, 3, 8), ZoneOffset.ofHours(-5), 1);
787        checkOffset(test, createLDT(2008, 3, 9), ZoneOffset.ofHours(-5), 1);
788        checkOffset(test, createLDT(2008, 3, 10), ZoneOffset.ofHours(-4), 1);
789        checkOffset(test, createLDT(2008, 3, 11), ZoneOffset.ofHours(-4), 1);
790        checkOffset(test, createLDT(2008, 3, 12), ZoneOffset.ofHours(-4), 1);
791        checkOffset(test, createLDT(2008, 3, 13), ZoneOffset.ofHours(-4), 1);
792        checkOffset(test, createLDT(2008, 3, 14), ZoneOffset.ofHours(-4), 1);
793        // cutover at 02:00 local
794        checkOffset(test, LocalDateTime.of(2008, 3, 9, 1, 59, 59, 999999999), ZoneOffset.ofHours(-5), 1);
795        checkOffset(test, LocalDateTime.of(2008, 3, 9, 3, 0, 0, 0), ZoneOffset.ofHours(-4), 1);
796    }
797
798    public void test_NewYork_getOffsetInfo_fromDST() {
799        ZoneRules test = americaNewYork();
800        checkOffset(test, createLDT(2008, 11, 1), ZoneOffset.ofHours(-4), 1);
801        checkOffset(test, createLDT(2008, 11, 2), ZoneOffset.ofHours(-4), 1);
802        checkOffset(test, createLDT(2008, 11, 3), ZoneOffset.ofHours(-5), 1);
803        checkOffset(test, createLDT(2008, 11, 4), ZoneOffset.ofHours(-5), 1);
804        checkOffset(test, createLDT(2008, 11, 5), ZoneOffset.ofHours(-5), 1);
805        checkOffset(test, createLDT(2008, 11, 6), ZoneOffset.ofHours(-5), 1);
806        checkOffset(test, createLDT(2008, 11, 7), ZoneOffset.ofHours(-5), 1);
807        // cutover at 02:00 local
808        checkOffset(test, LocalDateTime.of(2008, 11, 2, 0, 59, 59, 999999999), ZoneOffset.ofHours(-4), 1);
809        checkOffset(test, LocalDateTime.of(2008, 11, 2, 2, 0, 0, 0), ZoneOffset.ofHours(-5), 1);
810    }
811
812    public void test_NewYork_getOffsetInfo_gap() {
813        ZoneRules test = americaNewYork();
814        final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 9, 2, 0, 0, 0);
815        ZoneOffsetTransition trans = checkOffset(test, dateTime, ZoneOffset.ofHours(-5), GAP);
816        assertEquals(trans.isGap(), true);
817        assertEquals(trans.isOverlap(), false);
818        assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(-5));
819        assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(-4));
820        assertEquals(trans.getInstant(), createInstant(2008, 3, 9, 2, 0, ZoneOffset.ofHours(-5)));
821        assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
822        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-5)), false);
823        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-4)), false);
824        assertEquals(trans.toString(), "Transition[Gap at 2008-03-09T02:00-05:00 to -04:00]");
825
826        assertFalse(trans.equals(null));
827        assertFalse(trans.equals(ZoneOffset.ofHours(-5)));
828        assertTrue(trans.equals(trans));
829
830        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
831        assertTrue(trans.equals(otherTrans));
832        assertEquals(trans.hashCode(), otherTrans.hashCode());
833    }
834
835    public void test_NewYork_getOffsetInfo_overlap() {
836        ZoneRules test = americaNewYork();
837        final LocalDateTime dateTime = LocalDateTime.of(2008, 11, 2, 1, 0, 0, 0);
838        ZoneOffsetTransition trans = checkOffset(test, dateTime, ZoneOffset.ofHours(-4), OVERLAP);
839        assertEquals(trans.isGap(), false);
840        assertEquals(trans.isOverlap(), true);
841        assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(-4));
842        assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(-5));
843        assertEquals(trans.getInstant(), createInstant(2008, 11, 2, 2, 0, ZoneOffset.ofHours(-4)));
844        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-1)), false);
845        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-5)), true);
846        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-4)), true);
847        assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
848        assertEquals(trans.toString(), "Transition[Overlap at 2008-11-02T02:00-04:00 to -05:00]");
849
850        assertFalse(trans.equals(null));
851        assertFalse(trans.equals(ZoneOffset.ofHours(-4)));
852        assertTrue(trans.equals(trans));
853
854        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
855        assertTrue(trans.equals(otherTrans));
856        assertEquals(trans.hashCode(), otherTrans.hashCode());
857    }
858
859    public void test_NewYork_getStandardOffset() {
860        ZoneRules test = americaNewYork();
861        ZonedDateTime dateTime = createZDT(1860, 1, 1, ZoneOffset.UTC);
862        while (dateTime.getYear() < 2010) {
863            Instant instant = dateTime.toInstant();
864            if (dateTime.toLocalDate().isBefore(LocalDate.of(1883, 11, 18))) {
865                assertEquals(test.getStandardOffset(instant), ZoneOffset.of("-04:56:02"));
866            } else {
867                assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHours(-5));
868            }
869            dateTime = dateTime.plusMonths(6);
870        }
871    }
872
873    //-----------------------------------------------------------------------
874    // Kathmandu
875    //-----------------------------------------------------------------------
876    private ZoneRules asiaKathmandu() {
877        return ZoneId.of("Asia/Kathmandu").getRules();
878    }
879
880    public void test_Kathmandu_nextTransition_historic() {
881        ZoneRules test = asiaKathmandu();
882        List<ZoneOffsetTransition> trans = test.getTransitions();
883
884        ZoneOffsetTransition first = trans.get(0);
885        assertEquals(test.nextTransition(first.getInstant().minusNanos(1)), first);
886
887        for (int i = 0; i < trans.size() - 1; i++) {
888            ZoneOffsetTransition cur = trans.get(i);
889            ZoneOffsetTransition next = trans.get(i + 1);
890
891            assertEquals(test.nextTransition(cur.getInstant()), next);
892            assertEquals(test.nextTransition(next.getInstant().minusNanos(1)), next);
893        }
894    }
895
896    public void test_Kathmandu_nextTransition_noRules() {
897        ZoneRules test = asiaKathmandu();
898        List<ZoneOffsetTransition> trans = test.getTransitions();
899
900        ZoneOffsetTransition last = trans.get(trans.size() - 1);
901        assertEquals(test.nextTransition(last.getInstant()), null);
902    }
903
904    //-----------------------------------------------------------------------
905    // Apia
906    //-----------------------------------------------------------------------
907    private ZoneRules pacificApia() {
908        return ZoneId.of("Pacific/Apia").getRules();
909    }
910
911    public void test_Apia_nextTransition_historic() {
912        ZoneRules test = pacificApia();
913        List<ZoneOffsetTransition> trans = test.getTransitions();
914
915        ZoneOffsetTransition first = trans.get(0);
916        assertEquals(test.nextTransition(first.getInstant().minusNanos(1)), first);
917
918        for (int i = 0; i < trans.size() - 1; i++) {
919            ZoneOffsetTransition cur = trans.get(i);
920            ZoneOffsetTransition next = trans.get(i + 1);
921
922            assertEquals(test.nextTransition(cur.getInstant()), next);
923            assertEquals(test.nextTransition(next.getInstant().minusNanos(1)), next);
924        }
925    }
926
927    public void test_Apia_jumpOverInternationalDateLine_M10_to_P14() {
928        // transition occurred at 2011-12-30T00:00-10:00
929        ZoneRules test = pacificApia();
930        Instant instantBefore = LocalDate.of(2011, 12, 27).atStartOfDay(ZoneOffset.UTC).toInstant();
931        ZoneOffsetTransition trans = test.nextTransition(instantBefore);
932        assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(2011, 12, 30, 0, 0));
933        assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(2011, 12, 31, 0, 0));
934        assertEquals(trans.isGap(), true);
935        assertEquals(trans.isOverlap(), false);
936        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-10)), false);
937        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(+14)), false);
938        assertEquals(trans.getDuration(), Duration.ofHours(24));
939        assertEquals(trans.getInstant(), LocalDateTime.of(2011, 12, 31, 0, 0).toInstant(ZoneOffset.ofHours(+14)));
940
941        ZonedDateTime zdt = ZonedDateTime.of(2011, 12, 29, 23, 0, 0, 0, ZoneId.of("Pacific/Apia"));
942        assertEquals(zdt.plusHours(2).toLocalDateTime(), LocalDateTime.of(2011, 12, 31, 1, 0));
943    }
944
945    public void test_Apia_jumpForwardOverInternationalDateLine_P12_to_M12() {
946        // Android-changed: 1879 changed to 1892 in this test due to 2017c IANA update. Upstream
947        // will probably do the same. See https://bugs.openjdk.java.net/browse/JDK-8190259
948        // transition occurred at 1892-07-04T00:00+12:33:04
949        ZoneRules test = pacificApia();
950        Instant instantBefore = LocalDate.of(1892, 7, 2).atStartOfDay(ZoneOffset.UTC).toInstant();
951        ZoneOffsetTransition trans = test.nextTransition(instantBefore);
952        assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(1892, 7, 5, 0, 0));
953        assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(1892, 7, 4, 0, 0));
954        assertEquals(trans.isGap(), false);
955        assertEquals(trans.isOverlap(), true);
956        assertEquals(trans.isValidOffset(ZoneOffset.ofHoursMinutesSeconds(+12, 33, 4)), true);
957        assertEquals(trans.isValidOffset(ZoneOffset.ofHoursMinutesSeconds(-11, -26, -56)), true);
958        assertEquals(trans.getDuration(), Duration.ofHours(-24));
959        assertEquals(trans.getInstant(), LocalDateTime.of(1892, 7, 4, 0, 0).toInstant(ZoneOffset.ofHoursMinutesSeconds(-11, -26, -56)));
960
961        ZonedDateTime zdt = ZonedDateTime.of(1892, 7, 4, 23, 0, 0, 0, ZoneId.of("Pacific/Apia"));
962        assertEquals(zdt.plusHours(2).toLocalDateTime(), LocalDateTime.of(1892, 7, 4, 1, 0, 0));
963    }
964
965    //-------------------------------------------------------------------------
966    @Test(expectedExceptions=UnsupportedOperationException.class)
967    public void test_getTransitions_immutable() {
968        ZoneRules test = europeParis();
969        test.getTransitions().clear();
970    }
971
972    @Test(expectedExceptions=UnsupportedOperationException.class)
973    public void test_getTransitionRules_immutable() {
974        ZoneRules test = europeParis();
975        test.getTransitionRules().clear();
976    }
977
978    //-----------------------------------------------------------------------
979    // of()
980    //-----------------------------------------------------------------------
981    public void test_of(){
982        //used for standard offset
983        ZoneOffset stdOffset1 = ZoneOffset.UTC;
984        ZoneOffset stdOffset2 = ZoneOffset.ofHours(1);
985        LocalDateTime time_of_stdOffsetTransition1 = LocalDateTime.of(2013, 1, 5, 1, 0);
986        ZoneOffsetTransition  stdOffsetTransition1 = ZoneOffsetTransition.of(time_of_stdOffsetTransition1, stdOffset1, stdOffset2);
987        List<ZoneOffsetTransition> stdOffsetTransition_list = new ArrayList<ZoneOffsetTransition>();
988        stdOffsetTransition_list.add(stdOffsetTransition1);
989
990        //used for wall offset
991        ZoneOffset wallOffset1 = ZoneOffset.ofHours(2);
992        ZoneOffset wallOffset2 = ZoneOffset.ofHours(4);
993        ZoneOffset wallOffset3 = ZoneOffset.ofHours(7);
994
995        LocalDateTime time_of_wallOffsetTransition1 = LocalDateTime.of(2013, 2, 5, 1, 0);
996        LocalDateTime time_of_wallOffsetTransition2 = LocalDateTime.of(2013, 3, 5, 1, 0);
997        LocalDateTime time_of_wallOffsetTransition3 = LocalDateTime.of(2013, 10, 5, 1, 0);
998
999        ZoneOffsetTransition  wallOffsetTransition1 = ZoneOffsetTransition.of(time_of_wallOffsetTransition1, wallOffset1, wallOffset2);
1000        ZoneOffsetTransition  wallOffsetTransition2 = ZoneOffsetTransition.of(time_of_wallOffsetTransition2, wallOffset2, wallOffset3);
1001        ZoneOffsetTransition  wallOffsetTransition3 = ZoneOffsetTransition.of(time_of_wallOffsetTransition3, wallOffset3, wallOffset1);
1002
1003        List<ZoneOffsetTransition> wallOffsetTransition_list = new ArrayList<ZoneOffsetTransition>();
1004        wallOffsetTransition_list.add(wallOffsetTransition1);
1005        wallOffsetTransition_list.add(wallOffsetTransition2);
1006        wallOffsetTransition_list.add(wallOffsetTransition3);
1007
1008        //used for ZoneOffsetTransitionRule
1009        ZoneOffset ruleOffset = ZoneOffset.ofHours(3);
1010        ZoneOffsetTransitionRule.TimeDefinition timeDefinition = ZoneOffsetTransitionRule.TimeDefinition.valueOf("WALL");
1011        ZoneOffsetTransitionRule rule1 = ZoneOffsetTransitionRule.of(Month.FEBRUARY,
1012                                                                     2,
1013                                                                     DayOfWeek.MONDAY,
1014                                                                     LocalTime.of(1, 0),
1015                                                                     false,
1016                                                                     timeDefinition,
1017                                                                     ZoneOffset.UTC,
1018                                                                     ZoneOffset.UTC,
1019                                                                     ruleOffset
1020                                                                     );
1021         List<ZoneOffsetTransitionRule> rule_list = new ArrayList<ZoneOffsetTransitionRule>();
1022         rule_list.add(rule1);
1023
1024         //Begin verification
1025         ZoneRules zoneRule = ZoneRules.of(stdOffset1,
1026                                           wallOffset1,
1027                                           stdOffsetTransition_list,
1028                                           wallOffsetTransition_list,
1029                                           rule_list
1030                                           );
1031
1032         OffsetDateTime before_time_of_stdOffsetTransition1 = OffsetDateTime.of(time_of_stdOffsetTransition1, stdOffset1).minusSeconds(1);
1033         OffsetDateTime after_time_of_stdOffsetTransition1 = OffsetDateTime.of(time_of_stdOffsetTransition1, stdOffset1).plusSeconds(1);;
1034         assertEquals(zoneRule.getStandardOffset(before_time_of_stdOffsetTransition1.toInstant()), stdOffset1);
1035         assertEquals(zoneRule.getStandardOffset(after_time_of_stdOffsetTransition1.toInstant()), stdOffset2);
1036
1037         OffsetDateTime  before_time_of_wallOffsetTransition1 = OffsetDateTime.of(time_of_wallOffsetTransition1, wallOffset1).minusSeconds(1);
1038         OffsetDateTime  after_time_of_wallOffsetTransition1 = OffsetDateTime.of(time_of_wallOffsetTransition1, wallOffset1).plusSeconds(1);
1039         assertEquals(zoneRule.nextTransition(before_time_of_wallOffsetTransition1.toInstant()), wallOffsetTransition1);
1040         assertEquals(zoneRule.nextTransition(after_time_of_wallOffsetTransition1.toInstant()), wallOffsetTransition2);
1041
1042         OffsetDateTime  before_time_of_wallOffsetTransition2 = OffsetDateTime.of(time_of_wallOffsetTransition2, wallOffset2).minusSeconds(1);
1043         OffsetDateTime  after_time_of_wallOffsetTransition2 = OffsetDateTime.of(time_of_wallOffsetTransition2, wallOffset2).plusSeconds(1);
1044         assertEquals(zoneRule.nextTransition(before_time_of_wallOffsetTransition2.toInstant()), wallOffsetTransition2);
1045         assertEquals(zoneRule.nextTransition(after_time_of_wallOffsetTransition2.toInstant()), wallOffsetTransition3);
1046
1047         OffsetDateTime  before_time_of_wallOffsetTransition3 = OffsetDateTime.of(time_of_wallOffsetTransition3, wallOffset3).minusSeconds(1);
1048         OffsetDateTime  after_time_of_wallOffsetTransition3 = OffsetDateTime.of(time_of_wallOffsetTransition3, wallOffset3).plusSeconds(1);
1049         assertEquals(zoneRule.nextTransition(before_time_of_wallOffsetTransition3.toInstant()), wallOffsetTransition3);
1050         assertEquals(zoneRule.nextTransition(after_time_of_wallOffsetTransition3.toInstant()), rule1.createTransition(2014));
1051    }
1052
1053    //-----------------------------------------------------------------------
1054    // equals() / hashCode()
1055    //-----------------------------------------------------------------------
1056    public void test_equals() {
1057        ZoneRules test1 = europeLondon();
1058        ZoneRules test2 = europeParis();
1059        ZoneRules test2b = europeParis();
1060        assertEquals(test1.equals(test2), false);
1061        assertEquals(test2.equals(test1), false);
1062
1063        assertEquals(test1.equals(test1), true);
1064        assertEquals(test2.equals(test2), true);
1065        assertEquals(test2.equals(test2b), true);
1066
1067        assertEquals(test1.hashCode() == test1.hashCode(), true);
1068        assertEquals(test2.hashCode() == test2.hashCode(), true);
1069        assertEquals(test2.hashCode() == test2b.hashCode(), true);
1070    }
1071
1072    public void test_equals_null() {
1073        assertEquals(europeLondon().equals(null), false);
1074    }
1075
1076    public void test_equals_notZoneRules() {
1077        assertEquals(europeLondon().equals("Europe/London"), false);
1078    }
1079
1080    public void test_toString() {
1081        assertEquals(europeLondon().toString().contains("ZoneRules"), true);
1082    }
1083
1084    //-----------------------------------------------------------------------
1085    //-----------------------------------------------------------------------
1086    //-----------------------------------------------------------------------
1087    private Instant createInstant(int year, int month, int day, ZoneOffset offset) {
1088        return LocalDateTime.of(year, month, day, 0, 0).toInstant(offset);
1089    }
1090
1091    private Instant createInstant(int year, int month, int day, int hour, int min, ZoneOffset offset) {
1092        return LocalDateTime.of(year, month, day, hour, min).toInstant(offset);
1093    }
1094
1095    private Instant createInstant(int year, int month, int day, int hour, int min, int sec, int nano, ZoneOffset offset) {
1096        return LocalDateTime.of(year, month, day, hour, min, sec, nano).toInstant(offset);
1097    }
1098
1099    private ZonedDateTime createZDT(int year, int month, int day, ZoneId zone) {
1100        return LocalDateTime.of(year, month, day, 0, 0).atZone(zone);
1101    }
1102
1103    private LocalDateTime createLDT(int year, int month, int day) {
1104        return LocalDateTime.of(year, month, day, 0, 0);
1105    }
1106
1107    private ZoneOffsetTransition checkOffset(ZoneRules rules, LocalDateTime dateTime, ZoneOffset offset, int type) {
1108        List<ZoneOffset> validOffsets = rules.getValidOffsets(dateTime);
1109        assertEquals(validOffsets.size(), type);
1110        assertEquals(rules.getOffset(dateTime), offset);
1111        if (type == 1) {
1112            assertEquals(validOffsets.get(0), offset);
1113            return null;
1114        } else {
1115            ZoneOffsetTransition zot = rules.getTransition(dateTime);
1116            assertNotNull(zot);
1117            assertEquals(zot.isOverlap(), type == 2);
1118            assertEquals(zot.isGap(), type == 0);
1119            assertEquals(zot.isValidOffset(offset), type == 2);
1120            return zot;
1121        }
1122    }
1123
1124}
1125