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