1/* 2******************************************************************************* 3* Copyright (C) 2007-2012, International Business Machines Corporation and 4* others. All Rights Reserved. 5******************************************************************************* 6*/ 7 8#include "utypeinfo.h" // 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 20U_CDECL_BEGIN 21// UComparator function for sorting start times 22static int32_t U_CALLCONV 23compareDates(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} 29U_CDECL_END 30 31U_NAMESPACE_BEGIN 32 33TimeZoneRule::TimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings) 34: UObject(), fName(name), fRawOffset(rawOffset), fDSTSavings(dstSavings) { 35} 36 37TimeZoneRule::TimeZoneRule(const TimeZoneRule& source) 38: UObject(source), fName(source.fName), fRawOffset(source.fRawOffset), fDSTSavings(source.fDSTSavings) { 39} 40 41TimeZoneRule::~TimeZoneRule() { 42} 43 44TimeZoneRule& 45TimeZoneRule::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 54UBool 55TimeZoneRule::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 63UBool 64TimeZoneRule::operator!=(const TimeZoneRule& that) const { 65 return !operator==(that); 66} 67 68UnicodeString& 69TimeZoneRule::getName(UnicodeString& name) const { 70 name = fName; 71 return name; 72} 73 74int32_t 75TimeZoneRule::getRawOffset(void) const { 76 return fRawOffset; 77} 78 79int32_t 80TimeZoneRule::getDSTSavings(void) const { 81 return fDSTSavings; 82} 83 84UBool 85TimeZoneRule::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 93UOBJECT_DEFINE_RTTI_IMPLEMENTATION(InitialTimeZoneRule) 94 95InitialTimeZoneRule::InitialTimeZoneRule(const UnicodeString& name, 96 int32_t rawOffset, 97 int32_t dstSavings) 98: TimeZoneRule(name, rawOffset, dstSavings) { 99} 100 101InitialTimeZoneRule::InitialTimeZoneRule(const InitialTimeZoneRule& source) 102: TimeZoneRule(source) { 103} 104 105InitialTimeZoneRule::~InitialTimeZoneRule() { 106} 107 108InitialTimeZoneRule* 109InitialTimeZoneRule::clone(void) const { 110 return new InitialTimeZoneRule(*this); 111} 112 113InitialTimeZoneRule& 114InitialTimeZoneRule::operator=(const InitialTimeZoneRule& right) { 115 if (this != &right) { 116 TimeZoneRule::operator=(right); 117 } 118 return *this; 119} 120 121UBool 122InitialTimeZoneRule::operator==(const TimeZoneRule& that) const { 123 return ((this == &that) || 124 (typeid(*this) == typeid(that) && 125 TimeZoneRule::operator==(that))); 126} 127 128UBool 129InitialTimeZoneRule::operator!=(const TimeZoneRule& that) const { 130 return !operator==(that); 131} 132 133UBool 134InitialTimeZoneRule::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 144UBool 145InitialTimeZoneRule::getFirstStart(int32_t /*prevRawOffset*/, 146 int32_t /*prevDSTSavings*/, 147 UDate& /*result*/) const { 148 return FALSE; 149} 150 151UBool 152InitialTimeZoneRule::getFinalStart(int32_t /*prevRawOffset*/, 153 int32_t /*prevDSTSavings*/, 154 UDate& /*result*/) const { 155 return FALSE; 156} 157 158UBool 159InitialTimeZoneRule::getNextStart(UDate /*base*/, 160 int32_t /*prevRawOffset*/, 161 int32_t /*prevDSTSavings*/, 162 UBool /*inclusive*/, 163 UDate& /*result*/) const { 164 return FALSE; 165} 166 167UBool 168InitialTimeZoneRule::getPreviousStart(UDate /*base*/, 169 int32_t /*prevRawOffset*/, 170 int32_t /*prevDSTSavings*/, 171 UBool /*inclusive*/, 172 UDate& /*result*/) const { 173 return FALSE; 174} 175 176 177UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AnnualTimeZoneRule) 178 179const int32_t AnnualTimeZoneRule::MAX_YEAR = 0x7FFFFFFF; /* max signed int32 */ 180 181AnnualTimeZoneRule::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 191AnnualTimeZoneRule::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 201AnnualTimeZoneRule::AnnualTimeZoneRule(const AnnualTimeZoneRule& source) 202: TimeZoneRule(source), fDateTimeRule(new DateTimeRule(*(source.fDateTimeRule))), 203 fStartYear(source.fStartYear), fEndYear(source.fEndYear) { 204} 205 206AnnualTimeZoneRule::~AnnualTimeZoneRule() { 207 delete fDateTimeRule; 208} 209 210AnnualTimeZoneRule* 211AnnualTimeZoneRule::clone(void) const { 212 return new AnnualTimeZoneRule(*this); 213} 214 215AnnualTimeZoneRule& 216AnnualTimeZoneRule::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 227UBool 228AnnualTimeZoneRule::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 241UBool 242AnnualTimeZoneRule::operator!=(const TimeZoneRule& that) const { 243 return !operator==(that); 244} 245 246const DateTimeRule* 247AnnualTimeZoneRule::getRule() const { 248 return fDateTimeRule; 249} 250 251int32_t 252AnnualTimeZoneRule::getStartYear() const { 253 return fStartYear; 254} 255 256int32_t 257AnnualTimeZoneRule::getEndYear() const { 258 return fEndYear; 259} 260 261UBool 262AnnualTimeZoneRule::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 319UBool 320AnnualTimeZoneRule::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 333UBool 334AnnualTimeZoneRule::getFirstStart(int32_t prevRawOffset, 335 int32_t prevDSTSavings, 336 UDate& result) const { 337 return getStartInYear(fStartYear, prevRawOffset, prevDSTSavings, result); 338} 339 340UBool 341AnnualTimeZoneRule::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 350UBool 351AnnualTimeZoneRule::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 374UBool 375AnnualTimeZoneRule::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 398UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeArrayTimeZoneRule) 399 400TimeArrayTimeZoneRule::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 414TimeArrayTimeZoneRule::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 422TimeArrayTimeZoneRule::~TimeArrayTimeZoneRule() { 423 if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) { 424 uprv_free(fStartTimes); 425 } 426} 427 428TimeArrayTimeZoneRule* 429TimeArrayTimeZoneRule::clone(void) const { 430 return new TimeArrayTimeZoneRule(*this); 431} 432 433 434TimeArrayTimeZoneRule& 435TimeArrayTimeZoneRule::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 446UBool 447TimeArrayTimeZoneRule::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 470UBool 471TimeArrayTimeZoneRule::operator!=(const TimeZoneRule& that) const { 472 return !operator==(that); 473} 474 475DateTimeRule::TimeRuleType 476TimeArrayTimeZoneRule::getTimeType(void) const { 477 return fTimeRuleType; 478} 479 480UBool 481TimeArrayTimeZoneRule::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 489int32_t 490TimeArrayTimeZoneRule::countStartTimes(void) const { 491 return fNumStartTimes; 492} 493 494UBool 495TimeArrayTimeZoneRule::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 518UBool 519TimeArrayTimeZoneRule::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 529UBool 530TimeArrayTimeZoneRule::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 540UBool 541TimeArrayTimeZoneRule::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 560UBool 561TimeArrayTimeZoneRule::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 580UBool 581TimeArrayTimeZoneRule::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 611UDate 612TimeArrayTimeZoneRule::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 622U_NAMESPACE_END 623 624#endif /* #if !UCONFIG_NO_FORMATTING */ 625 626//eof 627 628