• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  *  * Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  *
12  *  * Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  *  * Neither the name of JSR-310 nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package org.threeten.bp.zone;
33 
34 import static org.testng.Assert.assertEquals;
35 import static org.testng.Assert.assertNotNull;
36 import static org.threeten.bp.DayOfWeek.FRIDAY;
37 import static org.threeten.bp.DayOfWeek.MONDAY;
38 import static org.threeten.bp.DayOfWeek.SATURDAY;
39 import static org.threeten.bp.DayOfWeek.SUNDAY;
40 import static org.threeten.bp.DayOfWeek.THURSDAY;
41 import static org.threeten.bp.DayOfWeek.TUESDAY;
42 import static org.threeten.bp.Month.APRIL;
43 import static org.threeten.bp.Month.AUGUST;
44 import static org.threeten.bp.Month.FEBRUARY;
45 import static org.threeten.bp.Month.MARCH;
46 import static org.threeten.bp.Month.MAY;
47 import static org.threeten.bp.Month.NOVEMBER;
48 import static org.threeten.bp.Month.OCTOBER;
49 import static org.threeten.bp.Month.SEPTEMBER;
50 import static org.threeten.bp.zone.ZoneOffsetTransitionRule.TimeDefinition.STANDARD;
51 import static org.threeten.bp.zone.ZoneOffsetTransitionRule.TimeDefinition.UTC;
52 import static org.threeten.bp.zone.ZoneOffsetTransitionRule.TimeDefinition.WALL;
53 
54 import java.util.List;
55 
56 import org.testng.annotations.Test;
57 import org.threeten.bp.DateTimeException;
58 import org.threeten.bp.LocalDateTime;
59 import org.threeten.bp.LocalTime;
60 import org.threeten.bp.Month;
61 import org.threeten.bp.Year;
62 import org.threeten.bp.ZoneOffset;
63 import org.threeten.bp.zone.ZoneOffsetTransitionRule.TimeDefinition;
64 
65 /**
66  * Test ZoneRulesBuilder.
67  */
68 @Test
69 public class TestZoneRulesBuilder {
70 
71     private static final ZoneOffset OFFSET_1 = ZoneOffset.ofHours(1);
72     private static final ZoneOffset OFFSET_2 = ZoneOffset.ofHours(2);
73     private static final ZoneOffset OFFSET_1_15 = ZoneOffset.ofHoursMinutes(1, 15);
74     private static final ZoneOffset OFFSET_2_30 = ZoneOffset.ofHoursMinutes(2, 30);
75     private static final int PERIOD_0 = 0;
76     private static final int PERIOD_1HOUR = 60 * 60;
77     private static final int PERIOD_1HOUR30MIN = ((1 * 60) + 30) * 60;
78     private static final LocalDateTime DATE_TIME_FIRST = dateTime(Year.MIN_VALUE, 1, 1, 0, 0);
79     private static final LocalDateTime DATE_TIME_LAST = dateTime(Year.MAX_VALUE, 12, 31, 23, 59);
80     private static final LocalDateTime DATE_TIME_2008_01_01 = dateTime(2008, 1, 1, 0, 0);
81     private static final LocalDateTime DATE_TIME_2008_07_01 = dateTime(2008, 7, 1, 0, 0);
82 
83     //-----------------------------------------------------------------------
84     // toRules()
85     //-----------------------------------------------------------------------
86     @Test(expectedExceptions=IllegalStateException.class)
test_toRules_noWindows()87     public void test_toRules_noWindows() {
88         ZoneRulesBuilder b = new ZoneRulesBuilder();
89         b.toRules("Europe/London");
90     }
91 
92     @Test(expectedExceptions=NullPointerException.class)
test_toRules_null()93     public void test_toRules_null() {
94         ZoneRulesBuilder b = new ZoneRulesBuilder();
95         b.addWindowForever(OFFSET_2_30);
96         b.toRules(null);
97     }
98 
99     //-----------------------------------------------------------------------
100     // Combined
101     //-----------------------------------------------------------------------
102     @Test
test_combined_singleCutover()103     public void test_combined_singleCutover() {
104         ZoneRulesBuilder b = new ZoneRulesBuilder();
105         b.addWindow(OFFSET_1, dateTime(1950, 1, 1, 1, 0), STANDARD);
106         b.addWindowForever(OFFSET_2);
107         ZoneRules test = b.toRules("Europe/London");
108         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
109         assertGap(test, 1950, 1, 1, 1, 30, OFFSET_1, OFFSET_2);
110         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_2);
111     }
112 
113     @Test
test_combined_localFixedRules()114     public void test_combined_localFixedRules() {
115         ZoneRulesBuilder b = new ZoneRulesBuilder();
116         b.addWindow(OFFSET_1_15, dateTime(1920, 1, 1, 1, 0), WALL);
117         b.addWindow(OFFSET_1, dateTime(1950, 1, 1, 1, 0), WALL);
118         b.addWindowForever(OFFSET_1);
119         b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
120         b.addRuleToWindow(2000, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_0);
121         ZoneRules test = b.toRules("Europe/London");
122         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1_15);
123         assertOverlap(test, 1920, 1, 1, 0, 55, OFFSET_1_15, OFFSET_1);
124         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
125         assertOffsetInfo(test, dateTime(1800, 7, 1, 1, 0), OFFSET_1_15);
126         assertOffsetInfo(test, dateTime(1920, 1, 1, 1, 0), OFFSET_1);
127         assertOffsetInfo(test, dateTime(1960, 1, 1, 1, 0), OFFSET_1);
128         assertOffsetInfo(test, dateTime(2000, 1, 1, 1, 0), OFFSET_1);
129         assertOffsetInfo(test, DATE_TIME_2008_01_01, OFFSET_1);
130         assertOffsetInfo(test, DATE_TIME_2008_07_01, OFFSET_2_30);
131         assertGap(test, 2008, 3, 30, 1, 20, OFFSET_1, OFFSET_2_30);
132         assertOverlap(test, 2008, 10, 26, 0, 20, OFFSET_2_30, OFFSET_1);
133     }
134 
135     @Test
test_combined_windowChangeDuringDST()136     public void test_combined_windowChangeDuringDST() {
137         ZoneRulesBuilder b = new ZoneRulesBuilder();
138         b.addWindow(OFFSET_1, dateTime(2000, 7, 1, 1, 0), WALL);
139         b.addWindowForever(OFFSET_1);
140         b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR);
141         b.addRuleToWindow(2000, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(2, 0), false, WALL, PERIOD_0);
142         ZoneRules test = b.toRules("Europe/Dublin");
143         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
144         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
145 
146         assertOffsetInfo(test, dateTime(2000, 1, 1, 0, 0), OFFSET_1);
147         assertOffsetInfo(test, dateTime(2000, 7, 1, 0, 0), OFFSET_1);
148         assertGap(test, 2000, 7, 1, 1, 20, OFFSET_1, OFFSET_2);
149         assertOffsetInfo(test, dateTime(2000, 7, 1, 3, 0), OFFSET_2);
150         assertOverlap(test, 2000, 10, 29, 1, 20, OFFSET_2, OFFSET_1);
151         assertOffsetInfo(test, dateTime(2000, 12, 1, 0, 0), OFFSET_1);
152     }
153 
154     @Test
test_combined_windowChangeWithinDST()155     public void test_combined_windowChangeWithinDST() {
156         ZoneRulesBuilder b = new ZoneRulesBuilder();
157         b.addWindow(OFFSET_1, dateTime(2000, 7, 1, 1, 0), WALL);
158         b.addWindow(OFFSET_1, dateTime(2000, 8, 1, 2, 0), WALL);
159         b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR);
160         b.addRuleToWindow(2000, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(2, 0), false, WALL, PERIOD_0);
161         b.addWindowForever(OFFSET_1);
162         ZoneRules test = b.toRules("Europe/Dublin");
163         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
164         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
165 
166         assertOffsetInfo(test, dateTime(2000, 1, 1, 0, 0), OFFSET_1);
167         assertOffsetInfo(test, dateTime(2000, 7, 1, 0, 0), OFFSET_1);
168         assertGap(test, 2000, 7, 1, 1, 20, OFFSET_1, OFFSET_2);
169         assertOffsetInfo(test, dateTime(2000, 7, 1, 3, 0), OFFSET_2);
170         assertOverlap(test, 2000, 8, 1, 1, 20, OFFSET_2, OFFSET_1);
171         assertOffsetInfo(test, dateTime(2000, 12, 1, 0, 0), OFFSET_1);
172     }
173 
174     @Test
test_combined_endsInSavings()175     public void test_combined_endsInSavings() {
176         ZoneRulesBuilder b = new ZoneRulesBuilder();
177         b.addWindow(OFFSET_1_15, dateTime(1920, 1, 1, 1, 0), WALL);
178         b.addWindowForever(OFFSET_1);
179         b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_0);
180         b.addRuleToWindow(2000, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR);
181         ZoneRules test = b.toRules("Pacific/Auckland");
182         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1_15);
183         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_2);
184         assertOverlap(test, 1920, 1, 1, 0, 55, OFFSET_1_15, OFFSET_1);
185         assertOffsetInfo(test, dateTime(2000, 3, 26, 0, 59), OFFSET_1);
186         assertOffsetInfo(test, dateTime(2000, 3, 26, 1, 00), OFFSET_1);
187         assertGap(test, 2000, 10, 29, 1, 20, OFFSET_1, OFFSET_2);
188         assertOverlap(test, 2001, 3, 25, 0, 20, OFFSET_2, OFFSET_1);
189         assertGap(test, 2001, 10, 28, 1, 20, OFFSET_1, OFFSET_2);
190     }
191 
192     @Test
test_combined_closeTransitions()193     public void test_combined_closeTransitions() {
194         ZoneRulesBuilder b = new ZoneRulesBuilder();
195         b.addWindow(OFFSET_1, dateTime(1920, 1, 1, 1, 0), WALL);
196         b.addWindowForever(OFFSET_1);
197         b.addRuleToWindow(2000, MARCH, 20, time(2, 0), false, WALL, PERIOD_1HOUR);
198         b.addRuleToWindow(2000, MARCH, 20, time(4, 2), false, WALL, PERIOD_0);
199         ZoneRules test = b.toRules("Europe/London");
200         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
201         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
202         assertOffsetInfo(test, dateTime(2000, 3, 20, 1, 59), OFFSET_1);
203         assertGap(test, 2000, 3, 20, 2, 0, OFFSET_1, OFFSET_2);
204         assertGap(test, 2000, 3, 20, 2, 59, OFFSET_1, OFFSET_2);
205         assertOffsetInfo(test, dateTime(2000, 3, 20, 3, 0), OFFSET_2);
206         assertOffsetInfo(test, dateTime(2000, 3, 20, 3, 1), OFFSET_2);
207         assertOverlap(test, 2000, 3, 20, 3, 2, OFFSET_2, OFFSET_1);
208         assertOverlap(test, 2000, 3, 20, 4, 1, OFFSET_2, OFFSET_1);
209         assertOffsetInfo(test, dateTime(2000, 3, 20, 4, 2), OFFSET_1);
210     }
211 
212     @Test
test_combined_closeTransitionsMeet()213     public void test_combined_closeTransitionsMeet() {
214         ZoneRulesBuilder b = new ZoneRulesBuilder();
215         b.addWindow(OFFSET_1, dateTime(1920, 1, 1, 1, 0), WALL);
216         b.addWindowForever(OFFSET_1);
217         b.addRuleToWindow(2000, MARCH, 20, time(2, 0), false, WALL, PERIOD_1HOUR);
218         b.addRuleToWindow(2000, MARCH, 20, time(4, 0), false, WALL, PERIOD_0);
219         ZoneRules test = b.toRules("Europe/London");
220         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
221         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
222         assertOffsetInfo(test, dateTime(2000, 3, 20, 1, 59), OFFSET_1);
223         assertGap(test, 2000, 3, 20, 2, 0, OFFSET_1, OFFSET_2);
224         assertGap(test, 2000, 3, 20, 2, 59, OFFSET_1, OFFSET_2);
225         assertOverlap(test, 2000, 3, 20, 3, 0, OFFSET_2, OFFSET_1);
226         assertOverlap(test, 2000, 3, 20, 3, 59, OFFSET_2, OFFSET_1);
227         assertOffsetInfo(test, dateTime(2000, 3, 20, 4, 0), OFFSET_1);
228     }
229 
230 // TODO: handle conflicting gap/overlap
231 //    public void test_combined_closeTransitionsConflictPartly() {
232 //        TransitionRulesBuilder b = new TransitionRulesBuilder(OFFSET_1, dateTime(1920, 1, 1, 1, 0), WALL);
233 //        b.addWindowForever(OFFSET_1);
234 //        b.addRuleToWindow(2000, MARCH, 20, time(2, 0), WALL, PERIOD_1HOUR);
235 //        b.addRuleToWindow(2000, MARCH, 20, time(3, 30), WALL, PERIOD_0);
236 //        ZoneRules test = b.toRules("Europe/London");
237 //        assertOffsetInfo(test, DATE_TIME_FIRST), OFFSET_1);
238 //        assertOffsetInfo(test, DATE_TIME_LAST), OFFSET_1);
239 //        assertOffsetInfo(test, dateTime(2000, 3, 20, 1, 59)), OFFSET_1);
240 //        assertGap(test, 2000, 3, 20, 2, 0, OFFSET_1, OFFSET_2);
241 //        assertGap(test, 2000, 3, 20, 2, 29, OFFSET_1, OFFSET_2);
242 //        assertOffsetInfo(test, dateTime(2000, 3, 20, 2, 30)), OFFSET_1);
243 //        assertOffsetInfo(test, dateTime(2000, 3, 20, 2, 59)), OFFSET_1);
244 //        assertOverlap(test, 2000, 3, 20, 3, 0, OFFSET_2, OFFSET_1);
245 //        assertOverlap(test, 2000, 3, 20, 3, 29, OFFSET_2, OFFSET_1);
246 //        assertOffsetInfo(test, dateTime(2000, 3, 20, 3, 30)), OFFSET_1);
247 //    }
248 
249     @Test
test_combined_weirdSavingsBeforeLast()250     public void test_combined_weirdSavingsBeforeLast() {
251         ZoneRulesBuilder b = new ZoneRulesBuilder();
252         b.addWindow(OFFSET_1, dateTime(1920, 1, 1, 1, 0), WALL);
253         b.addWindowForever(OFFSET_1);
254         b.addRuleToWindow(1998, MARCH, 20, time(2, 0), false, WALL, PERIOD_1HOUR30MIN);
255         b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, 20, null, time(2, 0), false, WALL, PERIOD_1HOUR);
256         b.addRuleToWindow(2000, Year.MAX_VALUE, OCTOBER, 20, null, time(2, 0), false, WALL, PERIOD_0);
257         ZoneRules test = b.toRules("Europe/London");
258 
259         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
260         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
261 
262         assertOffsetInfo(test, dateTime(1999, 1, 1, 0, 0), OFFSET_2_30);
263         assertOverlap(test, 2000, 3, 20, 1, 30, OFFSET_2_30, OFFSET_2);
264         assertOverlap(test, 2000, 10, 20, 1, 30, OFFSET_2, OFFSET_1);
265         assertGap(test, 2001, 3, 20, 2, 30, OFFSET_1, OFFSET_2);
266         assertOverlap(test, 2001, 10, 20, 1, 30, OFFSET_2, OFFSET_1);
267     }
268 
269     @Test
test_combined_differentLengthLastRules1()270     public void test_combined_differentLengthLastRules1() {
271         ZoneRulesBuilder b = new ZoneRulesBuilder();
272         b.addWindow(OFFSET_1, dateTime(1920, 1, 1, 1, 0), WALL);
273         b.addWindowForever(OFFSET_1);
274         b.addRuleToWindow(1998, MARCH, 20, time(2, 0), false, WALL, PERIOD_1HOUR);
275         b.addRuleToWindow(1998, Year.MAX_VALUE, OCTOBER, 30, null, time(2, 0), false, WALL, PERIOD_0);
276         b.addRuleToWindow(1999, MARCH, 21, time(2, 0), false, WALL, PERIOD_1HOUR);
277         b.addRuleToWindow(2000, MARCH, 22, time(2, 0), false, WALL, PERIOD_1HOUR);
278         b.addRuleToWindow(2001, MARCH, 23, time(2, 0), false, WALL, PERIOD_1HOUR);
279         b.addRuleToWindow(2002, Year.MAX_VALUE, MARCH, 24, null, time(2, 0), false, WALL, PERIOD_1HOUR);
280         ZoneRules test = b.toRules("Europe/London");
281 
282         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
283         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
284 
285         assertGap(test, 1998, 3, 20, 2, 30, OFFSET_1, OFFSET_2);
286         assertOverlap(test, 1998, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
287         assertGap(test, 1999, 3, 21, 2, 30, OFFSET_1, OFFSET_2);
288         assertOverlap(test, 1999, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
289         assertGap(test, 2000, 3, 22, 2, 30, OFFSET_1, OFFSET_2);
290         assertOverlap(test, 2000, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
291         assertGap(test, 2001, 3, 23, 2, 30, OFFSET_1, OFFSET_2);
292         assertOverlap(test, 2001, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
293         assertGap(test, 2002, 3, 24, 2, 30, OFFSET_1, OFFSET_2);
294         assertOverlap(test, 2002, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
295         assertGap(test, 2003, 3, 24, 2, 30, OFFSET_1, OFFSET_2);
296         assertOverlap(test, 2003, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
297         assertGap(test, 2004, 3, 24, 2, 30, OFFSET_1, OFFSET_2);
298         assertOverlap(test, 2004, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
299         assertGap(test, 2005, 3, 24, 2, 30, OFFSET_1, OFFSET_2);
300         assertOverlap(test, 2005, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
301     }
302 
303     @Test
test_combined_differentLengthLastRules2()304     public void test_combined_differentLengthLastRules2() {
305         ZoneRulesBuilder b = new ZoneRulesBuilder();
306         b.addWindow(OFFSET_1, dateTime(1920, 1, 1, 1, 0), WALL);
307         b.addWindowForever(OFFSET_1);
308         b.addRuleToWindow(1998, Year.MAX_VALUE, MARCH, 30, null, time(2, 0), false, WALL, PERIOD_1HOUR);
309         b.addRuleToWindow(1998, OCTOBER, 20, time(2, 0), false, WALL, PERIOD_0);
310         b.addRuleToWindow(1999, OCTOBER, 21, time(2, 0), false, WALL, PERIOD_0);
311         b.addRuleToWindow(2000, OCTOBER, 22, time(2, 0), false, WALL, PERIOD_0);
312         b.addRuleToWindow(2001, OCTOBER, 23, time(2, 0), false, WALL, PERIOD_0);
313         b.addRuleToWindow(2002, Year.MAX_VALUE, OCTOBER, 24, null, time(2, 0), false, WALL, PERIOD_0);
314         ZoneRules test = b.toRules("Europe/London");
315 
316         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
317         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
318 
319         assertGap(test, 1998, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
320         assertOverlap(test, 1998, 10, 20, 1, 30, OFFSET_2, OFFSET_1);
321         assertGap(test, 1999, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
322         assertOverlap(test, 1999, 10, 21, 1, 30, OFFSET_2, OFFSET_1);
323         assertGap(test, 2000, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
324         assertOverlap(test, 2000, 10, 22, 1, 30, OFFSET_2, OFFSET_1);
325         assertGap(test, 2001, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
326         assertOverlap(test, 2001, 10, 23, 1, 30, OFFSET_2, OFFSET_1);
327         assertGap(test, 2002, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
328         assertOverlap(test, 2002, 10, 24, 1, 30, OFFSET_2, OFFSET_1);
329         assertGap(test, 2003, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
330         assertOverlap(test, 2003, 10, 24, 1, 30, OFFSET_2, OFFSET_1);
331         assertGap(test, 2004, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
332         assertOverlap(test, 2004, 10, 24, 1, 30, OFFSET_2, OFFSET_1);
333         assertGap(test, 2005, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
334         assertOverlap(test, 2005, 10, 24, 1, 30, OFFSET_2, OFFSET_1);
335     }
336 
337     @Test
test_twoChangesSameDay()338     public void test_twoChangesSameDay() {
339         // ensures that TZRule.compare works
340         ZoneOffset plus2 = ZoneOffset.ofHours(2);
341         ZoneOffset plus3 = ZoneOffset.ofHours(3);
342         ZoneRulesBuilder b = new ZoneRulesBuilder();
343         b.addWindowForever(plus2);
344         b.addRuleToWindow(2010, 2010, SEPTEMBER, 10, null, time(12, 0), false, STANDARD, PERIOD_1HOUR);
345         b.addRuleToWindow(2010, 2010, SEPTEMBER, 10, null, time(23, 0), false, STANDARD, PERIOD_0);
346         ZoneRules test = b.toRules("Africa/Cairo");
347 
348         assertOffsetInfo(test, DATE_TIME_FIRST, plus2);
349         assertOffsetInfo(test, DATE_TIME_LAST, plus2);
350 
351         assertGap(test, 2010, 9, 10, 12, 0, plus2, plus3);  // jump forward from 12:00 to 13:00 on Tue 10th Sep
352         assertOverlap(test, 2010, 9, 10, 23, 0, plus3, plus2);  // overlaps from Wed 11th Sep 00:00 back to Tue 10th Sep 23:00
353     }
354 
355     @Test
test_twoChangesDifferentDefinition()356     public void test_twoChangesDifferentDefinition() {
357         // ensures that TZRule.compare works
358         ZoneOffset plus2 = ZoneOffset.ofHours(2);
359         ZoneOffset plus3 = ZoneOffset.ofHours(3);
360         ZoneRulesBuilder b = new ZoneRulesBuilder();
361         b.addWindowForever(plus2);
362         b.addRuleToWindow(2010, 2010, SEPTEMBER, -1, TUESDAY, time(0, 0), false, STANDARD, PERIOD_1HOUR);
363         b.addRuleToWindow(2010, 2010, SEPTEMBER, 29, null, time(23, 0), false, STANDARD, PERIOD_0);
364         ZoneRules test = b.toRules("Africa/Cairo");
365 
366         assertOffsetInfo(test, DATE_TIME_FIRST, plus2);
367         assertOffsetInfo(test, DATE_TIME_LAST, plus2);
368 
369         assertGap(test, 2010, 9, 28, 0, 0, plus2, plus3);  // jump forward from 00:00 to 01:00 on Tue 28th Sep
370         assertOverlap(test, 2010, 9, 29, 23, 0, plus3, plus2);  // overlaps from Thu 30th Sep 00:00 back to Wed 29th Sep 23:00
371     }
372 
373     //-----------------------------------------------------------------------
374     @Test
test_argentina()375     public void test_argentina() {
376         //  # On October 3, 1999, 0:00 local, Argentina implemented daylight savings time,
377         //  # which did not result in the switch of a time zone, as they stayed 9 hours
378         //  # from the International Date Line.
379         //    Rule    Arg     1989    1993    -       Mar     Sun>=1  0:00    0       -
380         //    Rule    Arg     1989    1992    -       Oct     Sun>=15 0:00    1:00    S
381         //    Rule    Arg     1999    only    -       Oct     Sun>=1  0:00    1:00    S
382         //    Rule    Arg     2000    only    -       Mar     3       0:00    0       -
383         //    Zone America/Argentina/Tucuman -4:20:52 - LMT   1894 Oct 31
384         //                -3:00   Arg AR%sT   1999 Oct  3
385         //                -4:00   Arg AR%sT   2000 Mar  3
386 
387         ZoneOffset minus3 = ZoneOffset.ofHours(-3);
388         ZoneOffset minus4 = ZoneOffset.ofHours(-4);
389         ZoneRulesBuilder b = new ZoneRulesBuilder();
390         b.addWindow(minus3, dateTime(1900, 1, 1, 0, 0), WALL);
391         b.addWindow(minus3, dateTime(1999, 10, 3, 0, 0), WALL);
392         b.addRuleToWindow(1993, MARCH, 3, time(0, 0), false, WALL, PERIOD_0);
393         b.addRuleToWindow(1999, OCTOBER, 3, time(0, 0), false, WALL, PERIOD_1HOUR);
394         b.addRuleToWindow(2000, MARCH, 3, time(0, 0), false, WALL, PERIOD_0);
395         b.addWindow(minus4, dateTime(2000, 3, 3, 0, 0), WALL);
396         b.addRuleToWindow(1993, MARCH, 3, time(0, 0), false, WALL, PERIOD_0);
397         b.addRuleToWindow(1999, OCTOBER, 3, time(0, 0), false, WALL, PERIOD_1HOUR);
398         b.addRuleToWindow(2000, MARCH, 3, time(0, 0), false, WALL, PERIOD_0);
399         b.addWindowForever(minus3);
400         ZoneRules test = b.toRules("America/Argentina/Tucuman");
401 
402         assertOffsetInfo(test, DATE_TIME_FIRST, minus3);
403         assertOffsetInfo(test, DATE_TIME_LAST, minus3);
404 
405         assertOffsetInfo(test, dateTime(1999, 10, 2, 22, 59), minus3);
406         assertOffsetInfo(test, dateTime(1999, 10, 2, 23, 59), minus3);
407         assertOffsetInfo(test, dateTime(1999, 10, 3, 0, 0), minus3);
408         assertOffsetInfo(test, dateTime(1999, 10, 3, 1, 0), minus3);
409 
410         assertOffsetInfo(test, dateTime(2000, 3, 2, 22, 59), minus3);
411         assertOffsetInfo(test, dateTime(2000, 3, 2, 23, 59), minus3);
412         assertOffsetInfo(test, dateTime(2000, 3, 3, 0, 0), minus3);
413         assertOffsetInfo(test, dateTime(2000, 3, 3, 1, 0), minus3);
414     }
415 
416     @Test
test_cairo_dateChange()417     public void test_cairo_dateChange() {
418         //    Rule    Egypt   2008    max -   Apr lastFri  0:00s  1:00    S
419         //    Rule    Egypt   2008    max -   Aug lastThu 23:00s  0   -
420         //    Zone    Africa/Cairo    2:05:00 -     LMT   1900  Oct
421         //                            2:00    Egypt EE%sT
422         ZoneOffset plus2 = ZoneOffset.ofHours(2);
423         ZoneOffset plus3 = ZoneOffset.ofHours(3);
424         ZoneRulesBuilder b = new ZoneRulesBuilder();
425         b.addWindowForever(plus2);
426         b.addRuleToWindow(2008, Year.MAX_VALUE, APRIL, -1, FRIDAY, time(0, 0), false, STANDARD, PERIOD_1HOUR);
427         b.addRuleToWindow(2008, Year.MAX_VALUE, AUGUST, -1, THURSDAY, time(23, 0), false, STANDARD, PERIOD_0);
428         ZoneRules test = b.toRules("Africa/Cairo");
429 
430         assertOffsetInfo(test, DATE_TIME_FIRST, plus2);
431         assertOffsetInfo(test, DATE_TIME_LAST, plus2);
432 
433         assertGap(test, 2009, 4, 24, 0, 0, plus2, plus3);
434         assertOverlap(test, 2009, 8, 27, 23, 0, plus3, plus2);  // overlaps from Fri 00:00 back to Thu 23:00
435     }
436 
437     @Test
test_cairo_twoChangesSameMonth()438     public void test_cairo_twoChangesSameMonth() {
439         // 2011i
440         //    Rule    Egypt    2010    only    -    Aug    11       0:00      0      -
441         //    Rule    Egypt    2010    only    -    Sep    10       0:00      1:00   S
442         //    Rule    Egypt    2010    only    -    Sep    lastThu  23:00s    0      -
443         //    Zone    Africa/Cairo    2:05:00 -     LMT   1900  Oct
444         //                            2:00    Egypt EE%sT
445         ZoneOffset plus2 = ZoneOffset.ofHours(2);
446         ZoneOffset plus3 = ZoneOffset.ofHours(3);
447         ZoneRulesBuilder b = new ZoneRulesBuilder();
448         b.addWindowForever(plus2);
449         b.addRuleToWindow(2010, 2010, AUGUST, 11, null, time(0, 0), false, STANDARD, PERIOD_0);
450         b.addRuleToWindow(2010, 2010, SEPTEMBER, 10, null, time(0, 0), false, STANDARD, PERIOD_1HOUR);
451         b.addRuleToWindow(2010, 2010, SEPTEMBER, -1, THURSDAY, time(23, 0), false, STANDARD, PERIOD_0);
452         ZoneRules test = b.toRules("Africa/Cairo");
453 
454         assertOffsetInfo(test, DATE_TIME_FIRST, plus2);
455         assertOffsetInfo(test, DATE_TIME_LAST, plus2);
456 
457         assertGap(test, 2010, 9, 10, 0, 0, plus2, plus3);  // jump forward from 00:00 to 01:00 on Fri 10th Sep
458         assertOverlap(test, 2010, 9, 30, 23, 0, plus3, plus2);  // overlaps from Fri 1st Oct 00:00 back to Thu 30th Sep 23:00 (!!!)
459     }
460 
461     @Test
test_sofia_lastRuleClash()462     public void test_sofia_lastRuleClash() {
463         // UTC rule change in 1996 occurs after Wall change
464         // need to ensure that last rule is only applied to last window
465         //        Rule    E-Eur   1981    max -   Mar lastSun  0:00   1:00    S
466         //        Rule    E-Eur   1996    max -   Oct lastSun  0:00   0   -
467         //        Rule    EU      1981    max -   Mar lastSun  1:00u  1:00    S
468         //        Rule    EU      1996    max -   Oct lastSun  1:00u  0   -
469         //        Zone    Europe/Sofia
470         //        2:00    E-Eur   EE%sT   1997
471         //        2:00    EU      EE%sT
472           ZoneOffset plus2 = ZoneOffset.ofHours(2);
473           ZoneOffset plus3 = ZoneOffset.ofHours(3);
474           ZoneRulesBuilder b = new ZoneRulesBuilder();
475           b.addWindow(plus2, dateTime(1997, 1, 1, 0, 0), WALL);
476           b.addRuleToWindow(1996, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR);
477           b.addRuleToWindow(1996, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_0);
478           b.addWindowForever(plus2);
479           b.addRuleToWindow(1996, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, UTC, PERIOD_1HOUR);
480           b.addRuleToWindow(1996, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(1, 0), false, UTC, PERIOD_0);
481           ZoneRules test = b.toRules("Europe/Sofia");
482 
483           assertOffsetInfo(test, DATE_TIME_FIRST, plus2);
484           assertOffsetInfo(test, DATE_TIME_LAST, plus2);
485 
486           assertGap(test, 1996, 3, 31, 1, 0, plus2, plus3);
487           assertOverlap(test, 1996, 10, 27, 0, 0, plus3, plus2);
488           assertOffsetInfo(test, dateTime(1996, 10, 27, 1, 0), plus2);
489           assertOffsetInfo(test, dateTime(1996, 10, 27, 2, 0), plus2);
490           assertOffsetInfo(test, dateTime(1996, 10, 27, 3, 0), plus2);
491           assertOffsetInfo(test, dateTime(1996, 10, 27, 4, 0), plus2);
492       }
493 
494     @Test
test_prague()495     public void test_prague() {
496         // need to calculate savings applicable at window start based on
497         // first rule being transition from no savings to DST
498         //    Rule    C-Eur   1944    1945    -   Apr Mon>=1   2:00s  1:00    S
499         //    Rule    C-Eur   1944    only    -   Oct  2   2:00s  0   -
500         //    Rule    C-Eur   1945    only    -   Sep 16   2:00s  0   -
501         //    Rule    Czech   1945    only    -   Apr  8  2:00s   1:00    S
502         //    Rule    Czech   1945    only    -   Nov 18  2:00s   0   -
503         //    Zone    Europe/Prague   0:57:44 -     LMT   1850
504         //                            0:57:44 -     PMT   1891 Oct
505         //                            1:00    C-Eur CE%sT 1944 Sep 17 2:00s
506         //                            1:00    Czech CE%sT 1979
507         //                            1:00    EU    CE%sT
508         ZoneOffset plus1 = ZoneOffset.ofHours(1);
509         ZoneOffset plus2 = ZoneOffset.ofHours(2);
510         ZoneRulesBuilder b = new ZoneRulesBuilder();
511         b.addWindow(plus1, dateTime(1944, 9, 17, 2, 0), STANDARD);
512         b.addRuleToWindow(1944, 1945, APRIL, 1, MONDAY, time(2, 0), false, STANDARD, PERIOD_1HOUR);
513         b.addRuleToWindow(1944, OCTOBER, 2, time(2, 0), false, STANDARD, PERIOD_0);
514         b.addRuleToWindow(1945, SEPTEMBER, 16, time(2, 0), false, STANDARD, PERIOD_0);
515         b.addWindow(plus1, dateTime(1979, 1, 1, 0, 0), WALL);
516         b.addRuleToWindow(1945, APRIL, 8, time(2, 0), false, STANDARD, PERIOD_1HOUR);
517         b.addRuleToWindow(1945, NOVEMBER, 18, time(2, 0), false, STANDARD, PERIOD_0);
518         b.addWindowForever(plus1);
519         ZoneRules test = b.toRules("Europe/Sofia");
520 
521         assertOffsetInfo(test, DATE_TIME_FIRST, plus1);
522         assertOffsetInfo(test, DATE_TIME_LAST, plus1);
523 
524         assertGap(test, 1944, 4, 3, 2, 30, plus1, plus2);
525         assertOverlap(test, 1944, 9, 17, 2, 30, plus2, plus1);
526         assertOffsetInfo(test, dateTime(1944, 9, 17, 3, 30), plus1);
527         assertOffsetInfo(test, dateTime(1944, 9, 17, 4, 30), plus1);
528         assertGap(test, 1945, 4, 8, 2, 30, plus1, plus2);
529         assertOverlap(test, 1945, 11, 18, 2, 30, plus2, plus1);
530     }
531 
532     @Test
test_tbilisi()533     public void test_tbilisi() {
534         // has transition into and out of 1 year of permanent DST (Mar96-Oct97)
535         // where the date in the window and rule are the same
536         // this is weird because the wall time in the rule is amended by the actual
537         // wall time from the zone lines
538         //      Rule E-EurAsia  1981    max   -   Mar lastSun  0:00   1:00  S
539         //      Rule E-EurAsia  1979    1995  -   Sep lastSun  0:00   0     -
540         //      Rule E-EurAsia  1996    max   -   Oct lastSun  0:00   0     -
541         //    Zone    Asia/Tbilisi    2:59:16 -   LMT 1880
542         //    4:00 E-EurAsia  GE%sT   1996 Oct lastSun
543         //    4:00    1:00    GEST    1997 Mar lastSun
544         //    4:00 E-EurAsia  GE%sT   2004 Jun 27
545         //    3:00 RussiaAsia GE%sT   2005 Mar lastSun 2:00
546         //    4:00    -   GET
547         ZoneOffset plus4 = ZoneOffset.ofHours(4);
548         ZoneOffset plus5 = ZoneOffset.ofHours(5);
549         ZoneRulesBuilder b = new ZoneRulesBuilder();
550         b.addWindow(plus4, dateTime(1996, 10, 27, 0, 0), WALL);
551         b.addRuleToWindow(1996, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(0, 0), false, WALL, PERIOD_1HOUR);
552         b.addRuleToWindow(1996, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(0, 0), false, WALL, PERIOD_0);
553         b.addWindow(plus4, dateTime(1997, 3, 30, 0, 0), WALL);
554         b.setFixedSavingsToWindow(PERIOD_1HOUR);
555         b.addWindowForever(plus4);
556         b.addRuleToWindow(1996, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(0, 0), false, WALL, PERIOD_1HOUR);
557         b.addRuleToWindow(1996, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(0, 0), false, WALL, PERIOD_0);
558         ZoneRules test = b.toRules("Europe/Sofia");
559 
560         assertOffsetInfo(test, DATE_TIME_FIRST, plus4);
561         assertOffsetInfo(test, DATE_TIME_LAST, plus4);
562 
563         assertGap(test, 1996, 3, 31, 0, 30, plus4, plus5);
564         // assertOverlap(test, 1996, 10, 26, 23, 30, plus5, plus4);  // fixed DST blocks overlap
565         assertOffsetInfo(test, dateTime(1996, 10, 26, 22, 30), plus5);
566         assertOffsetInfo(test, dateTime(1996, 10, 26, 23, 30), plus5);
567         assertOffsetInfo(test, dateTime(1996, 10, 27, 0, 30), plus5);
568         // assertOverlap(test, 1997, 3, 30, 0, 30, plus5, plus4);  // end of fixed blocks overlap
569         assertOffsetInfo(test, dateTime(1997, 3, 29, 22, 30), plus5);
570         assertOffsetInfo(test, dateTime(1997, 3, 29, 23, 30), plus5);
571         assertOffsetInfo(test, dateTime(1997, 3, 30, 0, 30), plus5);
572         assertOffsetInfo(test, dateTime(1997, 3, 30, 1, 30), plus5);
573         assertOffsetInfo(test, dateTime(1997, 3, 30, 2, 30), plus5);
574         assertOverlap(test, 1997, 10, 25, 23, 30, plus5, plus4);
575     }
576 
577     @Test
test_vincennes()578     public void test_vincennes() {
579         // need to ensure that at least one real rule is added to expand on the last rule
580         //        Rule    US  2007  max  -   Mar Sun>=8  2:00  1:00  D
581         //        Rule    US  2007  max  -   Nov Sun>=1  2:00  0     S
582         //    -5:00   -   EST 2006 Apr  2 2:00
583         //    -6:00   US  C%sT    2007 Nov  4 2:00
584         //    -5:00   US  E%sT
585         ZoneOffset minus5 = ZoneOffset.ofHours(-5);
586         ZoneOffset minus6 = ZoneOffset.ofHours(-6);
587         ZoneRulesBuilder b = new ZoneRulesBuilder();
588         b.addWindow(minus6, dateTime(2007, 11, 4, 2, 0), WALL);
589         b.addRuleToWindow(2007, Year.MAX_VALUE, MARCH, 8, SUNDAY, time(2, 0), false, WALL, PERIOD_1HOUR);
590         b.addRuleToWindow(2007, Year.MAX_VALUE, NOVEMBER, 1, SUNDAY, time(2, 0), false, WALL, PERIOD_0);
591         b.addWindowForever(minus5);
592         b.addRuleToWindow(2007, Year.MAX_VALUE, MARCH, 8, SUNDAY, time(2, 0), false, WALL, PERIOD_1HOUR);
593         b.addRuleToWindow(2007, Year.MAX_VALUE, NOVEMBER, 1, SUNDAY, time(2, 0), false, WALL, PERIOD_0);
594         ZoneRules test = b.toRules("America/Indiana/Vincennes");
595 
596         assertOffsetInfo(test, DATE_TIME_FIRST, minus6);
597         assertOffsetInfo(test, DATE_TIME_LAST, minus5);
598 
599         assertOffsetInfo(test, dateTime(2007, 3, 11, 0, 0), minus6);
600         assertOffsetInfo(test, dateTime(2007, 3, 11, 1, 0), minus6);
601         assertGap(test, 2007, 3, 11, 2, 0, minus6, minus5);
602         assertOffsetInfo(test, dateTime(2007, 3, 11, 3, 0), minus5);
603         assertOffsetInfo(test, dateTime(2007, 3, 11, 4, 0), minus5);
604         assertOffsetInfo(test, dateTime(2007, 3, 11, 5, 0), minus5);
605     }
606 
607     @Test
test_iqaluit()608     public void test_iqaluit() {
609         // two hour overlap due to end of daylight and change of standard offset
610         //      Rule    Canada  1987   2006 -   Apr Sun>=1  2:00    1:00  D
611         //      Rule    Canada  1974   2006 -   Oct lastSun 2:00    0     S
612         //      Rule    NT_YK   1987   2006 -   Apr Sun>=1  2:00    1:00  D
613         //      Rule    NT_YK   1980   2006 -   Oct lastSun 2:00    0     S
614         //                    -5:00   NT_YK   E%sT    1999 Oct 31 2:00
615         //                    -6:00   Canada  C%sT
616         ZoneOffset minus4 = ZoneOffset.ofHours(-4);
617         ZoneOffset minus5 = ZoneOffset.ofHours(-5);
618         ZoneOffset minus6 = ZoneOffset.ofHours(-6);
619         ZoneRulesBuilder b = new ZoneRulesBuilder();
620         b.addWindow(minus5, dateTime(1999, 10, 31, 2, 0), WALL);
621         b.addRuleToWindow(1987, Year.MAX_VALUE, APRIL, 1, SUNDAY, time(2, 0), false, WALL, PERIOD_1HOUR);
622         b.addRuleToWindow(1987, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(2, 0), false, WALL, PERIOD_0);
623         b.addWindowForever(minus6);
624         b.addRuleToWindow(1987, Year.MAX_VALUE, APRIL, 1, SUNDAY, time(2, 0), false, WALL, PERIOD_1HOUR);
625         b.addRuleToWindow(1987, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(2, 0), false, WALL, PERIOD_0);
626         ZoneRules test = b.toRules("America/Iqaluit");
627 
628         assertOffsetInfo(test, DATE_TIME_FIRST, minus5);
629         assertOffsetInfo(test, DATE_TIME_LAST, minus6);
630 
631         assertOffsetInfo(test, dateTime(1999, 10, 30, 23, 0), minus4);
632         assertOverlap(test, 1999, 10, 31, 0, 0, minus4, minus6);
633         assertOverlap(test, 1999, 10, 31, 1, 0, minus4, minus6);
634         assertOverlap(test, 1999, 10, 31, 1, 59, minus4, minus6);
635         assertOffsetInfo(test, dateTime(1999, 10, 31, 2, 0), minus6);
636         assertOffsetInfo(test, dateTime(1999, 10, 31, 3, 0), minus6);
637     }
638 
639     @Test
test_jordan2400()640     public void test_jordan2400() {
641         // rule is 24:00 - this is simplified from the TZDB
642         //    Rule    Jordan  2002    max -   Mar lastThu 24:00   1:00    S
643         //    Rule    Jordan  2002    max -   Sep lastFri 0:00s   0   -
644         //    # Zone  NAME        GMTOFF  RULES   FORMAT  [UNTIL]
645         //                2:00    Jordan  EE%sT
646         ZoneOffset plus2 = ZoneOffset.ofHours(2);
647         ZoneOffset plus3 = ZoneOffset.ofHours(3);
648         ZoneRulesBuilder b = new ZoneRulesBuilder();
649         b.addWindowForever(plus2);
650         b.addRuleToWindow(2002, Year.MAX_VALUE, MARCH, -1, THURSDAY, time(0, 0), true, WALL, PERIOD_1HOUR);
651         b.addRuleToWindow(2002, Year.MAX_VALUE, SEPTEMBER, -1, FRIDAY, time(0, 0), false, STANDARD, PERIOD_0);
652         ZoneRules test = b.toRules("Asia/Amman");
653 
654         assertOffsetInfo(test, DATE_TIME_FIRST, plus2);
655         assertOffsetInfo(test, DATE_TIME_LAST, plus2);
656 
657         assertGap(test, 2002, 3, 29, 0, 0, plus2, plus3);
658         assertOffsetInfo(test, dateTime(2002, 3, 28, 23, 0), plus2);
659         assertOffsetInfo(test, dateTime(2002, 3, 29, 1, 0), plus3);
660 
661         assertOverlap(test, 2002, 9, 27, 0, 0, plus3, plus2);
662         assertOffsetInfo(test, dateTime(2002, 9, 26, 23, 0), plus3);
663         assertOffsetInfo(test, dateTime(2002, 9, 27, 1, 0), plus2);
664     }
665 
666     @Test
test_japan2500()667     public void test_japan2500() {
668         // cutover time overflows into next day
669         //    Rule  Japan   1948    only    -   May Sat>=1  24:00   1:00    D
670         //    Rule  Japan   1948    1951    -   Sep Sat>=8  25:00   0   S
671         //    Rule  Japan   1949    only    -   Apr Sat>=1  24:00   1:00    D
672         //    Rule  Japan   1950    1951    -   May Sat>=1  24:00   1:00    D
673         ZoneOffset plus9 = ZoneOffset.ofHours(9);
674         ZoneOffset plus10 = ZoneOffset.ofHours(10);
675         ZoneRulesBuilder b = new ZoneRulesBuilder();
676         b.addWindowForever(plus9);
677         b.addRuleToWindow(1948, 1948, MAY, 1, SATURDAY, time(0, 0), true, WALL, PERIOD_1HOUR);
678         b.addRuleToWindow(1948, 1951, SEPTEMBER, 8, SATURDAY, time(1, 0), 1, WALL, PERIOD_0);
679         b.addRuleToWindow(1949, 1949, APRIL, 1, SATURDAY, time(0, 0), true, WALL, PERIOD_1HOUR);
680         b.addRuleToWindow(1950, 1951, MAY, 1, SATURDAY, time(0, 0), true, WALL, PERIOD_1HOUR);
681         ZoneRules test = b.toRules("Japan");
682          assertOffsetInfo(test, DATE_TIME_FIRST, plus9);
683         assertOffsetInfo(test, DATE_TIME_LAST, plus9);
684          // Sat>=1 => May 1st
685         assertGap(test, 1948, 5, 2, 0, 0, plus9, plus10);
686         assertOffsetInfo(test, dateTime(1948, 5, 1, 23, 0), plus9);
687         assertOffsetInfo(test, dateTime(1948, 5, 2, 1, 0), plus10);
688          // Sat>=8 => September 11th
689         assertOverlap(test, 1948, 9, 12, 0, 0, plus10, plus9);
690         assertOffsetInfo(test, dateTime(1948, 9, 11, 23, 0), plus10);
691         assertOffsetInfo(test, dateTime(1948, 9, 12, 1, 0), plus9);
692          // Sat>=1 => May 2nd
693         assertGap(test, 1949, 4, 3, 0, 0, plus9, plus10);
694         assertOffsetInfo(test, dateTime(1949, 4, 2, 23, 0), plus9);
695         assertOffsetInfo(test, dateTime(1949, 4, 3, 1, 0), plus10);
696     }
697 
698     //-----------------------------------------------------------------------
699     // addWindow()
700     //-----------------------------------------------------------------------
701     @Test
test_addWindow_constrainedRules()702     public void test_addWindow_constrainedRules() {
703         ZoneRulesBuilder b = new ZoneRulesBuilder();
704         b.addWindow(OFFSET_1, dateTime(1800, 7, 1, 0, 0), WALL);
705         b.addWindow(OFFSET_1, dateTime(2008, 6, 30, 0, 0), STANDARD);
706         b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
707         b.addRuleToWindow(2000, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_0);
708         ZoneRules test = b.toRules("Europe/London");
709         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
710         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_2_30);
711         assertOffsetInfo(test, DATE_TIME_2008_01_01, OFFSET_1);
712         assertOffsetInfo(test, DATE_TIME_2008_07_01, OFFSET_2_30);
713         assertGap(test, 2000, 3, 26, 1, 30, OFFSET_1, OFFSET_2_30);
714         assertOverlap(test, 2000, 10, 29, 0, 30, OFFSET_2_30, OFFSET_1);
715         assertGap(test, 2008, 3, 30, 1, 30, OFFSET_1, OFFSET_2_30);
716         assertOffsetInfo(test, dateTime(2008, 10, 26, 0, 30), OFFSET_2_30);
717     }
718 
719     @Test
test_addWindow_noRules()720     public void test_addWindow_noRules() {
721         ZoneRulesBuilder b = new ZoneRulesBuilder();
722         b.addWindow(OFFSET_1, dateTime(1800, 7, 1, 0, 0), WALL);
723         b.addWindow(OFFSET_1, dateTime(2008, 6, 30, 0, 0), STANDARD);
724         ZoneRules test = b.toRules("Europe/London");
725         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
726         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
727         assertOffsetInfo(test, DATE_TIME_2008_01_01, OFFSET_1);
728         assertOffsetInfo(test, DATE_TIME_2008_07_01, OFFSET_1);
729     }
730 
731     @Test(expectedExceptions=NullPointerException.class)
test_addWindow_nullOffset()732     public void test_addWindow_nullOffset() {
733         ZoneRulesBuilder b = new ZoneRulesBuilder();
734         b.addWindow((ZoneOffset) null, dateTime(2008, 6, 30, 0, 0), STANDARD);
735     }
736 
737     @Test(expectedExceptions=NullPointerException.class)
test_addWindow_nullTime()738     public void test_addWindow_nullTime() {
739         ZoneRulesBuilder b = new ZoneRulesBuilder();
740         b.addWindow(OFFSET_1, (LocalDateTime) null, STANDARD);
741     }
742 
743     @Test(expectedExceptions=NullPointerException.class)
test_addWindow_nullTimeDefinition()744     public void test_addWindow_nullTimeDefinition() {
745         ZoneRulesBuilder b = new ZoneRulesBuilder();
746         b.addWindow(OFFSET_1, dateTime(2008, 6, 30, 0, 0), (TimeDefinition) null);
747     }
748 
749     //-----------------------------------------------------------------------
750     // addWindowForever()
751     //-----------------------------------------------------------------------
752     @Test
test_addWindowForever_noRules()753     public void test_addWindowForever_noRules() {
754         ZoneRulesBuilder b = new ZoneRulesBuilder();
755         b.addWindowForever(OFFSET_1);
756         ZoneRules test = b.toRules("Europe/London");
757         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
758         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
759         assertOffsetInfo(test, DATE_TIME_2008_01_01, OFFSET_1);
760         assertOffsetInfo(test, DATE_TIME_2008_07_01, OFFSET_1);
761     }
762 
763     @Test
test_addWindowForever_rules()764     public void test_addWindowForever_rules() {
765         ZoneRulesBuilder b = new ZoneRulesBuilder();
766         b.addWindowForever(OFFSET_1);
767         b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
768         b.addRuleToWindow(2000, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_0);
769         ZoneRules test = b.toRules("Europe/London");
770         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
771         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
772         assertOffsetInfo(test, DATE_TIME_2008_01_01, OFFSET_1);
773         assertOffsetInfo(test, DATE_TIME_2008_07_01, OFFSET_2_30);
774         assertGap(test, 2008, 3, 30, 1, 20, OFFSET_1, OFFSET_2_30);
775         assertOverlap(test, 2008, 10, 26, 0, 20, OFFSET_2_30, OFFSET_1);
776     }
777 
778     @Test(expectedExceptions=NullPointerException.class)
test_addWindowForever_nullOffset()779     public void test_addWindowForever_nullOffset() {
780         ZoneRulesBuilder b = new ZoneRulesBuilder();
781         b.addWindowForever((ZoneOffset) null);
782     }
783 
784     //-----------------------------------------------------------------------
785     // setFixedSavings()
786     //-----------------------------------------------------------------------
787     @Test
test_setFixedSavingsToWindow()788     public void test_setFixedSavingsToWindow() {
789         ZoneRulesBuilder b = new ZoneRulesBuilder();
790         b.addWindow(OFFSET_1, dateTime(1800, 7, 1, 0, 0), WALL);
791         b.addWindowForever(OFFSET_1);
792         b.setFixedSavingsToWindow(PERIOD_1HOUR30MIN);
793         ZoneRules test = b.toRules("Europe/London");
794         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
795         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_2_30);
796         assertOffsetInfo(test, DATE_TIME_2008_01_01, OFFSET_2_30);
797         assertOffsetInfo(test, DATE_TIME_2008_07_01, OFFSET_2_30);
798         assertGap(test, 1800, 7, 1, 0, 0, OFFSET_1, OFFSET_2_30);
799     }
800 
801     @Test
test_setFixedSavingsToWindow_first()802     public void test_setFixedSavingsToWindow_first() {
803         ZoneRulesBuilder b = new ZoneRulesBuilder();
804         b.addWindowForever(OFFSET_1);
805         b.setFixedSavingsToWindow(PERIOD_1HOUR30MIN);
806         ZoneRules test = b.toRules("Europe/London");
807         assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_2_30);
808         assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_2_30);
809     }
810 
811     @Test(expectedExceptions=IllegalStateException.class)
test_setFixedSavingsToWindow_noWindow()812     public void test_setFixedSavingsToWindow_noWindow() {
813         ZoneRulesBuilder b = new ZoneRulesBuilder();
814         b.setFixedSavingsToWindow(PERIOD_1HOUR30MIN);
815     }
816 
817     @Test(expectedExceptions=IllegalStateException.class)
test_setFixedSavingsToWindow_cannotMixSavingsWithRule()818     public void test_setFixedSavingsToWindow_cannotMixSavingsWithRule() {
819         ZoneRulesBuilder b = new ZoneRulesBuilder();
820         b.addWindowForever(OFFSET_1);
821         b.addRuleToWindow(2000, 2020, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
822         b.setFixedSavingsToWindow(PERIOD_1HOUR30MIN);
823     }
824 
825     @Test(expectedExceptions=IllegalStateException.class)
test_setFixedSavingsToWindow_cannotMixSavingsWithLastRule()826     public void test_setFixedSavingsToWindow_cannotMixSavingsWithLastRule() {
827         ZoneRulesBuilder b = new ZoneRulesBuilder();
828         b.addWindowForever(OFFSET_1);
829         b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
830         b.setFixedSavingsToWindow(PERIOD_1HOUR30MIN);
831     }
832 
833     //-----------------------------------------------------------------------
834     // addRuleToWindow()
835     //-----------------------------------------------------------------------
836     @Test
test_addRuleToWindow_endOfMonth()837     public void test_addRuleToWindow_endOfMonth() {
838         ZoneRulesBuilder b = new ZoneRulesBuilder();
839         b.addWindowForever(OFFSET_1);
840         b.addRuleToWindow(2000, 2001, MARCH, -1, SUNDAY, time(1, 0), false, UTC, PERIOD_1HOUR);
841         b.addRuleToWindow(2000, 2001, OCTOBER, -1, SUNDAY, time(1, 0), false, UTC, PERIOD_0);
842         ZoneRules test = b.toRules("Europe/London");
843         assertOffsetInfo(test, dateTime(1999, 7, 1, 0, 0), OFFSET_1);
844 
845         assertOffsetInfo(test, dateTime(2000, 1, 1, 0, 0), OFFSET_1);
846         assertGap(test, 2000, 3, 26, 2, 30, OFFSET_1, OFFSET_2);
847         assertOffsetInfo(test, dateTime(2000, 7, 1, 0, 0), OFFSET_2);
848         assertOverlap(test, 2000, 10, 29, 2, 30, OFFSET_2, OFFSET_1);
849 
850         assertOffsetInfo(test, dateTime(2001, 1, 1, 0, 0), OFFSET_1);
851         assertGap(test, 2001, 3, 25, 2, 30, OFFSET_1, OFFSET_2);
852         assertOffsetInfo(test, dateTime(2001, 7, 1, 0, 0), OFFSET_2);
853         assertOverlap(test, 2001, 10, 28, 2, 30, OFFSET_2, OFFSET_1);
854 
855         assertOffsetInfo(test, dateTime(2002, 7, 1, 0, 0), OFFSET_1);
856     }
857 
858     @Test
test_addRuleToWindow_endOfMonthFeb()859     public void test_addRuleToWindow_endOfMonthFeb() {
860         ZoneRulesBuilder b = new ZoneRulesBuilder();
861         b.addWindowForever(OFFSET_1);
862         b.addRuleToWindow(2004, 2005, FEBRUARY, -1, SUNDAY, time(1, 0), false, UTC, PERIOD_1HOUR);
863         b.addRuleToWindow(2004, 2005, OCTOBER, -1, SUNDAY, time(1, 0), false, UTC, PERIOD_0);
864         ZoneRules test = b.toRules("Europe/London");
865         assertOffsetInfo(test, dateTime(2003, 7, 1, 0, 0), OFFSET_1);
866 
867         assertOffsetInfo(test, dateTime(2004, 1, 1, 0, 0), OFFSET_1);
868         assertGap(test, 2004, 2, 29, 2, 30, OFFSET_1, OFFSET_2);  // leap
869         assertOffsetInfo(test, dateTime(2004, 7, 1, 0, 0), OFFSET_2);
870         assertOverlap(test, 2004, 10, 31, 2, 30, OFFSET_2, OFFSET_1);
871 
872         assertOffsetInfo(test, dateTime(2005, 1, 1, 0, 0), OFFSET_1);
873         assertGap(test, 2005, 2, 27, 2, 30, OFFSET_1, OFFSET_2);
874         assertOffsetInfo(test, dateTime(2005, 7, 1, 0, 0), OFFSET_2);
875         assertOverlap(test, 2005, 10, 30, 2, 30, OFFSET_2, OFFSET_1);
876 
877         assertOffsetInfo(test, dateTime(2006, 7, 1, 0, 0), OFFSET_1);
878     }
879 
880     @Test
test_addRuleToWindow_fromDayOfMonth()881     public void test_addRuleToWindow_fromDayOfMonth() {
882         ZoneRulesBuilder b = new ZoneRulesBuilder();
883         b.addWindowForever(OFFSET_1);
884         b.addRuleToWindow(2000, 2001, MARCH, 10, SUNDAY, time(1, 0), false, UTC, PERIOD_1HOUR);
885         b.addRuleToWindow(2000, 2001, OCTOBER, 10, SUNDAY, time(1, 0), false, UTC, PERIOD_0);
886         ZoneRules test = b.toRules("Europe/London");
887         assertOffsetInfo(test, dateTime(1999, 7, 1, 0, 0), OFFSET_1);
888 
889         assertOffsetInfo(test, dateTime(2000, 1, 1, 0, 0), OFFSET_1);
890         assertGap(test, 2000, 3, 12, 2, 30, OFFSET_1, OFFSET_2);
891         assertOffsetInfo(test, dateTime(2000, 7, 1, 0, 0), OFFSET_2);
892         assertOverlap(test, 2000, 10, 15, 2, 30, OFFSET_2, OFFSET_1);
893 
894         assertOffsetInfo(test, dateTime(2001, 1, 1, 0, 0), OFFSET_1);
895         assertGap(test, 2001, 3, 11, 2, 30, OFFSET_1, OFFSET_2);
896         assertOffsetInfo(test, dateTime(2001, 7, 1, 0, 0), OFFSET_2);
897         assertOverlap(test, 2001, 10, 14, 2, 30, OFFSET_2, OFFSET_1);
898 
899         assertOffsetInfo(test, dateTime(2002, 7, 1, 0, 0), OFFSET_1);
900     }
901 
902     @Test(expectedExceptions=IllegalStateException.class)
test_addRuleToWindow_noWindow()903     public void test_addRuleToWindow_noWindow() {
904         ZoneRulesBuilder b = new ZoneRulesBuilder();
905         b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
906     }
907 
908     @Test(expectedExceptions=IllegalStateException.class)
test_addRuleToWindow_cannotMixRuleWithSavings()909     public void test_addRuleToWindow_cannotMixRuleWithSavings() {
910         ZoneRulesBuilder b = new ZoneRulesBuilder();
911         b.addWindowForever(OFFSET_1);
912         b.setFixedSavingsToWindow(PERIOD_1HOUR30MIN);
913         b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
914     }
915 
916     @Test(expectedExceptions=DateTimeException.class)
test_addRuleToWindow_illegalYear1()917     public void test_addRuleToWindow_illegalYear1() {
918         ZoneRulesBuilder b = new ZoneRulesBuilder();
919         b.addWindowForever(OFFSET_1);
920         b.addRuleToWindow(Year.MIN_VALUE - 1, 2008, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
921     }
922 
923     @Test(expectedExceptions=DateTimeException.class)
test_addRuleToWindow_illegalYear2()924     public void test_addRuleToWindow_illegalYear2() {
925         ZoneRulesBuilder b = new ZoneRulesBuilder();
926         b.addWindowForever(OFFSET_1);
927         b.addRuleToWindow(2000, Year.MIN_VALUE - 1, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
928     }
929 
930     @Test(expectedExceptions=IllegalArgumentException.class)
test_addRuleToWindow_illegalDayOfMonth_tooSmall()931     public void test_addRuleToWindow_illegalDayOfMonth_tooSmall() {
932         ZoneRulesBuilder b = new ZoneRulesBuilder();
933         b.addWindowForever(OFFSET_1);
934         b.addRuleToWindow(2000, 2008, MARCH, -29, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
935     }
936 
937     @Test(expectedExceptions=IllegalArgumentException.class)
test_addRuleToWindow_illegalDayOfMonth_zero()938     public void test_addRuleToWindow_illegalDayOfMonth_zero() {
939         ZoneRulesBuilder b = new ZoneRulesBuilder();
940         b.addWindowForever(OFFSET_1);
941         b.addRuleToWindow(2000, 2008, MARCH, 0, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
942     }
943 
944     @Test(expectedExceptions=IllegalArgumentException.class)
test_addRuleToWindow_illegalDayOfMonth_tooLarge()945     public void test_addRuleToWindow_illegalDayOfMonth_tooLarge() {
946         ZoneRulesBuilder b = new ZoneRulesBuilder();
947         b.addWindowForever(OFFSET_1);
948         b.addRuleToWindow(2000, 2008, MARCH, 32, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
949     }
950 
951     @Test(expectedExceptions=NullPointerException.class)
test_addRuleToWindow_nullMonth()952     public void test_addRuleToWindow_nullMonth() {
953         ZoneRulesBuilder b = new ZoneRulesBuilder();
954         b.addWindowForever(OFFSET_1);
955         b.addRuleToWindow(2000, Year.MAX_VALUE, (Month) null, 31, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
956     }
957 
958     @Test(expectedExceptions=NullPointerException.class)
test_addRuleToWindow_nullTime()959     public void test_addRuleToWindow_nullTime() {
960         ZoneRulesBuilder b = new ZoneRulesBuilder();
961         b.addWindowForever(OFFSET_1);
962         b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, (LocalTime) null, false, WALL, PERIOD_1HOUR30MIN);
963     }
964 
965     @Test(expectedExceptions=IllegalArgumentException.class)
test_addRuleToWindow_illegalEndOfDayTime()966     public void test_addRuleToWindow_illegalEndOfDayTime() {
967         ZoneRulesBuilder b = new ZoneRulesBuilder();
968         b.addWindowForever(OFFSET_1);
969         b.addRuleToWindow(2000, 2008, MARCH, 1, SUNDAY, time(1, 0), true, WALL, PERIOD_1HOUR30MIN);
970     }
971 
972     @Test(expectedExceptions=NullPointerException.class)
test_addRuleToWindow_nullTimeDefinition()973     public void test_addRuleToWindow_nullTimeDefinition() {
974         ZoneRulesBuilder b = new ZoneRulesBuilder();
975         b.addWindowForever(OFFSET_1);
976         b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, (TimeDefinition) null, PERIOD_1HOUR30MIN);
977     }
978 
979     //-----------------------------------------------------------------------
980     // addRuleToWindow() - single year object
981     //-----------------------------------------------------------------------
982     @Test
test_addRuleToWindow_singleYearObject()983     public void test_addRuleToWindow_singleYearObject() {
984         ZoneRulesBuilder b = new ZoneRulesBuilder();
985         b.addWindowForever(OFFSET_1);
986         b.addRuleToWindow(dateTime(2000, MARCH, 26, 1, 0), UTC, PERIOD_1HOUR);
987         b.addRuleToWindow(dateTime(2000, OCTOBER, 29, 1, 0), UTC, PERIOD_0);
988         ZoneRules test = b.toRules("Europe/London");
989         assertOffsetInfo(test, dateTime(1999, 7, 1, 0, 0), OFFSET_1);
990 
991         assertOffsetInfo(test, dateTime(2000, 1, 1, 0, 0), OFFSET_1);
992         assertGap(test, 2000, 3, 26, 2, 30, OFFSET_1, OFFSET_2);
993         assertOffsetInfo(test, dateTime(2000, 7, 1, 0, 0), OFFSET_2);
994         assertOverlap(test, 2000, 10, 29, 2, 30, OFFSET_2, OFFSET_1);
995 
996         assertOffsetInfo(test, dateTime(2001, 7, 1, 0, 0), OFFSET_1);
997     }
998 
999     @Test(expectedExceptions=NullPointerException.class)
test_addRuleToWindow_singleYearObject_nullTime()1000     public void test_addRuleToWindow_singleYearObject_nullTime() {
1001         ZoneRulesBuilder b = new ZoneRulesBuilder();
1002         b.addWindowForever(OFFSET_1);
1003         b.addRuleToWindow((LocalDateTime) null, WALL, PERIOD_1HOUR30MIN);
1004     }
1005 
1006     @Test(expectedExceptions=NullPointerException.class)
test_addRuleToWindow_singleYearObject_nullTimeDefinition()1007     public void test_addRuleToWindow_singleYearObject_nullTimeDefinition() {
1008         ZoneRulesBuilder b = new ZoneRulesBuilder();
1009         b.addWindowForever(OFFSET_1);
1010         b.addRuleToWindow(dateTime(2000, MARCH, 31, 1, 0), (TimeDefinition) null, PERIOD_1HOUR30MIN);
1011     }
1012 
1013     //-----------------------------------------------------------------------
1014     // addRuleToWindow() - single year
1015     //-----------------------------------------------------------------------
1016     @Test
test_addRuleToWindow_singleYear()1017     public void test_addRuleToWindow_singleYear() {
1018         ZoneRulesBuilder b = new ZoneRulesBuilder();
1019         b.addWindowForever(OFFSET_1);
1020         b.addRuleToWindow(2000, MARCH, 26, time(1, 0), false, UTC, PERIOD_1HOUR);
1021         b.addRuleToWindow(2000, OCTOBER, 29, time(1, 0), false, UTC, PERIOD_0);
1022         ZoneRules test = b.toRules("Europe/London");
1023         assertOffsetInfo(test, dateTime(1999, 7, 1, 0, 0), OFFSET_1);
1024 
1025         assertOffsetInfo(test, dateTime(2000, 1, 1, 0, 0), OFFSET_1);
1026         assertGap(test, 2000, 3, 26, 2, 30, OFFSET_1, OFFSET_2);
1027         assertOffsetInfo(test, dateTime(2000, 7, 1, 0, 0), OFFSET_2);
1028         assertOverlap(test, 2000, 10, 29, 2, 30, OFFSET_2, OFFSET_1);
1029 
1030         assertOffsetInfo(test, dateTime(2001, 7, 1, 0, 0), OFFSET_1);
1031     }
1032 
1033     @Test(expectedExceptions=IllegalStateException.class)
test_addRuleToWindow_singleYear_noWindow()1034     public void test_addRuleToWindow_singleYear_noWindow() {
1035         ZoneRulesBuilder b = new ZoneRulesBuilder();
1036         b.addRuleToWindow(2000, MARCH, 31, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
1037     }
1038 
1039     @Test(expectedExceptions=IllegalStateException.class)
test_addRuleToWindow_singleYear_cannotMixRuleWithSavings()1040     public void test_addRuleToWindow_singleYear_cannotMixRuleWithSavings() {
1041         ZoneRulesBuilder b = new ZoneRulesBuilder();
1042         b.addWindowForever(OFFSET_1);
1043         b.setFixedSavingsToWindow(PERIOD_1HOUR30MIN);
1044         b.addRuleToWindow(2000, MARCH, 31, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
1045     }
1046 
1047     @Test(expectedExceptions=DateTimeException.class)
test_addRuleToWindow_singleYear_illegalYear()1048     public void test_addRuleToWindow_singleYear_illegalYear() {
1049         ZoneRulesBuilder b = new ZoneRulesBuilder();
1050         b.addWindowForever(OFFSET_1);
1051         b.addRuleToWindow(Year.MIN_VALUE - 1, MARCH, 31, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
1052     }
1053 
1054     @Test(expectedExceptions=IllegalArgumentException.class)
test_addRuleToWindow_singleYear_illegalDayOfMonth_tooSmall()1055     public void test_addRuleToWindow_singleYear_illegalDayOfMonth_tooSmall() {
1056         ZoneRulesBuilder b = new ZoneRulesBuilder();
1057         b.addWindowForever(OFFSET_1);
1058         b.addRuleToWindow(2000, MARCH, -29, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
1059     }
1060 
1061     @Test(expectedExceptions=IllegalArgumentException.class)
test_addRuleToWindow_singleYear_illegalDayOfMonth_zero()1062     public void test_addRuleToWindow_singleYear_illegalDayOfMonth_zero() {
1063         ZoneRulesBuilder b = new ZoneRulesBuilder();
1064         b.addWindowForever(OFFSET_1);
1065         b.addRuleToWindow(2000, MARCH, 0, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
1066     }
1067 
1068     @Test(expectedExceptions=IllegalArgumentException.class)
test_addRuleToWindow_singleYear_illegalDayOfMonth_tooLarge()1069     public void test_addRuleToWindow_singleYear_illegalDayOfMonth_tooLarge() {
1070         ZoneRulesBuilder b = new ZoneRulesBuilder();
1071         b.addWindowForever(OFFSET_1);
1072         b.addRuleToWindow(2000, MARCH, 32, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
1073     }
1074 
1075     @Test(expectedExceptions=NullPointerException.class)
test_addRuleToWindow_singleYear_nullMonth()1076     public void test_addRuleToWindow_singleYear_nullMonth() {
1077         ZoneRulesBuilder b = new ZoneRulesBuilder();
1078         b.addWindowForever(OFFSET_1);
1079         b.addRuleToWindow(2000, (Month) null, 31, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
1080     }
1081 
1082     @Test(expectedExceptions=NullPointerException.class)
test_addRuleToWindow_singleYear_nullTime()1083     public void test_addRuleToWindow_singleYear_nullTime() {
1084         ZoneRulesBuilder b = new ZoneRulesBuilder();
1085         b.addWindowForever(OFFSET_1);
1086         b.addRuleToWindow(2000, MARCH, 31, (LocalTime) null, false, WALL, PERIOD_1HOUR30MIN);
1087     }
1088 
1089     @Test(expectedExceptions=NullPointerException.class)
test_addRuleToWindow_singleYear_nullTimeDefinition()1090     public void test_addRuleToWindow_singleYear_nullTimeDefinition() {
1091         ZoneRulesBuilder b = new ZoneRulesBuilder();
1092         b.addWindowForever(OFFSET_1);
1093         b.addRuleToWindow(2000, MARCH, 31, time(1, 0), false, (TimeDefinition) null, PERIOD_1HOUR30MIN);
1094     }
1095 
1096     //-----------------------------------------------------------------------
assertGap(ZoneRules test, int y, int m, int d, int hr, int min, ZoneOffset before, ZoneOffset after)1097     private static void assertGap(ZoneRules test, int y, int m, int d, int hr, int min, ZoneOffset before, ZoneOffset after) {
1098         LocalDateTime dt = dateTime(y, m, d, hr, min);
1099         ZoneOffsetTransition zot = test.getTransition(dt);
1100         assertNotNull(zot);
1101         assertEquals(zot.isGap(), true);
1102         assertEquals(zot.getOffsetBefore(), before);
1103         assertEquals(zot.getOffsetAfter(), after);
1104     }
1105 
assertOverlap(ZoneRules test, int y, int m, int d, int hr, int min, ZoneOffset before, ZoneOffset after)1106     private static void assertOverlap(ZoneRules test, int y, int m, int d, int hr, int min, ZoneOffset before, ZoneOffset after) {
1107         LocalDateTime dt = dateTime(y, m, d, hr, min);
1108         ZoneOffsetTransition zot = test.getTransition(dt);
1109         assertNotNull(zot);
1110         assertEquals(zot.isOverlap(), true);
1111         assertEquals(zot.getOffsetBefore(), before);
1112         assertEquals(zot.getOffsetAfter(), after);
1113     }
1114 
assertOffsetInfo(ZoneRules test, LocalDateTime dateTime, ZoneOffset offset)1115     private void assertOffsetInfo(ZoneRules test, LocalDateTime dateTime, ZoneOffset offset) {
1116         List<ZoneOffset> offsets = test.getValidOffsets(dateTime);
1117         assertEquals(offsets.size(), 1);
1118         assertEquals(offsets.get(0), offset);
1119     }
1120 
1121     //-----------------------------------------------------------------------
time(int h, int m)1122     private static LocalTime time(int h, int m) {
1123         return LocalTime.of(h, m);
1124     }
1125 
dateTime(int year, int month, int day, int h, int m)1126     private static LocalDateTime dateTime(int year, int month, int day, int h, int m) {
1127         return LocalDateTime.of(year, month, day, h, m);
1128     }
1129 
dateTime(int year, Month month, int day, int h, int m)1130     private static LocalDateTime dateTime(int year, Month month, int day, int h, int m) {
1131         return LocalDateTime.of(year, month, day, h, m);
1132     }
1133 
1134 }
1135