Package org.threeten.bp.zone

Source Code of org.threeten.bp.zone.TestZoneRulesBuilder

/*
* Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*  * Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*
*  * Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
*  * Neither the name of JSR-310 nor the names of its contributors
*    may be used to endorse or promote products derived from this software
*    without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.threeten.bp.zone;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.threeten.bp.DayOfWeek.FRIDAY;
import static org.threeten.bp.DayOfWeek.MONDAY;
import static org.threeten.bp.DayOfWeek.SUNDAY;
import static org.threeten.bp.DayOfWeek.THURSDAY;
import static org.threeten.bp.DayOfWeek.TUESDAY;
import static org.threeten.bp.Month.APRIL;
import static org.threeten.bp.Month.AUGUST;
import static org.threeten.bp.Month.FEBRUARY;
import static org.threeten.bp.Month.MARCH;
import static org.threeten.bp.Month.NOVEMBER;
import static org.threeten.bp.Month.OCTOBER;
import static org.threeten.bp.Month.SEPTEMBER;
import static org.threeten.bp.zone.ZoneOffsetTransitionRule.TimeDefinition.STANDARD;
import static org.threeten.bp.zone.ZoneOffsetTransitionRule.TimeDefinition.UTC;
import static org.threeten.bp.zone.ZoneOffsetTransitionRule.TimeDefinition.WALL;

import java.util.List;

import org.testng.annotations.Test;
import org.threeten.bp.DateTimeException;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.LocalTime;
import org.threeten.bp.Month;
import org.threeten.bp.Year;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.zone.ZoneOffsetTransitionRule.TimeDefinition;

/**
* Test ZoneRulesBuilder.
*/
@Test
public class TestZoneRulesBuilder {

    private static final ZoneOffset OFFSET_1 = ZoneOffset.ofHours(1);
    private static final ZoneOffset OFFSET_2 = ZoneOffset.ofHours(2);
    private static final ZoneOffset OFFSET_1_15 = ZoneOffset.ofHoursMinutes(1, 15);
    private static final ZoneOffset OFFSET_2_30 = ZoneOffset.ofHoursMinutes(2, 30);
    private static final int PERIOD_0 = 0;
    private static final int PERIOD_1HOUR = 60 * 60;
    private static final int PERIOD_1HOUR30MIN = ((1 * 60) + 30) * 60;
    private static final LocalDateTime DATE_TIME_FIRST = dateTime(Year.MIN_VALUE, 1, 1, 0, 0);
    private static final LocalDateTime DATE_TIME_LAST = dateTime(Year.MAX_VALUE, 12, 31, 23, 59);
    private static final LocalDateTime DATE_TIME_2008_01_01 = dateTime(2008, 1, 1, 0, 0);
    private static final LocalDateTime DATE_TIME_2008_07_01 = dateTime(2008, 7, 1, 0, 0);

    //-----------------------------------------------------------------------
    // toRules()
    //-----------------------------------------------------------------------
    @Test(expectedExceptions=IllegalStateException.class)
    public void test_toRules_noWindows() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.toRules("Europe/London");
    }

    @Test(expectedExceptions=NullPointerException.class)
    public void test_toRules_null() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_2_30);
        b.toRules(null);
    }

    //-----------------------------------------------------------------------
    // Combined
    //-----------------------------------------------------------------------
    @Test
    public void test_combined_singleCutover() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(OFFSET_1, dateTime(1950, 1, 1, 1, 0), STANDARD);
        b.addWindowForever(OFFSET_2);
        ZoneRules test = b.toRules("Europe/London");
        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
        assertGap(test, 1950, 1, 1, 1, 30, OFFSET_1, OFFSET_2);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_2);
    }

    @Test
    public void test_combined_localFixedRules() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(OFFSET_1_15, dateTime(1920, 1, 1, 1, 0), WALL);
        b.addWindow(OFFSET_1, dateTime(1950, 1, 1, 1, 0), WALL);
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
        b.addRuleToWindow(2000, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_0);
        ZoneRules test = b.toRules("Europe/London");
        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1_15);
        assertOverlap(test, 1920, 1, 1, 0, 55, OFFSET_1_15, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
        assertOffsetInfo(test, dateTime(1800, 7, 1, 1, 0), OFFSET_1_15);
        assertOffsetInfo(test, dateTime(1920, 1, 1, 1, 0), OFFSET_1);
        assertOffsetInfo(test, dateTime(1960, 1, 1, 1, 0), OFFSET_1);
        assertOffsetInfo(test, dateTime(2000, 1, 1, 1, 0), OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_2008_01_01, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_2008_07_01, OFFSET_2_30);
        assertGap(test, 2008, 3, 30, 1, 20, OFFSET_1, OFFSET_2_30);
        assertOverlap(test, 2008, 10, 26, 0, 20, OFFSET_2_30, OFFSET_1);
    }

    @Test
    public void test_combined_windowChangeDuringDST() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(OFFSET_1, dateTime(2000, 7, 1, 1, 0), WALL);
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(2000, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(2, 0), false, WALL, PERIOD_0);
        ZoneRules test = b.toRules("Europe/Dublin");
        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);

        assertOffsetInfo(test, dateTime(2000, 1, 1, 0, 0), OFFSET_1);
        assertOffsetInfo(test, dateTime(2000, 7, 1, 0, 0), OFFSET_1);
        assertGap(test, 2000, 7, 1, 1, 20, OFFSET_1, OFFSET_2);
        assertOffsetInfo(test, dateTime(2000, 7, 1, 3, 0), OFFSET_2);
        assertOverlap(test, 2000, 10, 29, 1, 20, OFFSET_2, OFFSET_1);
        assertOffsetInfo(test, dateTime(2000, 12, 1, 0, 0), OFFSET_1);
    }

    @Test
    public void test_combined_windowChangeWithinDST() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(OFFSET_1, dateTime(2000, 7, 1, 1, 0), WALL);
        b.addWindow(OFFSET_1, dateTime(2000, 8, 1, 2, 0), WALL);
        b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(2000, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(2, 0), false, WALL, PERIOD_0);
        b.addWindowForever(OFFSET_1);
        ZoneRules test = b.toRules("Europe/Dublin");
        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);

        assertOffsetInfo(test, dateTime(2000, 1, 1, 0, 0), OFFSET_1);
        assertOffsetInfo(test, dateTime(2000, 7, 1, 0, 0), OFFSET_1);
        assertGap(test, 2000, 7, 1, 1, 20, OFFSET_1, OFFSET_2);
        assertOffsetInfo(test, dateTime(2000, 7, 1, 3, 0), OFFSET_2);
        assertOverlap(test, 2000, 8, 1, 1, 20, OFFSET_2, OFFSET_1);
        assertOffsetInfo(test, dateTime(2000, 12, 1, 0, 0), OFFSET_1);
    }

    @Test
    public void test_combined_endsInSavings() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(OFFSET_1_15, dateTime(1920, 1, 1, 1, 0), WALL);
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_0);
        b.addRuleToWindow(2000, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR);
        ZoneRules test = b.toRules("Pacific/Auckland");
        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1_15);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_2);
        assertOverlap(test, 1920, 1, 1, 0, 55, OFFSET_1_15, OFFSET_1);
        assertOffsetInfo(test, dateTime(2000, 3, 26, 0, 59), OFFSET_1);
        assertOffsetInfo(test, dateTime(2000, 3, 26, 1, 00), OFFSET_1);
        assertGap(test, 2000, 10, 29, 1, 20, OFFSET_1, OFFSET_2);
        assertOverlap(test, 2001, 3, 25, 0, 20, OFFSET_2, OFFSET_1);
        assertGap(test, 2001, 10, 28, 1, 20, OFFSET_1, OFFSET_2);
    }

    @Test
    public void test_combined_closeTransitions() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(OFFSET_1, dateTime(1920, 1, 1, 1, 0), WALL);
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, MARCH, 20, time(2, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(2000, MARCH, 20, time(4, 2), false, WALL, PERIOD_0);
        ZoneRules test = b.toRules("Europe/London");
        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
        assertOffsetInfo(test, dateTime(2000, 3, 20, 1, 59), OFFSET_1);
        assertGap(test, 2000, 3, 20, 2, 0, OFFSET_1, OFFSET_2);
        assertGap(test, 2000, 3, 20, 2, 59, OFFSET_1, OFFSET_2);
        assertOffsetInfo(test, dateTime(2000, 3, 20, 3, 0), OFFSET_2);
        assertOffsetInfo(test, dateTime(2000, 3, 20, 3, 1), OFFSET_2);
        assertOverlap(test, 2000, 3, 20, 3, 2, OFFSET_2, OFFSET_1);
        assertOverlap(test, 2000, 3, 20, 4, 1, OFFSET_2, OFFSET_1);
        assertOffsetInfo(test, dateTime(2000, 3, 20, 4, 2), OFFSET_1);
    }

    @Test
    public void test_combined_closeTransitionsMeet() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(OFFSET_1, dateTime(1920, 1, 1, 1, 0), WALL);
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, MARCH, 20, time(2, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(2000, MARCH, 20, time(4, 0), false, WALL, PERIOD_0);
        ZoneRules test = b.toRules("Europe/London");
        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
        assertOffsetInfo(test, dateTime(2000, 3, 20, 1, 59), OFFSET_1);
        assertGap(test, 2000, 3, 20, 2, 0, OFFSET_1, OFFSET_2);
        assertGap(test, 2000, 3, 20, 2, 59, OFFSET_1, OFFSET_2);
        assertOverlap(test, 2000, 3, 20, 3, 0, OFFSET_2, OFFSET_1);
        assertOverlap(test, 2000, 3, 20, 3, 59, OFFSET_2, OFFSET_1);
        assertOffsetInfo(test, dateTime(2000, 3, 20, 4, 0), OFFSET_1);
    }

