OLD | NEW |
(Empty) | |
| 1 /* |
| 2 ******************************************************************************* |
| 3 * Copyright (C) 1997-2010, International Business Machines Corporation and |
| 4 * others. All Rights Reserved. |
| 5 ******************************************************************************* |
| 6 * |
| 7 * File SIMPLETZ.H |
| 8 * |
| 9 * Modification History: |
| 10 * |
| 11 * Date Name Description |
| 12 * 12/05/96 clhuang Creation. |
| 13 * 04/21/97 aliu Fixed miscellaneous bugs found by inspection and |
| 14 * testing. |
| 15 * 07/29/97 aliu Ported source bodies back from Java version with |
| 16 * numerous feature enhancements and bug fixes. |
| 17 * 08/10/98 stephen JDK 1.2 sync. |
| 18 * 09/17/98 stephen Fixed getOffset() for last hour of year and DST |
| 19 * 12/02/99 aliu Added TimeMode and constructor and setStart/EndRule |
| 20 * methods that take TimeMode. Whitespace cleanup. |
| 21 *******************************************************************************
* |
| 22 */ |
| 23 |
| 24 #include <typeinfo> // for 'typeid' to work |
| 25 |
| 26 #include "unicode/utypes.h" |
| 27 |
| 28 #if !UCONFIG_NO_FORMATTING |
| 29 |
| 30 #include "unicode/simpletz.h" |
| 31 #include "unicode/gregocal.h" |
| 32 #include "unicode/smpdtfmt.h" |
| 33 |
| 34 #include "gregoimp.h" |
| 35 |
| 36 U_NAMESPACE_BEGIN |
| 37 |
| 38 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleTimeZone) |
| 39 |
| 40 // Use only for decodeStartRule() and decodeEndRule() where the year is not |
| 41 // available. Set February to 29 days to accomodate rules with that date |
| 42 // and day-of-week-on-or-before-that-date mode (DOW_LE_DOM_MODE). |
| 43 // The compareToRule() method adjusts to February 28 in non-leap years. |
| 44 // |
| 45 // For actual getOffset() calculations, use Grego::monthLength() and |
| 46 // Grego::previousMonthLength() which take leap years into account. |
| 47 // We handle leap years assuming always |
| 48 // Gregorian, since we know they didn't have daylight time when |
| 49 // Gregorian calendar started. |
| 50 const int8_t SimpleTimeZone::STATICMONTHLENGTH[] = {31,29,31,30,31,30,31,31,30,3
1,30,31}; |
| 51 |
| 52 static const UChar DST_STR[] = {0x0028,0x0044,0x0053,0x0054,0x0029,0}; // "(DST)
" |
| 53 static const UChar STD_STR[] = {0x0028,0x0053,0x0054,0x0044,0x0029,0}; // "(STD)
" |
| 54 |
| 55 |
| 56 // ***************************************************************************** |
| 57 // class SimpleTimeZone |
| 58 // ***************************************************************************** |
| 59 |
| 60 |
| 61 SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID) |
| 62 : BasicTimeZone(ID), |
| 63 startMonth(0), |
| 64 startDay(0), |
| 65 startDayOfWeek(0), |
| 66 startTime(0), |
| 67 startTimeMode(WALL_TIME), |
| 68 endTimeMode(WALL_TIME), |
| 69 endMonth(0), |
| 70 endDay(0), |
| 71 endDayOfWeek(0), |
| 72 endTime(0), |
| 73 startYear(0), |
| 74 rawOffset(rawOffsetGMT), |
| 75 useDaylight(FALSE), |
| 76 startMode(DOM_MODE), |
| 77 endMode(DOM_MODE), |
| 78 dstSavings(U_MILLIS_PER_HOUR) |
| 79 { |
| 80 clearTransitionRules(); |
| 81 } |
| 82 |
| 83 // ------------------------------------- |
| 84 |
| 85 SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID, |
| 86 int8_t savingsStartMonth, int8_t savingsStartDay, |
| 87 int8_t savingsStartDayOfWeek, int32_t savingsStartTime, |
| 88 int8_t savingsEndMonth, int8_t savingsEndDay, |
| 89 int8_t savingsEndDayOfWeek, int32_t savingsEndTime, |
| 90 UErrorCode& status) |
| 91 : BasicTimeZone(ID) |
| 92 { |
| 93 clearTransitionRules(); |
| 94 construct(rawOffsetGMT, |
| 95 savingsStartMonth, savingsStartDay, savingsStartDayOfWeek, |
| 96 savingsStartTime, WALL_TIME, |
| 97 savingsEndMonth, savingsEndDay, savingsEndDayOfWeek, |
| 98 savingsEndTime, WALL_TIME, |
| 99 U_MILLIS_PER_HOUR, status); |
| 100 } |
| 101 |
| 102 // ------------------------------------- |
| 103 |
| 104 SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID, |
| 105 int8_t savingsStartMonth, int8_t savingsStartDay, |
| 106 int8_t savingsStartDayOfWeek, int32_t savingsStartTime, |
| 107 int8_t savingsEndMonth, int8_t savingsEndDay, |
| 108 int8_t savingsEndDayOfWeek, int32_t savingsEndTime, |
| 109 int32_t savingsDST, UErrorCode& status) |
| 110 : BasicTimeZone(ID) |
| 111 { |
| 112 clearTransitionRules(); |
| 113 construct(rawOffsetGMT, |
| 114 savingsStartMonth, savingsStartDay, savingsStartDayOfWeek, |
| 115 savingsStartTime, WALL_TIME, |
| 116 savingsEndMonth, savingsEndDay, savingsEndDayOfWeek, |
| 117 savingsEndTime, WALL_TIME, |
| 118 savingsDST, status); |
| 119 } |
| 120 |
| 121 // ------------------------------------- |
| 122 |
| 123 SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID, |
| 124 int8_t savingsStartMonth, int8_t savingsStartDay, |
| 125 int8_t savingsStartDayOfWeek, int32_t savingsStartTime, |
| 126 TimeMode savingsStartTimeMode, |
| 127 int8_t savingsEndMonth, int8_t savingsEndDay, |
| 128 int8_t savingsEndDayOfWeek, int32_t savingsEndTime, |
| 129 TimeMode savingsEndTimeMode, |
| 130 int32_t savingsDST, UErrorCode& status) |
| 131 : BasicTimeZone(ID) |
| 132 { |
| 133 clearTransitionRules(); |
| 134 construct(rawOffsetGMT, |
| 135 savingsStartMonth, savingsStartDay, savingsStartDayOfWeek, |
| 136 savingsStartTime, savingsStartTimeMode, |
| 137 savingsEndMonth, savingsEndDay, savingsEndDayOfWeek, |
| 138 savingsEndTime, savingsEndTimeMode, |
| 139 savingsDST, status); |
| 140 } |
| 141 |
| 142 /** |
| 143 * Internal construction method. |
| 144 */ |
| 145 void SimpleTimeZone::construct(int32_t rawOffsetGMT, |
| 146 int8_t savingsStartMonth, |
| 147 int8_t savingsStartDay, |
| 148 int8_t savingsStartDayOfWeek, |
| 149 int32_t savingsStartTime, |
| 150 TimeMode savingsStartTimeMode, |
| 151 int8_t savingsEndMonth, |
| 152 int8_t savingsEndDay, |
| 153 int8_t savingsEndDayOfWeek, |
| 154 int32_t savingsEndTime, |
| 155 TimeMode savingsEndTimeMode, |
| 156 int32_t savingsDST, |
| 157 UErrorCode& status) |
| 158 { |
| 159 this->rawOffset = rawOffsetGMT; |
| 160 this->startMonth = savingsStartMonth; |
| 161 this->startDay = savingsStartDay; |
| 162 this->startDayOfWeek = savingsStartDayOfWeek; |
| 163 this->startTime = savingsStartTime; |
| 164 this->startTimeMode = savingsStartTimeMode; |
| 165 this->endMonth = savingsEndMonth; |
| 166 this->endDay = savingsEndDay; |
| 167 this->endDayOfWeek = savingsEndDayOfWeek; |
| 168 this->endTime = savingsEndTime; |
| 169 this->endTimeMode = savingsEndTimeMode; |
| 170 this->dstSavings = savingsDST; |
| 171 this->startYear = 0; |
| 172 this->startMode = DOM_MODE; |
| 173 this->endMode = DOM_MODE; |
| 174 |
| 175 decodeRules(status); |
| 176 |
| 177 if (savingsDST <= 0) { |
| 178 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 179 } |
| 180 } |
| 181 |
| 182 // ------------------------------------- |
| 183 |
| 184 SimpleTimeZone::~SimpleTimeZone() |
| 185 { |
| 186 deleteTransitionRules(); |
| 187 } |
| 188 |
| 189 // ------------------------------------- |
| 190 |
| 191 // Called by TimeZone::createDefault(), then clone() inside a Mutex - be careful
. |
| 192 SimpleTimeZone::SimpleTimeZone(const SimpleTimeZone &source) |
| 193 : BasicTimeZone(source) |
| 194 { |
| 195 *this = source; |
| 196 } |
| 197 |
| 198 // ------------------------------------- |
| 199 |
| 200 // Called by TimeZone::createDefault(), then clone() inside a Mutex - be careful
. |
| 201 SimpleTimeZone & |
| 202 SimpleTimeZone::operator=(const SimpleTimeZone &right) |
| 203 { |
| 204 if (this != &right) |
| 205 { |
| 206 TimeZone::operator=(right); |
| 207 rawOffset = right.rawOffset; |
| 208 startMonth = right.startMonth; |
| 209 startDay = right.startDay; |
| 210 startDayOfWeek = right.startDayOfWeek; |
| 211 startTime = right.startTime; |
| 212 startTimeMode = right.startTimeMode; |
| 213 startMode = right.startMode; |
| 214 endMonth = right.endMonth; |
| 215 endDay = right.endDay; |
| 216 endDayOfWeek = right.endDayOfWeek; |
| 217 endTime = right.endTime; |
| 218 endTimeMode = right.endTimeMode; |
| 219 endMode = right.endMode; |
| 220 startYear = right.startYear; |
| 221 dstSavings = right.dstSavings; |
| 222 useDaylight = right.useDaylight; |
| 223 clearTransitionRules(); |
| 224 } |
| 225 return *this; |
| 226 } |
| 227 |
| 228 // ------------------------------------- |
| 229 |
| 230 UBool |
| 231 SimpleTimeZone::operator==(const TimeZone& that) const |
| 232 { |
| 233 return ((this == &that) || |
| 234 (typeid(*this) == typeid(that) && |
| 235 TimeZone::operator==(that) && |
| 236 hasSameRules(that))); |
| 237 } |
| 238 |
| 239 // ------------------------------------- |
| 240 |
| 241 // Called by TimeZone::createDefault() inside a Mutex - be careful. |
| 242 TimeZone* |
| 243 SimpleTimeZone::clone() const |
| 244 { |
| 245 return new SimpleTimeZone(*this); |
| 246 } |
| 247 |
| 248 // ------------------------------------- |
| 249 |
| 250 /** |
| 251 * Sets the daylight savings starting year, that is, the year this time zone beg
an |
| 252 * observing its specified daylight savings time rules. The time zone is consid
ered |
| 253 * not to observe daylight savings time prior to that year; SimpleTimeZone doesn
't |
| 254 * support historical daylight-savings-time rules. |
| 255 * @param year the daylight savings starting year. |
| 256 */ |
| 257 void |
| 258 SimpleTimeZone::setStartYear(int32_t year) |
| 259 { |
| 260 startYear = year; |
| 261 transitionRulesInitialized = FALSE; |
| 262 } |
| 263 |
| 264 // ------------------------------------- |
| 265 |
| 266 /** |
| 267 * Sets the daylight savings starting rule. For example, in the U.S., Daylight S
avings |
| 268 * Time starts at the first Sunday in April, at 2 AM in standard time. |
| 269 * Therefore, you can set the start rule by calling: |
| 270 * setStartRule(TimeFields.APRIL, 1, TimeFields.SUNDAY, 2*60*60*1000); |
| 271 * The dayOfWeekInMonth and dayOfWeek parameters together specify how to calcula
te |
| 272 * the exact starting date. Their exact meaning depend on their respective sign
s, |
| 273 * allowing various types of rules to be constructed, as follows:<ul> |
| 274 * <li>If both dayOfWeekInMonth and dayOfWeek are positive, they specify the |
| 275 * day of week in the month (e.g., (2, WEDNESDAY) is the second Wednesday |
| 276 * of the month). |
| 277 * <li>If dayOfWeek is positive and dayOfWeekInMonth is negative, they specify |
| 278 * the day of week in the month counting backward from the end of the mont
h. |
| 279 * (e.g., (-1, MONDAY) is the last Monday in the month) |
| 280 * <li>If dayOfWeek is zero and dayOfWeekInMonth is positive, dayOfWeekInMonth |
| 281 * specifies the day of the month, regardless of what day of the week it i
s. |
| 282 * (e.g., (10, 0) is the tenth day of the month) |
| 283 * <li>If dayOfWeek is zero and dayOfWeekInMonth is negative, dayOfWeekInMonth |
| 284 * specifies the day of the month counting backward from the end of the |
| 285 * month, regardless of what day of the week it is (e.g., (-2, 0) is the |
| 286 * next-to-last day of the month). |
| 287 * <li>If dayOfWeek is negative and dayOfWeekInMonth is positive, they specify
the |
| 288 * first specified day of the week on or after the specfied day of the mon
th. |
| 289 * (e.g., (15, -SUNDAY) is the first Sunday after the 15th of the month |
| 290 * [or the 15th itself if the 15th is a Sunday].) |
| 291 * <li>If dayOfWeek and DayOfWeekInMonth are both negative, they specify the |
| 292 * last specified day of the week on or before the specified day of the mo
nth. |
| 293 * (e.g., (-20, -TUESDAY) is the last Tuesday before the 20th of the month |
| 294 * [or the 20th itself if the 20th is a Tuesday].)</ul> |
| 295 * @param month the daylight savings starting month. Month is 0-based. |
| 296 * eg, 0 for January. |
| 297 * @param dayOfWeekInMonth the daylight savings starting |
| 298 * day-of-week-in-month. Please see the member description for an example. |
| 299 * @param dayOfWeek the daylight savings starting day-of-week. Please see |
| 300 * the member description for an example. |
| 301 * @param time the daylight savings starting time. Please see the member |
| 302 * description for an example. |
| 303 */ |
| 304 |
| 305 void |
| 306 SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfWeekInMonth, int32_t da
yOfWeek, |
| 307 int32_t time, TimeMode mode, UErrorCode& status) |
| 308 { |
| 309 startMonth = (int8_t)month; |
| 310 startDay = (int8_t)dayOfWeekInMonth; |
| 311 startDayOfWeek = (int8_t)dayOfWeek; |
| 312 startTime = time; |
| 313 startTimeMode = mode; |
| 314 decodeStartRule(status); |
| 315 transitionRulesInitialized = FALSE; |
| 316 } |
| 317 |
| 318 // ------------------------------------- |
| 319 |
| 320 void |
| 321 SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfMonth, |
| 322 int32_t time, TimeMode mode, UErrorCode& status) |
| 323 { |
| 324 setStartRule(month, dayOfMonth, 0, time, mode, status); |
| 325 } |
| 326 |
| 327 // ------------------------------------- |
| 328 |
| 329 void |
| 330 SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWee
k, |
| 331 int32_t time, TimeMode mode, UBool after, UErrorCod
e& status) |
| 332 { |
| 333 setStartRule(month, after ? dayOfMonth : -dayOfMonth, |
| 334 -dayOfWeek, time, mode, status); |
| 335 } |
| 336 |
| 337 // ------------------------------------- |
| 338 |
| 339 /** |
| 340 * Sets the daylight savings ending rule. For example, in the U.S., Daylight |
| 341 * Savings Time ends at the last (-1) Sunday in October, at 2 AM in standard tim
e. |
| 342 * Therefore, you can set the end rule by calling: |
| 343 * setEndRule(TimeFields.OCTOBER, -1, TimeFields.SUNDAY, 2*60*60*1000); |
| 344 * Various other types of rules can be specified by manipulating the dayOfWeek |
| 345 * and dayOfWeekInMonth parameters. For complete details, see the documentation |
| 346 * for setStartRule(). |
| 347 * @param month the daylight savings ending month. Month is 0-based. |
| 348 * eg, 0 for January. |
| 349 * @param dayOfWeekInMonth the daylight savings ending |
| 350 * day-of-week-in-month. See setStartRule() for a complete explanation. |
| 351 * @param dayOfWeek the daylight savings ending day-of-week. See setStartRule() |
| 352 * for a complete explanation. |
| 353 * @param time the daylight savings ending time. Please see the member |
| 354 * description for an example. |
| 355 */ |
| 356 |
| 357 void |
| 358 SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfWeekInMonth, int32_t dayO
fWeek, |
| 359 int32_t time, TimeMode mode, UErrorCode& status) |
| 360 { |
| 361 endMonth = (int8_t)month; |
| 362 endDay = (int8_t)dayOfWeekInMonth; |
| 363 endDayOfWeek = (int8_t)dayOfWeek; |
| 364 endTime = time; |
| 365 endTimeMode = mode; |
| 366 decodeEndRule(status); |
| 367 transitionRulesInitialized = FALSE; |
| 368 } |
| 369 |
| 370 // ------------------------------------- |
| 371 |
| 372 void |
| 373 SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfMonth, |
| 374 int32_t time, TimeMode mode, UErrorCode& status) |
| 375 { |
| 376 setEndRule(month, dayOfMonth, 0, time, mode, status); |
| 377 } |
| 378 |
| 379 // ------------------------------------- |
| 380 |
| 381 void |
| 382 SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
|
| 383 int32_t time, TimeMode mode, UBool after, UErrorCode&
status) |
| 384 { |
| 385 setEndRule(month, after ? dayOfMonth : -dayOfMonth, |
| 386 -dayOfWeek, time, mode, status); |
| 387 } |
| 388 |
| 389 // ------------------------------------- |
| 390 |
| 391 int32_t |
| 392 SimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day, |
| 393 uint8_t dayOfWeek, int32_t millis, UErrorCode& status)
const |
| 394 { |
| 395 // Check the month before calling Grego::monthLength(). This |
| 396 // duplicates the test that occurs in the 7-argument getOffset(), |
| 397 // however, this is unavoidable. We don't mind because this method, in |
| 398 // fact, should not be called; internal code should always call the |
| 399 // 7-argument getOffset(), and outside code should use Calendar.get(int |
| 400 // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of |
| 401 // this method because it's public API. - liu 8/10/98 |
| 402 if(month < UCAL_JANUARY || month > UCAL_DECEMBER) { |
| 403 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 404 return 0; |
| 405 } |
| 406 |
| 407 return getOffset(era, year, month, day, dayOfWeek, millis, Grego::monthLengt
h(year, month), status); |
| 408 } |
| 409 |
| 410 int32_t |
| 411 SimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day, |
| 412 uint8_t dayOfWeek, int32_t millis, |
| 413 int32_t /*monthLength*/, UErrorCode& status) const |
| 414 { |
| 415 // Check the month before calling Grego::monthLength(). This |
| 416 // duplicates a test that occurs in the 9-argument getOffset(), |
| 417 // however, this is unavoidable. We don't mind because this method, in |
| 418 // fact, should not be called; internal code should always call the |
| 419 // 9-argument getOffset(), and outside code should use Calendar.get(int |
| 420 // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of |
| 421 // this method because it's public API. - liu 8/10/98 |
| 422 if (month < UCAL_JANUARY |
| 423 || month > UCAL_DECEMBER) { |
| 424 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 425 return -1; |
| 426 } |
| 427 |
| 428 // We ignore monthLength because it can be derived from year and month. |
| 429 // This is so that February in leap years is calculated correctly. |
| 430 // We keep this argument in this function for backwards compatibility. |
| 431 return getOffset(era, year, month, day, dayOfWeek, millis, |
| 432 Grego::monthLength(year, month), |
| 433 Grego::previousMonthLength(year, month), |
| 434 status); |
| 435 } |
| 436 |
| 437 int32_t |
| 438 SimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day, |
| 439 uint8_t dayOfWeek, int32_t millis, |
| 440 int32_t monthLength, int32_t prevMonthLength, |
| 441 UErrorCode& status) const |
| 442 { |
| 443 if(U_FAILURE(status)) return 0; |
| 444 |
| 445 if ((era != GregorianCalendar::AD && era != GregorianCalendar::BC) |
| 446 || month < UCAL_JANUARY |
| 447 || month > UCAL_DECEMBER |
| 448 || day < 1 |
| 449 || day > monthLength |
| 450 || dayOfWeek < UCAL_SUNDAY |
| 451 || dayOfWeek > UCAL_SATURDAY |
| 452 || millis < 0 |
| 453 || millis >= U_MILLIS_PER_DAY |
| 454 || monthLength < 28 |
| 455 || monthLength > 31 |
| 456 || prevMonthLength < 28 |
| 457 || prevMonthLength > 31) { |
| 458 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 459 return -1; |
| 460 } |
| 461 |
| 462 int32_t result = rawOffset; |
| 463 |
| 464 // Bail out if we are before the onset of daylight savings time |
| 465 if(!useDaylight || year < startYear || era != GregorianCalendar::AD) |
| 466 return result; |
| 467 |
| 468 // Check for southern hemisphere. We assume that the start and end |
| 469 // month are different. |
| 470 UBool southern = (startMonth > endMonth); |
| 471 |
| 472 // Compare the date to the starting and ending rules.+1 = date>rule, -1 |
| 473 // = date<rule, 0 = date==rule. |
| 474 int32_t startCompare = compareToRule((int8_t)month, (int8_t)monthLength, (in
t8_t)prevMonthLength, |
| 475 (int8_t)day, (int8_t)dayOfWeek, millis, |
| 476 startTimeMode == UTC_TIME ? -rawOffset
: 0, |
| 477 startMode, (int8_t)startMonth, (int8_t)
startDayOfWeek, |
| 478 (int8_t)startDay, startTime); |
| 479 int32_t endCompare = 0; |
| 480 |
| 481 /* We don't always have to compute endCompare. For many instances, |
| 482 * startCompare is enough to determine if we are in DST or not. In the |
| 483 * northern hemisphere, if we are before the start rule, we can't have |
| 484 * DST. In the southern hemisphere, if we are after the start rule, we |
| 485 * must have DST. This is reflected in the way the next if statement |
| 486 * (not the one immediately following) short circuits. */ |
| 487 if(southern != (startCompare >= 0)) { |
| 488 endCompare = compareToRule((int8_t)month, (int8_t)monthLength, (int8_t)p
revMonthLength, |
| 489 (int8_t)day, (int8_t)dayOfWeek, millis, |
| 490 endTimeMode == WALL_TIME ? dstSavings : |
| 491 (endTimeMode == UTC_TIME ? -rawOffset : 0), |
| 492 endMode, (int8_t)endMonth, (int8_t)endDayOfWe
ek, |
| 493 (int8_t)endDay, endTime); |
| 494 } |
| 495 |
| 496 // Check for both the northern and southern hemisphere cases. We |
| 497 // assume that in the northern hemisphere, the start rule is before the |
| 498 // end rule within the calendar year, and vice versa for the southern |
| 499 // hemisphere. |
| 500 if ((!southern && (startCompare >= 0 && endCompare < 0)) || |
| 501 (southern && (startCompare >= 0 || endCompare < 0))) |
| 502 result += dstSavings; |
| 503 |
| 504 return result; |
| 505 } |
| 506 |
| 507 void |
| 508 SimpleTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32
_t duplicatedTimeOpt, |
| 509 int32_t& rawOffsetGMT, int32_t& savingsDST, U
ErrorCode& status) /*const*/ { |
| 510 if (U_FAILURE(status)) { |
| 511 return; |
| 512 } |
| 513 |
| 514 rawOffsetGMT = getRawOffset(); |
| 515 int32_t year, month, dom, dow; |
| 516 double day = uprv_floor(date / U_MILLIS_PER_DAY); |
| 517 int32_t millis = (int32_t) (date - day * U_MILLIS_PER_DAY); |
| 518 |
| 519 Grego::dayToFields(day, year, month, dom, dow); |
| 520 |
| 521 savingsDST = getOffset(GregorianCalendar::AD, year, month, dom, |
| 522 (uint8_t) dow, millis, |
| 523 Grego::monthLength(year, month), |
| 524 status) - rawOffsetGMT; |
| 525 if (U_FAILURE(status)) { |
| 526 return; |
| 527 } |
| 528 |
| 529 UBool recalc = FALSE; |
| 530 |
| 531 // Now we need some adjustment |
| 532 if (savingsDST > 0) { |
| 533 if ((nonExistingTimeOpt & kStdDstMask) == kStandard |
| 534 || ((nonExistingTimeOpt & kStdDstMask) != kDaylight && (nonExistingT
imeOpt & kFormerLatterMask) != kLatter)) { |
| 535 date -= getDSTSavings(); |
| 536 recalc = TRUE; |
| 537 } |
| 538 } else { |
| 539 if ((duplicatedTimeOpt & kStdDstMask) == kDaylight |
| 540 || ((duplicatedTimeOpt & kStdDstMask) != kStandard && (duplicate
dTimeOpt & kFormerLatterMask) == kFormer)) { |
| 541 date -= getDSTSavings(); |
| 542 recalc = TRUE; |
| 543 } |
| 544 } |
| 545 if (recalc) { |
| 546 day = uprv_floor(date / U_MILLIS_PER_DAY); |
| 547 millis = (int32_t) (date - day * U_MILLIS_PER_DAY); |
| 548 Grego::dayToFields(day, year, month, dom, dow); |
| 549 savingsDST = getOffset(GregorianCalendar::AD, year, month, dom, |
| 550 (uint8_t) dow, millis, |
| 551 Grego::monthLength(year, month), |
| 552 status) - rawOffsetGMT; |
| 553 } |
| 554 } |
| 555 |
| 556 // ------------------------------------- |
| 557 |
| 558 /** |
| 559 * Compare a given date in the year to a rule. Return 1, 0, or -1, depending |
| 560 * on whether the date is after, equal to, or before the rule date. The |
| 561 * millis are compared directly against the ruleMillis, so any |
| 562 * standard-daylight adjustments must be handled by the caller. |
| 563 * |
| 564 * @return 1 if the date is after the rule date, -1 if the date is before |
| 565 * the rule date, or 0 if the date is equal to the rule date. |
| 566 */ |
| 567 int32_t |
| 568 SimpleTimeZone::compareToRule(int8_t month, int8_t monthLen, int8_t prevMonthLen
, |
| 569 int8_t dayOfMonth, |
| 570 int8_t dayOfWeek, int32_t millis, int32_t millisDe
lta, |
| 571 EMode ruleMode, int8_t ruleMonth, int8_t ruleDayOf
Week, |
| 572 int8_t ruleDay, int32_t ruleMillis) |
| 573 { |
| 574 // Make adjustments for startTimeMode and endTimeMode |
| 575 millis += millisDelta; |
| 576 while (millis >= U_MILLIS_PER_DAY) { |
| 577 millis -= U_MILLIS_PER_DAY; |
| 578 ++dayOfMonth; |
| 579 dayOfWeek = (int8_t)(1 + (dayOfWeek % 7)); // dayOfWeek is one-based |
| 580 if (dayOfMonth > monthLen) { |
| 581 dayOfMonth = 1; |
| 582 /* When incrementing the month, it is desirible to overflow |
| 583 * from DECEMBER to DECEMBER+1, since we use the result to |
| 584 * compare against a real month. Wraparound of the value |
| 585 * leads to bug 4173604. */ |
| 586 ++month; |
| 587 } |
| 588 } |
| 589 while (millis < 0) { |
| 590 millis += U_MILLIS_PER_DAY; |
| 591 --dayOfMonth; |
| 592 dayOfWeek = (int8_t)(1 + ((dayOfWeek+5) % 7)); // dayOfWeek is one-based |
| 593 if (dayOfMonth < 1) { |
| 594 dayOfMonth = prevMonthLen; |
| 595 --month; |
| 596 } |
| 597 } |
| 598 |
| 599 // first compare months. If they're different, we don't have to worry about
days |
| 600 // and times |
| 601 if (month < ruleMonth) return -1; |
| 602 else if (month > ruleMonth) return 1; |
| 603 |
| 604 // calculate the actual day of month for the rule |
| 605 int32_t ruleDayOfMonth = 0; |
| 606 |
| 607 // Adjust the ruleDay to the monthLen, for non-leap year February 29 rule da
ys. |
| 608 if (ruleDay > monthLen) { |
| 609 ruleDay = monthLen; |
| 610 } |
| 611 |
| 612 switch (ruleMode) |
| 613 { |
| 614 // if the mode is day-of-month, the day of month is given |
| 615 case DOM_MODE: |
| 616 ruleDayOfMonth = ruleDay; |
| 617 break; |
| 618 |
| 619 // if the mode is day-of-week-in-month, calculate the day-of-month from it |
| 620 case DOW_IN_MONTH_MODE: |
| 621 // In this case ruleDay is the day-of-week-in-month (this code is using |
| 622 // the dayOfWeek and dayOfMonth parameters to figure out the day-of-week |
| 623 // of the first day of the month, so it's trusting that they're really |
| 624 // consistent with each other) |
| 625 if (ruleDay > 0) |
| 626 ruleDayOfMonth = 1 + (ruleDay - 1) * 7 + |
| 627 (7 + ruleDayOfWeek - (dayOfWeek - dayOfMonth + 1)) % 7; |
| 628 |
| 629 // if ruleDay is negative (we assume it's not zero here), we have to do |
| 630 // the same calculation figuring backward from the last day of the month
. |
| 631 else |
| 632 { |
| 633 // (again, this code is trusting that dayOfWeek and dayOfMonth are |
| 634 // consistent with each other here, since we're using them to figure |
| 635 // the day of week of the first of the month) |
| 636 ruleDayOfMonth = monthLen + (ruleDay + 1) * 7 - |
| 637 (7 + (dayOfWeek + monthLen - dayOfMonth) - ruleDayOfWeek) % 7; |
| 638 } |
| 639 break; |
| 640 |
| 641 case DOW_GE_DOM_MODE: |
| 642 ruleDayOfMonth = ruleDay + |
| 643 (49 + ruleDayOfWeek - ruleDay - dayOfWeek + dayOfMonth) % 7; |
| 644 break; |
| 645 |
| 646 case DOW_LE_DOM_MODE: |
| 647 ruleDayOfMonth = ruleDay - |
| 648 (49 - ruleDayOfWeek + ruleDay + dayOfWeek - dayOfMonth) % 7; |
| 649 // Note at this point ruleDayOfMonth may be <1, although it will |
| 650 // be >=1 for well-formed rules. |
| 651 break; |
| 652 } |
| 653 |
| 654 // now that we have a real day-in-month for the rule, we can compare days... |
| 655 if (dayOfMonth < ruleDayOfMonth) return -1; |
| 656 else if (dayOfMonth > ruleDayOfMonth) return 1; |
| 657 |
| 658 // ...and if they're equal, we compare times |
| 659 if (millis < ruleMillis) return -1; |
| 660 else if (millis > ruleMillis) return 1; |
| 661 else return 0; |
| 662 } |
| 663 |
| 664 // ------------------------------------- |
| 665 |
| 666 int32_t |
| 667 SimpleTimeZone::getRawOffset() const |
| 668 { |
| 669 return rawOffset; |
| 670 } |
| 671 |
| 672 // ------------------------------------- |
| 673 |
| 674 void |
| 675 SimpleTimeZone::setRawOffset(int32_t offsetMillis) |
| 676 { |
| 677 rawOffset = offsetMillis; |
| 678 transitionRulesInitialized = FALSE; |
| 679 } |
| 680 |
| 681 // ------------------------------------- |
| 682 |
| 683 void |
| 684 SimpleTimeZone::setDSTSavings(int32_t millisSavedDuringDST, UErrorCode& status) |
| 685 { |
| 686 if (millisSavedDuringDST <= 0) { |
| 687 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 688 } |
| 689 else { |
| 690 dstSavings = millisSavedDuringDST; |
| 691 } |
| 692 transitionRulesInitialized = FALSE; |
| 693 } |
| 694 |
| 695 // ------------------------------------- |
| 696 |
| 697 int32_t |
| 698 SimpleTimeZone::getDSTSavings() const |
| 699 { |
| 700 return dstSavings; |
| 701 } |
| 702 |
| 703 // ------------------------------------- |
| 704 |
| 705 UBool |
| 706 SimpleTimeZone::useDaylightTime() const |
| 707 { |
| 708 return useDaylight; |
| 709 } |
| 710 |
| 711 // ------------------------------------- |
| 712 |
| 713 /** |
| 714 * Overrides TimeZone |
| 715 * Queries if the given date is in Daylight Savings Time. |
| 716 */ |
| 717 UBool SimpleTimeZone::inDaylightTime(UDate date, UErrorCode& status) const |
| 718 { |
| 719 // This method is wasteful since it creates a new GregorianCalendar and |
| 720 // deletes it each time it is called. However, this is a deprecated method |
| 721 // and provided only for Java compatibility as of 8/6/97 [LIU]. |
| 722 if (U_FAILURE(status)) return FALSE; |
| 723 GregorianCalendar *gc = new GregorianCalendar(*this, status); |
| 724 /* test for NULL */ |
| 725 if (gc == 0) { |
| 726 status = U_MEMORY_ALLOCATION_ERROR; |
| 727 return FALSE; |
| 728 } |
| 729 gc->setTime(date, status); |
| 730 UBool result = gc->inDaylightTime(status); |
| 731 delete gc; |
| 732 return result; |
| 733 } |
| 734 |
| 735 // ------------------------------------- |
| 736 |
| 737 /** |
| 738 * Return true if this zone has the same rules and offset as another zone. |
| 739 * @param other the TimeZone object to be compared with |
| 740 * @return true if the given zone has the same rules and offset as this one |
| 741 */ |
| 742 UBool |
| 743 SimpleTimeZone::hasSameRules(const TimeZone& other) const |
| 744 { |
| 745 if (this == &other) return TRUE; |
| 746 if (typeid(*this) != typeid(other)) return FALSE; |
| 747 SimpleTimeZone *that = (SimpleTimeZone*)&other; |
| 748 return rawOffset == that->rawOffset && |
| 749 useDaylight == that->useDaylight && |
| 750 (!useDaylight |
| 751 // Only check rules if using DST |
| 752 || (dstSavings == that->dstSavings && |
| 753 startMode == that->startMode && |
| 754 startMonth == that->startMonth && |
| 755 startDay == that->startDay && |
| 756 startDayOfWeek == that->startDayOfWeek && |
| 757 startTime == that->startTime && |
| 758 startTimeMode == that->startTimeMode && |
| 759 endMode == that->endMode && |
| 760 endMonth == that->endMonth && |
| 761 endDay == that->endDay && |
| 762 endDayOfWeek == that->endDayOfWeek && |
| 763 endTime == that->endTime && |
| 764 endTimeMode == that->endTimeMode && |
| 765 startYear == that->startYear)); |
| 766 } |
| 767 |
| 768 // ------------------------------------- |
| 769 |
| 770 //---------------------------------------------------------------------- |
| 771 // Rule representation |
| 772 // |
| 773 // We represent the following flavors of rules: |
| 774 // 5 the fifth of the month |
| 775 // lastSun the last Sunday in the month |
| 776 // lastMon the last Monday in the month |
| 777 // Sun>=8 first Sunday on or after the eighth |
| 778 // Sun<=25 last Sunday on or before the 25th |
| 779 // This is further complicated by the fact that we need to remain |
| 780 // backward compatible with the 1.1 FCS. Finally, we need to minimize |
| 781 // API changes. In order to satisfy these requirements, we support |
| 782 // three representation systems, and we translate between them. |
| 783 // |
| 784 // INTERNAL REPRESENTATION |
| 785 // This is the format SimpleTimeZone objects take after construction or |
| 786 // streaming in is complete. Rules are represented directly, using an |
| 787 // unencoded format. We will discuss the start rule only below; the end |
| 788 // rule is analogous. |
| 789 // startMode Takes on enumerated values DAY_OF_MONTH, |
| 790 // DOW_IN_MONTH, DOW_AFTER_DOM, or DOW_BEFORE_DOM. |
| 791 // startDay The day of the month, or for DOW_IN_MONTH mode, a |
| 792 // value indicating which DOW, such as +1 for first, |
| 793 // +2 for second, -1 for last, etc. |
| 794 // startDayOfWeek The day of the week. Ignored for DAY_OF_MONTH. |
| 795 // |
| 796 // ENCODED REPRESENTATION |
| 797 // This is the format accepted by the constructor and by setStartRule() |
| 798 // and setEndRule(). It uses various combinations of positive, negative, |
| 799 // and zero values to encode the different rules. This representation |
| 800 // allows us to specify all the different rule flavors without altering |
| 801 // the API. |
| 802 // MODE startMonth startDay startDayOfWeek |
| 803 // DOW_IN_MONTH_MODE >=0 !=0 >0 |
| 804 // DOM_MODE >=0 >0 ==0 |
| 805 // DOW_GE_DOM_MODE >=0 >0 <0 |
| 806 // DOW_LE_DOM_MODE >=0 <0 <0 |
| 807 // (no DST) don't care ==0 don't care |
| 808 // |
| 809 // STREAMED REPRESENTATION |
| 810 // We must retain binary compatibility with the 1.1 FCS. The 1.1 code only |
| 811 // handles DOW_IN_MONTH_MODE and non-DST mode, the latter indicated by the |
| 812 // flag useDaylight. When we stream an object out, we translate into an |
| 813 // approximate DOW_IN_MONTH_MODE representation so the object can be parsed |
| 814 // and used by 1.1 code. Following that, we write out the full |
| 815 // representation separately so that contemporary code can recognize and |
| 816 // parse it. The full representation is written in a "packed" format, |
| 817 // consisting of a version number, a length, and an array of bytes. Future |
| 818 // versions of this class may specify different versions. If they wish to |
| 819 // include additional data, they should do so by storing them after the |
| 820 // packed representation below. |
| 821 //---------------------------------------------------------------------- |
| 822 |
| 823 /** |
| 824 * Given a set of encoded rules in startDay and startDayOfMonth, decode |
| 825 * them and set the startMode appropriately. Do the same for endDay and |
| 826 * endDayOfMonth. Upon entry, the day of week variables may be zero or |
| 827 * negative, in order to indicate special modes. The day of month |
| 828 * variables may also be negative. Upon exit, the mode variables will be |
| 829 * set, and the day of week and day of month variables will be positive. |
| 830 * This method also recognizes a startDay or endDay of zero as indicating |
| 831 * no DST. |
| 832 */ |
| 833 void |
| 834 SimpleTimeZone::decodeRules(UErrorCode& status) |
| 835 { |
| 836 decodeStartRule(status); |
| 837 decodeEndRule(status); |
| 838 } |
| 839 |
| 840 /** |
| 841 * Decode the start rule and validate the parameters. The parameters are |
| 842 * expected to be in encoded form, which represents the various rule modes |
| 843 * by negating or zeroing certain values. Representation formats are: |
| 844 * <p> |
| 845 * <pre> |
| 846 * DOW_IN_MONTH DOM DOW>=DOM DOW<=DOM no DST |
| 847 * ------------ ----- -------- -------- ---------- |
| 848 * month 0..11 same same same don't care |
| 849 * day -5..5 1..31 1..31 -1..-31 0 |
| 850 * dayOfWeek 1..7 0 -1..-7 -1..-7 don't care |
| 851 * time 0..ONEDAY same same same don't care |
| 852 * </pre> |
| 853 * The range for month does not include UNDECIMBER since this class is |
| 854 * really specific to GregorianCalendar, which does not use that month. |
| 855 * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the |
| 856 * end rule is an exclusive limit point. That is, the range of times that |
| 857 * are in DST include those >= the start and < the end. For this reason, |
| 858 * it should be possible to specify an end of ONEDAY in order to include the |
| 859 * entire day. Although this is equivalent to time 0 of the following day, |
| 860 * it's not always possible to specify that, for example, on December 31. |
| 861 * While arguably the start range should still be 0..ONEDAY-1, we keep |
| 862 * the start and end ranges the same for consistency. |
| 863 */ |
| 864 void |
| 865 SimpleTimeZone::decodeStartRule(UErrorCode& status) |
| 866 { |
| 867 if(U_FAILURE(status)) return; |
| 868 |
| 869 useDaylight = (UBool)((startDay != 0) && (endDay != 0) ? TRUE : FALSE); |
| 870 if (useDaylight && dstSavings == 0) { |
| 871 dstSavings = U_MILLIS_PER_HOUR; |
| 872 } |
| 873 if (startDay != 0) { |
| 874 if (startMonth < UCAL_JANUARY || startMonth > UCAL_DECEMBER) { |
| 875 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 876 return; |
| 877 } |
| 878 if (startTime < 0 || startTime > U_MILLIS_PER_DAY || |
| 879 startTimeMode < WALL_TIME || startTimeMode > UTC_TIME) { |
| 880 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 881 return; |
| 882 } |
| 883 if (startDayOfWeek == 0) { |
| 884 startMode = DOM_MODE; |
| 885 } else { |
| 886 if (startDayOfWeek > 0) { |
| 887 startMode = DOW_IN_MONTH_MODE; |
| 888 } else { |
| 889 startDayOfWeek = (int8_t)-startDayOfWeek; |
| 890 if (startDay > 0) { |
| 891 startMode = DOW_GE_DOM_MODE; |
| 892 } else { |
| 893 startDay = (int8_t)-startDay; |
| 894 startMode = DOW_LE_DOM_MODE; |
| 895 } |
| 896 } |
| 897 if (startDayOfWeek > UCAL_SATURDAY) { |
| 898 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 899 return; |
| 900 } |
| 901 } |
| 902 if (startMode == DOW_IN_MONTH_MODE) { |
| 903 if (startDay < -5 || startDay > 5) { |
| 904 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 905 return; |
| 906 } |
| 907 } else if (startDay<1 || startDay > STATICMONTHLENGTH[startMonth]) { |
| 908 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 909 return; |
| 910 } |
| 911 } |
| 912 } |
| 913 |
| 914 /** |
| 915 * Decode the end rule and validate the parameters. This method is exactly |
| 916 * analogous to decodeStartRule(). |
| 917 * @see decodeStartRule |
| 918 */ |
| 919 void |
| 920 SimpleTimeZone::decodeEndRule(UErrorCode& status) |
| 921 { |
| 922 if(U_FAILURE(status)) return; |
| 923 |
| 924 useDaylight = (UBool)((startDay != 0) && (endDay != 0) ? TRUE : FALSE); |
| 925 if (useDaylight && dstSavings == 0) { |
| 926 dstSavings = U_MILLIS_PER_HOUR; |
| 927 } |
| 928 if (endDay != 0) { |
| 929 if (endMonth < UCAL_JANUARY || endMonth > UCAL_DECEMBER) { |
| 930 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 931 return; |
| 932 } |
| 933 if (endTime < 0 || endTime > U_MILLIS_PER_DAY || |
| 934 endTimeMode < WALL_TIME || endTimeMode > UTC_TIME) { |
| 935 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 936 return; |
| 937 } |
| 938 if (endDayOfWeek == 0) { |
| 939 endMode = DOM_MODE; |
| 940 } else { |
| 941 if (endDayOfWeek > 0) { |
| 942 endMode = DOW_IN_MONTH_MODE; |
| 943 } else { |
| 944 endDayOfWeek = (int8_t)-endDayOfWeek; |
| 945 if (endDay > 0) { |
| 946 endMode = DOW_GE_DOM_MODE; |
| 947 } else { |
| 948 endDay = (int8_t)-endDay; |
| 949 endMode = DOW_LE_DOM_MODE; |
| 950 } |
| 951 } |
| 952 if (endDayOfWeek > UCAL_SATURDAY) { |
| 953 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 954 return; |
| 955 } |
| 956 } |
| 957 if (endMode == DOW_IN_MONTH_MODE) { |
| 958 if (endDay < -5 || endDay > 5) { |
| 959 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 960 return; |
| 961 } |
| 962 } else if (endDay<1 || endDay > STATICMONTHLENGTH[endMonth]) { |
| 963 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 964 return; |
| 965 } |
| 966 } |
| 967 } |
| 968 |
| 969 UBool |
| 970 SimpleTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransitio
n& result) /*const*/ { |
| 971 if (!useDaylight) { |
| 972 return FALSE; |
| 973 } |
| 974 |
| 975 UErrorCode status = U_ZERO_ERROR; |
| 976 initTransitionRules(status); |
| 977 if (U_FAILURE(status)) { |
| 978 return FALSE; |
| 979 } |
| 980 |
| 981 UDate firstTransitionTime = firstTransition->getTime(); |
| 982 if (base < firstTransitionTime || (inclusive && base == firstTransitionTime)
) { |
| 983 result = *firstTransition; |
| 984 } |
| 985 UDate stdDate, dstDate; |
| 986 UBool stdAvail = stdRule->getNextStart(base, dstRule->getRawOffset(), dstRul
e->getDSTSavings(), inclusive, stdDate); |
| 987 UBool dstAvail = dstRule->getNextStart(base, stdRule->getRawOffset(), stdRul
e->getDSTSavings(), inclusive, dstDate); |
| 988 if (stdAvail && (!dstAvail || stdDate < dstDate)) { |
| 989 result.setTime(stdDate); |
| 990 result.setFrom((const TimeZoneRule&)*dstRule); |
| 991 result.setTo((const TimeZoneRule&)*stdRule); |
| 992 return TRUE; |
| 993 } |
| 994 if (dstAvail && (!stdAvail || dstDate < stdDate)) { |
| 995 result.setTime(dstDate); |
| 996 result.setFrom((const TimeZoneRule&)*stdRule); |
| 997 result.setTo((const TimeZoneRule&)*dstRule); |
| 998 return TRUE; |
| 999 } |
| 1000 return FALSE; |
| 1001 } |
| 1002 |
| 1003 UBool |
| 1004 SimpleTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTrans
ition& result) /*const*/ { |
| 1005 if (!useDaylight) { |
| 1006 return FALSE; |
| 1007 } |
| 1008 |
| 1009 UErrorCode status = U_ZERO_ERROR; |
| 1010 initTransitionRules(status); |
| 1011 if (U_FAILURE(status)) { |
| 1012 return FALSE; |
| 1013 } |
| 1014 |
| 1015 UDate firstTransitionTime = firstTransition->getTime(); |
| 1016 if (base < firstTransitionTime || (!inclusive && base == firstTransitionTime
)) { |
| 1017 return FALSE; |
| 1018 } |
| 1019 UDate stdDate, dstDate; |
| 1020 UBool stdAvail = stdRule->getPreviousStart(base, dstRule->getRawOffset(), ds
tRule->getDSTSavings(), inclusive, stdDate); |
| 1021 UBool dstAvail = dstRule->getPreviousStart(base, stdRule->getRawOffset(), st
dRule->getDSTSavings(), inclusive, dstDate); |
| 1022 if (stdAvail && (!dstAvail || stdDate > dstDate)) { |
| 1023 result.setTime(stdDate); |
| 1024 result.setFrom((const TimeZoneRule&)*dstRule); |
| 1025 result.setTo((const TimeZoneRule&)*stdRule); |
| 1026 return TRUE; |
| 1027 } |
| 1028 if (dstAvail && (!stdAvail || dstDate > stdDate)) { |
| 1029 result.setTime(dstDate); |
| 1030 result.setFrom((const TimeZoneRule&)*stdRule); |
| 1031 result.setTo((const TimeZoneRule&)*dstRule); |
| 1032 return TRUE; |
| 1033 } |
| 1034 return FALSE; |
| 1035 } |
| 1036 |
| 1037 void |
| 1038 SimpleTimeZone::clearTransitionRules(void) { |
| 1039 initialRule = NULL; |
| 1040 firstTransition = NULL; |
| 1041 stdRule = NULL; |
| 1042 dstRule = NULL; |
| 1043 transitionRulesInitialized = FALSE; |
| 1044 } |
| 1045 |
| 1046 void |
| 1047 SimpleTimeZone::deleteTransitionRules(void) { |
| 1048 if (initialRule != NULL) { |
| 1049 delete initialRule; |
| 1050 } |
| 1051 if (firstTransition != NULL) { |
| 1052 delete firstTransition; |
| 1053 } |
| 1054 if (stdRule != NULL) { |
| 1055 delete stdRule; |
| 1056 } |
| 1057 if (dstRule != NULL) { |
| 1058 delete dstRule; |
| 1059 } |
| 1060 clearTransitionRules(); |
| 1061 } |
| 1062 |
| 1063 void |
| 1064 SimpleTimeZone::initTransitionRules(UErrorCode& status) { |
| 1065 if (U_FAILURE(status)) { |
| 1066 return; |
| 1067 } |
| 1068 if (transitionRulesInitialized) { |
| 1069 return; |
| 1070 } |
| 1071 deleteTransitionRules(); |
| 1072 UnicodeString tzid; |
| 1073 getID(tzid); |
| 1074 |
| 1075 if (useDaylight) { |
| 1076 DateTimeRule* dtRule; |
| 1077 DateTimeRule::TimeRuleType timeRuleType; |
| 1078 UDate firstStdStart, firstDstStart; |
| 1079 |
| 1080 // Create a TimeZoneRule for daylight saving time |
| 1081 timeRuleType = (startTimeMode == STANDARD_TIME) ? DateTimeRule::STANDARD
_TIME : |
| 1082 ((startTimeMode == UTC_TIME) ? DateTimeRule::UTC_TIME : DateTimeRule
::WALL_TIME); |
| 1083 switch (startMode) { |
| 1084 case DOM_MODE: |
| 1085 dtRule = new DateTimeRule(startMonth, startDay, startTime, timeRuleT
ype); |
| 1086 break; |
| 1087 case DOW_IN_MONTH_MODE: |
| 1088 dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, star
tTime, timeRuleType); |
| 1089 break; |
| 1090 case DOW_GE_DOM_MODE: |
| 1091 dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, true
, startTime, timeRuleType); |
| 1092 break; |
| 1093 case DOW_LE_DOM_MODE: |
| 1094 dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, fals
e, startTime, timeRuleType); |
| 1095 break; |
| 1096 default: |
| 1097 status = U_INVALID_STATE_ERROR; |
| 1098 return; |
| 1099 } |
| 1100 // Check for Null pointer |
| 1101 if (dtRule == NULL) { |
| 1102 status = U_MEMORY_ALLOCATION_ERROR; |
| 1103 return; |
| 1104 } |
| 1105 // For now, use ID + "(DST)" as the name |
| 1106 dstRule = new AnnualTimeZoneRule(tzid+DST_STR, getRawOffset(), getDSTSav
ings(), |
| 1107 dtRule, startYear, AnnualTimeZoneRule::MAX_YEAR); |
| 1108 |
| 1109 // Check for Null pointer |
| 1110 if (dstRule == NULL) { |
| 1111 status = U_MEMORY_ALLOCATION_ERROR; |
| 1112 deleteTransitionRules(); |
| 1113 return; |
| 1114 } |
| 1115 |
| 1116 // Calculate the first DST start time |
| 1117 dstRule->getFirstStart(getRawOffset(), 0, firstDstStart); |
| 1118 |
| 1119 // Create a TimeZoneRule for standard time |
| 1120 timeRuleType = (endTimeMode == STANDARD_TIME) ? DateTimeRule::STANDARD_T
IME : |
| 1121 ((endTimeMode == UTC_TIME) ? DateTimeRule::UTC_TIME : DateTimeRule::
WALL_TIME); |
| 1122 switch (endMode) { |
| 1123 case DOM_MODE: |
| 1124 dtRule = new DateTimeRule(endMonth, endDay, endTime, timeRuleType); |
| 1125 break; |
| 1126 case DOW_IN_MONTH_MODE: |
| 1127 dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, endTime, t
imeRuleType); |
| 1128 break; |
| 1129 case DOW_GE_DOM_MODE: |
| 1130 dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, true, endT
ime, timeRuleType); |
| 1131 break; |
| 1132 case DOW_LE_DOM_MODE: |
| 1133 dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, false, end
Time, timeRuleType); |
| 1134 break; |
| 1135 } |
| 1136 |
| 1137 // Check for Null pointer |
| 1138 if (dtRule == NULL) { |
| 1139 status = U_MEMORY_ALLOCATION_ERROR; |
| 1140 deleteTransitionRules(); |
| 1141 return; |
| 1142 } |
| 1143 // For now, use ID + "(STD)" as the name |
| 1144 stdRule = new AnnualTimeZoneRule(tzid+STD_STR, getRawOffset(), 0, |
| 1145 dtRule, startYear, AnnualTimeZoneRule::MAX_YEAR); |
| 1146 |
| 1147 //Check for Null pointer |
| 1148 if (stdRule == NULL) { |
| 1149 status = U_MEMORY_ALLOCATION_ERROR; |
| 1150 deleteTransitionRules(); |
| 1151 return; |
| 1152 } |
| 1153 |
| 1154 // Calculate the first STD start time |
| 1155 stdRule->getFirstStart(getRawOffset(), dstRule->getDSTSavings(), firstSt
dStart); |
| 1156 |
| 1157 // Create a TimeZoneRule for initial time |
| 1158 if (firstStdStart < firstDstStart) { |
| 1159 initialRule = new InitialTimeZoneRule(tzid+DST_STR, getRawOffset(),
dstRule->getDSTSavings()); |
| 1160 firstTransition = new TimeZoneTransition(firstStdStart, *initialRule
, *stdRule); |
| 1161 } else { |
| 1162 initialRule = new InitialTimeZoneRule(tzid+STD_STR, getRawOffset(),
0); |
| 1163 firstTransition = new TimeZoneTransition(firstDstStart, *initialRule
, *dstRule); |
| 1164 } |
| 1165 // Check for null pointers. |
| 1166 if (initialRule == NULL || firstTransition == NULL) { |
| 1167 status = U_MEMORY_ALLOCATION_ERROR; |
| 1168 deleteTransitionRules(); |
| 1169 return; |
| 1170 } |
| 1171 |
| 1172 } else { |
| 1173 // Create a TimeZoneRule for initial time |
| 1174 initialRule = new InitialTimeZoneRule(tzid, getRawOffset(), 0); |
| 1175 // Check for null pointer. |
| 1176 if (initialRule == NULL) { |
| 1177 status = U_MEMORY_ALLOCATION_ERROR; |
| 1178 deleteTransitionRules(); |
| 1179 return; |
| 1180 } |
| 1181 } |
| 1182 |
| 1183 transitionRulesInitialized = true; |
| 1184 } |
| 1185 |
| 1186 int32_t |
| 1187 SimpleTimeZone::countTransitionRules(UErrorCode& /*status*/) /*const*/ { |
| 1188 return (useDaylight) ? 2 : 0; |
| 1189 } |
| 1190 |
| 1191 void |
| 1192 SimpleTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial, |
| 1193 const TimeZoneRule* trsrules[], |
| 1194 int32_t& trscount, |
| 1195 UErrorCode& status) /*const*/ { |
| 1196 if (U_FAILURE(status)) { |
| 1197 return; |
| 1198 } |
| 1199 initTransitionRules(status); |
| 1200 if (U_FAILURE(status)) { |
| 1201 return; |
| 1202 } |
| 1203 initial = initialRule; |
| 1204 int32_t cnt = 0; |
| 1205 if (stdRule != NULL) { |
| 1206 if (cnt < trscount) { |
| 1207 trsrules[cnt++] = stdRule; |
| 1208 } |
| 1209 if (cnt < trscount) { |
| 1210 trsrules[cnt++] = dstRule; |
| 1211 } |
| 1212 } |
| 1213 trscount = cnt; |
| 1214 } |
| 1215 |
| 1216 |
| 1217 U_NAMESPACE_END |
| 1218 |
| 1219 #endif /* #if !UCONFIG_NO_FORMATTING */ |
| 1220 |
| 1221 //eof |
OLD | NEW |