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