]>
Commit | Line | Data |
---|---|---|
1 | /******************************************************************** | |
2 | * Copyright (c) 1997-2011, International Business Machines | |
3 | * Corporation and others. All Rights Reserved. | |
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 | // ***************************************************************************** | |
20 | /* length of an array */ | |
21 | #define ARRAY_LENGTH(array) (sizeof(array)/sizeof(array[0])) | |
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); | |
47 | CASE(17, Test4176686); | |
48 | CASE(18, Test4184229); | |
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; | |
130 | SimpleTimeZone *z = new SimpleTimeZone(0, "GMT"); | |
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 | dataerrln("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 | dataerrln("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 | */ | |
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); | |
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); | |
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); | |
237 | int32_t SToffset = (int32_t)(-8 * 60*60*1000L); | |
238 | int32_t DToffset = (int32_t)(-7 * 60*60*1000L); | |
239 | ||
240 | #define ERR_IF_FAIL(x) if(x) { dataerrln("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 | |
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 | dataerrln("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 | dataerrln("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, UCAL_APRIL, 5, 10, 0); | |
464 | ||
465 | if (! tz->useDaylightTime() || U_FAILURE(status)) | |
466 | dataerrln("We're not in Daylight Savings Time and we should be. - %s", u_errorName(status)); | |
467 | ||
468 | //cal.setTime(dt); | |
469 | int32_t era = cal->get(UCAL_ERA, status); | |
470 | int32_t year = cal->get(UCAL_YEAR, status); | |
471 | int32_t month = cal->get(UCAL_MONTH, status); | |
472 | int32_t day = cal->get(UCAL_DATE, status); | |
473 | int32_t dayOfWeek = cal->get(UCAL_DAY_OF_WEEK, status); | |
474 | int32_t millis = cal->get(UCAL_MILLISECOND, status) + | |
475 | (cal->get(UCAL_SECOND, status) + | |
476 | (cal->get(UCAL_MINUTE, status) + | |
477 | (cal->get(UCAL_HOUR, status) * 60) * 60) * 1000) - | |
478 | cal->get(UCAL_DST_OFFSET, status); | |
479 | ||
480 | failure(status, "cal->get"); | |
481 | int32_t offset = tz->getOffset((uint8_t)era, year, month, day, (uint8_t)dayOfWeek, millis, status); | |
482 | int32_t raw_offset = tz->getRawOffset(); | |
483 | ||
484 | if (offset == raw_offset) | |
485 | dataerrln("Offsets should match"); | |
486 | ||
487 | delete cal; | |
488 | } | |
489 | ||
490 | /** | |
491 | * @bug 4151406 | |
492 | * TimeZone::getAvailableIDs(int32_t) throws exception for certain values, | |
493 | * due to a faulty constant in TimeZone::java. | |
494 | */ | |
495 | void TimeZoneRegressionTest:: Test4151406() { | |
496 | int32_t max = 0; | |
497 | for (int32_t h=-28; h<=30; ++h) { | |
498 | // h is in half-hours from GMT; rawoffset is in millis | |
499 | int32_t rawoffset = h * 1800000; | |
500 | int32_t hh = (h<0) ? -h : h; | |
501 | UnicodeString hname = UnicodeString((h<0) ? "GMT-" : "GMT+") + | |
502 | ((hh/2 < 10) ? "0" : "") + | |
503 | (hh/2) + ':' + | |
504 | ((hh%2==0) ? "00" : "30"); | |
505 | //try { | |
506 | UErrorCode ec = U_ZERO_ERROR; | |
507 | int32_t count; | |
508 | StringEnumeration* ids = TimeZone::createEnumeration(rawoffset); | |
509 | if (ids == NULL) { | |
510 | dataerrln("Fail: TimeZone::createEnumeration(rawoffset)"); | |
511 | continue; | |
512 | } | |
513 | count = ids->count(ec); | |
514 | if (count> max) | |
515 | max = count; | |
516 | if (count > 0) { | |
517 | logln(hname + ' ' + (UnicodeString)count + (UnicodeString)" e.g. " + *ids->snext(ec)); | |
518 | } else { | |
519 | logln(hname + ' ' + count); | |
520 | } | |
521 | // weiv 11/27/2002: why uprv_free? This should be a delete | |
522 | delete ids; | |
523 | //delete [] ids; | |
524 | //uprv_free(ids); | |
525 | /*} catch (Exception e) { | |
526 | errln(hname + ' ' + "Fail: " + e); | |
527 | }*/ | |
528 | } | |
529 | logln("Maximum zones per offset = %d", max); | |
530 | } | |
531 | ||
532 | /** | |
533 | * @bug 4151429 | |
534 | */ | |
535 | void TimeZoneRegressionTest:: Test4151429() { | |
536 | // {sfb} silly test in C++, since we are using an enum and not an int | |
537 | //try { | |
538 | /*TimeZone *tz = TimeZone::createTimeZone("GMT"); | |
539 | UnicodeString name; | |
540 | tz->getDisplayName(TRUE, TimeZone::LONG, | |
541 | Locale.getDefault(), name); | |
542 | errln("IllegalArgumentException not thrown by TimeZone::getDisplayName()");*/ | |
543 | //} catch(IllegalArgumentException e) {} | |
544 | } | |
545 | ||
546 | /** | |
547 | * @bug 4154537 | |
548 | * SimpleTimeZone::hasSameRules() doesn't work for zones with no DST | |
549 | * and different DST parameters. | |
550 | */ | |
551 | void TimeZoneRegressionTest:: Test4154537() { | |
552 | UErrorCode status = U_ZERO_ERROR; | |
553 | // tz1 and tz2 have no DST and different rule parameters | |
554 | SimpleTimeZone *tz1 = new SimpleTimeZone(0, "1", 0, 0, 0, 0, 2, 0, 0, 0, status); | |
555 | SimpleTimeZone *tz2 = new SimpleTimeZone(0, "2", 1, 0, 0, 0, 3, 0, 0, 0, status); | |
556 | // tza and tzA have the same rule params | |
557 | SimpleTimeZone *tza = new SimpleTimeZone(0, "a", 0, 1, 0, 0, 3, 2, 0, 0, status); | |
558 | SimpleTimeZone *tzA = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 3, 2, 0, 0, status); | |
559 | // tzb differs from tza | |
560 | SimpleTimeZone *tzb = new SimpleTimeZone(0, "b", 0, 1, 0, 0, 3, 1, 0, 0, status); | |
561 | ||
562 | if(U_FAILURE(status)) | |
563 | errln("Couldn't create TimeZones"); | |
564 | ||
565 | if (tz1->useDaylightTime() || tz2->useDaylightTime() || | |
566 | !tza->useDaylightTime() || !tzA->useDaylightTime() || | |
567 | !tzb->useDaylightTime()) { | |
568 | errln("Test is broken -- rewrite it"); | |
569 | } | |
570 | if (!tza->hasSameRules(*tzA) || tza->hasSameRules(*tzb)) { | |
571 | errln("Fail: hasSameRules() broken for zones with rules"); | |
572 | } | |
573 | if (!tz1->hasSameRules(*tz2)) { | |
574 | errln("Fail: hasSameRules() returns false for zones without rules"); | |
575 | //errln("zone 1 = " + tz1); | |
576 | //errln("zone 2 = " + tz2); | |
577 | } | |
578 | ||
579 | delete tz1; | |
580 | delete tz2; | |
581 | delete tza; | |
582 | delete tzA; | |
583 | delete tzb; | |
584 | } | |
585 | ||
586 | /** | |
587 | * @bug 4154542 | |
588 | * SimpleTimeZOne constructors, setStartRule(), and setEndRule() don't | |
589 | * check for out-of-range arguments. | |
590 | */ | |
591 | void TimeZoneRegressionTest:: Test4154542() | |
592 | { | |
593 | const int32_t GOOD = 1; | |
594 | const int32_t BAD = 0; | |
595 | ||
596 | const int32_t GOOD_MONTH = UCAL_JANUARY; | |
597 | const int32_t GOOD_DAY = 1; | |
598 | const int32_t GOOD_DAY_OF_WEEK = UCAL_SUNDAY; | |
599 | const int32_t GOOD_TIME = 0; | |
600 | ||
601 | int32_t DATA [] = { | |
602 | GOOD, INT32_MIN, 0, INT32_MAX, INT32_MIN, | |
603 | GOOD, UCAL_JANUARY, -5, UCAL_SUNDAY, 0, | |
604 | GOOD, UCAL_DECEMBER, 5, UCAL_SATURDAY, 24*60*60*1000, | |
605 | BAD, UCAL_DECEMBER, 5, UCAL_SATURDAY, 24*60*60*1000+1, | |
606 | BAD, UCAL_DECEMBER, 5, UCAL_SATURDAY, -1, | |
607 | BAD, UCAL_JANUARY, -6, UCAL_SUNDAY, 0, | |
608 | BAD, UCAL_DECEMBER, 6, UCAL_SATURDAY, 24*60*60*1000, | |
609 | GOOD, UCAL_DECEMBER, 1, 0, 0, | |
610 | GOOD, UCAL_DECEMBER, 31, 0, 0, | |
611 | BAD, UCAL_APRIL, 31, 0, 0, | |
612 | BAD, UCAL_DECEMBER, 32, 0, 0, | |
613 | BAD, UCAL_JANUARY-1, 1, UCAL_SUNDAY, 0, | |
614 | BAD, UCAL_DECEMBER+1, 1, UCAL_SUNDAY, 0, | |
615 | GOOD, UCAL_DECEMBER, 31, -UCAL_SUNDAY, 0, | |
616 | GOOD, UCAL_DECEMBER, 31, -UCAL_SATURDAY, 0, | |
617 | BAD, UCAL_DECEMBER, 32, -UCAL_SATURDAY, 0, | |
618 | BAD, UCAL_DECEMBER, -32, -UCAL_SATURDAY, 0, | |
619 | BAD, UCAL_DECEMBER, 31, -UCAL_SATURDAY-1, 0, | |
620 | }; | |
621 | SimpleTimeZone *zone = new SimpleTimeZone(0, "Z"); | |
622 | for (int32_t i=0; i < 18*5; i+=5) { | |
623 | UBool shouldBeGood = (DATA[i] == GOOD); | |
624 | int32_t month = DATA[i+1]; | |
625 | int32_t day = DATA[i+2]; | |
626 | int32_t dayOfWeek = DATA[i+3]; | |
627 | int32_t time = DATA[i+4]; | |
628 | ||
629 | UErrorCode status = U_ZERO_ERROR; | |
630 | ||
631 | //Exception ex = null; | |
632 | //try { | |
633 | zone->setStartRule(month, day, dayOfWeek, time, status); | |
634 | //} catch (IllegalArgumentException e) { | |
635 | // ex = e; | |
636 | //} | |
637 | if (U_SUCCESS(status) != shouldBeGood) { | |
638 | errln(UnicodeString("setStartRule(month=") + month + ", day=" + day + | |
639 | ", dayOfWeek=" + dayOfWeek + ", time=" + time + | |
640 | (shouldBeGood ? (") should work") | |
641 | : ") should fail but doesn't")); | |
642 | } | |
643 | ||
644 | //ex = null; | |
645 | //try { | |
646 | status = U_ZERO_ERROR; | |
647 | zone->setEndRule(month, day, dayOfWeek, time, status); | |
648 | //} catch (IllegalArgumentException e) { | |
649 | // ex = e; | |
650 | //} | |
651 | if (U_SUCCESS(status) != shouldBeGood) { | |
652 | errln(UnicodeString("setEndRule(month=") + month + ", day=" + day + | |
653 | ", dayOfWeek=" + dayOfWeek + ", time=" + time + | |
654 | (shouldBeGood ? (") should work") | |
655 | : ") should fail but doesn't")); | |
656 | } | |
657 | ||
658 | //ex = null; | |
659 | //try { | |
660 | // {sfb} need to look into ctor problems! (UErrorCode vs. dst signature confusion) | |
661 | status = U_ZERO_ERROR; | |
662 | SimpleTimeZone *temp = new SimpleTimeZone(0, "Z", | |
663 | (int8_t)month, (int8_t)day, (int8_t)dayOfWeek, time, | |
664 | (int8_t)GOOD_MONTH, (int8_t)GOOD_DAY, (int8_t)GOOD_DAY_OF_WEEK, | |
665 | GOOD_TIME,status); | |
666 | //} catch (IllegalArgumentException e) { | |
667 | // ex = e; | |
668 | //} | |
669 | if (U_SUCCESS(status) != shouldBeGood) { | |
670 | errln(UnicodeString("SimpleTimeZone(month=") + month + ", day=" + day + | |
671 | ", dayOfWeek=" + dayOfWeek + ", time=" + time + | |
672 | (shouldBeGood ? (", <end>) should work")// + ex) | |
673 | : ", <end>) should fail but doesn't")); | |
674 | } | |
675 | ||
676 | delete temp; | |
677 | //ex = null; | |
678 | //try { | |
679 | status = U_ZERO_ERROR; | |
680 | temp = new SimpleTimeZone(0, "Z", | |
681 | (int8_t)GOOD_MONTH, (int8_t)GOOD_DAY, (int8_t)GOOD_DAY_OF_WEEK, | |
682 | GOOD_TIME, | |
683 | (int8_t)month, (int8_t)day, (int8_t)dayOfWeek, time,status); | |
684 | //} catch (IllegalArgumentException e) { | |
685 | // ex = e; | |
686 | //} | |
687 | if (U_SUCCESS(status) != shouldBeGood) { | |
688 | errln(UnicodeString("SimpleTimeZone(<start>, month=") + month + ", day=" + day + | |
689 | ", dayOfWeek=" + dayOfWeek + ", time=" + time + | |
690 | (shouldBeGood ? (") should work")// + ex) | |
691 | : ") should fail but doesn't")); | |
692 | } | |
693 | delete temp; | |
694 | } | |
695 | delete zone; | |
696 | } | |
697 | ||
698 | ||
699 | /** | |
700 | * @bug 4154525 | |
701 | * SimpleTimeZone accepts illegal DST savings values. These values | |
702 | * must be non-zero. There is no upper limit at this time. | |
703 | */ | |
704 | void | |
705 | TimeZoneRegressionTest::Test4154525() | |
706 | { | |
707 | const int32_t GOOD = 1, BAD = 0; | |
708 | ||
709 | int32_t DATA [] = { | |
710 | 1, GOOD, | |
711 | 0, BAD, | |
712 | -1, BAD, | |
713 | 60*60*1000, GOOD, | |
714 | INT32_MIN, BAD, | |
715 | // Integer.MAX_VALUE, ?, // no upper limit on DST savings at this time | |
716 | }; | |
717 | ||
718 | UErrorCode status = U_ZERO_ERROR; | |
719 | for(int32_t i = 0; i < 10; i+=2) { | |
720 | int32_t savings = DATA[i]; | |
721 | UBool valid = DATA[i+1] == GOOD; | |
722 | UnicodeString method; | |
723 | for(int32_t j=0; j < 2; ++j) { | |
724 | SimpleTimeZone *z=NULL; | |
725 | switch (j) { | |
726 | case 0: | |
727 | method = "constructor"; | |
728 | z = new SimpleTimeZone(0, "id", | |
729 | UCAL_JANUARY, 1, 0, 0, | |
730 | UCAL_MARCH, 1, 0, 0, | |
731 | savings, status); // <- what we're interested in | |
732 | break; | |
733 | case 1: | |
734 | method = "setDSTSavings()"; | |
735 | z = new SimpleTimeZone(0, "GMT"); | |
736 | z->setDSTSavings(savings, status); | |
737 | break; | |
738 | } | |
739 | ||
740 | if(U_FAILURE(status)) { | |
741 | if(valid) { | |
742 | errln(UnicodeString("Fail: DST savings of ") + savings + " to " + method + " gave " + u_errorName(status)); | |
743 | } | |
744 | else { | |
745 | logln(UnicodeString("Pass: DST savings of ") + savings + " to " + method + " gave " + u_errorName(status)); | |
746 | } | |
747 | } | |
748 | else { | |
749 | if(valid) { | |
750 | logln(UnicodeString("Pass: DST savings of ") + savings + " accepted by " + method); | |
751 | } | |
752 | else { | |
753 | errln(UnicodeString("Fail: DST savings of ") + savings + " accepted by " + method); | |
754 | } | |
755 | } | |
756 | status = U_ZERO_ERROR; | |
757 | delete z; | |
758 | } | |
759 | } | |
760 | } | |
761 | ||
762 | /** | |
763 | * @bug 4154650 | |
764 | * SimpleTimeZone.getOffset accepts illegal arguments. | |
765 | */ | |
766 | void | |
767 | TimeZoneRegressionTest::Test4154650() | |
768 | { | |
769 | const int32_t GOOD = 1, BAD = 0; | |
770 | const int32_t GOOD_ERA = GregorianCalendar::AD, GOOD_YEAR = 1998, GOOD_MONTH = UCAL_AUGUST; | |
771 | const int32_t GOOD_DAY = 2, GOOD_DOW = UCAL_SUNDAY, GOOD_TIME = 16*3600000; | |
772 | ||
773 | int32_t DATA []= { | |
774 | GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
775 | ||
776 | GOOD, GregorianCalendar::BC, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
777 | GOOD, GregorianCalendar::AD, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
778 | BAD, GregorianCalendar::BC-1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
779 | BAD, GregorianCalendar::AD+1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
780 | ||
781 | GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
782 | GOOD, GOOD_ERA, GOOD_YEAR, UCAL_DECEMBER, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
783 | BAD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY-1, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
784 | BAD, GOOD_ERA, GOOD_YEAR, UCAL_DECEMBER+1, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
785 | ||
786 | GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 1, GOOD_DOW, GOOD_TIME, | |
787 | GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 31, GOOD_DOW, GOOD_TIME, | |
788 | BAD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 0, GOOD_DOW, GOOD_TIME, | |
789 | BAD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 32, GOOD_DOW, GOOD_TIME, | |
790 | ||
791 | GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SUNDAY, GOOD_TIME, | |
792 | GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SATURDAY, GOOD_TIME, | |
793 | BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SUNDAY-1, GOOD_TIME, | |
794 | BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SATURDAY+1, GOOD_TIME, | |
795 | ||
796 | GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 0, | |
797 | GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000-1, | |
798 | BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, -1, | |
799 | BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000, | |
800 | }; | |
801 | ||
802 | int32_t dataLen = (int32_t)(sizeof(DATA) / sizeof(DATA[0])); | |
803 | ||
804 | UErrorCode status = U_ZERO_ERROR; | |
805 | TimeZone *tz = TimeZone::createDefault(); | |
806 | for(int32_t i = 0; i < dataLen; i += 7) { | |
807 | UBool good = DATA[i] == GOOD; | |
808 | //IllegalArgumentException e = null; | |
809 | //try { | |
810 | /*int32_t offset = */ | |
811 | tz->getOffset((uint8_t)DATA[i+1], DATA[i+2], DATA[i+3], | |
812 | DATA[i+4], (uint8_t)DATA[i+5], DATA[i+6], status); | |
813 | //} catch (IllegalArgumentException ex) { | |
814 | // e = ex; | |
815 | //} | |
816 | if(good != U_SUCCESS(status)) { | |
817 | UnicodeString errMsg; | |
818 | if (good) { | |
819 | errMsg = (UnicodeString(") threw ") + u_errorName(status)); | |
820 | } | |
821 | else { | |
822 | errMsg = UnicodeString(") accepts invalid args", ""); | |
823 | } | |
824 | errln(UnicodeString("Fail: getOffset(") + | |
825 | DATA[i+1] + ", " + DATA[i+2] + ", " + DATA[i+3] + ", " + | |
826 | DATA[i+4] + ", " + DATA[i+5] + ", " + DATA[i+6] + | |
827 | errMsg); | |
828 | } | |
829 | status = U_ZERO_ERROR; // reset | |
830 | } | |
831 | delete tz; | |
832 | } | |
833 | ||
834 | /** | |
835 | * @bug 4162593 | |
836 | * TimeZone broken at midnight. The TimeZone code fails to handle | |
837 | * transitions at midnight correctly. | |
838 | */ | |
839 | void | |
840 | TimeZoneRegressionTest::Test4162593() | |
841 | { | |
842 | UErrorCode status = U_ZERO_ERROR; | |
843 | SimpleDateFormat *fmt = new SimpleDateFormat("z", Locale::getUS(), status); | |
844 | if(U_FAILURE(status)) { | |
845 | dataerrln("Error creating calendar %s", u_errorName(status)); | |
846 | delete fmt; | |
847 | return; | |
848 | } | |
849 | const int32_t ONE_HOUR = 60*60*1000; | |
850 | ||
851 | SimpleTimeZone *asuncion = new SimpleTimeZone(-4*ONE_HOUR, "America/Asuncion" /*PY%sT*/, | |
852 | UCAL_OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR, | |
853 | UCAL_MARCH, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR, status); | |
854 | ||
855 | /* Zone | |
856 | * Starting time | |
857 | * Transition expected between start+1H and start+2H | |
858 | */ | |
859 | TimeZone *DATA_TZ [] = { | |
860 | 0, 0, 0 }; | |
861 | ||
862 | int32_t DATA_INT [] [5] = { | |
863 | // These years must be AFTER the Gregorian cutover | |
864 | {1998, UCAL_SEPTEMBER, 30, 22, 0}, | |
865 | {2000, UCAL_FEBRUARY, 28, 22, 0}, | |
866 | {2000, UCAL_FEBRUARY, 29, 22, 0}, | |
867 | }; | |
868 | ||
869 | UBool DATA_BOOL [] = { | |
870 | TRUE, | |
871 | FALSE, | |
872 | TRUE, | |
873 | }; | |
874 | ||
875 | UnicodeString zone [4];// = new String[4]; | |
876 | DATA_TZ[0] = | |
877 | new SimpleTimeZone(2*ONE_HOUR, "Asia/Damascus" /*EE%sT*/, | |
878 | UCAL_APRIL, 1, 0 /*DOM*/, 0*ONE_HOUR, | |
879 | UCAL_OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR, status); | |
880 | DATA_TZ[1] = asuncion; DATA_TZ[2] = asuncion; | |
881 | ||
882 | for(int32_t j = 0; j < 3; j++) { | |
883 | TimeZone *tz = (TimeZone*)DATA_TZ[j]; | |
884 | TimeZone::setDefault(*tz); | |
885 | fmt->setTimeZone(*tz); | |
886 | ||
887 | // Must construct the Date object AFTER setting the default zone | |
888 | int32_t *p = (int32_t*)DATA_INT[j]; | |
889 | UDate d = CalendarRegressionTest::makeDate(p[0], p[1], p[2], p[3], p[4]); | |
890 | UBool transitionExpected = DATA_BOOL[j]; | |
891 | ||
892 | UnicodeString temp; | |
893 | logln(tz->getID(temp) + ":"); | |
894 | for (int32_t i = 0; i < 4; ++i) { | |
895 | FieldPosition pos(0); | |
896 | zone[i].remove(); | |
897 | zone[i] = fmt->format(d+ i*ONE_HOUR, zone[i], pos); | |
898 | logln(UnicodeString("") + i + ": " + d + " / " + zone[i]); | |
899 | //d += (double) ONE_HOUR; | |
900 | } | |
901 | if(zone[0] == zone[1] && | |
902 | (zone[1] == zone[2]) != transitionExpected && | |
903 | zone[2] == zone[3]) { | |
904 | logln(UnicodeString("Ok: transition ") + transitionExpected); | |
905 | } | |
906 | else { | |
907 | errln("Fail: boundary transition incorrect"); | |
908 | } | |
909 | } | |
910 | delete fmt; | |
911 | delete asuncion; | |
912 | delete DATA_TZ[0]; | |
913 | } | |
914 | ||
915 | /** | |
916 | * getDisplayName doesn't work with unusual savings/offsets. | |
917 | */ | |
918 | void TimeZoneRegressionTest::Test4176686() { | |
919 | // Construct a zone that does not observe DST but | |
920 | // that does have a DST savings (which should be ignored). | |
921 | UErrorCode status = U_ZERO_ERROR; | |
922 | int32_t offset = 90 * 60000; // 1:30 | |
923 | SimpleTimeZone* z1 = new SimpleTimeZone(offset, "_std_zone_"); | |
924 | z1->setDSTSavings(45 * 60000, status); // 0:45 | |
925 | ||
926 | // Construct a zone that observes DST for the first 6 months. | |
927 | SimpleTimeZone* z2 = new SimpleTimeZone(offset, "_dst_zone_"); | |
928 | z2->setDSTSavings(45 * 60000, status); // 0:45 | |
929 | z2->setStartRule(UCAL_JANUARY, 1, 0, status); | |
930 | z2->setEndRule(UCAL_JULY, 1, 0, status); | |
931 | ||
932 | // Also check DateFormat | |
933 | DateFormat* fmt1 = new SimpleDateFormat(UnicodeString("z"), status); | |
934 | if (U_FAILURE(status)) { | |
935 | dataerrln("Failure trying to construct: %s", u_errorName(status)); | |
936 | return; | |
937 | } | |
938 | fmt1->setTimeZone(*z1); // Format uses standard zone | |
939 | DateFormat* fmt2 = new SimpleDateFormat(UnicodeString("z"), status); | |
940 | if(!assertSuccess("trying to construct", status))return; | |
941 | fmt2->setTimeZone(*z2); // Format uses DST zone | |
942 | Calendar* tempcal = Calendar::createInstance(status); | |
943 | tempcal->clear(); | |
944 | tempcal->set(1970, UCAL_FEBRUARY, 1); | |
945 | UDate dst = tempcal->getTime(status); // Time in DST | |
946 | tempcal->set(1970, UCAL_AUGUST, 1); | |
947 | UDate std = tempcal->getTime(status); // Time in standard | |
948 | ||
949 | // Description, Result, Expected Result | |
950 | UnicodeString a,b,c,d,e,f,g,h,i,j,k,l; | |
951 | UnicodeString DATA[] = { | |
952 | "z1->getDisplayName(false, SHORT)/std zone", | |
953 | z1->getDisplayName(FALSE, TimeZone::SHORT, a), "GMT+01:30", | |
954 | "z1->getDisplayName(false, LONG)/std zone", | |
955 | z1->getDisplayName(FALSE, TimeZone::LONG, b), "GMT+01:30", | |
956 | "z1->getDisplayName(true, SHORT)/std zone", | |
957 | z1->getDisplayName(TRUE, TimeZone::SHORT, c), "GMT+01:30", | |
958 | "z1->getDisplayName(true, LONG)/std zone", | |
959 | z1->getDisplayName(TRUE, TimeZone::LONG, d ), "GMT+01:30", | |
960 | "z2->getDisplayName(false, SHORT)/dst zone", | |
961 | z2->getDisplayName(FALSE, TimeZone::SHORT, e), "GMT+01:30", | |
962 | "z2->getDisplayName(false, LONG)/dst zone", | |
963 | z2->getDisplayName(FALSE, TimeZone::LONG, f ), "GMT+01:30", | |
964 | "z2->getDisplayName(true, SHORT)/dst zone", | |
965 | z2->getDisplayName(TRUE, TimeZone::SHORT, g), "GMT+02:15", | |
966 | "z2->getDisplayName(true, LONG)/dst zone", | |
967 | z2->getDisplayName(TRUE, TimeZone::LONG, h ), "GMT+02:15", | |
968 | "DateFormat.format(std)/std zone", fmt1->format(std, i), "GMT+01:30", | |
969 | "DateFormat.format(dst)/std zone", fmt1->format(dst, j), "GMT+01:30", | |
970 | "DateFormat.format(std)/dst zone", fmt2->format(std, k), "GMT+01:30", | |
971 | "DateFormat.format(dst)/dst zone", fmt2->format(dst, l), "GMT+02:15", | |
972 | }; | |
973 | ||
974 | for (int32_t idx=0; idx<(int32_t)ARRAY_LENGTH(DATA); idx+=3) { | |
975 | if (DATA[idx+1]!=(DATA[idx+2])) { | |
976 | errln("FAIL: " + DATA[idx] + " -> " + DATA[idx+1] + ", exp " + DATA[idx+2]); | |
977 | } | |
978 | } | |
979 | delete z1; | |
980 | delete z2; | |
981 | delete fmt1; | |
982 | delete fmt2; | |
983 | delete tempcal; | |
984 | } | |
985 | ||
986 | /** | |
987 | * Make sure setStartRule and setEndRule set the DST savings to nonzero | |
988 | * if it was zero. | |
989 | */ | |
990 | void TimeZoneRegressionTest::TestJ186() { | |
991 | UErrorCode status = U_ZERO_ERROR; | |
992 | // NOTE: Setting the DST savings to zero is illegal, so we | |
993 | // are limited in the testing we can do here. This is why | |
994 | // lines marked //~ are commented out. | |
995 | SimpleTimeZone z(0, "ID"); | |
996 | //~z.setDSTSavings(0, status); // Must do this! | |
997 | z.setStartRule(UCAL_FEBRUARY, 1, UCAL_SUNDAY, 0, status); | |
998 | failure(status, "setStartRule()"); | |
999 | if (z.useDaylightTime()) { | |
1000 | errln("Fail: useDaylightTime true with start rule only"); | |
1001 | } | |
1002 | //~if (z.getDSTSavings() != 0) { | |
1003 | //~ errln("Fail: dst savings != 0 with start rule only"); | |
1004 | //~} | |
1005 | z.setEndRule(UCAL_MARCH, -1, UCAL_SUNDAY, 0, status); | |
1006 | failure(status, "setStartRule()"); | |
1007 | if (!z.useDaylightTime()) { | |
1008 | errln("Fail: useDaylightTime false with rules set"); | |
1009 | } | |
1010 | if (z.getDSTSavings() == 0) { | |
1011 | errln("Fail: dst savings == 0 with rules set"); | |
1012 | } | |
1013 | } | |
1014 | ||
1015 | /** | |
1016 | * Test to see if DateFormat understands zone equivalency groups. It | |
1017 | * might seem that this should be a DateFormat test, but it's really a | |
1018 | * TimeZone test -- the changes to DateFormat are minor. | |
1019 | * | |
1020 | * We use two known, stable zones that shouldn't change much over time | |
1021 | * -- America/Vancouver and America/Los_Angeles. However, they MAY | |
1022 | * change at some point -- if that happens, replace them with any two | |
1023 | * zones in an equivalency group where one zone has localized name | |
1024 | * data, and the other doesn't, in some locale. | |
1025 | */ | |
1026 | void TimeZoneRegressionTest::TestJ449() { | |
1027 | UErrorCode status = U_ZERO_ERROR; | |
1028 | UnicodeString str; | |
1029 | ||
1030 | // Modify the following three as necessary. The two IDs must | |
1031 | // specify two zones in the same equivalency group. One must have | |
1032 | // locale data in 'loc'; the other must not. | |
1033 | const char* idWithLocaleData = "America/Los_Angeles"; | |
1034 | const char* idWithoutLocaleData = "US/Pacific"; | |
1035 | const Locale loc("en", "", ""); | |
1036 | ||
1037 | TimeZone *zoneWith = TimeZone::createTimeZone(idWithLocaleData); | |
1038 | TimeZone *zoneWithout = TimeZone::createTimeZone(idWithoutLocaleData); | |
1039 | // Make sure we got valid zones | |
1040 | if (zoneWith->getID(str) != UnicodeString(idWithLocaleData) || | |
1041 | zoneWithout->getID(str) != UnicodeString(idWithoutLocaleData)) { | |
1042 | dataerrln(UnicodeString("Fail: Unable to create zones - wanted ") + idWithLocaleData + ", got " + zoneWith->getID(str) + ", and wanted " + idWithoutLocaleData + " but got " + zoneWithout->getID(str)); | |
1043 | } else { | |
1044 | GregorianCalendar calWith(*zoneWith, status); | |
1045 | GregorianCalendar calWithout(*zoneWithout, status); | |
1046 | SimpleDateFormat fmt("MMM d yyyy hh:mm a zzz", loc, status); | |
1047 | if (U_FAILURE(status)) { | |
1048 | errln("Fail: Unable to create GregorianCalendar/SimpleDateFormat"); | |
1049 | } else { | |
1050 | UDate date = 0; | |
1051 | UnicodeString strWith, strWithout; | |
1052 | fmt.setCalendar(calWith); | |
1053 | fmt.format(date, strWith); | |
1054 | fmt.setCalendar(calWithout); | |
1055 | fmt.format(date, strWithout); | |
1056 | if (strWith == strWithout) { | |
1057 | logln((UnicodeString)"Ok: " + idWithLocaleData + " -> " + | |
1058 | strWith + "; " + idWithoutLocaleData + " -> " + | |
1059 | strWithout); | |
1060 | } else { | |
1061 | errln((UnicodeString)"FAIL: " + idWithLocaleData + " -> " + | |
1062 | strWith + "; " + idWithoutLocaleData + " -> " + | |
1063 | strWithout); | |
1064 | } | |
1065 | } | |
1066 | } | |
1067 | ||
1068 | delete zoneWith; | |
1069 | delete zoneWithout; | |
1070 | } | |
1071 | ||
1072 | // test new API for JDK 1.2 8/31 putback | |
1073 | void | |
1074 | TimeZoneRegressionTest::TestJDK12API() | |
1075 | { | |
1076 | // TimeZone *pst = TimeZone::createTimeZone("PST"); | |
1077 | // TimeZone *cst1 = TimeZone::createTimeZone("CST"); | |
1078 | UErrorCode ec = U_ZERO_ERROR; | |
1079 | //d,-28800,3,1,-1,120,w,9,-1,1,120,w,60 | |
1080 | TimeZone *pst = new SimpleTimeZone(-28800*U_MILLIS_PER_SECOND, | |
1081 | "PST", | |
1082 | 3,1,-1,120*U_MILLIS_PER_MINUTE, | |
1083 | SimpleTimeZone::WALL_TIME, | |
1084 | 9,-1,1,120*U_MILLIS_PER_MINUTE, | |
1085 | SimpleTimeZone::WALL_TIME, | |
1086 | 60*U_MILLIS_PER_MINUTE,ec); | |
1087 | //d,-21600,3,1,-1,120,w,9,-1,1,120,w,60 | |
1088 | TimeZone *cst1 = new SimpleTimeZone(-21600*U_MILLIS_PER_SECOND, | |
1089 | "CST", | |
1090 | 3,1,-1,120*U_MILLIS_PER_MINUTE, | |
1091 | SimpleTimeZone::WALL_TIME, | |
1092 | 9,-1,1,120*U_MILLIS_PER_MINUTE, | |
1093 | SimpleTimeZone::WALL_TIME, | |
1094 | 60*U_MILLIS_PER_MINUTE,ec); | |
1095 | if (U_FAILURE(ec)) { | |
1096 | errln("FAIL: SimpleTimeZone constructor"); | |
1097 | return; | |
1098 | } | |
1099 | ||
1100 | SimpleTimeZone *cst = dynamic_cast<SimpleTimeZone *>(cst1); | |
1101 | ||
1102 | if(pst->hasSameRules(*cst)) { | |
1103 | errln("FAILURE: PST and CST have same rules"); | |
1104 | } | |
1105 | ||
1106 | UErrorCode status = U_ZERO_ERROR; | |
1107 | int32_t offset1 = pst->getOffset(1, | |
1108 | 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), status); | |
1109 | failure(status, "getOffset() failed"); | |
1110 | ||
1111 | ||
1112 | int32_t offset2 = cst->getOffset(1, | |
1113 | 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), 31, status); | |
1114 | failure(status, "getOffset() failed"); | |
1115 | ||
1116 | if(offset1 == offset2) | |
1117 | errln("FAILURE: Sunday Oct. 26 1997 2:00 has same offset for PST and CST"); | |
1118 | ||
1119 | // verify error checking | |
1120 | pst->getOffset(1, | |
1121 | 1997, UCAL_FIELD_COUNT+1, 26, UCAL_SUNDAY, (2*60*60*1000), status); | |
1122 | if(U_SUCCESS(status)) | |
1123 | errln("FAILURE: getOffset() succeeded with -1 for month"); | |
1124 | ||
1125 | status = U_ZERO_ERROR; | |
1126 | cst->setDSTSavings(60*60*1000, status); | |
1127 | failure(status, "setDSTSavings() failed"); | |
1128 | ||
1129 | int32_t savings = cst->getDSTSavings(); | |
1130 | if(savings != 60*60*1000) { | |
1131 | errln("setDSTSavings() failed"); | |
1132 | } | |
1133 | ||
1134 | delete pst; | |
1135 | delete cst; | |
1136 | } | |
1137 | /** | |
1138 | * SimpleTimeZone allows invalid DOM values. | |
1139 | */ | |
1140 | void TimeZoneRegressionTest::Test4184229() { | |
1141 | SimpleTimeZone* zone = NULL; | |
1142 | UErrorCode status = U_ZERO_ERROR; | |
1143 | zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 0, status); | |
1144 | if(U_SUCCESS(status)){ | |
1145 | errln("Failed. No exception has been thrown for DOM -1 startDay"); | |
1146 | }else{ | |
1147 | logln("(a) " + UnicodeString( u_errorName(status))); | |
1148 | } | |
1149 | status = U_ZERO_ERROR; | |
1150 | delete zone; | |
1151 | ||
1152 | zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, status); | |
1153 | if(U_SUCCESS(status)){ | |
1154 | errln("Failed. No exception has been thrown for DOM -1 endDay"); | |
1155 | }else{ | |
1156 | logln("(b) " + UnicodeString(u_errorName(status))); | |
1157 | } | |
1158 | status = U_ZERO_ERROR; | |
1159 | delete zone; | |
1160 | ||
1161 | zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 1000, status); | |
1162 | if(U_SUCCESS(status)){ | |
1163 | errln("Failed. No exception has been thrown for DOM -1 startDay+savings"); | |
1164 | }else{ | |
1165 | logln("(c) " + UnicodeString(u_errorName(status))); | |
1166 | } | |
1167 | status = U_ZERO_ERROR; | |
1168 | delete zone; | |
1169 | zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, 1000, status); | |
1170 | if(U_SUCCESS(status)){ | |
1171 | errln("Failed. No exception has been thrown for DOM -1 endDay+ savings"); | |
1172 | }else{ | |
1173 | logln("(d) " + UnicodeString(u_errorName(status))); | |
1174 | } | |
1175 | status = U_ZERO_ERROR; | |
1176 | delete zone; | |
1177 | // Make a valid constructor call for subsequent tests. | |
1178 | zone = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 0, 1, 0, 0, status); | |
1179 | ||
1180 | zone->setStartRule(0, -1, 0, 0, status); | |
1181 | if(U_SUCCESS(status)){ | |
1182 | errln("Failed. No exception has been thrown for DOM -1 setStartRule +savings"); | |
1183 | } else{ | |
1184 | logln("(e) " + UnicodeString(u_errorName(status))); | |
1185 | } | |
1186 | zone->setStartRule(0, -1, 0, status); | |
1187 | if(U_SUCCESS(status)){ | |
1188 | errln("Failed. No exception has been thrown for DOM -1 setStartRule"); | |
1189 | } else{ | |
1190 | logln("(f) " + UnicodeString(u_errorName(status))); | |
1191 | } | |
1192 | ||
1193 | zone->setEndRule(0, -1, 0, 0, status); | |
1194 | if(U_SUCCESS(status)){ | |
1195 | errln("Failed. No exception has been thrown for DOM -1 setEndRule+savings"); | |
1196 | } else{ | |
1197 | logln("(g) " + UnicodeString(u_errorName(status))); | |
1198 | } | |
1199 | ||
1200 | zone->setEndRule(0, -1, 0, status); | |
1201 | if(U_SUCCESS(status)){ | |
1202 | errln("Failed. No exception has been thrown for DOM -1 setEndRule"); | |
1203 | } else{ | |
1204 | logln("(h) " + UnicodeString(u_errorName(status))); | |
1205 | } | |
1206 | delete zone; | |
1207 | } | |
1208 | ||
1209 | #endif /* #if !UCONFIG_NO_FORMATTING */ |