Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 1 | // © 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 | |
| 25 | void |
| 26 | TimeZoneRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) |
| 27 | { |
| 28 | // if (exec) logln((UnicodeString)"TestSuite NumberFormatRegressionTest"); |
| 29 | switch (index) { |
| 30 | |
| 31 | CASE(0, Test4052967); |
| 32 | CASE(1, Test4073209); |
| 33 | CASE(2, Test4073215); |
| 34 | CASE(3, Test4084933); |
| 35 | CASE(4, Test4096952); |
| 36 | CASE(5, Test4109314); |
| 37 | CASE(6, Test4126678); |
| 38 | CASE(7, Test4151406); |
| 39 | CASE(8, Test4151429); |
| 40 | CASE(9, Test4154537); |
| 41 | CASE(10, Test4154542); |
| 42 | CASE(11, Test4154650); |
| 43 | CASE(12, Test4154525); |
| 44 | CASE(13, Test4162593); |
| 45 | CASE(14, TestJ186); |
| 46 | CASE(15, TestJ449); |
| 47 | CASE(16, TestJDK12API); |
| 48 | CASE(17, Test4176686); |
| 49 | CASE(18, Test4184229); |
| 50 | CASE(19, TestNegativeDaylightSaving); |
| 51 | default: name = ""; break; |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | UBool |
| 56 | TimeZoneRegressionTest::failure(UErrorCode status, const char* msg) |
| 57 | { |
| 58 | if(U_FAILURE(status)) { |
| 59 | errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status)); |
Frank Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 60 | return true; |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 61 | } |
| 62 | |
Frank Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 63 | return false; |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 64 | } |
| 65 | |
| 66 | /** |
| 67 | * @bug 4052967 |
| 68 | */ |
| 69 | void TimeZoneRegressionTest:: Test4052967() { |
| 70 | // {sfb} not applicable in C++ ? |
| 71 | /*logln("*** CHECK TIMEZONE AGAINST HOST OS SETTING ***"); |
| 72 | logln("user.timezone:" + System.getProperty("user.timezone", "<not set>")); |
| 73 | logln(new Date().toString()); |
| 74 | logln("*** THE RESULTS OF THIS TEST MUST BE VERIFIED MANUALLY ***");*/ |
| 75 | } |
| 76 | |
| 77 | /** |
| 78 | * @bug 4073209 |
| 79 | */ |
| 80 | void TimeZoneRegressionTest:: Test4073209() { |
| 81 | TimeZone *z1 = TimeZone::createTimeZone("PST"); |
| 82 | TimeZone *z2 = TimeZone::createTimeZone("PST"); |
| 83 | if (z1 == z2) |
| 84 | errln("Fail: TimeZone should return clones"); |
| 85 | delete z1; |
| 86 | delete z2; |
| 87 | } |
| 88 | |
| 89 | UDate TimeZoneRegressionTest::findTransitionBinary(const SimpleTimeZone& tz, UDate min, UDate max) { |
| 90 | UErrorCode status = U_ZERO_ERROR; |
| 91 | UBool startsInDST = tz.inDaylightTime(min, status); |
| 92 | if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; |
| 93 | if (tz.inDaylightTime(max, status) == startsInDST) { |
Frank Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 94 | logln((UnicodeString)"Error: inDaylightTime() != " + ((!startsInDST)?"true":"false")); |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 95 | return 0; |
| 96 | } |
| 97 | if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; |
| 98 | while ((max - min) > 100) { // Min accuracy in ms |
| 99 | UDate mid = (min + max) / 2; |
| 100 | if (tz.inDaylightTime(mid, status) == startsInDST) { |
| 101 | min = mid; |
| 102 | } else { |
| 103 | max = mid; |
| 104 | } |
| 105 | if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; |
| 106 | } |
| 107 | return (min + max) / 2; |
| 108 | } |
| 109 | |
| 110 | UDate TimeZoneRegressionTest::findTransitionStepwise(const SimpleTimeZone& tz, UDate min, UDate max) { |
| 111 | UErrorCode status = U_ZERO_ERROR; |
| 112 | UBool startsInDST = tz.inDaylightTime(min, status); |
| 113 | if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; |
| 114 | while (min < max) { |
| 115 | if (tz.inDaylightTime(min, status) != startsInDST) { |
| 116 | return min; |
| 117 | } |
| 118 | if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; |
| 119 | min += (UDate)24*60*60*1000; // one day |
| 120 | } |
| 121 | return 0; |
| 122 | } |
| 123 | |
| 124 | /** |
| 125 | * @bug 4073215 |
| 126 | */ |
| 127 | // {sfb} will this work using a Calendar? |
| 128 | void TimeZoneRegressionTest:: Test4073215() |
| 129 | { |
| 130 | UErrorCode status = U_ZERO_ERROR; |
| 131 | UnicodeString str, str2; |
| 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 Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 169 | errln("Fail: Jan 31 inDaylightTime=true, exp false"); |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 170 | } |
| 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 Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 178 | errln((UnicodeString)"Fail: " + str + " inDaylightTime=false, exp true"); |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 179 | } |
| 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 Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 184 | errln("Fail: Mar 31 inDaylightTime=true, exp false"); |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 185 | } |
| 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 | */ |
| 215 | void 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 | */ |
| 270 | void TimeZoneRegressionTest:: Test4096952() { |
| 271 | // {sfb} serialization not applicable |
| 272 | /* |
| 273 | UnicodeString ZONES [] = { UnicodeString("GMT"), UnicodeString("MET"), UnicodeString("IST") }; |
Frank Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 274 | UBool pass = true; |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 275 | //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 | */ |
| 317 | void 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 Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 337 | UBool pass = true; |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 338 | 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 Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 346 | pass = false; |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 347 | 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 | |
| 357 | UBool |
| 358 | TimeZoneRegressionTest::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 | */ |
| 462 | void 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 | */ |
| 507 | void 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 | */ |
| 547 | void 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 Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 552 | tz->getDisplayName(true, TimeZone::LONG, |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 553 | 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 | */ |
| 563 | void 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 | */ |
| 599 | void 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 | */ |
| 725 | void |
| 726 | TimeZoneRegressionTest::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 | */ |
| 788 | void |
| 789 | TimeZoneRegressionTest::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 | */ |
| 861 | void |
| 862 | TimeZoneRegressionTest::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 | */ |
| 947 | void 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 Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 982 | z1.getDisplayName(false, TimeZone::SHORT, a), "GMT+1:30", |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 983 | "z1.getDisplayName(false, LONG)/std zone", |
Frank Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 984 | z1.getDisplayName(false, TimeZone::LONG, b), "GMT+01:30", |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 985 | "z1.getDisplayName(true, SHORT)/std zone", |
Frank Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 986 | z1.getDisplayName(true, TimeZone::SHORT, c), "GMT+1:30", |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 987 | "z1.getDisplayName(true, LONG)/std zone", |
Frank Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 988 | z1.getDisplayName(true, TimeZone::LONG, d ), "GMT+01:30", |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 989 | "z2.getDisplayName(false, SHORT)/dst zone", |
Frank Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 990 | z2.getDisplayName(false, TimeZone::SHORT, e), "GMT+1:30", |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 991 | "z2.getDisplayName(false, LONG)/dst zone", |
Frank Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 992 | z2.getDisplayName(false, TimeZone::LONG, f ), "GMT+01:30", |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 993 | "z2.getDisplayName(true, SHORT)/dst zone", |
Frank Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 994 | z2.getDisplayName(true, TimeZone::SHORT, g), "GMT+2:15", |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 995 | "z2.getDisplayName(true, LONG)/dst zone", |
Frank Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 996 | z2.getDisplayName(true, TimeZone::LONG, h ), "GMT+02:15", |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 997 | "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 | */ |
| 1014 | void 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 | */ |
| 1050 | void 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 |
| 1097 | void |
| 1098 | TimeZoneRegressionTest::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 | */ |
| 1161 | void 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 | |
| 1230 | void 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 Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 1260 | stzDublin.getOffset(testDate, false, rawOffset, dstOffset, status); |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 1261 | 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 Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 1277 | stzDublin.getOffset(testDate, false, rawOffset, dstOffset, status); |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 1278 | 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 */ |