tzrule.cpp (19295B)
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-2012, International Business Machines Corporation and 6 * others. All Rights Reserved. 7 ******************************************************************************* 8 */ 9 10 #include "utypeinfo.h" // for 'typeid' to work 11 12 #include "unicode/utypes.h" 13 14 #if !UCONFIG_NO_FORMATTING 15 16 #include "unicode/tzrule.h" 17 #include "unicode/ucal.h" 18 #include "gregoimp.h" 19 #include "cmemory.h" 20 #include "uarrsort.h" 21 22 U_CDECL_BEGIN 23 // UComparator function for sorting start times 24 static int32_t U_CALLCONV 25 compareDates(const void * /*context*/, const void *left, const void *right) { 26 UDate l = *((UDate*)left); 27 UDate r = *((UDate*)right); 28 int32_t res = l < r ? -1 : (l == r ? 0 : 1); 29 return res; 30 } 31 U_CDECL_END 32 33 U_NAMESPACE_BEGIN 34 35 TimeZoneRule::TimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings) 36 : UObject(), fName(name), fRawOffset(rawOffset), fDSTSavings(dstSavings) { 37 } 38 39 TimeZoneRule::TimeZoneRule(const TimeZoneRule& source) 40 : UObject(source), fName(source.fName), fRawOffset(source.fRawOffset), fDSTSavings(source.fDSTSavings) { 41 } 42 43 TimeZoneRule::~TimeZoneRule() { 44 } 45 46 TimeZoneRule& 47 TimeZoneRule::operator=(const TimeZoneRule& right) { 48 if (this != &right) { 49 fName = right.fName; 50 fRawOffset = right.fRawOffset; 51 fDSTSavings = right.fDSTSavings; 52 } 53 return *this; 54 } 55 56 bool 57 TimeZoneRule::operator==(const TimeZoneRule& that) const { 58 return ((this == &that) || 59 (typeid(*this) == typeid(that) && 60 fName == that.fName && 61 fRawOffset == that.fRawOffset && 62 fDSTSavings == that.fDSTSavings)); 63 } 64 65 bool 66 TimeZoneRule::operator!=(const TimeZoneRule& that) const { 67 return !operator==(that); 68 } 69 70 UnicodeString& 71 TimeZoneRule::getName(UnicodeString& name) const { 72 name = fName; 73 return name; 74 } 75 76 int32_t 77 TimeZoneRule::getRawOffset() const { 78 return fRawOffset; 79 } 80 81 int32_t 82 TimeZoneRule::getDSTSavings() const { 83 return fDSTSavings; 84 } 85 86 UBool 87 TimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const { 88 return ((this == &other) || 89 (typeid(*this) == typeid(other) && 90 fRawOffset == other.fRawOffset && 91 fDSTSavings == other.fDSTSavings)); 92 } 93 94 95 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(InitialTimeZoneRule) 96 97 InitialTimeZoneRule::InitialTimeZoneRule(const UnicodeString& name, 98 int32_t rawOffset, 99 int32_t dstSavings) 100 : TimeZoneRule(name, rawOffset, dstSavings) { 101 } 102 103 InitialTimeZoneRule::InitialTimeZoneRule(const InitialTimeZoneRule& source) 104 : TimeZoneRule(source) { 105 } 106 107 InitialTimeZoneRule::~InitialTimeZoneRule() { 108 } 109 110 InitialTimeZoneRule* 111 InitialTimeZoneRule::clone() const { 112 return new InitialTimeZoneRule(*this); 113 } 114 115 InitialTimeZoneRule& 116 InitialTimeZoneRule::operator=(const InitialTimeZoneRule& right) { 117 if (this != &right) { 118 TimeZoneRule::operator=(right); 119 } 120 return *this; 121 } 122 123 bool 124 InitialTimeZoneRule::operator==(const TimeZoneRule& that) const { 125 return ((this == &that) || 126 (typeid(*this) == typeid(that) && 127 TimeZoneRule::operator==(that))); 128 } 129 130 bool 131 InitialTimeZoneRule::operator!=(const TimeZoneRule& that) const { 132 return !operator==(that); 133 } 134 135 UBool 136 InitialTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const { 137 if (this == &other) { 138 return true; 139 } 140 if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == false) { 141 return false; 142 } 143 return true; 144 } 145 146 UBool 147 InitialTimeZoneRule::getFirstStart(int32_t /*prevRawOffset*/, 148 int32_t /*prevDSTSavings*/, 149 UDate& /*result*/) const { 150 return false; 151 } 152 153 UBool 154 InitialTimeZoneRule::getFinalStart(int32_t /*prevRawOffset*/, 155 int32_t /*prevDSTSavings*/, 156 UDate& /*result*/) const { 157 return false; 158 } 159 160 UBool 161 InitialTimeZoneRule::getNextStart(UDate /*base*/, 162 int32_t /*prevRawOffset*/, 163 int32_t /*prevDSTSavings*/, 164 UBool /*inclusive*/, 165 UDate& /*result*/) const { 166 return false; 167 } 168 169 UBool 170 InitialTimeZoneRule::getPreviousStart(UDate /*base*/, 171 int32_t /*prevRawOffset*/, 172 int32_t /*prevDSTSavings*/, 173 UBool /*inclusive*/, 174 UDate& /*result*/) const { 175 return false; 176 } 177 178 179 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AnnualTimeZoneRule) 180 181 const int32_t AnnualTimeZoneRule::MAX_YEAR = 0x7FFFFFFF; /* max signed int32 */ 182 183 AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString& name, 184 int32_t rawOffset, 185 int32_t dstSavings, 186 const DateTimeRule& dateTimeRule, 187 int32_t startYear, 188 int32_t endYear) 189 : TimeZoneRule(name, rawOffset, dstSavings), fDateTimeRule(new DateTimeRule(dateTimeRule)), 190 fStartYear(startYear), fEndYear(endYear) { 191 } 192 193 AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString& name, 194 int32_t rawOffset, 195 int32_t dstSavings, 196 DateTimeRule* dateTimeRule, 197 int32_t startYear, 198 int32_t endYear) 199 : TimeZoneRule(name, rawOffset, dstSavings), fDateTimeRule(dateTimeRule), 200 fStartYear(startYear), fEndYear(endYear) { 201 } 202 203 AnnualTimeZoneRule::AnnualTimeZoneRule(const AnnualTimeZoneRule& source) 204 : TimeZoneRule(source), fDateTimeRule(new DateTimeRule(*(source.fDateTimeRule))), 205 fStartYear(source.fStartYear), fEndYear(source.fEndYear) { 206 } 207 208 AnnualTimeZoneRule::~AnnualTimeZoneRule() { 209 delete fDateTimeRule; 210 } 211 212 AnnualTimeZoneRule* 213 AnnualTimeZoneRule::clone() const { 214 return new AnnualTimeZoneRule(*this); 215 } 216 217 AnnualTimeZoneRule& 218 AnnualTimeZoneRule::operator=(const AnnualTimeZoneRule& right) { 219 if (this != &right) { 220 TimeZoneRule::operator=(right); 221 delete fDateTimeRule; 222 fDateTimeRule = right.fDateTimeRule->clone(); 223 fStartYear = right.fStartYear; 224 fEndYear = right.fEndYear; 225 } 226 return *this; 227 } 228 229 bool 230 AnnualTimeZoneRule::operator==(const TimeZoneRule& that) const { 231 if (this == &that) { 232 return true; 233 } 234 if (typeid(*this) != typeid(that)) { 235 return false; 236 } 237 AnnualTimeZoneRule *atzr = (AnnualTimeZoneRule*)&that; 238 return (*fDateTimeRule == *(atzr->fDateTimeRule) && 239 fStartYear == atzr->fStartYear && 240 fEndYear == atzr->fEndYear); 241 } 242 243 bool 244 AnnualTimeZoneRule::operator!=(const TimeZoneRule& that) const { 245 return !operator==(that); 246 } 247 248 const DateTimeRule* 249 AnnualTimeZoneRule::getRule() const { 250 return fDateTimeRule; 251 } 252 253 int32_t 254 AnnualTimeZoneRule::getStartYear() const { 255 return fStartYear; 256 } 257 258 int32_t 259 AnnualTimeZoneRule::getEndYear() const { 260 return fEndYear; 261 } 262 263 UBool 264 AnnualTimeZoneRule::getStartInYear(int32_t year, 265 int32_t prevRawOffset, 266 int32_t prevDSTSavings, 267 UDate &result) const { 268 if (year < fStartYear || year > fEndYear) { 269 return false; 270 } 271 double ruleDay; 272 DateTimeRule::DateRuleType type = fDateTimeRule->getDateRuleType(); 273 if (type == DateTimeRule::DOM) { 274 ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(), fDateTimeRule->getRuleDayOfMonth()); 275 } else { 276 UBool after = true; 277 if (type == DateTimeRule::DOW) { 278 // Normalize DOW rule into DOW_GEQ_DOM or DOW_LEQ_DOM 279 int32_t weeks = fDateTimeRule->getRuleWeekInMonth(); 280 if (weeks > 0) { 281 ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(), 1); 282 ruleDay += 7 * (weeks - 1); 283 } else { 284 after = false; 285 ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(), 286 Grego::monthLength(year, fDateTimeRule->getRuleMonth())); 287 ruleDay += 7 * (weeks + 1); 288 } 289 } else { 290 int32_t month = fDateTimeRule->getRuleMonth(); 291 int32_t dom = fDateTimeRule->getRuleDayOfMonth(); 292 if (type == DateTimeRule::DOW_LEQ_DOM) { 293 after = false; 294 // Handle Feb <=29 295 if (month == UCAL_FEBRUARY && dom == 29 && !Grego::isLeapYear(year)) { 296 dom--; 297 } 298 } 299 ruleDay = Grego::fieldsToDay(year, month, dom); 300 } 301 int32_t dow = Grego::dayOfWeek(ruleDay); 302 int32_t delta = fDateTimeRule->getRuleDayOfWeek() - dow; 303 if (after) { 304 delta = delta < 0 ? delta + 7 : delta; 305 } else { 306 delta = delta > 0 ? delta - 7 : delta; 307 } 308 ruleDay += delta; 309 } 310 311 result = ruleDay*U_MILLIS_PER_DAY + fDateTimeRule->getRuleMillisInDay(); 312 if (fDateTimeRule->getTimeRuleType() != DateTimeRule::UTC_TIME) { 313 result -= prevRawOffset; 314 } 315 if (fDateTimeRule->getTimeRuleType() == DateTimeRule::WALL_TIME) { 316 result -= prevDSTSavings; 317 } 318 return true; 319 } 320 321 UBool 322 AnnualTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const { 323 if (this == &other) { 324 return true; 325 } 326 if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == false) { 327 return false; 328 } 329 AnnualTimeZoneRule* that = (AnnualTimeZoneRule*)&other; 330 return (*fDateTimeRule == *(that->fDateTimeRule) && 331 fStartYear == that->fStartYear && 332 fEndYear == that->fEndYear); 333 } 334 335 UBool 336 AnnualTimeZoneRule::getFirstStart(int32_t prevRawOffset, 337 int32_t prevDSTSavings, 338 UDate& result) const { 339 return getStartInYear(fStartYear, prevRawOffset, prevDSTSavings, result); 340 } 341 342 UBool 343 AnnualTimeZoneRule::getFinalStart(int32_t prevRawOffset, 344 int32_t prevDSTSavings, 345 UDate& result) const { 346 if (fEndYear == MAX_YEAR) { 347 return false; 348 } 349 return getStartInYear(fEndYear, prevRawOffset, prevDSTSavings, result); 350 } 351 352 UBool 353 AnnualTimeZoneRule::getNextStart(UDate base, 354 int32_t prevRawOffset, 355 int32_t prevDSTSavings, 356 UBool inclusive, 357 UDate& result) const { 358 UErrorCode status = U_ZERO_ERROR; 359 int32_t year = Grego::timeToYear(base, status); 360 U_ASSERT(U_SUCCESS(status)); 361 if (year < fStartYear) { 362 return getFirstStart(prevRawOffset, prevDSTSavings, result); 363 } 364 UDate tmp; 365 if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) { 366 if (tmp < base || (!inclusive && (tmp == base))) { 367 // Return the next one 368 return getStartInYear(year + 1, prevRawOffset, prevDSTSavings, result); 369 } else { 370 result = tmp; 371 return true; 372 } 373 } 374 return false; 375 } 376 377 UBool 378 AnnualTimeZoneRule::getPreviousStart(UDate base, 379 int32_t prevRawOffset, 380 int32_t prevDSTSavings, 381 UBool inclusive, 382 UDate& result) const { 383 UErrorCode status = U_ZERO_ERROR; 384 int32_t year = Grego::timeToYear(base, status); 385 U_ASSERT(U_SUCCESS(status)); 386 if (year > fEndYear) { 387 return getFinalStart(prevRawOffset, prevDSTSavings, result); 388 } 389 UDate tmp; 390 if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) { 391 if (tmp > base || (!inclusive && (tmp == base))) { 392 // Return the previous one 393 return getStartInYear(year - 1, prevRawOffset, prevDSTSavings, result); 394 } else { 395 result = tmp; 396 return true; 397 } 398 } 399 return false; 400 } 401 402 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeArrayTimeZoneRule) 403 404 TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const UnicodeString& name, 405 int32_t rawOffset, 406 int32_t dstSavings, 407 const UDate* startTimes, 408 int32_t numStartTimes, 409 DateTimeRule::TimeRuleType timeRuleType) 410 : TimeZoneRule(name, rawOffset, dstSavings), fTimeRuleType(timeRuleType), 411 fStartTimes(nullptr) { 412 UErrorCode status = U_ZERO_ERROR; 413 initStartTimes(startTimes, numStartTimes, status); 414 //TODO - status? 415 } 416 417 418 TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const TimeArrayTimeZoneRule& source) 419 : TimeZoneRule(source), fTimeRuleType(source.fTimeRuleType), fStartTimes(nullptr) { 420 UErrorCode status = U_ZERO_ERROR; 421 initStartTimes(source.fStartTimes, source.fNumStartTimes, status); 422 //TODO - status? 423 } 424 425 426 TimeArrayTimeZoneRule::~TimeArrayTimeZoneRule() { 427 if (fStartTimes != nullptr && fStartTimes != fLocalStartTimes) { 428 uprv_free(fStartTimes); 429 } 430 } 431 432 TimeArrayTimeZoneRule* 433 TimeArrayTimeZoneRule::clone() const { 434 return new TimeArrayTimeZoneRule(*this); 435 } 436 437 438 TimeArrayTimeZoneRule& 439 TimeArrayTimeZoneRule::operator=(const TimeArrayTimeZoneRule& right) { 440 if (this != &right) { 441 TimeZoneRule::operator=(right); 442 UErrorCode status = U_ZERO_ERROR; 443 initStartTimes(right.fStartTimes, right.fNumStartTimes, status); 444 //TODO - status? 445 fTimeRuleType = right.fTimeRuleType; 446 } 447 return *this; 448 } 449 450 bool 451 TimeArrayTimeZoneRule::operator==(const TimeZoneRule& that) const { 452 if (this == &that) { 453 return true; 454 } 455 if (typeid(*this) != typeid(that) || !TimeZoneRule::operator==(that)) { 456 return false; 457 } 458 TimeArrayTimeZoneRule *tatzr = (TimeArrayTimeZoneRule*)&that; 459 if (fTimeRuleType != tatzr->fTimeRuleType || 460 fNumStartTimes != tatzr->fNumStartTimes) { 461 return false; 462 } 463 // Compare start times 464 bool res = true; 465 for (int32_t i = 0; i < fNumStartTimes; i++) { 466 if (fStartTimes[i] != tatzr->fStartTimes[i]) { 467 res = false; 468 break; 469 } 470 } 471 return res; 472 } 473 474 bool 475 TimeArrayTimeZoneRule::operator!=(const TimeZoneRule& that) const { 476 return !operator==(that); 477 } 478 479 DateTimeRule::TimeRuleType 480 TimeArrayTimeZoneRule::getTimeType() const { 481 return fTimeRuleType; 482 } 483 484 UBool 485 TimeArrayTimeZoneRule::getStartTimeAt(int32_t index, UDate& result) const { 486 if (index >= fNumStartTimes || index < 0) { 487 return false; 488 } 489 result = fStartTimes[index]; 490 return true; 491 } 492 493 int32_t 494 TimeArrayTimeZoneRule::countStartTimes() const { 495 return fNumStartTimes; 496 } 497 498 UBool 499 TimeArrayTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const { 500 if (this == &other) { 501 return true; 502 } 503 if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == false) { 504 return false; 505 } 506 TimeArrayTimeZoneRule* that = (TimeArrayTimeZoneRule*)&other; 507 if (fTimeRuleType != that->fTimeRuleType || 508 fNumStartTimes != that->fNumStartTimes) { 509 return false; 510 } 511 // Compare start times 512 UBool res = true; 513 for (int32_t i = 0; i < fNumStartTimes; i++) { 514 if (fStartTimes[i] != that->fStartTimes[i]) { 515 res = false; 516 break; 517 } 518 } 519 return res; 520 } 521 522 UBool 523 TimeArrayTimeZoneRule::getFirstStart(int32_t prevRawOffset, 524 int32_t prevDSTSavings, 525 UDate& result) const { 526 if (fNumStartTimes <= 0 || fStartTimes == nullptr) { 527 return false; 528 } 529 result = getUTC(fStartTimes[0], prevRawOffset, prevDSTSavings); 530 return true; 531 } 532 533 UBool 534 TimeArrayTimeZoneRule::getFinalStart(int32_t prevRawOffset, 535 int32_t prevDSTSavings, 536 UDate& result) const { 537 if (fNumStartTimes <= 0 || fStartTimes == nullptr) { 538 return false; 539 } 540 result = getUTC(fStartTimes[fNumStartTimes - 1], prevRawOffset, prevDSTSavings); 541 return true; 542 } 543 544 UBool 545 TimeArrayTimeZoneRule::getNextStart(UDate base, 546 int32_t prevRawOffset, 547 int32_t prevDSTSavings, 548 UBool inclusive, 549 UDate& result) const { 550 int32_t i = fNumStartTimes - 1; 551 for (; i >= 0; i--) { 552 UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings); 553 if (time < base || (!inclusive && time == base)) { 554 break; 555 } 556 result = time; 557 } 558 if (i == fNumStartTimes - 1) { 559 return false; 560 } 561 return true; 562 } 563 564 UBool 565 TimeArrayTimeZoneRule::getPreviousStart(UDate base, 566 int32_t prevRawOffset, 567 int32_t prevDSTSavings, 568 UBool inclusive, 569 UDate& result) const { 570 int32_t i = fNumStartTimes - 1; 571 for (; i >= 0; i--) { 572 UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings); 573 if (time < base || (inclusive && time == base)) { 574 result = time; 575 return true; 576 } 577 } 578 return false; 579 } 580 581 582 // ---- private methods ------ 583 584 UBool 585 TimeArrayTimeZoneRule::initStartTimes(const UDate source[], int32_t size, UErrorCode& status) { 586 // Free old array 587 if (fStartTimes != nullptr && fStartTimes != fLocalStartTimes) { 588 uprv_free(fStartTimes); 589 } 590 // Allocate new one if needed 591 if (size > TIMEARRAY_STACK_BUFFER_SIZE) { 592 fStartTimes = static_cast<UDate*>(uprv_malloc(sizeof(UDate) * size)); 593 if (fStartTimes == nullptr) { 594 status = U_MEMORY_ALLOCATION_ERROR; 595 fNumStartTimes = 0; 596 return false; 597 } 598 } else { 599 fStartTimes = (UDate*)fLocalStartTimes; 600 } 601 uprv_memcpy(fStartTimes, source, sizeof(UDate)*size); 602 fNumStartTimes = size; 603 // Sort dates 604 uprv_sortArray(fStartTimes, fNumStartTimes, static_cast<int32_t>(sizeof(UDate)), compareDates, nullptr, true, &status); 605 if (U_FAILURE(status)) { 606 if (fStartTimes != nullptr && fStartTimes != fLocalStartTimes) { 607 uprv_free(fStartTimes); 608 } 609 fNumStartTimes = 0; 610 return false; 611 } 612 return true; 613 } 614 615 UDate 616 TimeArrayTimeZoneRule::getUTC(UDate time, int32_t raw, int32_t dst) const { 617 if (fTimeRuleType != DateTimeRule::UTC_TIME) { 618 time -= raw; 619 } 620 if (fTimeRuleType == DateTimeRule::WALL_TIME) { 621 time -= dst; 622 } 623 return time; 624 } 625 626 U_NAMESPACE_END 627 628 #endif /* #if !UCONFIG_NO_FORMATTING */ 629 630 //eof