LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - simpletz.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 519 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 43 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13