// TODO: handle conflicting gap/overlap
//    public void test_combined_closeTransitionsConflictPartly() {
//        TransitionRulesBuilder b = new TransitionRulesBuilder(OFFSET_1, dateTime(1920, 1, 1, 1, 0), WALL);
//        b.addWindowForever(OFFSET_1);
//        b.addRuleToWindow(2000, MARCH, 20, time(2, 0), WALL, PERIOD_1HOUR);
//        b.addRuleToWindow(2000, MARCH, 20, time(3, 30), WALL, PERIOD_0);
//        ZoneRules test = b.toRules("Europe/London");
//        assertOffsetInfo(test, DATE_TIME_FIRST), OFFSET_1);
//        assertOffsetInfo(test, DATE_TIME_LAST), OFFSET_1);
//        assertOffsetInfo(test, dateTime(2000, 3, 20, 1, 59)), OFFSET_1);
//        assertGap(test, 2000, 3, 20, 2, 0, OFFSET_1, OFFSET_2);
//        assertGap(test, 2000, 3, 20, 2, 29, OFFSET_1, OFFSET_2);
//        assertOffsetInfo(test, dateTime(2000, 3, 20, 2, 30)), OFFSET_1);
//        assertOffsetInfo(test, dateTime(2000, 3, 20, 2, 59)), OFFSET_1);
//        assertOverlap(test, 2000, 3, 20, 3, 0, OFFSET_2, OFFSET_1);
//        assertOverlap(test, 2000, 3, 20, 3, 29, OFFSET_2, OFFSET_1);
//        assertOffsetInfo(test, dateTime(2000, 3, 20, 3, 30)), OFFSET_1);
//    }

    @Test
    public void test_combined_weirdSavingsBeforeLast() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(OFFSET_1, dateTime(1920, 1, 1, 1, 0), WALL);
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(1998, MARCH, 20, time(2, 0), false, WALL, PERIOD_1HOUR30MIN);
        b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, 20, null, time(2, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(2000, Year.MAX_VALUE, OCTOBER, 20, null, time(2, 0), false, WALL, PERIOD_0);
        ZoneRules test = b.toRules("Europe/London");

        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);

        assertOffsetInfo(test, dateTime(1999, 1, 1, 0, 0), OFFSET_2_30);
        assertOverlap(test, 2000, 3, 20, 1, 30, OFFSET_2_30, OFFSET_2);
        assertOverlap(test, 2000, 10, 20, 1, 30, OFFSET_2, OFFSET_1);
        assertGap(test, 2001, 3, 20, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 2001, 10, 20, 1, 30, OFFSET_2, OFFSET_1);
    }

    @Test
    public void test_combined_differentLengthLastRules1() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(OFFSET_1, dateTime(1920, 1, 1, 1, 0), WALL);
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(1998, MARCH, 20, time(2, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(1998, Year.MAX_VALUE, OCTOBER, 30, null, time(2, 0), false, WALL, PERIOD_0);
        b.addRuleToWindow(1999, MARCH, 21, time(2, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(2000, MARCH, 22, time(2, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(2001, MARCH, 23, time(2, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(2002, Year.MAX_VALUE, MARCH, 24, null, time(2, 0), false, WALL, PERIOD_1HOUR);
        ZoneRules test = b.toRules("Europe/London");

        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);

        assertGap(test, 1998, 3, 20, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 1998, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
        assertGap(test, 1999, 3, 21, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 1999, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
        assertGap(test, 2000, 3, 22, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 2000, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
        assertGap(test, 2001, 3, 23, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 2001, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
        assertGap(test, 2002, 3, 24, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 2002, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
        assertGap(test, 2003, 3, 24, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 2003, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
        assertGap(test, 2004, 3, 24, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 2004, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
        assertGap(test, 2005, 3, 24, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 2005, 10, 30, 1, 30, OFFSET_2, OFFSET_1);
    }

    @Test
    public void test_combined_differentLengthLastRules2() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(OFFSET_1, dateTime(1920, 1, 1, 1, 0), WALL);
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(1998, Year.MAX_VALUE, MARCH, 30, null, time(2, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(1998, OCTOBER, 20, time(2, 0), false, WALL, PERIOD_0);
        b.addRuleToWindow(1999, OCTOBER, 21, time(2, 0), false, WALL, PERIOD_0);
        b.addRuleToWindow(2000, OCTOBER, 22, time(2, 0), false, WALL, PERIOD_0);
        b.addRuleToWindow(2001, OCTOBER, 23, time(2, 0), false, WALL, PERIOD_0);
        b.addRuleToWindow(2002, Year.MAX_VALUE, OCTOBER, 24, null, time(2, 0), false, WALL, PERIOD_0);
        ZoneRules test = b.toRules("Europe/London");

        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);

        assertGap(test, 1998, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 1998, 10, 20, 1, 30, OFFSET_2, OFFSET_1);
        assertGap(test, 1999, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 1999, 10, 21, 1, 30, OFFSET_2, OFFSET_1);
        assertGap(test, 2000, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 2000, 10, 22, 1, 30, OFFSET_2, OFFSET_1);
        assertGap(test, 2001, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 2001, 10, 23, 1, 30, OFFSET_2, OFFSET_1);
        assertGap(test, 2002, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 2002, 10, 24, 1, 30, OFFSET_2, OFFSET_1);
        assertGap(test, 2003, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 2003, 10, 24, 1, 30, OFFSET_2, OFFSET_1);
        assertGap(test, 2004, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 2004, 10, 24, 1, 30, OFFSET_2, OFFSET_1);
        assertGap(test, 2005, 3, 30, 2, 30, OFFSET_1, OFFSET_2);
        assertOverlap(test, 2005, 10, 24, 1, 30, OFFSET_2, OFFSET_1);
    }

    @Test
    public void test_twoChangesSameDay() {
        // ensures that TZRule.compare works
        ZoneOffset plus2 = ZoneOffset.ofHours(2);
        ZoneOffset plus3 = ZoneOffset.ofHours(3);
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(plus2);
        b.addRuleToWindow(2010, 2010, SEPTEMBER, 10, null, time(12, 0), false, STANDARD, PERIOD_1HOUR);
        b.addRuleToWindow(2010, 2010, SEPTEMBER, 10, null, time(23, 0), false, STANDARD, PERIOD_0);
        ZoneRules test = b.toRules("Africa/Cairo");

        assertOffsetInfo(test, DATE_TIME_FIRST, plus2);
        assertOffsetInfo(test, DATE_TIME_LAST, plus2);

        assertGap(test, 2010, 9, 10, 12, 0, plus2, plus3)// jump forward from 12:00 to 13:00 on Tue 10th Sep
        assertOverlap(test, 2010, 9, 10, 23, 0, plus3, plus2)// overlaps from Wed 11th Sep 00:00 back to Tue 10th Sep 23:00
    }

    @Test
    public void test_twoChangesDifferentDefinition() {
        // ensures that TZRule.compare works
        ZoneOffset plus2 = ZoneOffset.ofHours(2);
        ZoneOffset plus3 = ZoneOffset.ofHours(3);
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(plus2);
        b.addRuleToWindow(2010, 2010, SEPTEMBER, -1, TUESDAY, time(0, 0), false, STANDARD, PERIOD_1HOUR);
        b.addRuleToWindow(2010, 2010, SEPTEMBER, 29, null, time(23, 0), false, STANDARD, PERIOD_0);
        ZoneRules test = b.toRules("Africa/Cairo");

        assertOffsetInfo(test, DATE_TIME_FIRST, plus2);
        assertOffsetInfo(test, DATE_TIME_LAST, plus2);

        assertGap(test, 2010, 9, 28, 0, 0, plus2, plus3)// jump forward from 00:00 to 01:00 on Tue 28th Sep
        assertOverlap(test, 2010, 9, 29, 23, 0, plus3, plus2)// overlaps from Thu 30th Sep 00:00 back to Wed 29th Sep 23:00
    }

    //-----------------------------------------------------------------------
    @Test
    public void test_argentina() {
        //  # On October 3, 1999, 0:00 local, Argentina implemented daylight savings time,
        //  # which did not result in the switch of a time zone, as they stayed 9 hours
        //  # from the International Date Line.
        //    Rule    Arg     1989    1993    -       Mar     Sun>=1  0:00    0       -
        //    Rule    Arg     1989    1992    -       Oct     Sun>=15 0:00    1:00    S
        //    Rule    Arg     1999    only    -       Oct     Sun>=1  0:00    1:00    S
        //    Rule    Arg     2000    only    -       Mar     3       0:00    0       -
        //    Zone America/Argentina/Tucuman -4:20:52 - LMT   1894 Oct 31
        //                -3:00   Arg AR%sT   1999 Oct  3
        //                -4:00   Arg AR%sT   2000 Mar  3

        ZoneOffset minus3 = ZoneOffset.ofHours(-3);
        ZoneOffset minus4 = ZoneOffset.ofHours(-4);
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(minus3, dateTime(1900, 1, 1, 0, 0), WALL);
        b.addWindow(minus3, dateTime(1999, 10, 3, 0, 0), WALL);
        b.addRuleToWindow(1993, MARCH, 3, time(0, 0), false, WALL, PERIOD_0);
        b.addRuleToWindow(1999, OCTOBER, 3, time(0, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(2000, MARCH, 3, time(0, 0), false, WALL, PERIOD_0);
        b.addWindow(minus4, dateTime(2000, 3, 3, 0, 0), WALL);
        b.addRuleToWindow(1993, MARCH, 3, time(0, 0), false, WALL, PERIOD_0);
        b.addRuleToWindow(1999, OCTOBER, 3, time(0, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(2000, MARCH, 3, time(0, 0), false, WALL, PERIOD_0);
        b.addWindowForever(minus3);
        ZoneRules test = b.toRules("America/Argentina/Tucuman");

        assertOffsetInfo(test, DATE_TIME_FIRST, minus3);
        assertOffsetInfo(test, DATE_TIME_LAST, minus3);

        assertOffsetInfo(test, dateTime(1999, 10, 2, 22, 59), minus3);
        assertOffsetInfo(test, dateTime(1999, 10, 2, 23, 59), minus3);
        assertOffsetInfo(test, dateTime(1999, 10, 3, 0, 0), minus3);
        assertOffsetInfo(test, dateTime(1999, 10, 3, 1, 0), minus3);

        assertOffsetInfo(test, dateTime(2000, 3, 2, 22, 59), minus3);
        assertOffsetInfo(test, dateTime(2000, 3, 2, 23, 59), minus3);
        assertOffsetInfo(test, dateTime(2000, 3, 3, 0, 0), minus3);
        assertOffsetInfo(test, dateTime(2000, 3, 3, 1, 0), minus3);
    }

    @Test
    public void test_cairo_dateChange() {
        //    Rule    Egypt   2008    max -   Apr lastFri  0:00s  1:00    S
        //    Rule    Egypt   2008    max -   Aug lastThu 23:00s  0   -
        //    Zone    Africa/Cairo    2:05:00 -     LMT   1900  Oct
        //                            2:00    Egypt EE%sT
        ZoneOffset plus2 = ZoneOffset.ofHours(2);
        ZoneOffset plus3 = ZoneOffset.ofHours(3);
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(plus2);
        b.addRuleToWindow(2008, Year.MAX_VALUE, APRIL, -1, FRIDAY, time(0, 0), false, STANDARD, PERIOD_1HOUR);
        b.addRuleToWindow(2008, Year.MAX_VALUE, AUGUST, -1, THURSDAY, time(23, 0), false, STANDARD, PERIOD_0);
        ZoneRules test = b.toRules("Africa/Cairo");

        assertOffsetInfo(test, DATE_TIME_FIRST, plus2);
        assertOffsetInfo(test, DATE_TIME_LAST, plus2);

        assertGap(test, 2009, 4, 24, 0, 0, plus2, plus3);
        assertOverlap(test, 2009, 8, 27, 23, 0, plus3, plus2)// overlaps from Fri 00:00 back to Thu 23:00
    }

    @Test
    public void test_cairo_twoChangesSameMonth() {
        // 2011i
        //    Rule    Egypt    2010    only    -    Aug    11       0:00      0      -
        //    Rule    Egypt    2010    only    -    Sep    10       0:00      1:00   S
        //    Rule    Egypt    2010    only    -    Sep    lastThu  23:00s    0      -
        //    Zone    Africa/Cairo    2:05:00 -     LMT   1900  Oct
        //                            2:00    Egypt EE%sT
        ZoneOffset plus2 = ZoneOffset.ofHours(2);
        ZoneOffset plus3 = ZoneOffset.ofHours(3);
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(plus2);
        b.addRuleToWindow(2010, 2010, AUGUST, 11, null, time(0, 0), false, STANDARD, PERIOD_0);
        b.addRuleToWindow(2010, 2010, SEPTEMBER, 10, null, time(0, 0), false, STANDARD, PERIOD_1HOUR);
        b.addRuleToWindow(2010, 2010, SEPTEMBER, -1, THURSDAY, time(23, 0), false, STANDARD, PERIOD_0);
        ZoneRules test = b.toRules("Africa/Cairo");

        assertOffsetInfo(test, DATE_TIME_FIRST, plus2);
        assertOffsetInfo(test, DATE_TIME_LAST, plus2);

        assertGap(test, 2010, 9, 10, 0, 0, plus2, plus3)// jump forward from 00:00 to 01:00 on Fri 10th Sep
        assertOverlap(test, 2010, 9, 30, 23, 0, plus3, plus2)// overlaps from Fri 1st Oct 00:00 back to Thu 30th Sep 23:00 (!!!)
    }

    @Test
    public void test_sofia_lastRuleClash() {
        // UTC rule change in 1996 occurs after Wall change
        // need to ensure that last rule is only applied to last window
        //        Rule    E-Eur   1981    max -   Mar lastSun  0:00   1:00    S
        //        Rule    E-Eur   1996    max -   Oct lastSun  0:00   0   -
        //        Rule    EU      1981    max -   Mar lastSun  1:00u  1:00    S
        //        Rule    EU      1996    max -   Oct lastSun  1:00u  0   -
        //        Zone    Europe/Sofia
        //        2:00    E-Eur   EE%sT   1997
        //        2:00    EU      EE%sT
          ZoneOffset plus2 = ZoneOffset.ofHours(2);
          ZoneOffset plus3 = ZoneOffset.ofHours(3);
          ZoneRulesBuilder b = new ZoneRulesBuilder();
          b.addWindow(plus2, dateTime(1997, 1, 1, 0, 0), WALL);
          b.addRuleToWindow(1996, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR);
          b.addRuleToWindow(1996, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_0);
          b.addWindowForever(plus2);
          b.addRuleToWindow(1996, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, UTC, PERIOD_1HOUR);
          b.addRuleToWindow(1996, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(1, 0), false, UTC, PERIOD_0);
          ZoneRules test = b.toRules("Europe/Sofia");

          assertOffsetInfo(test, DATE_TIME_FIRST, plus2);
          assertOffsetInfo(test, DATE_TIME_LAST, plus2);

          assertGap(test, 1996, 3, 31, 1, 0, plus2, plus3);
          assertOverlap(test, 1996, 10, 27, 0, 0, plus3, plus2);
          assertOffsetInfo(test, dateTime(1996, 10, 27, 1, 0), plus2);
          assertOffsetInfo(test, dateTime(1996, 10, 27, 2, 0), plus2);
          assertOffsetInfo(test, dateTime(1996, 10, 27, 3, 0), plus2);
          assertOffsetInfo(test, dateTime(1996, 10, 27, 4, 0), plus2);
      }

    @Test
    public void test_prague() {
        // need to calculate savings applicable at window start based on
        // first rule being transition from no savings to DST
        //    Rule    C-Eur   1944    1945    -   Apr Mon>=1   2:00s  1:00    S
        //    Rule    C-Eur   1944    only    -   Oct  2   2:00s  0   -
        //    Rule    C-Eur   1945    only    -   Sep 16   2:00s  0   -
        //    Rule    Czech   1945    only    -   Apr  8  2:00s   1:00    S
        //    Rule    Czech   1945    only    -   Nov 18  2:00s   0   -
        //    Zone    Europe/Prague   0:57:44 -     LMT   1850
        //                            0:57:44 -     PMT   1891 Oct
        //                            1:00    C-Eur CE%sT 1944 Sep 17 2:00s
        //                            1:00    Czech CE%sT 1979
        //                            1:00    EU    CE%sT
        ZoneOffset plus1 = ZoneOffset.ofHours(1);
        ZoneOffset plus2 = ZoneOffset.ofHours(2);
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(plus1, dateTime(1944, 9, 17, 2, 0), STANDARD);
        b.addRuleToWindow(1944, 1945, APRIL, 1, MONDAY, time(2, 0), false, STANDARD, PERIOD_1HOUR);
        b.addRuleToWindow(1944, OCTOBER, 2, time(2, 0), false, STANDARD, PERIOD_0);
        b.addRuleToWindow(1945, SEPTEMBER, 16, time(2, 0), false, STANDARD, PERIOD_0);
        b.addWindow(plus1, dateTime(1979, 1, 1, 0, 0), WALL);
        b.addRuleToWindow(1945, APRIL, 8, time(2, 0), false, STANDARD, PERIOD_1HOUR);
        b.addRuleToWindow(1945, NOVEMBER, 18, time(2, 0), false, STANDARD, PERIOD_0);
        b.addWindowForever(plus1);
        ZoneRules test = b.toRules("Europe/Sofia");

        assertOffsetInfo(test, DATE_TIME_FIRST, plus1);
        assertOffsetInfo(test, DATE_TIME_LAST, plus1);

        assertGap(test, 1944, 4, 3, 2, 30, plus1, plus2);
        assertOverlap(test, 1944, 9, 17, 2, 30, plus2, plus1);
        assertOffsetInfo(test, dateTime(1944, 9, 17, 3, 30), plus1);
        assertOffsetInfo(test, dateTime(1944, 9, 17, 4, 30), plus1);
        assertGap(test, 1945, 4, 8, 2, 30, plus1, plus2);
        assertOverlap(test, 1945, 11, 18, 2, 30, plus2, plus1);
    }

    @Test
    public void test_tbilisi() {
        // has transition into and out of 1 year of permanent DST (Mar96-Oct97)
        // where the date in the window and rule are the same
        // this is weird because the wall time in the rule is amended by the actual
        // wall time from the zone lines
        //      Rule E-EurAsia  1981    max   -   Mar lastSun  0:00   1:00  S
        //      Rule E-EurAsia  1979    1995  -   Sep lastSun  0:00   0     -
        //      Rule E-EurAsia  1996    max   -   Oct lastSun  0:00   0     -
        //    Zone    Asia/Tbilisi    2:59:16 -   LMT 1880
        //    4:00 E-EurAsia  GE%sT   1996 Oct lastSun
        //    4:00    1:00    GEST    1997 Mar lastSun
        //    4:00 E-EurAsia  GE%sT   2004 Jun 27
        //    3:00 RussiaAsia GE%sT   2005 Mar lastSun 2:00
        //    4:00    -   GET
        ZoneOffset plus4 = ZoneOffset.ofHours(4);
        ZoneOffset plus5 = ZoneOffset.ofHours(5);
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(plus4, dateTime(1996, 10, 27, 0, 0), WALL);
        b.addRuleToWindow(1996, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(0, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(1996, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(0, 0), false, WALL, PERIOD_0);
        b.addWindow(plus4, dateTime(1997, 3, 30, 0, 0), WALL);
        b.setFixedSavingsToWindow(PERIOD_1HOUR);
        b.addWindowForever(plus4);
        b.addRuleToWindow(1996, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(0, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(1996, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(0, 0), false, WALL, PERIOD_0);
        ZoneRules test = b.toRules("Europe/Sofia");

        assertOffsetInfo(test, DATE_TIME_FIRST, plus4);
        assertOffsetInfo(test, DATE_TIME_LAST, plus4);

        assertGap(test, 1996, 3, 31, 0, 30, plus4, plus5);
        // assertOverlap(test, 1996, 10, 26, 23, 30, plus5, plus4);  // fixed DST blocks overlap
        assertOffsetInfo(test, dateTime(1996, 10, 26, 22, 30), plus5);
        assertOffsetInfo(test, dateTime(1996, 10, 26, 23, 30), plus5);
        assertOffsetInfo(test, dateTime(1996, 10, 27, 0, 30), plus5);
        // assertOverlap(test, 1997, 3, 30, 0, 30, plus5, plus4);  // end of fixed blocks overlap
        assertOffsetInfo(test, dateTime(1997, 3, 29, 22, 30), plus5);
        assertOffsetInfo(test, dateTime(1997, 3, 29, 23, 30), plus5);
        assertOffsetInfo(test, dateTime(1997, 3, 30, 0, 30), plus5);
        assertOffsetInfo(test, dateTime(1997, 3, 30, 1, 30), plus5);
        assertOffsetInfo(test, dateTime(1997, 3, 30, 2, 30), plus5);
        assertOverlap(test, 1997, 10, 25, 23, 30, plus5, plus4);
    }

    @Test
    public void test_vincennes() {
        // need to ensure that at least one real rule is added to expand on the last rule
        //        Rule    US  2007  max  -   Mar Sun>=8  2:00  1:00  D
        //        Rule    US  2007  max  -   Nov Sun>=1  2:00  0     S
        //    -5:00   -   EST 2006 Apr  2 2:00
        //    -6:00   US  C%sT    2007 Nov  4 2:00
        //    -5:00   US  E%sT
        ZoneOffset minus5 = ZoneOffset.ofHours(-5);
        ZoneOffset minus6 = ZoneOffset.ofHours(-6);
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(minus6, dateTime(2007, 11, 4, 2, 0), WALL);
        b.addRuleToWindow(2007, Year.MAX_VALUE, MARCH, 8, SUNDAY, time(2, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(2007, Year.MAX_VALUE, NOVEMBER, 1, SUNDAY, time(2, 0), false, WALL, PERIOD_0);
        b.addWindowForever(minus5);
        b.addRuleToWindow(2007, Year.MAX_VALUE, MARCH, 8, SUNDAY, time(2, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(2007, Year.MAX_VALUE, NOVEMBER, 1, SUNDAY, time(2, 0), false, WALL, PERIOD_0);
        ZoneRules test = b.toRules("America/Indiana/Vincennes");

        assertOffsetInfo(test, DATE_TIME_FIRST, minus6);
        assertOffsetInfo(test, DATE_TIME_LAST, minus5);

        assertOffsetInfo(test, dateTime(2007, 3, 11, 0, 0), minus6);
        assertOffsetInfo(test, dateTime(2007, 3, 11, 1, 0), minus6);
        assertGap(test, 2007, 3, 11, 2, 0, minus6, minus5);
        assertOffsetInfo(test, dateTime(2007, 3, 11, 3, 0), minus5);
        assertOffsetInfo(test, dateTime(2007, 3, 11, 4, 0), minus5);
        assertOffsetInfo(test, dateTime(2007, 3, 11, 5, 0), minus5);
    }

    @Test
    public void test_iqaluit() {
        // two hour overlap due to end of daylight and change of standard offset
        //      Rule    Canada  1987   2006 -   Apr Sun>=1  2:00    1:00  D
        //      Rule    Canada  1974   2006 -   Oct lastSun 2:00    0     S
        //      Rule    NT_YK   1987   2006 -   Apr Sun>=1  2:00    1:00  D
        //      Rule    NT_YK   1980   2006 -   Oct lastSun 2:00    0     S
        //                    -5:00   NT_YK   E%sT    1999 Oct 31 2:00
        //                    -6:00   Canada  C%sT
        ZoneOffset minus4 = ZoneOffset.ofHours(-4);
        ZoneOffset minus5 = ZoneOffset.ofHours(-5);
        ZoneOffset minus6 = ZoneOffset.ofHours(-6);
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(minus5, dateTime(1999, 10, 31, 2, 0), WALL);
        b.addRuleToWindow(1987, Year.MAX_VALUE, APRIL, 1, SUNDAY, time(2, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(1987, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(2, 0), false, WALL, PERIOD_0);
        b.addWindowForever(minus6);
        b.addRuleToWindow(1987, Year.MAX_VALUE, APRIL, 1, SUNDAY, time(2, 0), false, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(1987, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(2, 0), false, WALL, PERIOD_0);
        ZoneRules test = b.toRules("America/Iqaluit");

        assertOffsetInfo(test, DATE_TIME_FIRST, minus5);
        assertOffsetInfo(test, DATE_TIME_LAST, minus6);

        assertOffsetInfo(test, dateTime(1999, 10, 30, 23, 0), minus4);
        assertOverlap(test, 1999, 10, 31, 0, 0, minus4, minus6);
        assertOverlap(test, 1999, 10, 31, 1, 0, minus4, minus6);
        assertOverlap(test, 1999, 10, 31, 1, 59, minus4, minus6);
        assertOffsetInfo(test, dateTime(1999, 10, 31, 2, 0), minus6);
        assertOffsetInfo(test, dateTime(1999, 10, 31, 3, 0), minus6);
    }

    @Test
    public void test_jordan2400() {
        // rule is 24:00 - this is simplified from the TZDB
        //    Rule    Jordan  2002    max -   Mar lastThu 24:00   1:00    S
        //    Rule    Jordan  2002    max -   Sep lastFri 0:00s   0   -
        //    # Zone  NAME        GMTOFF  RULES   FORMAT  [UNTIL]
        //                2:00    Jordan  EE%sT
        ZoneOffset plus2 = ZoneOffset.ofHours(2);
        ZoneOffset plus3 = ZoneOffset.ofHours(3);
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(plus2);
        b.addRuleToWindow(2002, Year.MAX_VALUE, MARCH, -1, THURSDAY, time(0, 0), true, WALL, PERIOD_1HOUR);
        b.addRuleToWindow(2002, Year.MAX_VALUE, SEPTEMBER, -1, FRIDAY, time(0, 0), false, STANDARD, PERIOD_0);
        ZoneRules test = b.toRules("Asia/Amman");

        assertOffsetInfo(test, DATE_TIME_FIRST, plus2);
        assertOffsetInfo(test, DATE_TIME_LAST, plus2);

        assertGap(test, 2002, 3, 29, 0, 0, plus2, plus3);
        assertOffsetInfo(test, dateTime(2002, 3, 28, 23, 0), plus2);
        assertOffsetInfo(test, dateTime(2002, 3, 29, 1, 0), plus3);

        assertOverlap(test, 2002, 9, 27, 0, 0, plus3, plus2);
        assertOffsetInfo(test, dateTime(2002, 9, 26, 23, 0), plus3);
        assertOffsetInfo(test, dateTime(2002, 9, 27, 1, 0), plus2);
    }

    //-----------------------------------------------------------------------
    // addWindow()
    //-----------------------------------------------------------------------
    @Test
    public void test_addWindow_constrainedRules() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(OFFSET_1, dateTime(1800, 7, 1, 0, 0), WALL);
        b.addWindow(OFFSET_1, dateTime(2008, 6, 30, 0, 0), STANDARD);
        b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
        b.addRuleToWindow(2000, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_0);
        ZoneRules test = b.toRules("Europe/London");
        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_2_30);
        assertOffsetInfo(test, DATE_TIME_2008_01_01, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_2008_07_01, OFFSET_2_30);
        assertGap(test, 2000, 3, 26, 1, 30, OFFSET_1, OFFSET_2_30);
        assertOverlap(test, 2000, 10, 29, 0, 30, OFFSET_2_30, OFFSET_1);
        assertGap(test, 2008, 3, 30, 1, 30, OFFSET_1, OFFSET_2_30);
        assertOffsetInfo(test, dateTime(2008, 10, 26, 0, 30), OFFSET_2_30);
    }

    @Test
    public void test_addWindow_noRules() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(OFFSET_1, dateTime(1800, 7, 1, 0, 0), WALL);
        b.addWindow(OFFSET_1, dateTime(2008, 6, 30, 0, 0), STANDARD);
        ZoneRules test = b.toRules("Europe/London");
        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_2008_01_01, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_2008_07_01, OFFSET_1);
    }

    @Test(expectedExceptions=NullPointerException.class)
    public void test_addWindow_nullOffset() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow((ZoneOffset) null, dateTime(2008, 6, 30, 0, 0), STANDARD);
    }

    @Test(expectedExceptions=NullPointerException.class)
    public void test_addWindow_nullTime() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(OFFSET_1, (LocalDateTime) null, STANDARD);
    }

    @Test(expectedExceptions=NullPointerException.class)
    public void test_addWindow_nullTimeDefinition() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(OFFSET_1, dateTime(2008, 6, 30, 0, 0), (TimeDefinition) null);
    }

    //-----------------------------------------------------------------------
    // addWindowForever()
    //-----------------------------------------------------------------------
    @Test
    public void test_addWindowForever_noRules() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        ZoneRules test = b.toRules("Europe/London");
        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_2008_01_01, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_2008_07_01, OFFSET_1);
    }

    @Test
    public void test_addWindowForever_rules() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
        b.addRuleToWindow(2000, Year.MAX_VALUE, OCTOBER, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_0);
        ZoneRules test = b.toRules("Europe/London");
        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_2008_01_01, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_2008_07_01, OFFSET_2_30);
        assertGap(test, 2008, 3, 30, 1, 20, OFFSET_1, OFFSET_2_30);
        assertOverlap(test, 2008, 10, 26, 0, 20, OFFSET_2_30, OFFSET_1);
    }

    @Test(expectedExceptions=NullPointerException.class)
    public void test_addWindowForever_nullOffset() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever((ZoneOffset) null);
    }

    //-----------------------------------------------------------------------
    // setFixedSavings()
    //-----------------------------------------------------------------------
    @Test
    public void test_setFixedSavingsToWindow() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindow(OFFSET_1, dateTime(1800, 7, 1, 0, 0), WALL);
        b.addWindowForever(OFFSET_1);
        b.setFixedSavingsToWindow(PERIOD_1HOUR30MIN);
        ZoneRules test = b.toRules("Europe/London");
        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_1);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_2_30);
        assertOffsetInfo(test, DATE_TIME_2008_01_01, OFFSET_2_30);
        assertOffsetInfo(test, DATE_TIME_2008_07_01, OFFSET_2_30);
        assertGap(test, 1800, 7, 1, 0, 0, OFFSET_1, OFFSET_2_30);
    }

    @Test
    public void test_setFixedSavingsToWindow_first() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.setFixedSavingsToWindow(PERIOD_1HOUR30MIN);
        ZoneRules test = b.toRules("Europe/London");
        assertOffsetInfo(test, DATE_TIME_FIRST, OFFSET_2_30);
        assertOffsetInfo(test, DATE_TIME_LAST, OFFSET_2_30);
    }

    @Test(expectedExceptions=IllegalStateException.class)
    public void test_setFixedSavingsToWindow_noWindow() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.setFixedSavingsToWindow(PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=IllegalStateException.class)
    public void test_setFixedSavingsToWindow_cannotMixSavingsWithRule() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, 2020, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
        b.setFixedSavingsToWindow(PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=IllegalStateException.class)
    public void test_setFixedSavingsToWindow_cannotMixSavingsWithLastRule() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
        b.setFixedSavingsToWindow(PERIOD_1HOUR30MIN);
    }

    //-----------------------------------------------------------------------
    // addRuleToWindow()
    //-----------------------------------------------------------------------
    @Test
    public void test_addRuleToWindow_endOfMonth() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, 2001, MARCH, -1, SUNDAY, time(1, 0), false, UTC, PERIOD_1HOUR);
        b.addRuleToWindow(2000, 2001, OCTOBER, -1, SUNDAY, time(1, 0), false, UTC, PERIOD_0);
        ZoneRules test = b.toRules("Europe/London");
        assertOffsetInfo(test, dateTime(1999, 7, 1, 0, 0), OFFSET_1);

        assertOffsetInfo(test, dateTime(2000, 1, 1, 0, 0), OFFSET_1);
        assertGap(test, 2000, 3, 26, 2, 30, OFFSET_1, OFFSET_2);
        assertOffsetInfo(test, dateTime(2000, 7, 1, 0, 0), OFFSET_2);
        assertOverlap(test, 2000, 10, 29, 2, 30, OFFSET_2, OFFSET_1);

        assertOffsetInfo(test, dateTime(2001, 1, 1, 0, 0), OFFSET_1);
        assertGap(test, 2001, 3, 25, 2, 30, OFFSET_1, OFFSET_2);
        assertOffsetInfo(test, dateTime(2001, 7, 1, 0, 0), OFFSET_2);
        assertOverlap(test, 2001, 10, 28, 2, 30, OFFSET_2, OFFSET_1);

        assertOffsetInfo(test, dateTime(2002, 7, 1, 0, 0), OFFSET_1);
    }

    @Test
    public void test_addRuleToWindow_endOfMonthFeb() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2004, 2005, FEBRUARY, -1, SUNDAY, time(1, 0), false, UTC, PERIOD_1HOUR);
        b.addRuleToWindow(2004, 2005, OCTOBER, -1, SUNDAY, time(1, 0), false, UTC, PERIOD_0);
        ZoneRules test = b.toRules("Europe/London");
        assertOffsetInfo(test, dateTime(2003, 7, 1, 0, 0), OFFSET_1);

        assertOffsetInfo(test, dateTime(2004, 1, 1, 0, 0), OFFSET_1);
        assertGap(test, 2004, 2, 29, 2, 30, OFFSET_1, OFFSET_2)// leap
        assertOffsetInfo(test, dateTime(2004, 7, 1, 0, 0), OFFSET_2);
        assertOverlap(test, 2004, 10, 31, 2, 30, OFFSET_2, OFFSET_1);

        assertOffsetInfo(test, dateTime(2005, 1, 1, 0, 0), OFFSET_1);
        assertGap(test, 2005, 2, 27, 2, 30, OFFSET_1, OFFSET_2);
        assertOffsetInfo(test, dateTime(2005, 7, 1, 0, 0), OFFSET_2);
        assertOverlap(test, 2005, 10, 30, 2, 30, OFFSET_2, OFFSET_1);

        assertOffsetInfo(test, dateTime(2006, 7, 1, 0, 0), OFFSET_1);
    }

    @Test
    public void test_addRuleToWindow_fromDayOfMonth() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, 2001, MARCH, 10, SUNDAY, time(1, 0), false, UTC, PERIOD_1HOUR);
        b.addRuleToWindow(2000, 2001, OCTOBER, 10, SUNDAY, time(1, 0), false, UTC, PERIOD_0);
        ZoneRules test = b.toRules("Europe/London");
        assertOffsetInfo(test, dateTime(1999, 7, 1, 0, 0), OFFSET_1);

        assertOffsetInfo(test, dateTime(2000, 1, 1, 0, 0), OFFSET_1);
        assertGap(test, 2000, 3, 12, 2, 30, OFFSET_1, OFFSET_2);
        assertOffsetInfo(test, dateTime(2000, 7, 1, 0, 0), OFFSET_2);
        assertOverlap(test, 2000, 10, 15, 2, 30, OFFSET_2, OFFSET_1);

        assertOffsetInfo(test, dateTime(2001, 1, 1, 0, 0), OFFSET_1);
        assertGap(test, 2001, 3, 11, 2, 30, OFFSET_1, OFFSET_2);
        assertOffsetInfo(test, dateTime(2001, 7, 1, 0, 0), OFFSET_2);
        assertOverlap(test, 2001, 10, 14, 2, 30, OFFSET_2, OFFSET_1);

        assertOffsetInfo(test, dateTime(2002, 7, 1, 0, 0), OFFSET_1);
    }

    @Test(expectedExceptions=IllegalStateException.class)
    public void test_addRuleToWindow_noWindow() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=IllegalStateException.class)
    public void test_addRuleToWindow_cannotMixRuleWithSavings() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.setFixedSavingsToWindow(PERIOD_1HOUR30MIN);
        b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=DateTimeException.class)
    public void test_addRuleToWindow_illegalYear1() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(Year.MIN_VALUE - 1, 2008, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=DateTimeException.class)
    public void test_addRuleToWindow_illegalYear2() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, Year.MIN_VALUE - 1, MARCH, -1, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=IllegalArgumentException.class)
    public void test_addRuleToWindow_illegalDayOfMonth_tooSmall() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, 2008, MARCH, -29, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=IllegalArgumentException.class)
    public void test_addRuleToWindow_illegalDayOfMonth_zero() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, 2008, MARCH, 0, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=IllegalArgumentException.class)
    public void test_addRuleToWindow_illegalDayOfMonth_tooLarge() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, 2008, MARCH, 32, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=NullPointerException.class)
    public void test_addRuleToWindow_nullMonth() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, Year.MAX_VALUE, (Month) null, 31, SUNDAY, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=NullPointerException.class)
    public void test_addRuleToWindow_nullTime() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, (LocalTime) null, false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=IllegalArgumentException.class)
    public void test_addRuleToWindow_illegalEndOfDayTime() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, 2008, MARCH, 1, SUNDAY, time(1, 0), true, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=NullPointerException.class)
    public void test_addRuleToWindow_nullTimeDefinition() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, Year.MAX_VALUE, MARCH, -1, SUNDAY, time(1, 0), false, (TimeDefinition) null, PERIOD_1HOUR30MIN);
    }

    //-----------------------------------------------------------------------
    // addRuleToWindow() - single year object
    //-----------------------------------------------------------------------
    @Test
    public void test_addRuleToWindow_singleYearObject() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(dateTime(2000, MARCH, 26, 1, 0), UTC, PERIOD_1HOUR);
        b.addRuleToWindow(dateTime(2000, OCTOBER, 29, 1, 0), UTC, PERIOD_0);
        ZoneRules test = b.toRules("Europe/London");
        assertOffsetInfo(test, dateTime(1999, 7, 1, 0, 0), OFFSET_1);

        assertOffsetInfo(test, dateTime(2000, 1, 1, 0, 0), OFFSET_1);
        assertGap(test, 2000, 3, 26, 2, 30, OFFSET_1, OFFSET_2);
        assertOffsetInfo(test, dateTime(2000, 7, 1, 0, 0), OFFSET_2);
        assertOverlap(test, 2000, 10, 29, 2, 30, OFFSET_2, OFFSET_1);

        assertOffsetInfo(test, dateTime(2001, 7, 1, 0, 0), OFFSET_1);
    }

    @Test(expectedExceptions=NullPointerException.class)
    public void test_addRuleToWindow_singleYearObject_nullTime() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow((LocalDateTime) null, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=NullPointerException.class)
    public void test_addRuleToWindow_singleYearObject_nullTimeDefinition() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(dateTime(2000, MARCH, 31, 1, 0), (TimeDefinition) null, PERIOD_1HOUR30MIN);
    }

    //-----------------------------------------------------------------------
    // addRuleToWindow() - single year
    //-----------------------------------------------------------------------
    @Test
    public void test_addRuleToWindow_singleYear() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, MARCH, 26, time(1, 0), false, UTC, PERIOD_1HOUR);
        b.addRuleToWindow(2000, OCTOBER, 29, time(1, 0), false, UTC, PERIOD_0);
        ZoneRules test = b.toRules("Europe/London");
        assertOffsetInfo(test, dateTime(1999, 7, 1, 0, 0), OFFSET_1);

        assertOffsetInfo(test, dateTime(2000, 1, 1, 0, 0), OFFSET_1);
        assertGap(test, 2000, 3, 26, 2, 30, OFFSET_1, OFFSET_2);
        assertOffsetInfo(test, dateTime(2000, 7, 1, 0, 0), OFFSET_2);
        assertOverlap(test, 2000, 10, 29, 2, 30, OFFSET_2, OFFSET_1);

        assertOffsetInfo(test, dateTime(2001, 7, 1, 0, 0), OFFSET_1);
    }

    @Test(expectedExceptions=IllegalStateException.class)
    public void test_addRuleToWindow_singleYear_noWindow() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addRuleToWindow(2000, MARCH, 31, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=IllegalStateException.class)
    public void test_addRuleToWindow_singleYear_cannotMixRuleWithSavings() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.setFixedSavingsToWindow(PERIOD_1HOUR30MIN);
        b.addRuleToWindow(2000, MARCH, 31, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=DateTimeException.class)
    public void test_addRuleToWindow_singleYear_illegalYear() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(Year.MIN_VALUE - 1, MARCH, 31, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=IllegalArgumentException.class)
    public void test_addRuleToWindow_singleYear_illegalDayOfMonth_tooSmall() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, MARCH, -29, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=IllegalArgumentException.class)
    public void test_addRuleToWindow_singleYear_illegalDayOfMonth_zero() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, MARCH, 0, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=IllegalArgumentException.class)
    public void test_addRuleToWindow_singleYear_illegalDayOfMonth_tooLarge() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, MARCH, 32, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=NullPointerException.class)
    public void test_addRuleToWindow_singleYear_nullMonth() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, (Month) null, 31, time(1, 0), false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=NullPointerException.class)
    public void test_addRuleToWindow_singleYear_nullTime() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, MARCH, 31, (LocalTime) null, false, WALL, PERIOD_1HOUR30MIN);
    }

    @Test(expectedExceptions=NullPointerException.class)
    public void test_addRuleToWindow_singleYear_nullTimeDefinition() {
        ZoneRulesBuilder b = new ZoneRulesBuilder();
        b.addWindowForever(OFFSET_1);
        b.addRuleToWindow(2000, MARCH, 31, time(1, 0), false, (TimeDefinition) null, PERIOD_1HOUR30MIN);
    }

    //-----------------------------------------------------------------------
    private static void assertGap(ZoneRules test, int y, int m, int d, int hr, int min, ZoneOffset before, ZoneOffset after) {
        LocalDateTime dt = dateTime(y, m, d, hr, min);
        ZoneOffsetTransition zot = test.getTransition(dt);
        assertNotNull(zot);
        assertEquals(zot.isGap(), true);
        assertEquals(zot.getOffsetBefore(), before);
        assertEquals(zot.getOffsetAfter(), after);
    }

    private static void assertOverlap(ZoneRules test, int y, int m, int d, int hr, int min, ZoneOffset before, ZoneOffset after) {
        LocalDateTime dt = dateTime(y, m, d, hr, min);
        ZoneOffsetTransition zot = test.getTransition(dt);
        assertNotNull(zot);
        assertEquals(zot.isOverlap(), true);
        assertEquals(zot.getOffsetBefore(), before);
        assertEquals(zot.getOffsetAfter(), after);
    }

    private void assertOffsetInfo(ZoneRules test, LocalDateTime dateTime, ZoneOffset offset) {
        List<ZoneOffset> offsets = test.getValidOffsets(dateTime);
        assertEquals(offsets.size(), 1);
        assertEquals(offsets.get(0), offset);
    }

    //-----------------------------------------------------------------------
    private static LocalTime time(int h, int m) {
        return LocalTime.of(h, m);
    }

    private static LocalDateTime dateTime(int year, int month, int day, int h, int m) {
        return LocalDateTime.of(year, month, day, h, m);
    }

    private static LocalDateTime dateTime(int year, Month month, int day, int h, int m) {
        return LocalDateTime.of(year, month, day, h, m);
    }

}
TOP

Related Classes of org.threeten.bp.zone.TestZoneRulesBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.