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 package test.java.time.zone;
25
26 import java.time.DayOfWeek;
27 import java.time.Instant;
28 import java.time.LocalDate;
29 import java.time.LocalDateTime;
30 import java.time.LocalTime;
31 import java.time.Month;
32 import java.time.Year;
33 import java.time.ZonedDateTime;
34 import java.time.ZoneId;
35 import java.time.ZoneOffset;
36 import java.time.zone.ZoneOffsetTransition;
37 import java.time.zone.ZoneOffsetTransitionRule;
38 import java.time.zone.ZoneRules;
39 import java.util.Collections;
40
41 import org.testng.annotations.Test;
42 import org.testng.annotations.DataProvider;
43 import static org.testng.Assert.assertEquals;
44 import static org.testng.Assert.assertTrue;
45
46 /**
47 * @summary Tests for ZoneRules class.
48 *
49 * @bug 8212970 8236903
50 */
51 @Test
52 public class TestZoneRules {
53
54 private static final ZoneId DUBLIN = ZoneId.of("Europe/Dublin");
55 private static final ZoneId PRAGUE = ZoneId.of("Europe/Prague");
56 private static final ZoneId WINDHOEK = ZoneId.of("Africa/Windhoek");
57 private static final ZoneId CASABLANCA = ZoneId.of("Africa/Casablanca");
58
59 private static final ZoneId TOKYO = ZoneId.of("Asia/Tokyo");
60 private static final LocalTime ONE_AM = LocalTime.of(1, 0);
61
62 @DataProvider
63 private Object[][] negativeDST () {
64 return new Object[][] {
65 // ZoneId, localDate, offset, standard offset, isDaylightSavings
66 // Europe/Dublin for the Rule "Eire"
67 {DUBLIN, LocalDate.of(1970, 6, 23), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
68 {DUBLIN, LocalDate.of(1971, 6, 23), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
69 {DUBLIN, LocalDate.of(1971, 11, 1), ZoneOffset.ofHours(0), ZoneOffset.ofHours(0), false},
70 {DUBLIN, LocalDate.of(2019, 6, 23), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
71 {DUBLIN, LocalDate.of(2019, 12, 23), ZoneOffset.ofHours(0), ZoneOffset.ofHours(0), false},
72
73 // Europe/Prague which contains fixed negative savings (not a named Rule)
74 {PRAGUE, LocalDate.of(1946, 9, 30), ZoneOffset.ofHours(2), ZoneOffset.ofHours(1), true},
75 {PRAGUE, LocalDate.of(1946, 10, 10), ZoneOffset.ofHours(1), ZoneOffset.ofHours(1), false},
76 {PRAGUE, LocalDate.of(1946, 12, 3), ZoneOffset.ofHours(0), ZoneOffset.ofHours(0), false},
77 {PRAGUE, LocalDate.of(1947, 2, 25), ZoneOffset.ofHours(1), ZoneOffset.ofHours(1), false},
78 {PRAGUE, LocalDate.of(1947, 4, 30), ZoneOffset.ofHours(2), ZoneOffset.ofHours(1), true},
79
80 // Africa/Windhoek for the Rule "Namibia"
81 {WINDHOEK, LocalDate.of(1994, 3, 23), ZoneOffset.ofHours(1), ZoneOffset.ofHours(1), false},
82 {WINDHOEK, LocalDate.of(2016, 9, 23), ZoneOffset.ofHours(2), ZoneOffset.ofHours(1), true},
83
84 // Africa/Casablanca for the Rule "Morocco" Defines negative DST till 2037 as of 2019a.
85 {CASABLANCA, LocalDate.of(1939, 9, 13), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
86 {CASABLANCA, LocalDate.of(1939, 11, 20), ZoneOffset.ofHours(0), ZoneOffset.ofHours(0), false},
87 {CASABLANCA, LocalDate.of(2018, 6, 18), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
88 {CASABLANCA, LocalDate.of(2019, 1, 1), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
89 {CASABLANCA, LocalDate.of(2019, 5, 6), ZoneOffset.ofHours(0), ZoneOffset.ofHours(0), false},
90 {CASABLANCA, LocalDate.of(2037, 10, 5), ZoneOffset.ofHours(0), ZoneOffset.ofHours(0), false},
91 {CASABLANCA, LocalDate.of(2037, 11, 16), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
92 {CASABLANCA, LocalDate.of(2038, 11, 1), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
93 };
94 }
95
96 @DataProvider
97 private Object[][] transitionBeyondDay() {
98 return new Object[][] {
99 // ZoneId, LocalDateTime, beforeOffset, afterOffset
100
101 // Asserts that the rule:
102 // Rule Japan 1948 1951 - Sep Sat>=8 25:00 0 S
103 // translates to the next day.
104 {TOKYO, LocalDateTime.of(LocalDate.of(1948, 9, 12), ONE_AM), ZoneOffset.ofHours(10), ZoneOffset.ofHours(9)},
105 {TOKYO, LocalDateTime.of(LocalDate.of(1949, 9, 11), ONE_AM), ZoneOffset.ofHours(10), ZoneOffset.ofHours(9)},
106 {TOKYO, LocalDateTime.of(LocalDate.of(1950, 9, 10), ONE_AM), ZoneOffset.ofHours(10), ZoneOffset.ofHours(9)},
107 {TOKYO, LocalDateTime.of(LocalDate.of(1951, 9, 9), ONE_AM), ZoneOffset.ofHours(10), ZoneOffset.ofHours(9)},
108 };
109 }
110
111 /**
112 * Test ZoneRules whether the savings are positive in time zones that have
113 * negative savings in the source TZ files.
114 * @bug 8212970
115 */
116 @Test(dataProvider="negativeDST")
117 public void test_NegativeDST(ZoneId zid, LocalDate ld, ZoneOffset offset, ZoneOffset stdOffset, boolean isDST) {
118 Instant i = Instant.from(ZonedDateTime.of(ld, LocalTime.MIN, zid));
119 ZoneRules zr = zid.getRules();
120 assertEquals(zr.getOffset(i), offset);
121 assertEquals(zr.getStandardOffset(i), stdOffset);
122 assertEquals(zr.isDaylightSavings(i), isDST);
123 }
124
125 /**
126 * Check the transition cutover time beyond 24:00, which should translate into the next day.
127 * @bug 8212970
128 */
129 @Test(dataProvider="transitionBeyondDay")
130 public void test_TransitionBeyondDay(ZoneId zid, LocalDateTime ldt, ZoneOffset before, ZoneOffset after) {
131 ZoneOffsetTransition zot = ZoneOffsetTransition.of(ldt, before, after);
132 ZoneRules zr = zid.getRules();
133 assertTrue(zr.getTransitions().contains(zot));
134 }
135
136 /**
137 * Make sure ZoneRules.findYear() won't throw out-of-range DateTimeException for
138 * year calculation.
139 * @bug 8236903
140 */
141 @Test
142 public void test_TransitionLastRuleYear() {
143 Instant maxLocalDateTime = LocalDateTime.of(Year.MAX_VALUE,
144 12,
145 31,
146 23,
147 59,
148 59,
149 999999999).toInstant(ZoneOffset.UTC);
150 ZoneOffset offsetZero = ZoneOffset.ofHours(0);
151 ZoneOffset offsetPlusOneHour = ZoneOffset.ofHours(1);
152 ZoneRules zoneRulesA = ZoneRules.of(offsetPlusOneHour);
153 ZoneOffsetTransition transition = ZoneOffsetTransition.of(LocalDateTime.ofEpochSecond(0, 0, offsetZero),
154 offsetZero,
155 offsetPlusOneHour);
156 ZoneOffsetTransitionRule transitionRule = ZoneOffsetTransitionRule.of(Month.JANUARY,
157 1,
158 DayOfWeek.SUNDAY,
159 LocalTime.MIDNIGHT,
160 true,
161 ZoneOffsetTransitionRule.TimeDefinition.STANDARD,
162 offsetZero,
163 offsetZero,
164 offsetPlusOneHour);
165 ZoneRules zoneRulesB = ZoneRules.of(offsetZero,
166 offsetZero,
167 Collections.singletonList(transition),
168 Collections.singletonList(transition),
169 Collections.singletonList(transitionRule));
170 ZoneOffset offsetA = zoneRulesA.getOffset(maxLocalDateTime);
171 ZoneOffset offsetB = zoneRulesB.getOffset(maxLocalDateTime);
172 assertEquals(offsetA, offsetB);
173 }
174 }
|
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 package test.java.time.zone;
25
26 import java.time.DayOfWeek;
27 import java.time.Duration;
28 import java.time.Instant;
29 import java.time.LocalDate;
30 import java.time.LocalDateTime;
31 import java.time.LocalTime;
32 import java.time.Month;
33 import java.time.Year;
34 import java.time.ZonedDateTime;
35 import java.time.ZoneId;
36 import java.time.ZoneOffset;
37 import java.time.zone.ZoneOffsetTransition;
38 import java.time.zone.ZoneOffsetTransitionRule;
39 import java.time.zone.ZoneRules;
40 import java.util.Collections;
41 import java.util.List;
42
43 import org.testng.annotations.DataProvider;
44 import org.testng.annotations.Test;
45 import static org.testng.Assert.assertEquals;
46 import static org.testng.Assert.assertTrue;
47
48 /**
49 * @summary Tests for ZoneRules class.
50 *
51 * @bug 8212970 8236903 8239836
52 */
53 @Test
54 public class TestZoneRules {
55
56 private static final ZoneId DUBLIN = ZoneId.of("Europe/Dublin");
57 private static final ZoneId PRAGUE = ZoneId.of("Europe/Prague");
58 private static final ZoneId WINDHOEK = ZoneId.of("Africa/Windhoek");
59 private static final ZoneId CASABLANCA = ZoneId.of("Africa/Casablanca");
60
61 private static final ZoneId TOKYO = ZoneId.of("Asia/Tokyo");
62 private static final LocalTime ONE_AM = LocalTime.of(1, 0);
63
64 private static final ZoneOffset OFF_0 = ZoneOffset.ofHours(0);
65 private static final ZoneOffset OFF_1 = ZoneOffset.ofHours(1);
66 private static final ZoneOffset OFF_2 = ZoneOffset.ofHours(2);
67 private static final List EL = Collections.emptyList();
68 private static final ZoneOffsetTransition ZOT = ZoneId.of("America/Los_Angeles").getRules().getTransitions().get(0);
69 private static final ZoneOffsetTransitionRule ZOTR = ZoneId.of("America/Los_Angeles").getRules().getTransitionRules().get(0);
70
71 @DataProvider
72 private Object[][] negativeDST () {
73 return new Object[][] {
74 // ZoneId, localDate, offset, standard offset, isDaylightSavings
75 // Europe/Dublin for the Rule "Eire"
76 {DUBLIN, LocalDate.of(1970, 6, 23), OFF_1, OFF_0, true},
77 {DUBLIN, LocalDate.of(1971, 6, 23), OFF_1, OFF_0, true},
78 {DUBLIN, LocalDate.of(1971, 11, 1), OFF_0, OFF_0, false},
79 {DUBLIN, LocalDate.of(2019, 6, 23), OFF_1, OFF_0, true},
80 {DUBLIN, LocalDate.of(2019, 12, 23), OFF_0, OFF_0, false},
81
82 // Europe/Prague which contains fixed negative savings (not a named Rule)
83 {PRAGUE, LocalDate.of(1946, 9, 30), OFF_2, OFF_1, true},
84 {PRAGUE, LocalDate.of(1946, 10, 10), OFF_1, OFF_1, false},
85 {PRAGUE, LocalDate.of(1946, 12, 3), OFF_0, OFF_0, false},
86 {PRAGUE, LocalDate.of(1947, 2, 25), OFF_1, OFF_1, false},
87 {PRAGUE, LocalDate.of(1947, 4, 30), OFF_2, OFF_1, true},
88
89 // Africa/Windhoek for the Rule "Namibia"
90 {WINDHOEK, LocalDate.of(1994, 3, 23), OFF_1, OFF_1, false},
91 {WINDHOEK, LocalDate.of(2016, 9, 23), OFF_2, OFF_1, true},
92
93 // Africa/Casablanca for the Rule "Morocco" Defines negative DST till 2037 as of 2019a.
94 {CASABLANCA, LocalDate.of(1939, 9, 13), OFF_1, OFF_0, true},
95 {CASABLANCA, LocalDate.of(1939, 11, 20), OFF_0, OFF_0, false},
96 {CASABLANCA, LocalDate.of(2018, 6, 18), OFF_1, OFF_0, true},
97 {CASABLANCA, LocalDate.of(2019, 1, 1), OFF_1, OFF_0, true},
98 {CASABLANCA, LocalDate.of(2019, 5, 6), OFF_0, OFF_0, false},
99 {CASABLANCA, LocalDate.of(2037, 10, 5), OFF_0, OFF_0, false},
100 {CASABLANCA, LocalDate.of(2037, 11, 16), OFF_1, OFF_0, true},
101 {CASABLANCA, LocalDate.of(2038, 11, 1), OFF_1, OFF_0, true},
102 };
103 }
104
105 @DataProvider
106 private Object[][] transitionBeyondDay() {
107 return new Object[][] {
108 // ZoneId, LocalDateTime, beforeOffset, afterOffset
109
110 // Asserts that the rule:
111 // Rule Japan 1948 1951 - Sep Sat>=8 25:00 0 S
112 // translates to the next day.
113 {TOKYO, LocalDateTime.of(LocalDate.of(1948, 9, 12), ONE_AM), ZoneOffset.ofHours(10), ZoneOffset.ofHours(9)},
114 {TOKYO, LocalDateTime.of(LocalDate.of(1949, 9, 11), ONE_AM), ZoneOffset.ofHours(10), ZoneOffset.ofHours(9)},
115 {TOKYO, LocalDateTime.of(LocalDate.of(1950, 9, 10), ONE_AM), ZoneOffset.ofHours(10), ZoneOffset.ofHours(9)},
116 {TOKYO, LocalDateTime.of(LocalDate.of(1951, 9, 9), ONE_AM), ZoneOffset.ofHours(10), ZoneOffset.ofHours(9)},
117 };
118 }
119
120 @DataProvider
121 private Object[][] emptyTransitionList() {
122 return new Object[][] {
123 // days, offset, std offset, savings, isDST
124 {7, 1, 2, -1, true},
125 {-7, 1, 1, 0, false},
126 };
127 }
128
129 @DataProvider
130 private Object[][] isFixedOffset() {
131 return new Object[][] {
132 // ZoneRules, expected
133 {ZoneRules.of(OFF_0), true},
134 {ZoneRules.of(OFF_0, OFF_0, EL, EL, EL), true},
135 {ZoneRules.of(OFF_0, OFF_1, EL, EL, EL), false},
136 {ZoneRules.of(OFF_0, OFF_0, Collections.singletonList(ZOT), EL, EL), false},
137 {ZoneRules.of(OFF_0, OFF_0, EL, Collections.singletonList(ZOT), EL), false},
138 {ZoneRules.of(OFF_0, OFF_0, EL, EL, Collections.singletonList(ZOTR)), false},
139 };
140 }
141
142 /**
143 * Test ZoneRules whether the savings are positive in time zones that have
144 * negative savings in the source TZ files.
145 * @bug 8212970
146 */
147 @Test(dataProvider="negativeDST")
148 public void test_NegativeDST(ZoneId zid, LocalDate ld, ZoneOffset offset, ZoneOffset stdOffset, boolean isDST) {
149 Instant i = Instant.from(ZonedDateTime.of(ld, LocalTime.MIN, zid));
150 ZoneRules zr = zid.getRules();
151 assertEquals(zr.getOffset(i), offset);
152 assertEquals(zr.getStandardOffset(i), stdOffset);
153 assertEquals(zr.isDaylightSavings(i), isDST);
154 }
155
156 /**
157 * Check the transition cutover time beyond 24:00, which should translate into the next day.
158 * @bug 8212970
159 */
160 @Test(dataProvider="transitionBeyondDay")
161 public void test_TransitionBeyondDay(ZoneId zid, LocalDateTime ldt, ZoneOffset before, ZoneOffset after) {
162 ZoneOffsetTransition zot = ZoneOffsetTransition.of(ldt, before, after);
163 ZoneRules zr = zid.getRules();
164 assertTrue(zr.getTransitions().contains(zot));
165 }
166
167 /**
168 * Make sure ZoneRules.findYear() won't throw out-of-range DateTimeException for
169 * year calculation.
170 * @bug 8236903
171 */
172 @Test
173 public void test_TransitionLastRuleYear() {
174 Instant maxLocalDateTime = LocalDateTime.of(Year.MAX_VALUE,
175 12,
176 31,
177 23,
178 59,
179 59,
180 999999999).toInstant(ZoneOffset.UTC);
181 ZoneRules zoneRulesA = ZoneRules.of(OFF_1);
182 ZoneOffsetTransition transition = ZoneOffsetTransition.of(LocalDateTime.ofEpochSecond(0, 0, OFF_0),
183 OFF_0,
184 OFF_1);
185 ZoneOffsetTransitionRule transitionRule = ZoneOffsetTransitionRule.of(Month.JANUARY,
186 1,
187 DayOfWeek.SUNDAY,
188 LocalTime.MIDNIGHT,
189 true,
190 ZoneOffsetTransitionRule.TimeDefinition.STANDARD,
191 OFF_0,
192 OFF_0,
193 OFF_1);
194 ZoneRules zoneRulesB = ZoneRules.of(OFF_0,
195 OFF_0,
196 Collections.singletonList(transition),
197 Collections.singletonList(transition),
198 Collections.singletonList(transitionRule));
199 ZoneOffset offsetA = zoneRulesA.getOffset(maxLocalDateTime);
200 ZoneOffset offsetB = zoneRulesB.getOffset(maxLocalDateTime);
201 assertEquals(offsetA, offsetB);
202 }
203
204 /**
205 * Tests whether empty "transitionList" is correctly interpreted.
206 * @bug 8239836
207 */
208 @Test(dataProvider="emptyTransitionList")
209 public void test_EmptyTransitionList(int days, int offset, int stdOffset, int savings, boolean isDST) {
210 LocalDateTime transitionDay = LocalDateTime.of(2020, 1, 1, 2, 0);
211 Instant testDay = transitionDay.plusDays(days).toInstant(ZoneOffset.UTC);
212 ZoneOffsetTransition trans = ZoneOffsetTransition.of(
213 transitionDay,
214 OFF_1,
215 OFF_2);
216 ZoneRules rules = ZoneRules.of(OFF_1, OFF_1,
217 Collections.singletonList(trans),
218 Collections.emptyList(), Collections.emptyList());
219
220 assertEquals(rules.getOffset(testDay), ZoneOffset.ofHours(offset));
221 assertEquals(rules.getStandardOffset(testDay), ZoneOffset.ofHours(stdOffset));
222 assertEquals(rules.getDaylightSavings(testDay), Duration.ofHours(savings));
223 assertEquals(rules.isDaylightSavings(testDay), isDST);
224 }
225
226 /**
227 * Tests whether isFixedOffset() is working correctly
228 * @bug 8239836
229 */
230 @Test(dataProvider="isFixedOffset")
231 public void test_IsFixedOffset(ZoneRules zr, boolean expected) {
232 assertEquals(zr.isFixedOffset(), expected);
233 }
234 }
|