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