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 UBool 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 UBool 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(void) const { 78 return fRawOffset; 79 } 80 81 int32_t 82 TimeZoneRule::getDSTSavings(void) 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(void) 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 UBool 124 InitialTimeZoneRule::operator==(const TimeZoneRule& that) const { 125 return ((this == &that) || 126 (typeid(*this) == typeid(that) && 127 TimeZoneRule::operator==(that))); 128 } 129 130 UBool 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(void) 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 UBool 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 UBool 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 int32_t year, month, dom, dow, doy, mid; 359 Grego::timeToFields(base, year, month, dom, dow, doy, mid); 360 if (year < fStartYear) { 361 return getFirstStart(prevRawOffset, prevDSTSavings, result); 362 } 363 UDate tmp; 364 if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) { 365 if (tmp < base || (!inclusive && (tmp == base))) { 366 // Return the next one 367 return getStartInYear(year + 1, prevRawOffset, prevDSTSavings, result); 368 } else { 369 result = tmp; 370 return TRUE; 371 } 372 } 373 return FALSE; 374 } 375 376 UBool 377 AnnualTimeZoneRule::getPreviousStart(UDate base, 378 int32_t prevRawOffset, 379 int32_t prevDSTSavings, 380 UBool inclusive, 381 UDate& result) const { 382 int32_t year, month, dom, dow, doy, mid; 383 Grego::timeToFields(base, year, month, dom, dow, doy, mid); 384 if (year > fEndYear) { 385 return getFinalStart(prevRawOffset, prevDSTSavings, result); 386 } 387 UDate tmp; 388 if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) { 389 if (tmp > base || (!inclusive && (tmp == base))) { 390 // Return the previous one 391 return getStartInYear(year - 1, prevRawOffset, prevDSTSavings, result); 392 } else { 393 result = tmp; 394 return TRUE; 395 } 396 } 397 return FALSE; 398 } 399 400 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeArrayTimeZoneRule) 401 402 TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const UnicodeString& name, 403 int32_t rawOffset, 404 int32_t dstSavings, 405 const UDate* startTimes, 406 int32_t numStartTimes, 407 DateTimeRule::TimeRuleType timeRuleType) 408 : TimeZoneRule(name, rawOffset, dstSavings), fTimeRuleType(timeRuleType), 409 fStartTimes(NULL) { 410 UErrorCode status = U_ZERO_ERROR; 411 initStartTimes(startTimes, numStartTimes, status); 412 //TODO - status? 413 } 414 415 416 TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const TimeArrayTimeZoneRule& source) 417 : TimeZoneRule(source), fTimeRuleType(source.fTimeRuleType), fStartTimes(NULL) { 418 UErrorCode status = U_ZERO_ERROR; 419 initStartTimes(source.fStartTimes, source.fNumStartTimes, status); 420 //TODO - status? 421 } 422 423 424 TimeArrayTimeZoneRule::~TimeArrayTimeZoneRule() { 425 if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) { 426 uprv_free(fStartTimes); 427 } 428 } 429 430 TimeArrayTimeZoneRule* 431 TimeArrayTimeZoneRule::clone(void) const { 432 return new TimeArrayTimeZoneRule(*this); 433 } 434 435 436 TimeArrayTimeZoneRule& 437 TimeArrayTimeZoneRule::operator=(const TimeArrayTimeZoneRule& right) { 438 if (this != &right) { 439 TimeZoneRule::operator=(right); 440 UErrorCode status = U_ZERO_ERROR; 441 initStartTimes(right.fStartTimes, right.fNumStartTimes, status); 442 //TODO - status? 443 fTimeRuleType = right.fTimeRuleType; 444 } 445 return *this; 446 } 447 448 UBool 449 TimeArrayTimeZoneRule::operator==(const TimeZoneRule& that) const { 450 if (this == &that) { 451 return TRUE; 452 } 453 if (typeid(*this) != typeid(that) || TimeZoneRule::operator==(that) == FALSE) { 454 return FALSE; 455 } 456 TimeArrayTimeZoneRule *tatzr = (TimeArrayTimeZoneRule*)&that; 457 if (fTimeRuleType != tatzr->fTimeRuleType || 458 fNumStartTimes != tatzr->fNumStartTimes) { 459 return FALSE; 460 } 461 // Compare start times 462 UBool res = TRUE; 463 for (int32_t i = 0; i < fNumStartTimes; i++) { 464 if (fStartTimes[i] != tatzr->fStartTimes[i]) { 465 res = FALSE; 466 break; 467 } 468 } 469 return res; 470 } 471 472 UBool 473 TimeArrayTimeZoneRule::operator!=(const TimeZoneRule& that) const { 474 return !operator==(that); 475 } 476 477 DateTimeRule::TimeRuleType 478 TimeArrayTimeZoneRule::getTimeType(void) const { 479 return fTimeRuleType; 480 } 481 482 UBool 483 TimeArrayTimeZoneRule::getStartTimeAt(int32_t index, UDate& result) const { 484 if (index >= fNumStartTimes || index < 0) { 485 return FALSE; 486 } 487 result = fStartTimes[index]; 488 return TRUE; 489 } 490 491 int32_t 492 TimeArrayTimeZoneRule::countStartTimes(void) const { 493 return fNumStartTimes; 494 } 495 496 UBool 497 TimeArrayTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const { 498 if (this == &other) { 499 return TRUE; 500 } 501 if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == FALSE) { 502 return FALSE; 503 } 504 TimeArrayTimeZoneRule* that = (TimeArrayTimeZoneRule*)&other; 505 if (fTimeRuleType != that->fTimeRuleType || 506 fNumStartTimes != that->fNumStartTimes) { 507 return FALSE; 508 } 509 // Compare start times 510 UBool res = TRUE; 511 for (int32_t i = 0; i < fNumStartTimes; i++) { 512 if (fStartTimes[i] != that->fStartTimes[i]) { 513 res = FALSE; 514 break; 515 } 516 } 517 return res; 518 } 519 520 UBool 521 TimeArrayTimeZoneRule::getFirstStart(int32_t prevRawOffset, 522 int32_t prevDSTSavings, 523 UDate& result) const { 524 if (fNumStartTimes <= 0 || fStartTimes == NULL) { 525 return FALSE; 526 } 527 result = getUTC(fStartTimes[0], prevRawOffset, prevDSTSavings); 528 return TRUE; 529 } 530 531 UBool 532 TimeArrayTimeZoneRule::getFinalStart(int32_t prevRawOffset, 533 int32_t prevDSTSavings, 534 UDate& result) const { 535 if (fNumStartTimes <= 0 || fStartTimes == NULL) { 536 return FALSE; 537 } 538 result = getUTC(fStartTimes[fNumStartTimes - 1], prevRawOffset, prevDSTSavings); 539 return TRUE; 540 } 541 542 UBool 543 TimeArrayTimeZoneRule::getNextStart(UDate base, 544 int32_t prevRawOffset, 545 int32_t prevDSTSavings, 546 UBool inclusive, 547 UDate& result) const { 548 int32_t i = fNumStartTimes - 1; 549 for (; i >= 0; i--) { 550 UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings); 551 if (time < base || (!inclusive && time == base)) { 552 break; 553 } 554 result = time; 555 } 556 if (i == fNumStartTimes - 1) { 557 return FALSE; 558 } 559 return TRUE; 560 } 561 562 UBool 563 TimeArrayTimeZoneRule::getPreviousStart(UDate base, 564 int32_t prevRawOffset, 565 int32_t prevDSTSavings, 566 UBool inclusive, 567 UDate& result) const { 568 int32_t i = fNumStartTimes - 1; 569 for (; i >= 0; i--) { 570 UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings); 571 if (time < base || (inclusive && time == base)) { 572 result = time; 573 return TRUE; 574 } 575 } 576 return FALSE; 577 } 578 579 580 // ---- private methods ------ 581 582 UBool 583 TimeArrayTimeZoneRule::initStartTimes(const UDate source[], int32_t size, UErrorCode& status) { 584 // Free old array 585 if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) { 586 uprv_free(fStartTimes); 587 } 588 // Allocate new one if needed 589 if (size > TIMEARRAY_STACK_BUFFER_SIZE) { 590 fStartTimes = (UDate*)uprv_malloc(sizeof(UDate)*size); 591 if (fStartTimes == NULL) { 592 status = U_MEMORY_ALLOCATION_ERROR; 593 fNumStartTimes = 0; 594 return FALSE; 595 } 596 } else { 597 fStartTimes = (UDate*)fLocalStartTimes; 598 } 599 uprv_memcpy(fStartTimes, source, sizeof(UDate)*size); 600 fNumStartTimes = size; 601 // Sort dates 602 uprv_sortArray(fStartTimes, fNumStartTimes, (int32_t)sizeof(UDate), compareDates, NULL, TRUE, &status); 603 if (U_FAILURE(status)) { 604 if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) { 605 uprv_free(fStartTimes); 606 } 607 fNumStartTimes = 0; 608 return FALSE; 609 } 610 return TRUE; 611 } 612 613 UDate 614 TimeArrayTimeZoneRule::getUTC(UDate time, int32_t raw, int32_t dst) const { 615 if (fTimeRuleType != DateTimeRule::UTC_TIME) { 616 time -= raw; 617 } 618 if (fTimeRuleType == DateTimeRule::WALL_TIME) { 619 time -= dst; 620 } 621 return time; 622 } 623 624 U_NAMESPACE_END 625 626 #endif /* #if !UCONFIG_NO_FORMATTING */ 627 628 //eof 629 630