intl/icu/source/i18n/simpletz.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial