1 /*
   2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import static org.testng.Assert.assertEquals;
  25 
  26 import java.time.Instant;
  27 import java.time.LocalDate;
  28 import java.time.LocalTime;
  29 import java.time.ZonedDateTime;
  30 import java.time.ZoneId;
  31 import java.util.Date;
  32 import java.util.TimeZone;
  33 
  34 import org.testng.annotations.Test;
  35 import org.testng.annotations.DataProvider;
  36 import static org.testng.Assert.assertEquals;
  37 
  38 /**
  39  * @test
  40  * @bug 8212970
  41  * @summary Test whether the savings are positive in time zones that have
  42  *      negative savings in the source TZ files.
  43  * @run testng NegativeDSTTest 
  44  */
  45 @Test
  46 public class NegativeDSTTest {
  47 
  48     private static final TimeZone DUBLIN = TimeZone.getTimeZone("Europe/Dublin");
  49     private static final TimeZone PRAGUE = TimeZone.getTimeZone("Europe/Prague");
  50     private static final TimeZone WINDHOEK = TimeZone.getTimeZone("Africa/Windhoek");
  51     private static final TimeZone CASABLANCA = TimeZone.getTimeZone("Africa/Casablanca");
  52     private static final int ONE_HOUR = 3600_000;
  53 
  54     @DataProvider
  55     private Object[][] negativeDST () {
  56         return new Object[][] {
  57             // TimeZone, localDate, offset, isDaylightSavings
  58             // Europe/Dublin for the Rule "Eire"
  59             {DUBLIN, LocalDate.of(1970, 6, 23), ONE_HOUR, true},
  60             {DUBLIN, LocalDate.of(1971, 6, 23), ONE_HOUR, true},
  61             {DUBLIN, LocalDate.of(1971, 11, 1), 0, false},
  62             {DUBLIN, LocalDate.of(2019, 6, 23), ONE_HOUR, true},
  63             {DUBLIN, LocalDate.of(2019, 12, 23), 0, false},
  64 
  65             // Europe/Prague which contains fixed negative savings (not a named Rule)
  66             {PRAGUE, LocalDate.of(1946, 9, 30), 2 * ONE_HOUR, true},
  67             {PRAGUE, LocalDate.of(1946, 10, 10), ONE_HOUR, false},
  68             {PRAGUE, LocalDate.of(1946, 12, 3), 0, false},
  69             {PRAGUE, LocalDate.of(1947, 2, 25), ONE_HOUR, false},
  70             {PRAGUE, LocalDate.of(1947, 4, 30), 2 * ONE_HOUR, true},
  71 
  72             // Africa/Windhoek for the Rule "Namibia"
  73             {WINDHOEK, LocalDate.of(1994, 3, 23), ONE_HOUR, false},
  74             {WINDHOEK, LocalDate.of(2016, 9, 23), 2 * ONE_HOUR, true},
  75 
  76             // Africa/Casablanca for the Rule "Morocco" Defines negative DST till 2037 as of 2019a.
  77             {CASABLANCA, LocalDate.of(1939, 9, 13), ONE_HOUR, true},
  78             {CASABLANCA, LocalDate.of(1939, 11, 20), 0, false},
  79             {CASABLANCA, LocalDate.of(2018, 6, 18), ONE_HOUR, true},
  80             {CASABLANCA, LocalDate.of(2019, 1, 1), ONE_HOUR, true},
  81             {CASABLANCA, LocalDate.of(2019, 5, 6), 0, false},
  82             {CASABLANCA, LocalDate.of(2037, 10, 5), 0, false},
  83             {CASABLANCA, LocalDate.of(2037, 11, 16), ONE_HOUR, true},
  84             {CASABLANCA, LocalDate.of(2038, 11, 1), ONE_HOUR, true},
  85         };
  86     }
  87 
  88     @Test(dataProvider="negativeDST")
  89     public void test_NegativeDST(TimeZone tz, LocalDate ld, int offset, boolean isDST) {
  90         Date d = Date.from(Instant.from(ZonedDateTime.of(ld, LocalTime.MIN, tz.toZoneId())));
  91         assertEquals(tz.getOffset(d.getTime()), offset);
  92         assertEquals(tz.inDaylightTime(d), isDST);
  93     }
  94 }