]>
Commit | Line | Data |
---|---|---|
f3c0d7a5 A |
1 | // © 2016 and later: Unicode, Inc. and others. |
2 | // License & terms of use: http://www.unicode.org/copyright.html | |
b75a7d8f | 3 | /******************************************************************** |
2ca993e8 | 4 | * Copyright (c) 1997-2016, International Business Machines |
4162bf98 | 5 | * Corporation and others. All Rights Reserved. |
b75a7d8f A |
6 | ********************************************************************/ |
7 | ||
8 | #include "unicode/utypes.h" | |
9 | ||
10 | #if !UCONFIG_NO_FORMATTING | |
11 | ||
12 | #include "unicode/simpletz.h" | |
13 | #include "unicode/smpdtfmt.h" | |
14 | #include "unicode/strenum.h" | |
0f5d89e8 | 15 | #include "unicode/gregocal.h" |
b75a7d8f A |
16 | #include "tzregts.h" |
17 | #include "calregts.h" | |
18 | #include "cmemory.h" | |
19 | ||
20 | // ***************************************************************************** | |
21 | // class TimeZoneRegressionTest | |
22 | // ***************************************************************************** | |
b75a7d8f A |
23 | #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break |
24 | ||
25 | void | |
26 | TimeZoneRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) | |
27 | { | |
28 | // if (exec) logln((UnicodeString)"TestSuite NumberFormatRegressionTest"); | |
29 | switch (index) { | |
30 | ||
31 | CASE(0, Test4052967); | |
32 | CASE(1, Test4073209); | |
33 | CASE(2, Test4073215); | |
34 | CASE(3, Test4084933); | |
35 | CASE(4, Test4096952); | |
36 | CASE(5, Test4109314); | |
37 | CASE(6, Test4126678); | |
38 | CASE(7, Test4151406); | |
39 | CASE(8, Test4151429); | |
40 | CASE(9, Test4154537); | |
41 | CASE(10, Test4154542); | |
42 | CASE(11, Test4154650); | |
43 | CASE(12, Test4154525); | |
44 | CASE(13, Test4162593); | |
45 | CASE(14, TestJ186); | |
46 | CASE(15, TestJ449); | |
47 | CASE(16, TestJDK12API); | |
73c04bcf A |
48 | CASE(17, Test4176686); |
49 | CASE(18, Test4184229); | |
0f5d89e8 | 50 | CASE(19, TestNegativeDaylightSaving); |
b75a7d8f A |
51 | default: name = ""; break; |
52 | } | |
53 | } | |
54 | ||
55 | UBool | |
56 | TimeZoneRegressionTest::failure(UErrorCode status, const char* msg) | |
57 | { | |
58 | if(U_FAILURE(status)) { | |
59 | errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status)); | |
60 | return TRUE; | |
61 | } | |
62 | ||
63 | return FALSE; | |
64 | } | |
65 | ||
66 | /** | |
67 | * @bug 4052967 | |
68 | */ | |
69 | void TimeZoneRegressionTest:: Test4052967() { | |
70 | // {sfb} not applicable in C++ ? | |
71 | /*logln("*** CHECK TIMEZONE AGAINST HOST OS SETTING ***"); | |
72 | logln("user.timezone:" + System.getProperty("user.timezone", "<not set>")); | |
73 | logln(new Date().toString()); | |
74 | logln("*** THE RESULTS OF THIS TEST MUST BE VERIFIED MANUALLY ***");*/ | |
75 | } | |
76 | ||
77 | /** | |
78 | * @bug 4073209 | |
79 | */ | |
80 | void TimeZoneRegressionTest:: Test4073209() { | |
81 | TimeZone *z1 = TimeZone::createTimeZone("PST"); | |
82 | TimeZone *z2 = TimeZone::createTimeZone("PST"); | |
83 | if (z1 == z2) | |
84 | errln("Fail: TimeZone should return clones"); | |
85 | delete z1; | |
86 | delete z2; | |
87 | } | |
88 | ||
89 | UDate TimeZoneRegressionTest::findTransitionBinary(const SimpleTimeZone& tz, UDate min, UDate max) { | |
90 | UErrorCode status = U_ZERO_ERROR; | |
91 | UBool startsInDST = tz.inDaylightTime(min, status); | |
92 | if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; | |
93 | if (tz.inDaylightTime(max, status) == startsInDST) { | |
94 | logln((UnicodeString)"Error: inDaylightTime() != " + ((!startsInDST)?"TRUE":"FALSE")); | |
95 | return 0; | |
96 | } | |
97 | if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; | |
98 | while ((max - min) > 100) { // Min accuracy in ms | |
99 | UDate mid = (min + max) / 2; | |
100 | if (tz.inDaylightTime(mid, status) == startsInDST) { | |
101 | min = mid; | |
102 | } else { | |
103 | max = mid; | |
104 | } | |
105 | if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; | |
106 | } | |
107 | return (min + max) / 2; | |
108 | } | |
109 | ||
110 | UDate TimeZoneRegressionTest::findTransitionStepwise(const SimpleTimeZone& tz, UDate min, UDate max) { | |
111 | UErrorCode status = U_ZERO_ERROR; | |
112 | UBool startsInDST = tz.inDaylightTime(min, status); | |
113 | if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; | |
114 | while (min < max) { | |
115 | if (tz.inDaylightTime(min, status) != startsInDST) { | |
116 | return min; | |
117 | } | |
118 | if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; | |
119 | min += (UDate)24*60*60*1000; // one day | |
120 | } | |
121 | return 0; | |
122 | } | |
123 | ||
124 | /** | |
125 | * @bug 4073215 | |
126 | */ | |
127 | // {sfb} will this work using a Calendar? | |
128 | void TimeZoneRegressionTest:: Test4073215() | |
129 | { | |
130 | UErrorCode status = U_ZERO_ERROR; | |
131 | UnicodeString str, str2; | |
374ca955 | 132 | SimpleTimeZone *z = new SimpleTimeZone(0, "GMT"); |
b75a7d8f A |
133 | if (z->useDaylightTime()) |
134 | errln("Fail: Fix test to start with non-DST zone"); | |
135 | z->setStartRule(UCAL_FEBRUARY, 1, UCAL_SUNDAY, 0, status); | |
136 | failure(status, "z->setStartRule()"); | |
137 | z->setEndRule(UCAL_MARCH, -1, UCAL_SUNDAY, 0, status); | |
138 | failure(status, "z->setStartRule()"); | |
139 | if (!z->useDaylightTime()) | |
140 | errln("Fail: DST not active"); | |
141 | ||
142 | GregorianCalendar cal(1997, UCAL_JANUARY, 31, status); | |
143 | if(U_FAILURE(status)) { | |
729e4ab9 | 144 | dataerrln("Error creating calendar %s", u_errorName(status)); |
b75a7d8f A |
145 | return; |
146 | } | |
147 | failure(status, "new GregorianCalendar"); | |
148 | cal.adoptTimeZone(z); | |
149 | ||
150 | SimpleDateFormat sdf((UnicodeString)"E d MMM yyyy G HH:mm", status); | |
151 | if(U_FAILURE(status)) { | |
4388f060 | 152 | dataerrln("Error creating date format %s", u_errorName(status)); |
b75a7d8f A |
153 | return; |
154 | } | |
155 | sdf.setCalendar(cal); | |
156 | failure(status, "new SimpleDateFormat"); | |
157 | ||
158 | UDate jan31, mar1, mar31; | |
159 | ||
160 | UBool indt = z->inDaylightTime(jan31=cal.getTime(status), status); | |
161 | failure(status, "inDaylightTime or getTime call on Jan 31"); | |
162 | if (indt) { | |
163 | errln("Fail: Jan 31 inDaylightTime=TRUE, exp FALSE"); | |
164 | } | |
165 | cal.set(1997, UCAL_MARCH, 1); | |
166 | indt = z->inDaylightTime(mar1=cal.getTime(status), status); | |
167 | failure(status, "inDaylightTime or getTime call on Mar 1"); | |
168 | if (!indt) { | |
169 | UnicodeString str; | |
170 | sdf.format(cal.getTime(status), str); | |
171 | failure(status, "getTime"); | |
172 | errln((UnicodeString)"Fail: " + str + " inDaylightTime=FALSE, exp TRUE"); | |
173 | } | |
174 | cal.set(1997, UCAL_MARCH, 31); | |
175 | indt = z->inDaylightTime(mar31=cal.getTime(status), status); | |
176 | failure(status, "inDaylightTime or getTime call on Mar 31"); | |
177 | if (indt) { | |
178 | errln("Fail: Mar 31 inDaylightTime=TRUE, exp FALSE"); | |
179 | } | |
180 | ||
181 | /* | |
182 | cal.set(1997, Calendar::DECEMBER, 31); | |
183 | UDate dec31 = cal.getTime(status); | |
184 | failure(status, "getTime"); | |
185 | UDate trans = findTransitionStepwise(*z, jan31, dec31); | |
186 | logln((UnicodeString)"Stepwise from " + | |
187 | sdf.format(jan31, str.remove()) + "; transition at " + | |
188 | (trans?sdf.format(trans, str2.remove()):(UnicodeString)"NONE")); | |
189 | trans = findTransitionStepwise(*z, mar1, dec31); | |
190 | logln((UnicodeString)"Stepwise from " + | |
191 | sdf.format(mar1, str.remove()) + "; transition at " + | |
192 | (trans?sdf.format(trans, str2.remove()):(UnicodeString)"NONE")); | |
193 | trans = findTransitionStepwise(*z, mar31, dec31); | |
194 | logln((UnicodeString)"Stepwise from " + | |
195 | sdf.format(mar31, str.remove()) + "; transition at " + | |
196 | (trans?sdf.format(trans, str2.remove()):(UnicodeString)"NONE")); | |
197 | */ | |
198 | } | |
199 | ||
200 | /** | |
201 | * @bug 4084933 | |
202 | * The expected behavior of TimeZone around the boundaries is: | |
203 | * (Assume transition time of 2:00 AM) | |
204 | * day of onset 1:59 AM STD = display name 1:59 AM ST | |
205 | * 2:00 AM STD = display name 3:00 AM DT | |
206 | * day of end 0:59 AM STD = display name 1:59 AM DT | |
207 | * 1:00 AM STD = display name 1:00 AM ST | |
208 | */ | |
209 | void TimeZoneRegressionTest:: Test4084933() { | |
210 | UErrorCode status = U_ZERO_ERROR; | |
211 | TimeZone *tz = TimeZone::createTimeZone("PST"); | |
212 | ||
213 | int32_t offset1 = tz->getOffset(1, | |
214 | 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), status); | |
215 | int32_t offset2 = tz->getOffset(1, | |
216 | 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000)-1, status); | |
217 | ||
218 | int32_t offset3 = tz->getOffset(1, | |
219 | 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (1*60*60*1000), status); | |
220 | int32_t offset4 = tz->getOffset(1, | |
221 | 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (1*60*60*1000)-1, status); | |
222 | ||
223 | /* | |
224 | * The following was added just for consistency. It shows that going *to* Daylight | |
225 | * Savings Time (PDT) does work at 2am. | |
226 | */ | |
b75a7d8f A |
227 | int32_t offset5 = tz->getOffset(1, |
228 | 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (2*60*60*1000), status); | |
229 | int32_t offset6 = tz->getOffset(1, | |
230 | 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (2*60*60*1000)-1, status); | |
73c04bcf A |
231 | int32_t offset5a = tz->getOffset(1, |
232 | 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (3*60*60*1000), status); | |
233 | int32_t offset6a = tz->getOffset(1, | |
234 | 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (3*60*60*1000)-1, status); | |
b75a7d8f A |
235 | int32_t offset7 = tz->getOffset(1, |
236 | 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (1*60*60*1000), status); | |
237 | int32_t offset8 = tz->getOffset(1, | |
238 | 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (1*60*60*1000)-1, status); | |
b75a7d8f A |
239 | int32_t SToffset = (int32_t)(-8 * 60*60*1000L); |
240 | int32_t DToffset = (int32_t)(-7 * 60*60*1000L); | |
73c04bcf | 241 | |
729e4ab9 | 242 | #define ERR_IF_FAIL(x) if(x) { dataerrln("FAIL: TimeZone misbehaving - %s", #x); } |
73c04bcf A |
243 | |
244 | ERR_IF_FAIL(U_FAILURE(status)) | |
245 | ERR_IF_FAIL(offset1 != SToffset) | |
246 | ERR_IF_FAIL(offset2 != SToffset) | |
247 | ERR_IF_FAIL(offset3 != SToffset) | |
248 | ERR_IF_FAIL(offset4 != DToffset) | |
249 | ERR_IF_FAIL(offset5 != DToffset) | |
250 | ERR_IF_FAIL(offset6 != SToffset) | |
251 | ERR_IF_FAIL(offset5a != DToffset) | |
252 | ERR_IF_FAIL(offset6a != DToffset) | |
253 | ERR_IF_FAIL(offset7 != SToffset) | |
254 | ERR_IF_FAIL(offset8 != SToffset) | |
255 | ||
256 | #undef ERR_IF_FAIL | |
b75a7d8f A |
257 | |
258 | delete tz; | |
259 | } | |
260 | ||
261 | /** | |
262 | * @bug 4096952 | |
263 | */ | |
264 | void TimeZoneRegressionTest:: Test4096952() { | |
265 | // {sfb} serialization not applicable | |
266 | /* | |
267 | UnicodeString ZONES [] = { UnicodeString("GMT"), UnicodeString("MET"), UnicodeString("IST") }; | |
268 | UBool pass = TRUE; | |
269 | //try { | |
270 | for (int32_t i=0; i < ZONES.length; ++i) { | |
271 | TimeZone *zone = TimeZone::createTimeZone(ZONES[i]); | |
272 | UnicodeString id; | |
273 | if (zone->getID(id) != ZONES[i]) | |
274 | errln("Fail: Test broken; zones not instantiating"); | |
275 | ||
276 | ByteArrayOutputStream baos; | |
277 | ObjectOutputStream ostream = | |
278 | new ObjectOutputStream(baos = new | |
279 | ByteArrayOutputStream()); | |
280 | ostream.writeObject(zone); | |
281 | ostream.close(); | |
282 | baos.close(); | |
283 | ObjectInputStream istream = | |
284 | new ObjectInputStream(new | |
285 | ByteArrayInputStream(baos.toByteArray())); | |
286 | TimeZone frankenZone = (TimeZone) istream.readObject(); | |
287 | //logln("Zone: " + zone); | |
288 | //logln("FrankenZone: " + frankenZone); | |
289 | if (!zone.equals(frankenZone)) { | |
290 | logln("TimeZone " + zone.getID() + | |
291 | " not equal to serialized/deserialized one"); | |
292 | pass = false; | |
293 | } | |
294 | } | |
295 | if (!pass) errln("Fail: TimeZone serialization/equality bug"); | |
296 | } | |
297 | catch (IOException e) { | |
298 | errln("Fail: " + e); | |
299 | e.print32_tStackTrace(); | |
300 | } | |
301 | catch (ClassNotFoundException e) { | |
302 | errln("Fail: " + e); | |
303 | e.print32_tStackTrace(); | |
304 | } | |
305 | */ | |
306 | } | |
307 | ||
308 | /** | |
309 | * @bug 4109314 | |
310 | */ | |
311 | void TimeZoneRegressionTest:: Test4109314() { | |
312 | UErrorCode status = U_ZERO_ERROR; | |
313 | GregorianCalendar *testCal = (GregorianCalendar*)Calendar::createInstance(status); | |
314 | if(U_FAILURE(status)) { | |
729e4ab9 | 315 | dataerrln("Error creating calendar %s", u_errorName(status)); |
b75a7d8f A |
316 | delete testCal; |
317 | return; | |
318 | } | |
319 | failure(status, "Calendar::createInstance"); | |
320 | TimeZone *PST = TimeZone::createTimeZone("PST"); | |
321 | /*Object[] testData = { | |
322 | PST, new Date(98,Calendar.APRIL,4,22,0), new Date(98, Calendar.APRIL, 5,6,0), | |
323 | PST, new Date(98,Calendar.OCTOBER,24,22,0), new Date(98,Calendar.OCTOBER,25,6,0), | |
324 | };*/ | |
325 | UDate testData [] = { | |
326 | CalendarRegressionTest::makeDate(98,UCAL_APRIL,4,22,0), | |
327 | CalendarRegressionTest::makeDate(98, UCAL_APRIL,5,6,0), | |
328 | CalendarRegressionTest::makeDate(98,UCAL_OCTOBER,24,22,0), | |
329 | CalendarRegressionTest::makeDate(98,UCAL_OCTOBER,25,6,0) | |
330 | }; | |
331 | UBool pass = TRUE; | |
332 | for (int32_t i = 0; i < 4; i+=2) { | |
333 | //testCal->setTimeZone((TimeZone) testData[i]); | |
334 | testCal->setTimeZone(*PST); | |
335 | UDate t = testData[i]; | |
336 | UDate end = testData[i+1]; | |
337 | while(testCal->getTime(status) < end) { | |
338 | testCal->setTime(t, status); | |
339 | if ( ! checkCalendar314(testCal, PST)) | |
340 | pass = FALSE; | |
341 | t += 60*60*1000.0; | |
342 | } | |
343 | } | |
344 | if ( ! pass) | |
345 | errln("Fail: TZ API inconsistent"); | |
346 | ||
347 | delete testCal; | |
348 | delete PST; | |
349 | } | |
350 | ||
351 | UBool | |
352 | TimeZoneRegressionTest::checkCalendar314(GregorianCalendar *testCal, TimeZone *testTZ) | |
353 | { | |
354 | UErrorCode status = U_ZERO_ERROR; | |
355 | // GregorianCalendar testCal = (GregorianCalendar)aCal.clone(); | |
356 | ||
357 | int32_t tzOffset, tzRawOffset; | |
358 | float tzOffsetFloat,tzRawOffsetFloat; | |
359 | // Here is where the user made an error. They were passing in the value of | |
360 | // the MILLSECOND field; you need to pass in the millis in the day in STANDARD | |
361 | // time. | |
362 | UDate millis = testCal->get(UCAL_MILLISECOND, status) + | |
363 | 1000.0 * (testCal->get(UCAL_SECOND, status) + | |
364 | 60.0 * (testCal->get(UCAL_MINUTE, status) + | |
365 | 60.0 * (testCal->get(UCAL_HOUR_OF_DAY, status)))) - | |
366 | testCal->get(UCAL_DST_OFFSET, status); | |
367 | ||
368 | /* Fix up millis to be in range. ASSUME THAT WE ARE NOT AT THE | |
369 | * BEGINNING OR END OF A MONTH. We must add this code because | |
370 | * getOffset() has been changed to be more strict about the parameters | |
371 | * it receives -- it turns out that this test was passing in illegal | |
372 | * values. */ | |
373 | int32_t date = testCal->get(UCAL_DATE, status); | |
374 | int32_t dow = testCal->get(UCAL_DAY_OF_WEEK, status); | |
375 | while(millis < 0) { | |
376 | millis += U_MILLIS_PER_DAY; | |
377 | --date; | |
378 | dow = UCAL_SUNDAY + ((dow - UCAL_SUNDAY + 6) % 7); | |
379 | } | |
380 | while (millis >= U_MILLIS_PER_DAY) { | |
381 | millis -= U_MILLIS_PER_DAY; | |
382 | ++date; | |
383 | dow = UCAL_SUNDAY + ((dow - UCAL_SUNDAY + 1) % 7); | |
384 | } | |
385 | ||
386 | tzOffset = testTZ->getOffset((uint8_t)testCal->get(UCAL_ERA, status), | |
387 | testCal->get(UCAL_YEAR, status), | |
388 | testCal->get(UCAL_MONTH, status), | |
389 | date, | |
390 | (uint8_t)dow, | |
391 | (int32_t)millis, | |
392 | status); | |
393 | tzRawOffset = testTZ->getRawOffset(); | |
394 | tzOffsetFloat = (float)tzOffset/(float)3600000; | |
395 | tzRawOffsetFloat = (float)tzRawOffset/(float)3600000; | |
396 | ||
397 | UDate testDate = testCal->getTime(status); | |
398 | ||
399 | UBool inDaylightTime = testTZ->inDaylightTime(testDate, status); | |
400 | SimpleDateFormat *sdf = new SimpleDateFormat((UnicodeString)"MM/dd/yyyy HH:mm", status); | |
401 | sdf->setCalendar(*testCal); | |
402 | UnicodeString inDaylightTimeString; | |
403 | ||
404 | UBool passed; | |
405 | ||
406 | if(inDaylightTime) | |
407 | { | |
408 | inDaylightTimeString = " DST "; | |
409 | passed = (tzOffset == (tzRawOffset + 3600000)); | |
410 | } | |
411 | else | |
412 | { | |
413 | inDaylightTimeString = " "; | |
414 | passed = (tzOffset == tzRawOffset); | |
415 | } | |
416 | ||
417 | UnicodeString output; | |
f3c0d7a5 | 418 | FieldPosition pos(FieldPosition::DONT_CARE); |
b75a7d8f A |
419 | output = testTZ->getID(output) + " " + sdf->format(testDate, output, pos) + |
420 | " Offset(" + tzOffsetFloat + ")" + | |
421 | " RawOffset(" + tzRawOffsetFloat + ")" + | |
422 | " " + millis/(float)3600000 + " " + | |
423 | inDaylightTimeString; | |
424 | ||
425 | if (passed) | |
426 | output += " "; | |
427 | else | |
428 | output += "ERROR"; | |
429 | ||
430 | if (passed) | |
431 | logln(output); | |
432 | else | |
433 | errln(output); | |
434 | ||
435 | delete sdf; | |
436 | return passed; | |
437 | } | |
438 | ||
439 | /** | |
440 | * @bug 4126678 | |
441 | * CANNOT REPRODUDE | |
442 | * | |
443 | * Yet another _alleged_ bug in TimeZone::getOffset(), a method that never | |
444 | * should have been made public. It's simply too hard to use correctly. | |
445 | * | |
446 | * The original test code failed to do the following: | |
447 | * (1) Call Calendar::setTime() before getting the fields! | |
448 | * (2) Use the right millis (as usual) for getOffset(); they were passing | |
449 | * in the MILLIS field, instead of the STANDARD MILLIS IN DAY. | |
450 | * When you fix these two problems, the test passes, as expected. | |
451 | */ | |
452 | void TimeZoneRegressionTest:: Test4126678() | |
453 | { | |
454 | UErrorCode status = U_ZERO_ERROR; | |
455 | Calendar *cal = Calendar::createInstance(status); | |
456 | if(U_FAILURE(status)) { | |
729e4ab9 | 457 | dataerrln("Error creating calendar %s", u_errorName(status)); |
b75a7d8f A |
458 | delete cal; |
459 | return; | |
460 | } | |
461 | failure(status, "Calendar::createInstance"); | |
462 | TimeZone *tz = TimeZone::createTimeZone("PST"); | |
463 | cal->adoptTimeZone(tz); | |
464 | ||
729e4ab9 | 465 | cal->set(1998, UCAL_APRIL, 5, 10, 0); |
b75a7d8f A |
466 | |
467 | if (! tz->useDaylightTime() || U_FAILURE(status)) | |
729e4ab9 | 468 | dataerrln("We're not in Daylight Savings Time and we should be. - %s", u_errorName(status)); |
b75a7d8f A |
469 | |
470 | //cal.setTime(dt); | |
471 | int32_t era = cal->get(UCAL_ERA, status); | |
472 | int32_t year = cal->get(UCAL_YEAR, status); | |
473 | int32_t month = cal->get(UCAL_MONTH, status); | |
474 | int32_t day = cal->get(UCAL_DATE, status); | |
475 | int32_t dayOfWeek = cal->get(UCAL_DAY_OF_WEEK, status); | |
476 | int32_t millis = cal->get(UCAL_MILLISECOND, status) + | |
477 | (cal->get(UCAL_SECOND, status) + | |
478 | (cal->get(UCAL_MINUTE, status) + | |
479 | (cal->get(UCAL_HOUR, status) * 60) * 60) * 1000) - | |
480 | cal->get(UCAL_DST_OFFSET, status); | |
481 | ||
482 | failure(status, "cal->get"); | |
483 | int32_t offset = tz->getOffset((uint8_t)era, year, month, day, (uint8_t)dayOfWeek, millis, status); | |
484 | int32_t raw_offset = tz->getRawOffset(); | |
729e4ab9 | 485 | |
b75a7d8f | 486 | if (offset == raw_offset) |
4388f060 | 487 | dataerrln("Offsets should match"); |
b75a7d8f A |
488 | |
489 | delete cal; | |
490 | } | |
491 | ||
492 | /** | |
493 | * @bug 4151406 | |
494 | * TimeZone::getAvailableIDs(int32_t) throws exception for certain values, | |
495 | * due to a faulty constant in TimeZone::java. | |
496 | */ | |
497 | void TimeZoneRegressionTest:: Test4151406() { | |
498 | int32_t max = 0; | |
499 | for (int32_t h=-28; h<=30; ++h) { | |
500 | // h is in half-hours from GMT; rawoffset is in millis | |
501 | int32_t rawoffset = h * 1800000; | |
502 | int32_t hh = (h<0) ? -h : h; | |
374ca955 | 503 | UnicodeString hname = UnicodeString((h<0) ? "GMT-" : "GMT+") + |
b75a7d8f A |
504 | ((hh/2 < 10) ? "0" : "") + |
505 | (hh/2) + ':' + | |
506 | ((hh%2==0) ? "00" : "30"); | |
507 | //try { | |
508 | UErrorCode ec = U_ZERO_ERROR; | |
509 | int32_t count; | |
510 | StringEnumeration* ids = TimeZone::createEnumeration(rawoffset); | |
4388f060 A |
511 | if (ids == NULL) { |
512 | dataerrln("Fail: TimeZone::createEnumeration(rawoffset)"); | |
513 | continue; | |
514 | } | |
b75a7d8f A |
515 | count = ids->count(ec); |
516 | if (count> max) | |
517 | max = count; | |
374ca955 A |
518 | if (count > 0) { |
519 | logln(hname + ' ' + (UnicodeString)count + (UnicodeString)" e.g. " + *ids->snext(ec)); | |
520 | } else { | |
521 | logln(hname + ' ' + count); | |
522 | } | |
b75a7d8f A |
523 | // weiv 11/27/2002: why uprv_free? This should be a delete |
524 | delete ids; | |
525 | //delete [] ids; | |
526 | //uprv_free(ids); | |
527 | /*} catch (Exception e) { | |
528 | errln(hname + ' ' + "Fail: " + e); | |
529 | }*/ | |
530 | } | |
531 | logln("Maximum zones per offset = %d", max); | |
532 | } | |
533 | ||
534 | /** | |
535 | * @bug 4151429 | |
536 | */ | |
537 | void TimeZoneRegressionTest:: Test4151429() { | |
538 | // {sfb} silly test in C++, since we are using an enum and not an int | |
539 | //try { | |
540 | /*TimeZone *tz = TimeZone::createTimeZone("GMT"); | |
541 | UnicodeString name; | |
542 | tz->getDisplayName(TRUE, TimeZone::LONG, | |
543 | Locale.getDefault(), name); | |
544 | errln("IllegalArgumentException not thrown by TimeZone::getDisplayName()");*/ | |
545 | //} catch(IllegalArgumentException e) {} | |
546 | } | |
547 | ||
548 | /** | |
549 | * @bug 4154537 | |
550 | * SimpleTimeZone::hasSameRules() doesn't work for zones with no DST | |
551 | * and different DST parameters. | |
552 | */ | |
553 | void TimeZoneRegressionTest:: Test4154537() { | |
554 | UErrorCode status = U_ZERO_ERROR; | |
555 | // tz1 and tz2 have no DST and different rule parameters | |
556 | SimpleTimeZone *tz1 = new SimpleTimeZone(0, "1", 0, 0, 0, 0, 2, 0, 0, 0, status); | |
557 | SimpleTimeZone *tz2 = new SimpleTimeZone(0, "2", 1, 0, 0, 0, 3, 0, 0, 0, status); | |
558 | // tza and tzA have the same rule params | |
559 | SimpleTimeZone *tza = new SimpleTimeZone(0, "a", 0, 1, 0, 0, 3, 2, 0, 0, status); | |
560 | SimpleTimeZone *tzA = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 3, 2, 0, 0, status); | |
561 | // tzb differs from tza | |
562 | SimpleTimeZone *tzb = new SimpleTimeZone(0, "b", 0, 1, 0, 0, 3, 1, 0, 0, status); | |
563 | ||
564 | if(U_FAILURE(status)) | |
565 | errln("Couldn't create TimeZones"); | |
566 | ||
567 | if (tz1->useDaylightTime() || tz2->useDaylightTime() || | |
568 | !tza->useDaylightTime() || !tzA->useDaylightTime() || | |
569 | !tzb->useDaylightTime()) { | |
570 | errln("Test is broken -- rewrite it"); | |
571 | } | |
572 | if (!tza->hasSameRules(*tzA) || tza->hasSameRules(*tzb)) { | |
573 | errln("Fail: hasSameRules() broken for zones with rules"); | |
574 | } | |
575 | if (!tz1->hasSameRules(*tz2)) { | |
576 | errln("Fail: hasSameRules() returns false for zones without rules"); | |
577 | //errln("zone 1 = " + tz1); | |
578 | //errln("zone 2 = " + tz2); | |
579 | } | |
580 | ||
581 | delete tz1; | |
582 | delete tz2; | |
583 | delete tza; | |
584 | delete tzA; | |
585 | delete tzb; | |
586 | } | |
587 | ||
588 | /** | |
589 | * @bug 4154542 | |
590 | * SimpleTimeZOne constructors, setStartRule(), and setEndRule() don't | |
591 | * check for out-of-range arguments. | |
592 | */ | |
593 | void TimeZoneRegressionTest:: Test4154542() | |
594 | { | |
595 | const int32_t GOOD = 1; | |
596 | const int32_t BAD = 0; | |
597 | ||
598 | const int32_t GOOD_MONTH = UCAL_JANUARY; | |
599 | const int32_t GOOD_DAY = 1; | |
600 | const int32_t GOOD_DAY_OF_WEEK = UCAL_SUNDAY; | |
601 | const int32_t GOOD_TIME = 0; | |
602 | ||
603 | int32_t DATA [] = { | |
604 | GOOD, INT32_MIN, 0, INT32_MAX, INT32_MIN, | |
605 | GOOD, UCAL_JANUARY, -5, UCAL_SUNDAY, 0, | |
606 | GOOD, UCAL_DECEMBER, 5, UCAL_SATURDAY, 24*60*60*1000, | |
607 | BAD, UCAL_DECEMBER, 5, UCAL_SATURDAY, 24*60*60*1000+1, | |
608 | BAD, UCAL_DECEMBER, 5, UCAL_SATURDAY, -1, | |
609 | BAD, UCAL_JANUARY, -6, UCAL_SUNDAY, 0, | |
610 | BAD, UCAL_DECEMBER, 6, UCAL_SATURDAY, 24*60*60*1000, | |
611 | GOOD, UCAL_DECEMBER, 1, 0, 0, | |
612 | GOOD, UCAL_DECEMBER, 31, 0, 0, | |
613 | BAD, UCAL_APRIL, 31, 0, 0, | |
614 | BAD, UCAL_DECEMBER, 32, 0, 0, | |
615 | BAD, UCAL_JANUARY-1, 1, UCAL_SUNDAY, 0, | |
616 | BAD, UCAL_DECEMBER+1, 1, UCAL_SUNDAY, 0, | |
617 | GOOD, UCAL_DECEMBER, 31, -UCAL_SUNDAY, 0, | |
618 | GOOD, UCAL_DECEMBER, 31, -UCAL_SATURDAY, 0, | |
619 | BAD, UCAL_DECEMBER, 32, -UCAL_SATURDAY, 0, | |
620 | BAD, UCAL_DECEMBER, -32, -UCAL_SATURDAY, 0, | |
621 | BAD, UCAL_DECEMBER, 31, -UCAL_SATURDAY-1, 0, | |
622 | }; | |
623 | SimpleTimeZone *zone = new SimpleTimeZone(0, "Z"); | |
624 | for (int32_t i=0; i < 18*5; i+=5) { | |
625 | UBool shouldBeGood = (DATA[i] == GOOD); | |
626 | int32_t month = DATA[i+1]; | |
627 | int32_t day = DATA[i+2]; | |
628 | int32_t dayOfWeek = DATA[i+3]; | |
629 | int32_t time = DATA[i+4]; | |
630 | ||
631 | UErrorCode status = U_ZERO_ERROR; | |
632 | ||
633 | //Exception ex = null; | |
634 | //try { | |
635 | zone->setStartRule(month, day, dayOfWeek, time, status); | |
636 | //} catch (IllegalArgumentException e) { | |
637 | // ex = e; | |
638 | //} | |
639 | if (U_SUCCESS(status) != shouldBeGood) { | |
640 | errln(UnicodeString("setStartRule(month=") + month + ", day=" + day + | |
641 | ", dayOfWeek=" + dayOfWeek + ", time=" + time + | |
642 | (shouldBeGood ? (") should work") | |
643 | : ") should fail but doesn't")); | |
644 | } | |
645 | ||
646 | //ex = null; | |
647 | //try { | |
648 | status = U_ZERO_ERROR; | |
649 | zone->setEndRule(month, day, dayOfWeek, time, status); | |
650 | //} catch (IllegalArgumentException e) { | |
651 | // ex = e; | |
652 | //} | |
653 | if (U_SUCCESS(status) != shouldBeGood) { | |
654 | errln(UnicodeString("setEndRule(month=") + month + ", day=" + day + | |
655 | ", dayOfWeek=" + dayOfWeek + ", time=" + time + | |
656 | (shouldBeGood ? (") should work") | |
657 | : ") should fail but doesn't")); | |
658 | } | |
659 | ||
660 | //ex = null; | |
661 | //try { | |
662 | // {sfb} need to look into ctor problems! (UErrorCode vs. dst signature confusion) | |
663 | status = U_ZERO_ERROR; | |
664 | SimpleTimeZone *temp = new SimpleTimeZone(0, "Z", | |
665 | (int8_t)month, (int8_t)day, (int8_t)dayOfWeek, time, | |
666 | (int8_t)GOOD_MONTH, (int8_t)GOOD_DAY, (int8_t)GOOD_DAY_OF_WEEK, | |
667 | GOOD_TIME,status); | |
668 | //} catch (IllegalArgumentException e) { | |
669 | // ex = e; | |
670 | //} | |
671 | if (U_SUCCESS(status) != shouldBeGood) { | |
672 | errln(UnicodeString("SimpleTimeZone(month=") + month + ", day=" + day + | |
673 | ", dayOfWeek=" + dayOfWeek + ", time=" + time + | |
674 | (shouldBeGood ? (", <end>) should work")// + ex) | |
675 | : ", <end>) should fail but doesn't")); | |
676 | } | |
677 | ||
678 | delete temp; | |
679 | //ex = null; | |
680 | //try { | |
681 | status = U_ZERO_ERROR; | |
682 | temp = new SimpleTimeZone(0, "Z", | |
683 | (int8_t)GOOD_MONTH, (int8_t)GOOD_DAY, (int8_t)GOOD_DAY_OF_WEEK, | |
684 | GOOD_TIME, | |
685 | (int8_t)month, (int8_t)day, (int8_t)dayOfWeek, time,status); | |
686 | //} catch (IllegalArgumentException e) { | |
687 | // ex = e; | |
688 | //} | |
689 | if (U_SUCCESS(status) != shouldBeGood) { | |
690 | errln(UnicodeString("SimpleTimeZone(<start>, month=") + month + ", day=" + day + | |
691 | ", dayOfWeek=" + dayOfWeek + ", time=" + time + | |
692 | (shouldBeGood ? (") should work")// + ex) | |
693 | : ") should fail but doesn't")); | |
694 | } | |
695 | delete temp; | |
696 | } | |
697 | delete zone; | |
698 | } | |
699 | ||
700 | ||
701 | /** | |
702 | * @bug 4154525 | |
703 | * SimpleTimeZone accepts illegal DST savings values. These values | |
704 | * must be non-zero. There is no upper limit at this time. | |
705 | */ | |
706 | void | |
707 | TimeZoneRegressionTest::Test4154525() | |
708 | { | |
709 | const int32_t GOOD = 1, BAD = 0; | |
710 | ||
711 | int32_t DATA [] = { | |
712 | 1, GOOD, | |
713 | 0, BAD, | |
0f5d89e8 | 714 | -1, GOOD, // #13566 updates SimpleTimeZone to support negative DST saving amount |
b75a7d8f | 715 | 60*60*1000, GOOD, |
0f5d89e8 A |
716 | INT32_MAX, GOOD, // no upper limit on DST savings at this time |
717 | INT32_MIN, GOOD // no lower limit as well | |
b75a7d8f A |
718 | }; |
719 | ||
720 | UErrorCode status = U_ZERO_ERROR; | |
721 | for(int32_t i = 0; i < 10; i+=2) { | |
722 | int32_t savings = DATA[i]; | |
723 | UBool valid = DATA[i+1] == GOOD; | |
724 | UnicodeString method; | |
725 | for(int32_t j=0; j < 2; ++j) { | |
726 | SimpleTimeZone *z=NULL; | |
727 | switch (j) { | |
728 | case 0: | |
729 | method = "constructor"; | |
730 | z = new SimpleTimeZone(0, "id", | |
731 | UCAL_JANUARY, 1, 0, 0, | |
732 | UCAL_MARCH, 1, 0, 0, | |
733 | savings, status); // <- what we're interested in | |
734 | break; | |
735 | case 1: | |
736 | method = "setDSTSavings()"; | |
737 | z = new SimpleTimeZone(0, "GMT"); | |
738 | z->setDSTSavings(savings, status); | |
739 | break; | |
740 | } | |
741 | ||
742 | if(U_FAILURE(status)) { | |
743 | if(valid) { | |
744 | errln(UnicodeString("Fail: DST savings of ") + savings + " to " + method + " gave " + u_errorName(status)); | |
745 | } | |
746 | else { | |
747 | logln(UnicodeString("Pass: DST savings of ") + savings + " to " + method + " gave " + u_errorName(status)); | |
748 | } | |
749 | } | |
750 | else { | |
751 | if(valid) { | |
752 | logln(UnicodeString("Pass: DST savings of ") + savings + " accepted by " + method); | |
753 | } | |
754 | else { | |
755 | errln(UnicodeString("Fail: DST savings of ") + savings + " accepted by " + method); | |
756 | } | |
757 | } | |
758 | status = U_ZERO_ERROR; | |
759 | delete z; | |
760 | } | |
761 | } | |
762 | } | |
763 | ||
764 | /** | |
765 | * @bug 4154650 | |
766 | * SimpleTimeZone.getOffset accepts illegal arguments. | |
767 | */ | |
768 | void | |
769 | TimeZoneRegressionTest::Test4154650() | |
770 | { | |
771 | const int32_t GOOD = 1, BAD = 0; | |
772 | const int32_t GOOD_ERA = GregorianCalendar::AD, GOOD_YEAR = 1998, GOOD_MONTH = UCAL_AUGUST; | |
773 | const int32_t GOOD_DAY = 2, GOOD_DOW = UCAL_SUNDAY, GOOD_TIME = 16*3600000; | |
774 | ||
775 | int32_t DATA []= { | |
776 | GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
777 | ||
778 | GOOD, GregorianCalendar::BC, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
779 | GOOD, GregorianCalendar::AD, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
780 | BAD, GregorianCalendar::BC-1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
781 | BAD, GregorianCalendar::AD+1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
782 | ||
783 | GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
784 | GOOD, GOOD_ERA, GOOD_YEAR, UCAL_DECEMBER, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
785 | BAD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY-1, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
786 | BAD, GOOD_ERA, GOOD_YEAR, UCAL_DECEMBER+1, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
787 | ||
788 | GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 1, GOOD_DOW, GOOD_TIME, | |
789 | GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 31, GOOD_DOW, GOOD_TIME, | |
790 | BAD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 0, GOOD_DOW, GOOD_TIME, | |
791 | BAD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 32, GOOD_DOW, GOOD_TIME, | |
792 | ||
793 | GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SUNDAY, GOOD_TIME, | |
794 | GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SATURDAY, GOOD_TIME, | |
795 | BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SUNDAY-1, GOOD_TIME, | |
796 | BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SATURDAY+1, GOOD_TIME, | |
797 | ||
798 | GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 0, | |
799 | GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000-1, | |
800 | BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, -1, | |
801 | BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000, | |
802 | }; | |
803 | ||
2ca993e8 | 804 | int32_t dataLen = UPRV_LENGTHOF(DATA); |
b75a7d8f A |
805 | |
806 | UErrorCode status = U_ZERO_ERROR; | |
807 | TimeZone *tz = TimeZone::createDefault(); | |
808 | for(int32_t i = 0; i < dataLen; i += 7) { | |
809 | UBool good = DATA[i] == GOOD; | |
810 | //IllegalArgumentException e = null; | |
811 | //try { | |
812 | /*int32_t offset = */ | |
813 | tz->getOffset((uint8_t)DATA[i+1], DATA[i+2], DATA[i+3], | |
814 | DATA[i+4], (uint8_t)DATA[i+5], DATA[i+6], status); | |
815 | //} catch (IllegalArgumentException ex) { | |
816 | // e = ex; | |
817 | //} | |
818 | if(good != U_SUCCESS(status)) { | |
374ca955 A |
819 | UnicodeString errMsg; |
820 | if (good) { | |
821 | errMsg = (UnicodeString(") threw ") + u_errorName(status)); | |
822 | } | |
823 | else { | |
824 | errMsg = UnicodeString(") accepts invalid args", ""); | |
825 | } | |
b75a7d8f A |
826 | errln(UnicodeString("Fail: getOffset(") + |
827 | DATA[i+1] + ", " + DATA[i+2] + ", " + DATA[i+3] + ", " + | |
828 | DATA[i+4] + ", " + DATA[i+5] + ", " + DATA[i+6] + | |
374ca955 | 829 | errMsg); |
b75a7d8f A |
830 | } |
831 | status = U_ZERO_ERROR; // reset | |
832 | } | |
833 | delete tz; | |
834 | } | |
835 | ||
836 | /** | |
837 | * @bug 4162593 | |
838 | * TimeZone broken at midnight. The TimeZone code fails to handle | |
839 | * transitions at midnight correctly. | |
840 | */ | |
841 | void | |
842 | TimeZoneRegressionTest::Test4162593() | |
843 | { | |
844 | UErrorCode status = U_ZERO_ERROR; | |
845 | SimpleDateFormat *fmt = new SimpleDateFormat("z", Locale::getUS(), status); | |
846 | if(U_FAILURE(status)) { | |
729e4ab9 | 847 | dataerrln("Error creating calendar %s", u_errorName(status)); |
b75a7d8f A |
848 | delete fmt; |
849 | return; | |
850 | } | |
851 | const int32_t ONE_HOUR = 60*60*1000; | |
852 | ||
853 | SimpleTimeZone *asuncion = new SimpleTimeZone(-4*ONE_HOUR, "America/Asuncion" /*PY%sT*/, | |
854 | UCAL_OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR, | |
855 | UCAL_MARCH, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR, status); | |
856 | ||
857 | /* Zone | |
858 | * Starting time | |
859 | * Transition expected between start+1H and start+2H | |
860 | */ | |
861 | TimeZone *DATA_TZ [] = { | |
862 | 0, 0, 0 }; | |
863 | ||
864 | int32_t DATA_INT [] [5] = { | |
374ca955 A |
865 | // These years must be AFTER the Gregorian cutover |
866 | {1998, UCAL_SEPTEMBER, 30, 22, 0}, | |
867 | {2000, UCAL_FEBRUARY, 28, 22, 0}, | |
868 | {2000, UCAL_FEBRUARY, 29, 22, 0}, | |
b75a7d8f A |
869 | }; |
870 | ||
871 | UBool DATA_BOOL [] = { | |
872 | TRUE, | |
873 | FALSE, | |
874 | TRUE, | |
875 | }; | |
876 | ||
877 | UnicodeString zone [4];// = new String[4]; | |
878 | DATA_TZ[0] = | |
879 | new SimpleTimeZone(2*ONE_HOUR, "Asia/Damascus" /*EE%sT*/, | |
880 | UCAL_APRIL, 1, 0 /*DOM*/, 0*ONE_HOUR, | |
881 | UCAL_OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR, status); | |
882 | DATA_TZ[1] = asuncion; DATA_TZ[2] = asuncion; | |
883 | ||
884 | for(int32_t j = 0; j < 3; j++) { | |
885 | TimeZone *tz = (TimeZone*)DATA_TZ[j]; | |
886 | TimeZone::setDefault(*tz); | |
887 | fmt->setTimeZone(*tz); | |
888 | ||
889 | // Must construct the Date object AFTER setting the default zone | |
890 | int32_t *p = (int32_t*)DATA_INT[j]; | |
891 | UDate d = CalendarRegressionTest::makeDate(p[0], p[1], p[2], p[3], p[4]); | |
73c04bcf | 892 | UBool transitionExpected = DATA_BOOL[j]; |
b75a7d8f A |
893 | |
894 | UnicodeString temp; | |
895 | logln(tz->getID(temp) + ":"); | |
896 | for (int32_t i = 0; i < 4; ++i) { | |
f3c0d7a5 | 897 | FieldPosition pos(FieldPosition::DONT_CARE); |
b75a7d8f | 898 | zone[i].remove(); |
73c04bcf | 899 | zone[i] = fmt->format(d+ i*ONE_HOUR, zone[i], pos); |
b75a7d8f | 900 | logln(UnicodeString("") + i + ": " + d + " / " + zone[i]); |
73c04bcf | 901 | //d += (double) ONE_HOUR; |
b75a7d8f A |
902 | } |
903 | if(zone[0] == zone[1] && | |
904 | (zone[1] == zone[2]) != transitionExpected && | |
905 | zone[2] == zone[3]) { | |
906 | logln(UnicodeString("Ok: transition ") + transitionExpected); | |
907 | } | |
908 | else { | |
909 | errln("Fail: boundary transition incorrect"); | |
910 | } | |
911 | } | |
912 | delete fmt; | |
913 | delete asuncion; | |
914 | delete DATA_TZ[0]; | |
915 | } | |
916 | ||
73c04bcf A |
917 | /** |
918 | * getDisplayName doesn't work with unusual savings/offsets. | |
919 | */ | |
920 | void TimeZoneRegressionTest::Test4176686() { | |
921 | // Construct a zone that does not observe DST but | |
922 | // that does have a DST savings (which should be ignored). | |
923 | UErrorCode status = U_ZERO_ERROR; | |
924 | int32_t offset = 90 * 60000; // 1:30 | |
925 | SimpleTimeZone* z1 = new SimpleTimeZone(offset, "_std_zone_"); | |
926 | z1->setDSTSavings(45 * 60000, status); // 0:45 | |
927 | ||
928 | // Construct a zone that observes DST for the first 6 months. | |
929 | SimpleTimeZone* z2 = new SimpleTimeZone(offset, "_dst_zone_"); | |
930 | z2->setDSTSavings(45 * 60000, status); // 0:45 | |
931 | z2->setStartRule(UCAL_JANUARY, 1, 0, status); | |
932 | z2->setEndRule(UCAL_JULY, 1, 0, status); | |
933 | ||
934 | // Also check DateFormat | |
935 | DateFormat* fmt1 = new SimpleDateFormat(UnicodeString("z"), status); | |
729e4ab9 A |
936 | if (U_FAILURE(status)) { |
937 | dataerrln("Failure trying to construct: %s", u_errorName(status)); | |
938 | return; | |
939 | } | |
73c04bcf A |
940 | fmt1->setTimeZone(*z1); // Format uses standard zone |
941 | DateFormat* fmt2 = new SimpleDateFormat(UnicodeString("z"), status); | |
942 | if(!assertSuccess("trying to construct", status))return; | |
943 | fmt2->setTimeZone(*z2); // Format uses DST zone | |
944 | Calendar* tempcal = Calendar::createInstance(status); | |
945 | tempcal->clear(); | |
946 | tempcal->set(1970, UCAL_FEBRUARY, 1); | |
947 | UDate dst = tempcal->getTime(status); // Time in DST | |
948 | tempcal->set(1970, UCAL_AUGUST, 1); | |
949 | UDate std = tempcal->getTime(status); // Time in standard | |
950 | ||
951 | // Description, Result, Expected Result | |
952 | UnicodeString a,b,c,d,e,f,g,h,i,j,k,l; | |
953 | UnicodeString DATA[] = { | |
954 | "z1->getDisplayName(false, SHORT)/std zone", | |
51004dcb | 955 | z1->getDisplayName(FALSE, TimeZone::SHORT, a), "GMT+1:30", |
73c04bcf A |
956 | "z1->getDisplayName(false, LONG)/std zone", |
957 | z1->getDisplayName(FALSE, TimeZone::LONG, b), "GMT+01:30", | |
958 | "z1->getDisplayName(true, SHORT)/std zone", | |
51004dcb | 959 | z1->getDisplayName(TRUE, TimeZone::SHORT, c), "GMT+1:30", |
73c04bcf A |
960 | "z1->getDisplayName(true, LONG)/std zone", |
961 | z1->getDisplayName(TRUE, TimeZone::LONG, d ), "GMT+01:30", | |
962 | "z2->getDisplayName(false, SHORT)/dst zone", | |
51004dcb | 963 | z2->getDisplayName(FALSE, TimeZone::SHORT, e), "GMT+1:30", |
73c04bcf A |
964 | "z2->getDisplayName(false, LONG)/dst zone", |
965 | z2->getDisplayName(FALSE, TimeZone::LONG, f ), "GMT+01:30", | |
966 | "z2->getDisplayName(true, SHORT)/dst zone", | |
51004dcb | 967 | z2->getDisplayName(TRUE, TimeZone::SHORT, g), "GMT+2:15", |
73c04bcf A |
968 | "z2->getDisplayName(true, LONG)/dst zone", |
969 | z2->getDisplayName(TRUE, TimeZone::LONG, h ), "GMT+02:15", | |
51004dcb A |
970 | "DateFormat.format(std)/std zone", fmt1->format(std, i), "GMT+1:30", |
971 | "DateFormat.format(dst)/std zone", fmt1->format(dst, j), "GMT+1:30", | |
972 | "DateFormat.format(std)/dst zone", fmt2->format(std, k), "GMT+1:30", | |
973 | "DateFormat.format(dst)/dst zone", fmt2->format(dst, l), "GMT+2:15", | |
73c04bcf A |
974 | }; |
975 | ||
2ca993e8 | 976 | for (int32_t idx=0; idx<UPRV_LENGTHOF(DATA); idx+=3) { |
73c04bcf A |
977 | if (DATA[idx+1]!=(DATA[idx+2])) { |
978 | errln("FAIL: " + DATA[idx] + " -> " + DATA[idx+1] + ", exp " + DATA[idx+2]); | |
979 | } | |
980 | } | |
981 | delete z1; | |
982 | delete z2; | |
983 | delete fmt1; | |
984 | delete fmt2; | |
985 | delete tempcal; | |
986 | } | |
987 | ||
b75a7d8f A |
988 | /** |
989 | * Make sure setStartRule and setEndRule set the DST savings to nonzero | |
990 | * if it was zero. | |
991 | */ | |
992 | void TimeZoneRegressionTest::TestJ186() { | |
993 | UErrorCode status = U_ZERO_ERROR; | |
994 | // NOTE: Setting the DST savings to zero is illegal, so we | |
995 | // are limited in the testing we can do here. This is why | |
996 | // lines marked //~ are commented out. | |
997 | SimpleTimeZone z(0, "ID"); | |
998 | //~z.setDSTSavings(0, status); // Must do this! | |
999 | z.setStartRule(UCAL_FEBRUARY, 1, UCAL_SUNDAY, 0, status); | |
1000 | failure(status, "setStartRule()"); | |
1001 | if (z.useDaylightTime()) { | |
1002 | errln("Fail: useDaylightTime true with start rule only"); | |
1003 | } | |
1004 | //~if (z.getDSTSavings() != 0) { | |
1005 | //~ errln("Fail: dst savings != 0 with start rule only"); | |
1006 | //~} | |
1007 | z.setEndRule(UCAL_MARCH, -1, UCAL_SUNDAY, 0, status); | |
1008 | failure(status, "setStartRule()"); | |
1009 | if (!z.useDaylightTime()) { | |
1010 | errln("Fail: useDaylightTime false with rules set"); | |
1011 | } | |
1012 | if (z.getDSTSavings() == 0) { | |
1013 | errln("Fail: dst savings == 0 with rules set"); | |
1014 | } | |
1015 | } | |
1016 | ||
1017 | /** | |
1018 | * Test to see if DateFormat understands zone equivalency groups. It | |
1019 | * might seem that this should be a DateFormat test, but it's really a | |
1020 | * TimeZone test -- the changes to DateFormat are minor. | |
1021 | * | |
1022 | * We use two known, stable zones that shouldn't change much over time | |
1023 | * -- America/Vancouver and America/Los_Angeles. However, they MAY | |
1024 | * change at some point -- if that happens, replace them with any two | |
1025 | * zones in an equivalency group where one zone has localized name | |
1026 | * data, and the other doesn't, in some locale. | |
1027 | */ | |
1028 | void TimeZoneRegressionTest::TestJ449() { | |
1029 | UErrorCode status = U_ZERO_ERROR; | |
1030 | UnicodeString str; | |
1031 | ||
1032 | // Modify the following three as necessary. The two IDs must | |
1033 | // specify two zones in the same equivalency group. One must have | |
1034 | // locale data in 'loc'; the other must not. | |
1035 | const char* idWithLocaleData = "America/Los_Angeles"; | |
374ca955 | 1036 | const char* idWithoutLocaleData = "US/Pacific"; |
b75a7d8f A |
1037 | const Locale loc("en", "", ""); |
1038 | ||
1039 | TimeZone *zoneWith = TimeZone::createTimeZone(idWithLocaleData); | |
1040 | TimeZone *zoneWithout = TimeZone::createTimeZone(idWithoutLocaleData); | |
1041 | // Make sure we got valid zones | |
1042 | if (zoneWith->getID(str) != UnicodeString(idWithLocaleData) || | |
1043 | zoneWithout->getID(str) != UnicodeString(idWithoutLocaleData)) { | |
729e4ab9 | 1044 | dataerrln(UnicodeString("Fail: Unable to create zones - wanted ") + idWithLocaleData + ", got " + zoneWith->getID(str) + ", and wanted " + idWithoutLocaleData + " but got " + zoneWithout->getID(str)); |
b75a7d8f A |
1045 | } else { |
1046 | GregorianCalendar calWith(*zoneWith, status); | |
1047 | GregorianCalendar calWithout(*zoneWithout, status); | |
1048 | SimpleDateFormat fmt("MMM d yyyy hh:mm a zzz", loc, status); | |
1049 | if (U_FAILURE(status)) { | |
1050 | errln("Fail: Unable to create GregorianCalendar/SimpleDateFormat"); | |
1051 | } else { | |
1052 | UDate date = 0; | |
1053 | UnicodeString strWith, strWithout; | |
1054 | fmt.setCalendar(calWith); | |
1055 | fmt.format(date, strWith); | |
1056 | fmt.setCalendar(calWithout); | |
1057 | fmt.format(date, strWithout); | |
1058 | if (strWith == strWithout) { | |
1059 | logln((UnicodeString)"Ok: " + idWithLocaleData + " -> " + | |
1060 | strWith + "; " + idWithoutLocaleData + " -> " + | |
1061 | strWithout); | |
1062 | } else { | |
1063 | errln((UnicodeString)"FAIL: " + idWithLocaleData + " -> " + | |
1064 | strWith + "; " + idWithoutLocaleData + " -> " + | |
1065 | strWithout); | |
1066 | } | |
1067 | } | |
1068 | } | |
1069 | ||
1070 | delete zoneWith; | |
1071 | delete zoneWithout; | |
1072 | } | |
1073 | ||
1074 | // test new API for JDK 1.2 8/31 putback | |
1075 | void | |
1076 | TimeZoneRegressionTest::TestJDK12API() | |
1077 | { | |
374ca955 A |
1078 | // TimeZone *pst = TimeZone::createTimeZone("PST"); |
1079 | // TimeZone *cst1 = TimeZone::createTimeZone("CST"); | |
1080 | UErrorCode ec = U_ZERO_ERROR; | |
1081 | //d,-28800,3,1,-1,120,w,9,-1,1,120,w,60 | |
1082 | TimeZone *pst = new SimpleTimeZone(-28800*U_MILLIS_PER_SECOND, | |
1083 | "PST", | |
1084 | 3,1,-1,120*U_MILLIS_PER_MINUTE, | |
1085 | SimpleTimeZone::WALL_TIME, | |
1086 | 9,-1,1,120*U_MILLIS_PER_MINUTE, | |
1087 | SimpleTimeZone::WALL_TIME, | |
1088 | 60*U_MILLIS_PER_MINUTE,ec); | |
1089 | //d,-21600,3,1,-1,120,w,9,-1,1,120,w,60 | |
1090 | TimeZone *cst1 = new SimpleTimeZone(-21600*U_MILLIS_PER_SECOND, | |
1091 | "CST", | |
1092 | 3,1,-1,120*U_MILLIS_PER_MINUTE, | |
1093 | SimpleTimeZone::WALL_TIME, | |
1094 | 9,-1,1,120*U_MILLIS_PER_MINUTE, | |
1095 | SimpleTimeZone::WALL_TIME, | |
1096 | 60*U_MILLIS_PER_MINUTE,ec); | |
1097 | if (U_FAILURE(ec)) { | |
1098 | errln("FAIL: SimpleTimeZone constructor"); | |
1099 | return; | |
1100 | } | |
b75a7d8f | 1101 | |
729e4ab9 | 1102 | SimpleTimeZone *cst = dynamic_cast<SimpleTimeZone *>(cst1); |
b75a7d8f A |
1103 | |
1104 | if(pst->hasSameRules(*cst)) { | |
1105 | errln("FAILURE: PST and CST have same rules"); | |
1106 | } | |
1107 | ||
1108 | UErrorCode status = U_ZERO_ERROR; | |
1109 | int32_t offset1 = pst->getOffset(1, | |
1110 | 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), status); | |
1111 | failure(status, "getOffset() failed"); | |
1112 | ||
1113 | ||
1114 | int32_t offset2 = cst->getOffset(1, | |
1115 | 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), 31, status); | |
1116 | failure(status, "getOffset() failed"); | |
1117 | ||
1118 | if(offset1 == offset2) | |
1119 | errln("FAILURE: Sunday Oct. 26 1997 2:00 has same offset for PST and CST"); | |
1120 | ||
1121 | // verify error checking | |
1122 | pst->getOffset(1, | |
73c04bcf | 1123 | 1997, UCAL_FIELD_COUNT+1, 26, UCAL_SUNDAY, (2*60*60*1000), status); |
b75a7d8f A |
1124 | if(U_SUCCESS(status)) |
1125 | errln("FAILURE: getOffset() succeeded with -1 for month"); | |
1126 | ||
1127 | status = U_ZERO_ERROR; | |
1128 | cst->setDSTSavings(60*60*1000, status); | |
1129 | failure(status, "setDSTSavings() failed"); | |
1130 | ||
1131 | int32_t savings = cst->getDSTSavings(); | |
1132 | if(savings != 60*60*1000) { | |
1133 | errln("setDSTSavings() failed"); | |
1134 | } | |
1135 | ||
1136 | delete pst; | |
1137 | delete cst; | |
1138 | } | |
73c04bcf A |
1139 | /** |
1140 | * SimpleTimeZone allows invalid DOM values. | |
1141 | */ | |
1142 | void TimeZoneRegressionTest::Test4184229() { | |
1143 | SimpleTimeZone* zone = NULL; | |
1144 | UErrorCode status = U_ZERO_ERROR; | |
1145 | zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 0, status); | |
1146 | if(U_SUCCESS(status)){ | |
1147 | errln("Failed. No exception has been thrown for DOM -1 startDay"); | |
1148 | }else{ | |
1149 | logln("(a) " + UnicodeString( u_errorName(status))); | |
1150 | } | |
1151 | status = U_ZERO_ERROR; | |
1152 | delete zone; | |
1153 | ||
1154 | zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, status); | |
1155 | if(U_SUCCESS(status)){ | |
1156 | errln("Failed. No exception has been thrown for DOM -1 endDay"); | |
1157 | }else{ | |
1158 | logln("(b) " + UnicodeString(u_errorName(status))); | |
1159 | } | |
1160 | status = U_ZERO_ERROR; | |
1161 | delete zone; | |
1162 | ||
1163 | zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 1000, status); | |
1164 | if(U_SUCCESS(status)){ | |
1165 | errln("Failed. No exception has been thrown for DOM -1 startDay+savings"); | |
1166 | }else{ | |
1167 | logln("(c) " + UnicodeString(u_errorName(status))); | |
1168 | } | |
1169 | status = U_ZERO_ERROR; | |
1170 | delete zone; | |
1171 | zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, 1000, status); | |
1172 | if(U_SUCCESS(status)){ | |
1173 | errln("Failed. No exception has been thrown for DOM -1 endDay+ savings"); | |
1174 | }else{ | |
1175 | logln("(d) " + UnicodeString(u_errorName(status))); | |
1176 | } | |
1177 | status = U_ZERO_ERROR; | |
1178 | delete zone; | |
1179 | // Make a valid constructor call for subsequent tests. | |
1180 | zone = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 0, 1, 0, 0, status); | |
1181 | ||
1182 | zone->setStartRule(0, -1, 0, 0, status); | |
1183 | if(U_SUCCESS(status)){ | |
1184 | errln("Failed. No exception has been thrown for DOM -1 setStartRule +savings"); | |
1185 | } else{ | |
1186 | logln("(e) " + UnicodeString(u_errorName(status))); | |
1187 | } | |
1188 | zone->setStartRule(0, -1, 0, status); | |
1189 | if(U_SUCCESS(status)){ | |
1190 | errln("Failed. No exception has been thrown for DOM -1 setStartRule"); | |
1191 | } else{ | |
1192 | logln("(f) " + UnicodeString(u_errorName(status))); | |
1193 | } | |
1194 | ||
1195 | zone->setEndRule(0, -1, 0, 0, status); | |
1196 | if(U_SUCCESS(status)){ | |
1197 | errln("Failed. No exception has been thrown for DOM -1 setEndRule+savings"); | |
1198 | } else{ | |
1199 | logln("(g) " + UnicodeString(u_errorName(status))); | |
1200 | } | |
1201 | ||
1202 | zone->setEndRule(0, -1, 0, status); | |
1203 | if(U_SUCCESS(status)){ | |
1204 | errln("Failed. No exception has been thrown for DOM -1 setEndRule"); | |
1205 | } else{ | |
1206 | logln("(h) " + UnicodeString(u_errorName(status))); | |
1207 | } | |
1208 | delete zone; | |
1209 | } | |
b75a7d8f | 1210 | |
0f5d89e8 A |
1211 | void TimeZoneRegressionTest::TestNegativeDaylightSaving() { |
1212 | UErrorCode status = U_ZERO_ERROR; | |
1213 | int32_t stdOff = 1 * 60*60*1000; // Standard offset UTC+1 | |
1214 | int save = -1 * 60*60*1000; // DST saving amount -1 hour | |
1215 | SimpleTimeZone stzDublin(stdOff, "Dublin-2018", | |
1216 | UCAL_OCTOBER, -1, -UCAL_SUNDAY, 2*60*60*1000, | |
1217 | UCAL_MARCH, -1, -UCAL_SUNDAY, 1*60*60*1000, | |
1218 | save, status); | |
1219 | failure(status, "SimpleTimeZone constructor"); | |
1220 | ||
1221 | if (save != stzDublin.getDSTSavings()) { | |
1222 | errln((UnicodeString)"FAIL: DST saving is not " + save); | |
1223 | } | |
1224 | ||
1225 | GregorianCalendar cal(* TimeZone::getGMT(), status); | |
1226 | failure(status, "GregorianCalendar constructor"); | |
1227 | ||
1228 | UDate testDate; | |
1229 | int32_t rawOffset; | |
1230 | int32_t dstOffset; | |
1231 | ||
1232 | cal.set(2018, UCAL_JANUARY, 15, 0, 0, 0); | |
1233 | testDate = cal.getTime(status); | |
1234 | failure(status, "calendar getTime() - Jan 15"); | |
1235 | ||
1236 | if (!stzDublin.inDaylightTime(testDate, status)) { | |
1237 | errln("FAIL: The test date (Jan 15) must be in DST."); | |
1238 | } | |
1239 | failure(status, "inDaylightTime() - Jan 15"); | |
1240 | ||
1241 | stzDublin.getOffset(testDate, FALSE, rawOffset, dstOffset, status); | |
1242 | failure(status, "getOffset() - Jan 15"); | |
1243 | if (rawOffset != stdOff || dstOffset != save) { | |
1244 | errln((UnicodeString)"FAIL: Expected [stdoff=" + stdOff + ",save=" + save | |
1245 | + "] on the test date (Jan 15), actual[stdoff=" + rawOffset | |
1246 | + ",save=" + dstOffset + "]"); | |
1247 | } | |
1248 | ||
1249 | cal.set(2018, UCAL_JULY, 15, 0, 0, 0); | |
1250 | testDate = cal.getTime(status); | |
1251 | failure(status, "calendar getTime() - Jul 15"); | |
1252 | ||
1253 | if (stzDublin.inDaylightTime(testDate, status)) { | |
1254 | errln("FAIL: The test date (Jul 15) must be in DST."); | |
1255 | } | |
1256 | failure(status, "inDaylightTime() - Jul 15"); | |
1257 | ||
1258 | stzDublin.getOffset(testDate, FALSE, rawOffset, dstOffset, status); | |
1259 | failure(status, "getOffset() - Jul 15"); | |
1260 | if (rawOffset != stdOff || dstOffset != 0) { | |
1261 | errln((UnicodeString)"FAIL: Expected [stdoff=" + stdOff + ",save=" + 0 | |
1262 | + "] on the test date (Jul 15), actual[stdoff=" + rawOffset | |
1263 | + ",save=" + dstOffset + "]"); | |
1264 | } | |
1265 | } | |
1266 | ||
1267 | ||
b75a7d8f | 1268 | #endif /* #if !UCONFIG_NO_FORMATTING */ |