| 1 | // © 2016 and later: Unicode, Inc. and others. | 
| 2 | // License & terms of use: http://www.unicode.org/copyright.html | 
| 3 | /* | 
| 4 | ******************************************************************************* | 
| 5 | * Copyright (C) 2007-2013, International Business Machines Corporation and | 
| 6 | * others. All Rights Reserved. | 
| 7 | ******************************************************************************* | 
| 8 | */ | 
| 9 |  | 
| 10 | #include "unicode/utypes.h" | 
| 11 |  | 
| 12 | #if !UCONFIG_NO_FORMATTING | 
| 13 |  | 
| 14 | #include "unicode/basictz.h" | 
| 15 | #include "gregoimp.h" | 
| 16 | #include "uvector.h" | 
| 17 | #include "cmemory.h" | 
| 18 |  | 
| 19 | U_NAMESPACE_BEGIN | 
| 20 |  | 
| 21 | #define MILLIS_PER_YEAR (365*24*60*60*1000.0) | 
| 22 |  | 
| 23 | BasicTimeZone::BasicTimeZone() | 
| 24 | : TimeZone() { | 
| 25 | } | 
| 26 |  | 
| 27 | BasicTimeZone::BasicTimeZone(const UnicodeString &id) | 
| 28 | : TimeZone(id) { | 
| 29 | } | 
| 30 |  | 
| 31 | BasicTimeZone::BasicTimeZone(const BasicTimeZone& source) | 
| 32 | : TimeZone(source) { | 
| 33 | } | 
| 34 |  | 
| 35 | BasicTimeZone::~BasicTimeZone() { | 
| 36 | } | 
| 37 |  | 
| 38 | UBool | 
| 39 | BasicTimeZone::hasEquivalentTransitions(const BasicTimeZone& tz, UDate start, UDate end, | 
| 40 |                                         UBool ignoreDstAmount, UErrorCode& status) const { | 
| 41 |     if (U_FAILURE(status)) { | 
| 42 |         return FALSE; | 
| 43 |     } | 
| 44 |     if (hasSameRules(tz)) { | 
| 45 |         return TRUE; | 
| 46 |     } | 
| 47 |     // Check the offsets at the start time | 
| 48 |     int32_t raw1, raw2, dst1, dst2; | 
| 49 |     getOffset(start, FALSE, raw1, dst1, status); | 
| 50 |     if (U_FAILURE(status)) { | 
| 51 |         return FALSE; | 
| 52 |     } | 
| 53 |     tz.getOffset(start, FALSE, raw2, dst2, status); | 
| 54 |     if (U_FAILURE(status)) { | 
| 55 |         return FALSE; | 
| 56 |     } | 
| 57 |     if (ignoreDstAmount) { | 
| 58 |         if ((raw1 + dst1 != raw2 + dst2) | 
| 59 |             || (dst1 != 0 && dst2 == 0) | 
| 60 |             || (dst1 == 0 && dst2 != 0)) { | 
| 61 |             return FALSE; | 
| 62 |         } | 
| 63 |     } else { | 
| 64 |         if (raw1 != raw2 || dst1 != dst2) { | 
| 65 |             return FALSE; | 
| 66 |         }             | 
| 67 |     } | 
| 68 |     // Check transitions in the range | 
| 69 |     UDate time = start; | 
| 70 |     TimeZoneTransition tr1, tr2; | 
| 71 |     while (TRUE) { | 
| 72 |         UBool avail1 = getNextTransition(time, FALSE, tr1); | 
| 73 |         UBool avail2 = tz.getNextTransition(time, FALSE, tr2); | 
| 74 |  | 
| 75 |         if (ignoreDstAmount) { | 
| 76 |             // Skip a transition which only differ the amount of DST savings | 
| 77 |             while (TRUE) { | 
| 78 |                 if (avail1 | 
| 79 |                         && tr1.getTime() <= end | 
| 80 |                         && (tr1.getFrom()->getRawOffset() + tr1.getFrom()->getDSTSavings() | 
| 81 |                                 == tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings()) | 
| 82 |                         && (tr1.getFrom()->getDSTSavings() != 0 && tr1.getTo()->getDSTSavings() != 0)) { | 
| 83 |                     getNextTransition(tr1.getTime(), FALSE, tr1); | 
| 84 |                 } else { | 
| 85 |                     break; | 
| 86 |                 } | 
| 87 |             } | 
| 88 |             while (TRUE) { | 
| 89 |                 if (avail2 | 
| 90 |                         && tr2.getTime() <= end | 
| 91 |                         && (tr2.getFrom()->getRawOffset() + tr2.getFrom()->getDSTSavings() | 
| 92 |                                 == tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings()) | 
| 93 |                         && (tr2.getFrom()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() != 0)) { | 
| 94 |                     tz.getNextTransition(tr2.getTime(), FALSE, tr2); | 
| 95 |                 } else { | 
| 96 |                     break; | 
| 97 |                 } | 
| 98 |             } | 
| 99 |         } | 
| 100 |  | 
| 101 |         UBool inRange1 = (avail1 && tr1.getTime() <= end); | 
| 102 |         UBool inRange2 = (avail2 && tr2.getTime() <= end); | 
| 103 |         if (!inRange1 && !inRange2) { | 
| 104 |             // No more transition in the range | 
| 105 |             break; | 
| 106 |         } | 
| 107 |         if (!inRange1 || !inRange2) { | 
| 108 |             return FALSE; | 
| 109 |         } | 
| 110 |         if (tr1.getTime() != tr2.getTime()) { | 
| 111 |             return FALSE; | 
| 112 |         } | 
| 113 |         if (ignoreDstAmount) { | 
| 114 |             if (tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings() | 
| 115 |                         != tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings() | 
| 116 |                     || (tr1.getTo()->getDSTSavings() != 0 &&  tr2.getTo()->getDSTSavings() == 0) | 
| 117 |                     || (tr1.getTo()->getDSTSavings() == 0 &&  tr2.getTo()->getDSTSavings() != 0)) { | 
| 118 |                 return FALSE; | 
| 119 |             } | 
| 120 |         } else { | 
| 121 |             if (tr1.getTo()->getRawOffset() != tr2.getTo()->getRawOffset() || | 
| 122 |                 tr1.getTo()->getDSTSavings() != tr2.getTo()->getDSTSavings()) { | 
| 123 |                 return FALSE; | 
| 124 |             } | 
| 125 |         } | 
| 126 |         time = tr1.getTime(); | 
| 127 |     } | 
| 128 |     return TRUE; | 
| 129 | } | 
| 130 |  | 
| 131 | void | 
| 132 | BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial, | 
| 133 |         AnnualTimeZoneRule*& std, AnnualTimeZoneRule*& dst, UErrorCode& status) const { | 
| 134 |     initial = NULL; | 
| 135 |     std = NULL; | 
| 136 |     dst = NULL; | 
| 137 |     if (U_FAILURE(status)) { | 
| 138 |         return; | 
| 139 |     } | 
| 140 |     int32_t initialRaw, initialDst; | 
| 141 |     UnicodeString initialName; | 
| 142 |  | 
| 143 |     AnnualTimeZoneRule *ar1 = NULL; | 
| 144 |     AnnualTimeZoneRule *ar2 = NULL; | 
| 145 |     UnicodeString name; | 
| 146 |  | 
| 147 |     UBool avail; | 
| 148 |     TimeZoneTransition tr; | 
| 149 |     // Get the next transition | 
| 150 |     avail = getNextTransition(date, FALSE, tr); | 
| 151 |     if (avail) { | 
| 152 |         tr.getFrom()->getName(initialName); | 
| 153 |         initialRaw = tr.getFrom()->getRawOffset(); | 
| 154 |         initialDst = tr.getFrom()->getDSTSavings(); | 
| 155 |  | 
| 156 |         // Check if the next transition is either DST->STD or STD->DST and | 
| 157 |         // within roughly 1 year from the specified date | 
| 158 |         UDate nextTransitionTime = tr.getTime(); | 
| 159 |         if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0) | 
| 160 |               || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) | 
| 161 |             && (date + MILLIS_PER_YEAR > nextTransitionTime)) { | 
| 162 |   | 
| 163 |             int32_t year, month, dom, dow, doy, mid; | 
| 164 |             UDate d; | 
| 165 |  | 
| 166 |             // Get local wall time for the next transition time | 
| 167 |             Grego::timeToFields(nextTransitionTime + initialRaw + initialDst, | 
| 168 |                 year, month, dom, dow, doy, mid); | 
| 169 |             int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom); | 
| 170 |             // Create DOW rule | 
| 171 |             DateTimeRule *dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME); | 
| 172 |             tr.getTo()->getName(name); | 
| 173 |  | 
| 174 |             // Note:  SimpleTimeZone does not support raw offset change. | 
| 175 |             // So we always use raw offset of the given time for the rule, | 
| 176 |             // even raw offset is changed.  This will result that the result | 
| 177 |             // zone to return wrong offset after the transition. | 
| 178 |             // When we encounter such case, we do not inspect next next | 
| 179 |             // transition for another rule. | 
| 180 |             ar1 = new AnnualTimeZoneRule(name, initialRaw, tr.getTo()->getDSTSavings(), | 
| 181 |                 dtr, year, AnnualTimeZoneRule::MAX_YEAR); | 
| 182 |  | 
| 183 |             if (tr.getTo()->getRawOffset() == initialRaw) { | 
| 184 |                 // Get the next next transition | 
| 185 |                 avail = getNextTransition(nextTransitionTime, FALSE, tr); | 
| 186 |                 if (avail) { | 
| 187 |                     // Check if the next next transition is either DST->STD or STD->DST | 
| 188 |                     // and within roughly 1 year from the next transition | 
| 189 |                     if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0) | 
| 190 |                           || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) | 
| 191 |                          && nextTransitionTime + MILLIS_PER_YEAR > tr.getTime()) { | 
| 192 |  | 
| 193 |                         // Get local wall time for the next transition time | 
| 194 |                         Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(), | 
| 195 |                             year, month, dom, dow, doy, mid); | 
| 196 |                         weekInMonth = Grego::dayOfWeekInMonth(year, month, dom); | 
| 197 |                         // Generate another DOW rule | 
| 198 |                         dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME); | 
| 199 |                         tr.getTo()->getName(name); | 
| 200 |                         ar2 = new AnnualTimeZoneRule(name, tr.getTo()->getRawOffset(), tr.getTo()->getDSTSavings(), | 
| 201 |                             dtr, year - 1, AnnualTimeZoneRule::MAX_YEAR); | 
| 202 |  | 
| 203 |                         // Make sure this rule can be applied to the specified date | 
| 204 |                         avail = ar2->getPreviousStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), TRUE, d); | 
| 205 |                         if (!avail || d > date | 
| 206 |                                 || initialRaw != tr.getTo()->getRawOffset() | 
| 207 |                                 || initialDst != tr.getTo()->getDSTSavings()) { | 
| 208 |                             // We cannot use this rule as the second transition rule | 
| 209 |                             delete ar2; | 
| 210 |                             ar2 = NULL; | 
| 211 |                         } | 
| 212 |                     } | 
| 213 |                 } | 
| 214 |             } | 
| 215 |             if (ar2 == NULL) { | 
| 216 |                 // Try previous transition | 
| 217 |                 avail = getPreviousTransition(date, TRUE, tr); | 
| 218 |                 if (avail) { | 
| 219 |                     // Check if the previous transition is either DST->STD or STD->DST. | 
| 220 |                     // The actual transition time does not matter here. | 
| 221 |                     if ((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0) | 
| 222 |                         || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) { | 
| 223 |  | 
| 224 |                         // Generate another DOW rule | 
| 225 |                         Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(), | 
| 226 |                             year, month, dom, dow, doy, mid); | 
| 227 |                         weekInMonth = Grego::dayOfWeekInMonth(year, month, dom); | 
| 228 |                         dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME); | 
| 229 |                         tr.getTo()->getName(name); | 
| 230 |  | 
| 231 |                         // second rule raw/dst offsets should match raw/dst offsets | 
| 232 |                         // at the given time | 
| 233 |                         ar2 = new AnnualTimeZoneRule(name, initialRaw, initialDst, | 
| 234 |                             dtr, ar1->getStartYear() - 1, AnnualTimeZoneRule::MAX_YEAR); | 
| 235 |  | 
| 236 |                         // Check if this rule start after the first rule after the specified date | 
| 237 |                         avail = ar2->getNextStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), FALSE, d); | 
| 238 |                         if (!avail || d <= nextTransitionTime) { | 
| 239 |                             // We cannot use this rule as the second transition rule | 
| 240 |                             delete ar2; | 
| 241 |                             ar2 = NULL; | 
| 242 |                         } | 
| 243 |                     } | 
| 244 |                 } | 
| 245 |             } | 
| 246 |             if (ar2 == NULL) { | 
| 247 |                 // Cannot find a good pair of AnnualTimeZoneRule | 
| 248 |                 delete ar1; | 
| 249 |                 ar1 = NULL; | 
| 250 |             } else { | 
| 251 |                 // The initial rule should represent the rule before the previous transition | 
| 252 |                 ar1->getName(initialName); | 
| 253 |                 initialRaw = ar1->getRawOffset(); | 
| 254 |                 initialDst = ar1->getDSTSavings(); | 
| 255 |             } | 
| 256 |         } | 
| 257 |     } | 
| 258 |     else { | 
| 259 |         // Try the previous one | 
| 260 |         avail = getPreviousTransition(date, TRUE, tr); | 
| 261 |         if (avail) { | 
| 262 |             tr.getTo()->getName(initialName); | 
| 263 |             initialRaw = tr.getTo()->getRawOffset(); | 
| 264 |             initialDst = tr.getTo()->getDSTSavings(); | 
| 265 |         } else { | 
| 266 |             // No transitions in the past.  Just use the current offsets | 
| 267 |             getOffset(date, FALSE, initialRaw, initialDst, status); | 
| 268 |             if (U_FAILURE(status)) { | 
| 269 |                 return; | 
| 270 |             } | 
| 271 |         } | 
| 272 |     } | 
| 273 |     // Set the initial rule | 
| 274 |     initial = new InitialTimeZoneRule(initialName, initialRaw, initialDst); | 
| 275 |  | 
| 276 |     // Set the standard and daylight saving rules | 
| 277 |     if (ar1 != NULL && ar2 != NULL) { | 
| 278 |         if (ar1->getDSTSavings() != 0) { | 
| 279 |             dst = ar1; | 
| 280 |             std = ar2; | 
| 281 |         } else { | 
| 282 |             std = ar1; | 
| 283 |             dst = ar2; | 
| 284 |         } | 
| 285 |     } | 
| 286 | } | 
| 287 |  | 
| 288 | void | 
| 289 | BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial, | 
| 290 |                                      UVector*& transitionRules, UErrorCode& status) const { | 
| 291 |     if (U_FAILURE(status)) { | 
| 292 |         return; | 
| 293 |     } | 
| 294 |  | 
| 295 |     const InitialTimeZoneRule *orgini; | 
| 296 |     const TimeZoneRule **orgtrs = NULL; | 
| 297 |     TimeZoneTransition tzt; | 
| 298 |     UBool avail; | 
| 299 |     UVector *orgRules = NULL; | 
| 300 |     int32_t ruleCount; | 
| 301 |     TimeZoneRule *r = NULL; | 
| 302 |     UBool *done = NULL; | 
| 303 |     InitialTimeZoneRule *res_initial = NULL; | 
| 304 |     UVector *filteredRules = NULL; | 
| 305 |     UnicodeString name; | 
| 306 |     int32_t i; | 
| 307 |     UDate time, t; | 
| 308 |     UDate *newTimes = NULL; | 
| 309 |     UDate firstStart; | 
| 310 |     UBool bFinalStd = FALSE, bFinalDst = FALSE; | 
| 311 |  | 
| 312 |     // Original transition rules | 
| 313 |     ruleCount = countTransitionRules(status); | 
| 314 |     if (U_FAILURE(status)) { | 
| 315 |         return; | 
| 316 |     } | 
| 317 |     orgRules = new UVector(ruleCount, status); | 
| 318 |     if (U_FAILURE(status)) { | 
| 319 |         return; | 
| 320 |     } | 
| 321 |     orgtrs = (const TimeZoneRule**)uprv_malloc(sizeof(TimeZoneRule*)*ruleCount); | 
| 322 |     if (orgtrs == NULL) { | 
| 323 |         status = U_MEMORY_ALLOCATION_ERROR; | 
| 324 |         goto error; | 
| 325 |     } | 
| 326 |     getTimeZoneRules(orgini, orgtrs, ruleCount, status); | 
| 327 |     if (U_FAILURE(status)) { | 
| 328 |         goto error; | 
| 329 |     } | 
| 330 |     for (i = 0; i < ruleCount; i++) { | 
| 331 |         orgRules->addElement(orgtrs[i]->clone(), status); | 
| 332 |         if (U_FAILURE(status)) { | 
| 333 |             goto error; | 
| 334 |         } | 
| 335 |     } | 
| 336 |     uprv_free(orgtrs); | 
| 337 |     orgtrs = NULL; | 
| 338 |  | 
| 339 |     avail = getPreviousTransition(start, TRUE, tzt); | 
| 340 |     if (!avail) { | 
| 341 |         // No need to filter out rules only applicable to time before the start | 
| 342 |         initial = orgini->clone(); | 
| 343 |         transitionRules = orgRules; | 
| 344 |         return; | 
| 345 |     } | 
| 346 |  | 
| 347 |     done = (UBool*)uprv_malloc(sizeof(UBool)*ruleCount); | 
| 348 |     if (done == NULL) { | 
| 349 |         status = U_MEMORY_ALLOCATION_ERROR; | 
| 350 |         goto error; | 
| 351 |     } | 
| 352 |     filteredRules = new UVector(status); | 
| 353 |     if (U_FAILURE(status)) { | 
| 354 |         goto error; | 
| 355 |     } | 
| 356 |  | 
| 357 |     // Create initial rule | 
| 358 |     tzt.getTo()->getName(name); | 
| 359 |     res_initial = new InitialTimeZoneRule(name, tzt.getTo()->getRawOffset(), | 
| 360 |         tzt.getTo()->getDSTSavings()); | 
| 361 |  | 
| 362 |     // Mark rules which does not need to be processed | 
| 363 |     for (i = 0; i < ruleCount; i++) { | 
| 364 |         r = (TimeZoneRule*)orgRules->elementAt(i); | 
| 365 |         avail = r->getNextStart(start, res_initial->getRawOffset(), res_initial->getDSTSavings(), FALSE, time); | 
| 366 |         done[i] = !avail; | 
| 367 |     } | 
| 368 |  | 
| 369 |     time = start; | 
| 370 |     while (!bFinalStd || !bFinalDst) { | 
| 371 |         avail = getNextTransition(time, FALSE, tzt); | 
| 372 |         if (!avail) { | 
| 373 |             break; | 
| 374 |         } | 
| 375 |         UDate updatedTime = tzt.getTime(); | 
| 376 |         if (updatedTime == time) { | 
| 377 |             // Can get here if rules for start & end of daylight time have exactly | 
| 378 |             // the same time.   | 
| 379 |             // TODO:  fix getNextTransition() to prevent it? | 
| 380 |             status = U_INVALID_STATE_ERROR; | 
| 381 |             goto error; | 
| 382 |         } | 
| 383 |         time = updatedTime; | 
| 384 |   | 
| 385 |         const TimeZoneRule *toRule = tzt.getTo(); | 
| 386 |         for (i = 0; i < ruleCount; i++) { | 
| 387 |             r = (TimeZoneRule*)orgRules->elementAt(i); | 
| 388 |             if (*r == *toRule) { | 
| 389 |                 break; | 
| 390 |             } | 
| 391 |         } | 
| 392 |         if (i >= ruleCount) { | 
| 393 |             // This case should never happen | 
| 394 |             status = U_INVALID_STATE_ERROR; | 
| 395 |             goto error; | 
| 396 |         } | 
| 397 |         if (done[i]) { | 
| 398 |             continue; | 
| 399 |         } | 
| 400 |         const TimeArrayTimeZoneRule *tar = dynamic_cast<const TimeArrayTimeZoneRule *>(toRule); | 
| 401 |         const AnnualTimeZoneRule *ar; | 
| 402 |         if (tar != NULL) { | 
| 403 |             // Get the previous raw offset and DST savings before the very first start time | 
| 404 |             TimeZoneTransition tzt0; | 
| 405 |             t = start; | 
| 406 |             while (TRUE) { | 
| 407 |                 avail = getNextTransition(t, FALSE, tzt0); | 
| 408 |                 if (!avail) { | 
| 409 |                     break; | 
| 410 |                 } | 
| 411 |                 if (*(tzt0.getTo()) == *tar) { | 
| 412 |                     break; | 
| 413 |                 } | 
| 414 |                 t = tzt0.getTime(); | 
| 415 |             } | 
| 416 |             if (avail) { | 
| 417 |                 // Check if the entire start times to be added | 
| 418 |                 tar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart); | 
| 419 |                 if (firstStart > start) { | 
| 420 |                     // Just add the rule as is | 
| 421 |                     filteredRules->addElement(tar->clone(), status); | 
| 422 |                     if (U_FAILURE(status)) { | 
| 423 |                         goto error; | 
| 424 |                     } | 
| 425 |                 } else { | 
| 426 |                     // Colllect transitions after the start time | 
| 427 |                     int32_t startTimes; | 
| 428 |                     DateTimeRule::TimeRuleType timeType; | 
| 429 |                     int32_t idx; | 
| 430 |  | 
| 431 |                     startTimes = tar->countStartTimes(); | 
| 432 |                     timeType = tar->getTimeType(); | 
| 433 |                     for (idx = 0; idx < startTimes; idx++) { | 
| 434 |                         tar->getStartTimeAt(idx, t); | 
| 435 |                         if (timeType == DateTimeRule::STANDARD_TIME) { | 
| 436 |                             t -= tzt.getFrom()->getRawOffset(); | 
| 437 |                         } | 
| 438 |                         if (timeType == DateTimeRule::WALL_TIME) { | 
| 439 |                             t -= tzt.getFrom()->getDSTSavings(); | 
| 440 |                         } | 
| 441 |                         if (t > start) { | 
| 442 |                             break; | 
| 443 |                         } | 
| 444 |                     } | 
| 445 |                     int32_t asize = startTimes - idx; | 
| 446 |                     if (asize > 0) { | 
| 447 |                         newTimes = (UDate*)uprv_malloc(sizeof(UDate) * asize); | 
| 448 |                         if (newTimes == NULL) { | 
| 449 |                             status = U_MEMORY_ALLOCATION_ERROR; | 
| 450 |                             goto error; | 
| 451 |                         } | 
| 452 |                         for (int32_t newidx = 0; newidx < asize; newidx++) { | 
| 453 |                             tar->getStartTimeAt(idx + newidx, newTimes[newidx]); | 
| 454 |                             if (U_FAILURE(status)) { | 
| 455 |                                 uprv_free(newTimes); | 
| 456 |                                 newTimes = NULL; | 
| 457 |                                 goto error; | 
| 458 |                             } | 
| 459 |                         } | 
| 460 |                         tar->getName(name); | 
| 461 |                         TimeArrayTimeZoneRule *newTar = new TimeArrayTimeZoneRule(name, | 
| 462 |                             tar->getRawOffset(), tar->getDSTSavings(), newTimes, asize, timeType); | 
| 463 |                         uprv_free(newTimes); | 
| 464 |                         filteredRules->addElement(newTar, status); | 
| 465 |                         if (U_FAILURE(status)) { | 
| 466 |                             goto error; | 
| 467 |                         } | 
| 468 |                     } | 
| 469 |                 } | 
| 470 |             } | 
| 471 |         } else if ((ar = dynamic_cast<const AnnualTimeZoneRule *>(toRule)) != NULL) { | 
| 472 |             ar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart); | 
| 473 |             if (firstStart == tzt.getTime()) { | 
| 474 |                 // Just add the rule as is | 
| 475 |                 filteredRules->addElement(ar->clone(), status); | 
| 476 |                 if (U_FAILURE(status)) { | 
| 477 |                     goto error; | 
| 478 |                 } | 
| 479 |             } else { | 
| 480 |                 // Calculate the transition year | 
| 481 |                 int32_t year, month, dom, dow, doy, mid; | 
| 482 |                 Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid); | 
| 483 |                 // Re-create the rule | 
| 484 |                 ar->getName(name); | 
| 485 |                 AnnualTimeZoneRule *newAr = new AnnualTimeZoneRule(name, ar->getRawOffset(), ar->getDSTSavings(), | 
| 486 |                     *(ar->getRule()), year, ar->getEndYear()); | 
| 487 |                 filteredRules->addElement(newAr, status); | 
| 488 |                 if (U_FAILURE(status)) { | 
| 489 |                     goto error; | 
| 490 |                 } | 
| 491 |             } | 
| 492 |             // check if this is a final rule | 
| 493 |             if (ar->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) { | 
| 494 |                 // After bot final standard and dst rules are processed, | 
| 495 |                 // exit this while loop. | 
| 496 |                 if (ar->getDSTSavings() == 0) { | 
| 497 |                     bFinalStd = TRUE; | 
| 498 |                 } else { | 
| 499 |                     bFinalDst = TRUE; | 
| 500 |                 } | 
| 501 |             } | 
| 502 |         } | 
| 503 |         done[i] = TRUE; | 
| 504 |     } | 
| 505 |  | 
| 506 |     // Set the results | 
| 507 |     if (orgRules != NULL) { | 
| 508 |         while (!orgRules->isEmpty()) { | 
| 509 |             r = (TimeZoneRule*)orgRules->orphanElementAt(0); | 
| 510 |             delete r; | 
| 511 |         } | 
| 512 |         delete orgRules; | 
| 513 |     } | 
| 514 |     if (done != NULL) { | 
| 515 |         uprv_free(done); | 
| 516 |     } | 
| 517 |  | 
| 518 |     initial = res_initial; | 
| 519 |     transitionRules = filteredRules; | 
| 520 |     return; | 
| 521 |  | 
| 522 | error: | 
| 523 |     if (orgtrs != NULL) { | 
| 524 |         uprv_free(orgtrs); | 
| 525 |     } | 
| 526 |     if (orgRules != NULL) { | 
| 527 |         while (!orgRules->isEmpty()) { | 
| 528 |             r = (TimeZoneRule*)orgRules->orphanElementAt(0); | 
| 529 |             delete r; | 
| 530 |         } | 
| 531 |         delete orgRules; | 
| 532 |     } | 
| 533 |     if (done != NULL) { | 
| 534 |         if (filteredRules != NULL) { | 
| 535 |             while (!filteredRules->isEmpty()) { | 
| 536 |                 r = (TimeZoneRule*)filteredRules->orphanElementAt(0); | 
| 537 |                 delete r; | 
| 538 |             } | 
| 539 |             delete filteredRules; | 
| 540 |         } | 
| 541 |         delete res_initial; | 
| 542 |         uprv_free(done); | 
| 543 |     } | 
| 544 |  | 
| 545 |     initial = NULL; | 
| 546 |     transitionRules = NULL; | 
| 547 | } | 
| 548 |  | 
| 549 | void | 
| 550 | BasicTimeZone::getOffsetFromLocal(UDate /*date*/, int32_t /*nonExistingTimeOpt*/, int32_t /*duplicatedTimeOpt*/, | 
| 551 |                             int32_t& /*rawOffset*/, int32_t& /*dstOffset*/, UErrorCode& status) const { | 
| 552 |     if (U_FAILURE(status)) { | 
| 553 |         return; | 
| 554 |     } | 
| 555 |     status = U_UNSUPPORTED_ERROR; | 
| 556 | } | 
| 557 |  | 
| 558 | U_NAMESPACE_END | 
| 559 |  | 
| 560 | #endif /* #if !UCONFIG_NO_FORMATTING */ | 
| 561 |  | 
| 562 | //eof | 
| 563 |  |