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