123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263 |
- // © 2016 and later: Unicode, Inc. and others.
- // License & terms of use: http://www.unicode.org/copyright.html
- /*
- *******************************************************************************
- * Copyright (C) 1997-2013, International Business Machines Corporation and
- * others. All Rights Reserved.
- *******************************************************************************
- *
- * File SIMPLETZ.H
- *
- * Modification History:
- *
- * Date Name Description
- * 12/05/96 clhuang Creation.
- * 04/21/97 aliu Fixed miscellaneous bugs found by inspection and
- * testing.
- * 07/29/97 aliu Ported source bodies back from Java version with
- * numerous feature enhancements and bug fixes.
- * 08/10/98 stephen JDK 1.2 sync.
- * 09/17/98 stephen Fixed getOffset() for last hour of year and DST
- * 12/02/99 aliu Added TimeMode and constructor and setStart/EndRule
- * methods that take TimeMode. Whitespace cleanup.
- ********************************************************************************
- */
- #include "utypeinfo.h" // for 'typeid' to work
- #include "unicode/utypes.h"
- #if !UCONFIG_NO_FORMATTING
- #include "unicode/simpletz.h"
- #include "unicode/gregocal.h"
- #include "unicode/smpdtfmt.h"
- #include "cmemory.h"
- #include "gregoimp.h"
- #include "umutex.h"
- U_NAMESPACE_BEGIN
- UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleTimeZone)
- // Use only for decodeStartRule() and decodeEndRule() where the year is not
- // available. Set February to 29 days to accommodate rules with that date
- // and day-of-week-on-or-before-that-date mode (DOW_LE_DOM_MODE).
- // The compareToRule() method adjusts to February 28 in non-leap years.
- //
- // For actual getOffset() calculations, use Grego::monthLength() and
- // Grego::previousMonthLength() which take leap years into account.
- // We handle leap years assuming always
- // Gregorian, since we know they didn't have daylight time when
- // Gregorian calendar started.
- const int8_t SimpleTimeZone::STATICMONTHLENGTH[] = {31,29,31,30,31,30,31,31,30,31,30,31};
- static const char16_t DST_STR[] = {0x0028,0x0044,0x0053,0x0054,0x0029,0}; // "(DST)"
- static const char16_t STD_STR[] = {0x0028,0x0053,0x0054,0x0044,0x0029,0}; // "(STD)"
- // *****************************************************************************
- // class SimpleTimeZone
- // *****************************************************************************
- SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID)
- : BasicTimeZone(ID),
- startMonth(0),
- startDay(0),
- startDayOfWeek(0),
- startTime(0),
- startTimeMode(WALL_TIME),
- endTimeMode(WALL_TIME),
- endMonth(0),
- endDay(0),
- endDayOfWeek(0),
- endTime(0),
- startYear(0),
- rawOffset(rawOffsetGMT),
- useDaylight(false),
- startMode(DOM_MODE),
- endMode(DOM_MODE),
- dstSavings(U_MILLIS_PER_HOUR)
- {
- clearTransitionRules();
- }
- // -------------------------------------
- SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID,
- int8_t savingsStartMonth, int8_t savingsStartDay,
- int8_t savingsStartDayOfWeek, int32_t savingsStartTime,
- int8_t savingsEndMonth, int8_t savingsEndDay,
- int8_t savingsEndDayOfWeek, int32_t savingsEndTime,
- UErrorCode& status)
- : BasicTimeZone(ID)
- {
- clearTransitionRules();
- construct(rawOffsetGMT,
- savingsStartMonth, savingsStartDay, savingsStartDayOfWeek,
- savingsStartTime, WALL_TIME,
- savingsEndMonth, savingsEndDay, savingsEndDayOfWeek,
- savingsEndTime, WALL_TIME,
- U_MILLIS_PER_HOUR, status);
- }
- // -------------------------------------
- SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID,
- int8_t savingsStartMonth, int8_t savingsStartDay,
- int8_t savingsStartDayOfWeek, int32_t savingsStartTime,
- int8_t savingsEndMonth, int8_t savingsEndDay,
- int8_t savingsEndDayOfWeek, int32_t savingsEndTime,
- int32_t savingsDST, UErrorCode& status)
- : BasicTimeZone(ID)
- {
- clearTransitionRules();
- construct(rawOffsetGMT,
- savingsStartMonth, savingsStartDay, savingsStartDayOfWeek,
- savingsStartTime, WALL_TIME,
- savingsEndMonth, savingsEndDay, savingsEndDayOfWeek,
- savingsEndTime, WALL_TIME,
- savingsDST, status);
- }
- // -------------------------------------
- SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID,
- int8_t savingsStartMonth, int8_t savingsStartDay,
- int8_t savingsStartDayOfWeek, int32_t savingsStartTime,
- TimeMode savingsStartTimeMode,
- int8_t savingsEndMonth, int8_t savingsEndDay,
- int8_t savingsEndDayOfWeek, int32_t savingsEndTime,
- TimeMode savingsEndTimeMode,
- int32_t savingsDST, UErrorCode& status)
- : BasicTimeZone(ID)
- {
- clearTransitionRules();
- construct(rawOffsetGMT,
- savingsStartMonth, savingsStartDay, savingsStartDayOfWeek,
- savingsStartTime, savingsStartTimeMode,
- savingsEndMonth, savingsEndDay, savingsEndDayOfWeek,
- savingsEndTime, savingsEndTimeMode,
- savingsDST, status);
- }
- /**
- * Internal construction method.
- */
- void SimpleTimeZone::construct(int32_t rawOffsetGMT,
- int8_t savingsStartMonth,
- int8_t savingsStartDay,
- int8_t savingsStartDayOfWeek,
- int32_t savingsStartTime,
- TimeMode savingsStartTimeMode,
- int8_t savingsEndMonth,
- int8_t savingsEndDay,
- int8_t savingsEndDayOfWeek,
- int32_t savingsEndTime,
- TimeMode savingsEndTimeMode,
- int32_t savingsDST,
- UErrorCode& status)
- {
- this->rawOffset = rawOffsetGMT;
- this->startMonth = savingsStartMonth;
- this->startDay = savingsStartDay;
- this->startDayOfWeek = savingsStartDayOfWeek;
- this->startTime = savingsStartTime;
- this->startTimeMode = savingsStartTimeMode;
- this->endMonth = savingsEndMonth;
- this->endDay = savingsEndDay;
- this->endDayOfWeek = savingsEndDayOfWeek;
- this->endTime = savingsEndTime;
- this->endTimeMode = savingsEndTimeMode;
- this->dstSavings = savingsDST;
- this->startYear = 0;
- this->startMode = DOM_MODE;
- this->endMode = DOM_MODE;
- decodeRules(status);
- if (savingsDST == 0) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- }
- }
- // -------------------------------------
- SimpleTimeZone::~SimpleTimeZone()
- {
- deleteTransitionRules();
- }
- // -------------------------------------
- // Called by TimeZone::createDefault(), then clone() inside a Mutex - be careful.
- SimpleTimeZone::SimpleTimeZone(const SimpleTimeZone &source)
- : BasicTimeZone(source)
- {
- *this = source;
- }
- // -------------------------------------
- // Called by TimeZone::createDefault(), then clone() inside a Mutex - be careful.
- SimpleTimeZone &
- SimpleTimeZone::operator=(const SimpleTimeZone &right)
- {
- if (this != &right)
- {
- TimeZone::operator=(right);
- rawOffset = right.rawOffset;
- startMonth = right.startMonth;
- startDay = right.startDay;
- startDayOfWeek = right.startDayOfWeek;
- startTime = right.startTime;
- startTimeMode = right.startTimeMode;
- startMode = right.startMode;
- endMonth = right.endMonth;
- endDay = right.endDay;
- endDayOfWeek = right.endDayOfWeek;
- endTime = right.endTime;
- endTimeMode = right.endTimeMode;
- endMode = right.endMode;
- startYear = right.startYear;
- dstSavings = right.dstSavings;
- useDaylight = right.useDaylight;
- clearTransitionRules();
- }
- return *this;
- }
- // -------------------------------------
- bool
- SimpleTimeZone::operator==(const TimeZone& that) const
- {
- return ((this == &that) ||
- (typeid(*this) == typeid(that) &&
- TimeZone::operator==(that) &&
- hasSameRules(that)));
- }
- // -------------------------------------
- // Called by TimeZone::createDefault() inside a Mutex - be careful.
- SimpleTimeZone*
- SimpleTimeZone::clone() const
- {
- return new SimpleTimeZone(*this);
- }
- // -------------------------------------
- /**
- * Sets the daylight savings starting year, that is, the year this time zone began
- * observing its specified daylight savings time rules. The time zone is considered
- * not to observe daylight savings time prior to that year; SimpleTimeZone doesn't
- * support historical daylight-savings-time rules.
- * @param year the daylight savings starting year.
- */
- void
- SimpleTimeZone::setStartYear(int32_t year)
- {
- startYear = year;
- transitionRulesInitialized = false;
- }
- // -------------------------------------
- /**
- * Sets the daylight savings starting rule. For example, in the U.S., Daylight Savings
- * Time starts at the first Sunday in April, at 2 AM in standard time.
- * Therefore, you can set the start rule by calling:
- * setStartRule(TimeFields.APRIL, 1, TimeFields.SUNDAY, 2*60*60*1000);
- * The dayOfWeekInMonth and dayOfWeek parameters together specify how to calculate
- * the exact starting date. Their exact meaning depend on their respective signs,
- * allowing various types of rules to be constructed, as follows:<ul>
- * <li>If both dayOfWeekInMonth and dayOfWeek are positive, they specify the
- * day of week in the month (e.g., (2, WEDNESDAY) is the second Wednesday
- * of the month).
- * <li>If dayOfWeek is positive and dayOfWeekInMonth is negative, they specify
- * the day of week in the month counting backward from the end of the month.
- * (e.g., (-1, MONDAY) is the last Monday in the month)
- * <li>If dayOfWeek is zero and dayOfWeekInMonth is positive, dayOfWeekInMonth
- * specifies the day of the month, regardless of what day of the week it is.
- * (e.g., (10, 0) is the tenth day of the month)
- * <li>If dayOfWeek is zero and dayOfWeekInMonth is negative, dayOfWeekInMonth
- * specifies the day of the month counting backward from the end of the
- * month, regardless of what day of the week it is (e.g., (-2, 0) is the
- * next-to-last day of the month).
- * <li>If dayOfWeek is negative and dayOfWeekInMonth is positive, they specify the
- * first specified day of the week on or after the specified day of the month.
- * (e.g., (15, -SUNDAY) is the first Sunday after the 15th of the month
- * [or the 15th itself if the 15th is a Sunday].)
- * <li>If dayOfWeek and DayOfWeekInMonth are both negative, they specify the
- * last specified day of the week on or before the specified day of the month.
- * (e.g., (-20, -TUESDAY) is the last Tuesday before the 20th of the month
- * [or the 20th itself if the 20th is a Tuesday].)</ul>
- * @param month the daylight savings starting month. Month is 0-based.
- * eg, 0 for January.
- * @param dayOfWeekInMonth the daylight savings starting
- * day-of-week-in-month. Please see the member description for an example.
- * @param dayOfWeek the daylight savings starting day-of-week. Please see
- * the member description for an example.
- * @param time the daylight savings starting time. Please see the member
- * description for an example.
- */
-
- void
- SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfWeekInMonth, int32_t dayOfWeek,
- int32_t time, TimeMode mode, UErrorCode& status)
- {
- startMonth = (int8_t)month;
- startDay = (int8_t)dayOfWeekInMonth;
- startDayOfWeek = (int8_t)dayOfWeek;
- startTime = time;
- startTimeMode = mode;
- decodeStartRule(status);
- transitionRulesInitialized = false;
- }
- // -------------------------------------
- void
- SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfMonth,
- int32_t time, TimeMode mode, UErrorCode& status)
- {
- setStartRule(month, dayOfMonth, 0, time, mode, status);
- }
- // -------------------------------------
- void
- SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
- int32_t time, TimeMode mode, UBool after, UErrorCode& status)
- {
- setStartRule(month, after ? dayOfMonth : -dayOfMonth,
- -dayOfWeek, time, mode, status);
- }
- // -------------------------------------
- /**
- * Sets the daylight savings ending rule. For example, in the U.S., Daylight
- * Savings Time ends at the last (-1) Sunday in October, at 2 AM in standard time.
- * Therefore, you can set the end rule by calling:
- * setEndRule(TimeFields.OCTOBER, -1, TimeFields.SUNDAY, 2*60*60*1000);
- * Various other types of rules can be specified by manipulating the dayOfWeek
- * and dayOfWeekInMonth parameters. For complete details, see the documentation
- * for setStartRule().
- * @param month the daylight savings ending month. Month is 0-based.
- * eg, 0 for January.
- * @param dayOfWeekInMonth the daylight savings ending
- * day-of-week-in-month. See setStartRule() for a complete explanation.
- * @param dayOfWeek the daylight savings ending day-of-week. See setStartRule()
- * for a complete explanation.
- * @param time the daylight savings ending time. Please see the member
- * description for an example.
- */
- void
- SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfWeekInMonth, int32_t dayOfWeek,
- int32_t time, TimeMode mode, UErrorCode& status)
- {
- endMonth = (int8_t)month;
- endDay = (int8_t)dayOfWeekInMonth;
- endDayOfWeek = (int8_t)dayOfWeek;
- endTime = time;
- endTimeMode = mode;
- decodeEndRule(status);
- transitionRulesInitialized = false;
- }
- // -------------------------------------
- void
- SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfMonth,
- int32_t time, TimeMode mode, UErrorCode& status)
- {
- setEndRule(month, dayOfMonth, 0, time, mode, status);
- }
- // -------------------------------------
- void
- SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
- int32_t time, TimeMode mode, UBool after, UErrorCode& status)
- {
- setEndRule(month, after ? dayOfMonth : -dayOfMonth,
- -dayOfWeek, time, mode, status);
- }
- // -------------------------------------
- int32_t
- SimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
- uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const
- {
- // Check the month before calling Grego::monthLength(). This
- // duplicates the test that occurs in the 7-argument getOffset(),
- // however, this is unavoidable. We don't mind because this method, in
- // fact, should not be called; internal code should always call the
- // 7-argument getOffset(), and outside code should use Calendar.get(int
- // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of
- // this method because it's public API. - liu 8/10/98
- if(month < UCAL_JANUARY || month > UCAL_DECEMBER) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
- return getOffset(era, year, month, day, dayOfWeek, millis, Grego::monthLength(year, month), status);
- }
- int32_t
- SimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
- uint8_t dayOfWeek, int32_t millis,
- int32_t /*monthLength*/, UErrorCode& status) const
- {
- // Check the month before calling Grego::monthLength(). This
- // duplicates a test that occurs in the 9-argument getOffset(),
- // however, this is unavoidable. We don't mind because this method, in
- // fact, should not be called; internal code should always call the
- // 9-argument getOffset(), and outside code should use Calendar.get(int
- // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of
- // this method because it's public API. - liu 8/10/98
- if (month < UCAL_JANUARY
- || month > UCAL_DECEMBER) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return -1;
- }
- // We ignore monthLength because it can be derived from year and month.
- // This is so that February in leap years is calculated correctly.
- // We keep this argument in this function for backwards compatibility.
- return getOffset(era, year, month, day, dayOfWeek, millis,
- Grego::monthLength(year, month),
- Grego::previousMonthLength(year, month),
- status);
- }
- int32_t
- SimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
- uint8_t dayOfWeek, int32_t millis,
- int32_t monthLength, int32_t prevMonthLength,
- UErrorCode& status) const
- {
- if(U_FAILURE(status)) return 0;
- if ((era != GregorianCalendar::AD && era != GregorianCalendar::BC)
- || month < UCAL_JANUARY
- || month > UCAL_DECEMBER
- || day < 1
- || day > monthLength
- || dayOfWeek < UCAL_SUNDAY
- || dayOfWeek > UCAL_SATURDAY
- || millis < 0
- || millis >= U_MILLIS_PER_DAY
- || monthLength < 28
- || monthLength > 31
- || prevMonthLength < 28
- || prevMonthLength > 31) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return -1;
- }
- int32_t result = rawOffset;
- // Bail out if we are before the onset of daylight savings time
- if(!useDaylight || year < startYear || era != GregorianCalendar::AD)
- return result;
- // Check for southern hemisphere. We assume that the start and end
- // month are different.
- UBool southern = (startMonth > endMonth);
- // Compare the date to the starting and ending rules.+1 = date>rule, -1
- // = date<rule, 0 = date==rule.
- int32_t startCompare = compareToRule((int8_t)month, (int8_t)monthLength, (int8_t)prevMonthLength,
- (int8_t)day, (int8_t)dayOfWeek, millis,
- startTimeMode == UTC_TIME ? -rawOffset : 0,
- startMode, (int8_t)startMonth, (int8_t)startDayOfWeek,
- (int8_t)startDay, startTime);
- int32_t endCompare = 0;
- /* We don't always have to compute endCompare. For many instances,
- * startCompare is enough to determine if we are in DST or not. In the
- * northern hemisphere, if we are before the start rule, we can't have
- * DST. In the southern hemisphere, if we are after the start rule, we
- * must have DST. This is reflected in the way the next if statement
- * (not the one immediately following) short circuits. */
- if(southern != (startCompare >= 0)) {
- endCompare = compareToRule((int8_t)month, (int8_t)monthLength, (int8_t)prevMonthLength,
- (int8_t)day, (int8_t)dayOfWeek, millis,
- endTimeMode == WALL_TIME ? dstSavings :
- (endTimeMode == UTC_TIME ? -rawOffset : 0),
- endMode, (int8_t)endMonth, (int8_t)endDayOfWeek,
- (int8_t)endDay, endTime);
- }
- // Check for both the northern and southern hemisphere cases. We
- // assume that in the northern hemisphere, the start rule is before the
- // end rule within the calendar year, and vice versa for the southern
- // hemisphere.
- if ((!southern && (startCompare >= 0 && endCompare < 0)) ||
- (southern && (startCompare >= 0 || endCompare < 0)))
- result += dstSavings;
- return result;
- }
- void
- SimpleTimeZone::getOffsetFromLocal(UDate date, UTimeZoneLocalOption nonExistingTimeOpt,
- UTimeZoneLocalOption duplicatedTimeOpt, int32_t& rawOffsetGMT,
- int32_t& savingsDST, UErrorCode& status) const
- {
- if (U_FAILURE(status)) {
- return;
- }
- rawOffsetGMT = getRawOffset();
- int32_t year, month, dom, dow, millis;
- int32_t day = ClockMath::floorDivide(date, U_MILLIS_PER_DAY, &millis);
- Grego::dayToFields(day, year, month, dom, dow);
- savingsDST = getOffset(GregorianCalendar::AD, year, month, dom,
- (uint8_t) dow, millis,
- Grego::monthLength(year, month),
- status) - rawOffsetGMT;
- if (U_FAILURE(status)) {
- return;
- }
- UBool recalc = false;
- // Now we need some adjustment
- if (savingsDST > 0) {
- if ((nonExistingTimeOpt & kStdDstMask) == kStandard
- || ((nonExistingTimeOpt & kStdDstMask) != kDaylight && (nonExistingTimeOpt & kFormerLatterMask) != kLatter)) {
- date -= getDSTSavings();
- recalc = true;
- }
- } else {
- if ((duplicatedTimeOpt & kStdDstMask) == kDaylight
- || ((duplicatedTimeOpt & kStdDstMask) != kStandard && (duplicatedTimeOpt & kFormerLatterMask) == kFormer)) {
- date -= getDSTSavings();
- recalc = true;
- }
- }
- if (recalc) {
- day = ClockMath::floorDivide(date, U_MILLIS_PER_DAY, &millis);
- Grego::dayToFields(day, year, month, dom, dow);
- savingsDST = getOffset(GregorianCalendar::AD, year, month, dom,
- (uint8_t) dow, millis,
- Grego::monthLength(year, month),
- status) - rawOffsetGMT;
- }
- }
- // -------------------------------------
- /**
- * Compare a given date in the year to a rule. Return 1, 0, or -1, depending
- * on whether the date is after, equal to, or before the rule date. The
- * millis are compared directly against the ruleMillis, so any
- * standard-daylight adjustments must be handled by the caller.
- *
- * @return 1 if the date is after the rule date, -1 if the date is before
- * the rule date, or 0 if the date is equal to the rule date.
- */
- int32_t
- SimpleTimeZone::compareToRule(int8_t month, int8_t monthLen, int8_t prevMonthLen,
- int8_t dayOfMonth,
- int8_t dayOfWeek, int32_t millis, int32_t millisDelta,
- EMode ruleMode, int8_t ruleMonth, int8_t ruleDayOfWeek,
- int8_t ruleDay, int32_t ruleMillis)
- {
- // Make adjustments for startTimeMode and endTimeMode
- millis += millisDelta;
- while (millis >= U_MILLIS_PER_DAY) {
- millis -= U_MILLIS_PER_DAY;
- ++dayOfMonth;
- dayOfWeek = (int8_t)(1 + (dayOfWeek % 7)); // dayOfWeek is one-based
- if (dayOfMonth > monthLen) {
- dayOfMonth = 1;
- /* When incrementing the month, it is desirable to overflow
- * from DECEMBER to DECEMBER+1, since we use the result to
- * compare against a real month. Wraparound of the value
- * leads to bug 4173604. */
- ++month;
- }
- }
- while (millis < 0) {
- millis += U_MILLIS_PER_DAY;
- --dayOfMonth;
- dayOfWeek = (int8_t)(1 + ((dayOfWeek+5) % 7)); // dayOfWeek is one-based
- if (dayOfMonth < 1) {
- dayOfMonth = prevMonthLen;
- --month;
- }
- }
- // first compare months. If they're different, we don't have to worry about days
- // and times
- if (month < ruleMonth) return -1;
- else if (month > ruleMonth) return 1;
- // calculate the actual day of month for the rule
- int32_t ruleDayOfMonth = 0;
- // Adjust the ruleDay to the monthLen, for non-leap year February 29 rule days.
- if (ruleDay > monthLen) {
- ruleDay = monthLen;
- }
- switch (ruleMode)
- {
- // if the mode is day-of-month, the day of month is given
- case DOM_MODE:
- ruleDayOfMonth = ruleDay;
- break;
- // if the mode is day-of-week-in-month, calculate the day-of-month from it
- case DOW_IN_MONTH_MODE:
- // In this case ruleDay is the day-of-week-in-month (this code is using
- // the dayOfWeek and dayOfMonth parameters to figure out the day-of-week
- // of the first day of the month, so it's trusting that they're really
- // consistent with each other)
- if (ruleDay > 0)
- ruleDayOfMonth = 1 + (ruleDay - 1) * 7 +
- (7 + ruleDayOfWeek - (dayOfWeek - dayOfMonth + 1)) % 7;
-
- // if ruleDay is negative (we assume it's not zero here), we have to do
- // the same calculation figuring backward from the last day of the month.
- else
- {
- // (again, this code is trusting that dayOfWeek and dayOfMonth are
- // consistent with each other here, since we're using them to figure
- // the day of week of the first of the month)
- ruleDayOfMonth = monthLen + (ruleDay + 1) * 7 -
- (7 + (dayOfWeek + monthLen - dayOfMonth) - ruleDayOfWeek) % 7;
- }
- break;
- case DOW_GE_DOM_MODE:
- ruleDayOfMonth = ruleDay +
- (49 + ruleDayOfWeek - ruleDay - dayOfWeek + dayOfMonth) % 7;
- break;
- case DOW_LE_DOM_MODE:
- ruleDayOfMonth = ruleDay -
- (49 - ruleDayOfWeek + ruleDay + dayOfWeek - dayOfMonth) % 7;
- // Note at this point ruleDayOfMonth may be <1, although it will
- // be >=1 for well-formed rules.
- break;
- }
- // now that we have a real day-in-month for the rule, we can compare days...
- if (dayOfMonth < ruleDayOfMonth) return -1;
- else if (dayOfMonth > ruleDayOfMonth) return 1;
- // ...and if they're equal, we compare times
- if (millis < ruleMillis) return -1;
- else if (millis > ruleMillis) return 1;
- else return 0;
- }
- // -------------------------------------
- int32_t
- SimpleTimeZone::getRawOffset() const
- {
- return rawOffset;
- }
- // -------------------------------------
- void
- SimpleTimeZone::setRawOffset(int32_t offsetMillis)
- {
- rawOffset = offsetMillis;
- transitionRulesInitialized = false;
- }
- // -------------------------------------
- void
- SimpleTimeZone::setDSTSavings(int32_t millisSavedDuringDST, UErrorCode& status)
- {
- if (millisSavedDuringDST == 0) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- }
- else {
- dstSavings = millisSavedDuringDST;
- }
- transitionRulesInitialized = false;
- }
- // -------------------------------------
- int32_t
- SimpleTimeZone::getDSTSavings() const
- {
- return dstSavings;
- }
- // -------------------------------------
- UBool
- SimpleTimeZone::useDaylightTime() const
- {
- return useDaylight;
- }
- // -------------------------------------
- /**
- * Overrides TimeZone
- * Queries if the given date is in Daylight Savings Time.
- */
- UBool SimpleTimeZone::inDaylightTime(UDate date, UErrorCode& status) const
- {
- // This method is wasteful since it creates a new GregorianCalendar and
- // deletes it each time it is called. However, this is a deprecated method
- // and provided only for Java compatibility as of 8/6/97 [LIU].
- if (U_FAILURE(status)) return false;
- GregorianCalendar *gc = new GregorianCalendar(*this, status);
- /* test for nullptr */
- if (gc == 0) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return false;
- }
- gc->setTime(date, status);
- UBool result = gc->inDaylightTime(status);
- delete gc;
- return result;
- }
- // -------------------------------------
- /**
- * Return true if this zone has the same rules and offset as another zone.
- * @param other the TimeZone object to be compared with
- * @return true if the given zone has the same rules and offset as this one
- */
- UBool
- SimpleTimeZone::hasSameRules(const TimeZone& other) const
- {
- if (this == &other) return true;
- if (typeid(*this) != typeid(other)) return false;
- SimpleTimeZone *that = (SimpleTimeZone*)&other;
- return rawOffset == that->rawOffset &&
- useDaylight == that->useDaylight &&
- (!useDaylight
- // Only check rules if using DST
- || (dstSavings == that->dstSavings &&
- startMode == that->startMode &&
- startMonth == that->startMonth &&
- startDay == that->startDay &&
- startDayOfWeek == that->startDayOfWeek &&
- startTime == that->startTime &&
- startTimeMode == that->startTimeMode &&
- endMode == that->endMode &&
- endMonth == that->endMonth &&
- endDay == that->endDay &&
- endDayOfWeek == that->endDayOfWeek &&
- endTime == that->endTime &&
- endTimeMode == that->endTimeMode &&
- startYear == that->startYear));
- }
- // -------------------------------------
- //----------------------------------------------------------------------
- // Rule representation
- //
- // We represent the following flavors of rules:
- // 5 the fifth of the month
- // lastSun the last Sunday in the month
- // lastMon the last Monday in the month
- // Sun>=8 first Sunday on or after the eighth
- // Sun<=25 last Sunday on or before the 25th
- // This is further complicated by the fact that we need to remain
- // backward compatible with the 1.1 FCS. Finally, we need to minimize
- // API changes. In order to satisfy these requirements, we support
- // three representation systems, and we translate between them.
- //
- // INTERNAL REPRESENTATION
- // This is the format SimpleTimeZone objects take after construction or
- // streaming in is complete. Rules are represented directly, using an
- // unencoded format. We will discuss the start rule only below; the end
- // rule is analogous.
- // startMode Takes on enumerated values DAY_OF_MONTH,
- // DOW_IN_MONTH, DOW_AFTER_DOM, or DOW_BEFORE_DOM.
- // startDay The day of the month, or for DOW_IN_MONTH mode, a
- // value indicating which DOW, such as +1 for first,
- // +2 for second, -1 for last, etc.
- // startDayOfWeek The day of the week. Ignored for DAY_OF_MONTH.
- //
- // ENCODED REPRESENTATION
- // This is the format accepted by the constructor and by setStartRule()
- // and setEndRule(). It uses various combinations of positive, negative,
- // and zero values to encode the different rules. This representation
- // allows us to specify all the different rule flavors without altering
- // the API.
- // MODE startMonth startDay startDayOfWeek
- // DOW_IN_MONTH_MODE >=0 !=0 >0
- // DOM_MODE >=0 >0 ==0
- // DOW_GE_DOM_MODE >=0 >0 <0
- // DOW_LE_DOM_MODE >=0 <0 <0
- // (no DST) don't care ==0 don't care
- //
- // STREAMED REPRESENTATION
- // We must retain binary compatibility with the 1.1 FCS. The 1.1 code only
- // handles DOW_IN_MONTH_MODE and non-DST mode, the latter indicated by the
- // flag useDaylight. When we stream an object out, we translate into an
- // approximate DOW_IN_MONTH_MODE representation so the object can be parsed
- // and used by 1.1 code. Following that, we write out the full
- // representation separately so that contemporary code can recognize and
- // parse it. The full representation is written in a "packed" format,
- // consisting of a version number, a length, and an array of bytes. Future
- // versions of this class may specify different versions. If they wish to
- // include additional data, they should do so by storing them after the
- // packed representation below.
- //----------------------------------------------------------------------
- /**
- * Given a set of encoded rules in startDay and startDayOfMonth, decode
- * them and set the startMode appropriately. Do the same for endDay and
- * endDayOfMonth. Upon entry, the day of week variables may be zero or
- * negative, in order to indicate special modes. The day of month
- * variables may also be negative. Upon exit, the mode variables will be
- * set, and the day of week and day of month variables will be positive.
- * This method also recognizes a startDay or endDay of zero as indicating
- * no DST.
- */
- void
- SimpleTimeZone::decodeRules(UErrorCode& status)
- {
- decodeStartRule(status);
- decodeEndRule(status);
- }
- /**
- * Decode the start rule and validate the parameters. The parameters are
- * expected to be in encoded form, which represents the various rule modes
- * by negating or zeroing certain values. Representation formats are:
- * <p>
- * <pre>
- * DOW_IN_MONTH DOM DOW>=DOM DOW<=DOM no DST
- * ------------ ----- -------- -------- ----------
- * month 0..11 same same same don't care
- * day -5..5 1..31 1..31 -1..-31 0
- * dayOfWeek 1..7 0 -1..-7 -1..-7 don't care
- * time 0..ONEDAY same same same don't care
- * </pre>
- * The range for month does not include UNDECIMBER since this class is
- * really specific to GregorianCalendar, which does not use that month.
- * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the
- * end rule is an exclusive limit point. That is, the range of times that
- * are in DST include those >= the start and < the end. For this reason,
- * it should be possible to specify an end of ONEDAY in order to include the
- * entire day. Although this is equivalent to time 0 of the following day,
- * it's not always possible to specify that, for example, on December 31.
- * While arguably the start range should still be 0..ONEDAY-1, we keep
- * the start and end ranges the same for consistency.
- */
- void
- SimpleTimeZone::decodeStartRule(UErrorCode& status)
- {
- if(U_FAILURE(status)) return;
- useDaylight = (UBool)((startDay != 0) && (endDay != 0) ? true : false);
- if (useDaylight && dstSavings == 0) {
- dstSavings = U_MILLIS_PER_HOUR;
- }
- if (startDay != 0) {
- if (startMonth < UCAL_JANUARY || startMonth > UCAL_DECEMBER) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- if (startTime < 0 || startTime > U_MILLIS_PER_DAY ||
- startTimeMode < WALL_TIME || startTimeMode > UTC_TIME) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- if (startDayOfWeek == 0) {
- startMode = DOM_MODE;
- } else {
- if (startDayOfWeek > 0) {
- startMode = DOW_IN_MONTH_MODE;
- } else {
- startDayOfWeek = (int8_t)-startDayOfWeek;
- if (startDay > 0) {
- startMode = DOW_GE_DOM_MODE;
- } else {
- startDay = (int8_t)-startDay;
- startMode = DOW_LE_DOM_MODE;
- }
- }
- if (startDayOfWeek > UCAL_SATURDAY) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- }
- if (startMode == DOW_IN_MONTH_MODE) {
- if (startDay < -5 || startDay > 5) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- } else if (startDay<1 || startDay > STATICMONTHLENGTH[startMonth]) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- }
- }
- /**
- * Decode the end rule and validate the parameters. This method is exactly
- * analogous to decodeStartRule().
- * @see decodeStartRule
- */
- void
- SimpleTimeZone::decodeEndRule(UErrorCode& status)
- {
- if(U_FAILURE(status)) return;
- useDaylight = (UBool)((startDay != 0) && (endDay != 0) ? true : false);
- if (useDaylight && dstSavings == 0) {
- dstSavings = U_MILLIS_PER_HOUR;
- }
- if (endDay != 0) {
- if (endMonth < UCAL_JANUARY || endMonth > UCAL_DECEMBER) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- if (endTime < 0 || endTime > U_MILLIS_PER_DAY ||
- endTimeMode < WALL_TIME || endTimeMode > UTC_TIME) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- if (endDayOfWeek == 0) {
- endMode = DOM_MODE;
- } else {
- if (endDayOfWeek > 0) {
- endMode = DOW_IN_MONTH_MODE;
- } else {
- endDayOfWeek = (int8_t)-endDayOfWeek;
- if (endDay > 0) {
- endMode = DOW_GE_DOM_MODE;
- } else {
- endDay = (int8_t)-endDay;
- endMode = DOW_LE_DOM_MODE;
- }
- }
- if (endDayOfWeek > UCAL_SATURDAY) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- }
- if (endMode == DOW_IN_MONTH_MODE) {
- if (endDay < -5 || endDay > 5) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- } else if (endDay<1 || endDay > STATICMONTHLENGTH[endMonth]) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- }
- }
- UBool
- SimpleTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
- if (!useDaylight) {
- return false;
- }
- UErrorCode status = U_ZERO_ERROR;
- checkTransitionRules(status);
- if (U_FAILURE(status)) {
- return false;
- }
- UDate firstTransitionTime = firstTransition->getTime();
- if (base < firstTransitionTime || (inclusive && base == firstTransitionTime)) {
- result = *firstTransition;
- }
- UDate stdDate, dstDate;
- UBool stdAvail = stdRule->getNextStart(base, dstRule->getRawOffset(), dstRule->getDSTSavings(), inclusive, stdDate);
- UBool dstAvail = dstRule->getNextStart(base, stdRule->getRawOffset(), stdRule->getDSTSavings(), inclusive, dstDate);
- if (stdAvail && (!dstAvail || stdDate < dstDate)) {
- result.setTime(stdDate);
- result.setFrom(*dstRule);
- result.setTo(*stdRule);
- return true;
- }
- if (dstAvail && (!stdAvail || dstDate < stdDate)) {
- result.setTime(dstDate);
- result.setFrom(*stdRule);
- result.setTo(*dstRule);
- return true;
- }
- return false;
- }
- UBool
- SimpleTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
- if (!useDaylight) {
- return false;
- }
- UErrorCode status = U_ZERO_ERROR;
- checkTransitionRules(status);
- if (U_FAILURE(status)) {
- return false;
- }
- UDate firstTransitionTime = firstTransition->getTime();
- if (base < firstTransitionTime || (!inclusive && base == firstTransitionTime)) {
- return false;
- }
- UDate stdDate, dstDate;
- UBool stdAvail = stdRule->getPreviousStart(base, dstRule->getRawOffset(), dstRule->getDSTSavings(), inclusive, stdDate);
- UBool dstAvail = dstRule->getPreviousStart(base, stdRule->getRawOffset(), stdRule->getDSTSavings(), inclusive, dstDate);
- if (stdAvail && (!dstAvail || stdDate > dstDate)) {
- result.setTime(stdDate);
- result.setFrom(*dstRule);
- result.setTo(*stdRule);
- return true;
- }
- if (dstAvail && (!stdAvail || dstDate > stdDate)) {
- result.setTime(dstDate);
- result.setFrom(*stdRule);
- result.setTo(*dstRule);
- return true;
- }
- return false;
- }
- void
- SimpleTimeZone::clearTransitionRules() {
- initialRule = nullptr;
- firstTransition = nullptr;
- stdRule = nullptr;
- dstRule = nullptr;
- transitionRulesInitialized = false;
- }
- void
- SimpleTimeZone::deleteTransitionRules() {
- if (initialRule != nullptr) {
- delete initialRule;
- }
- if (firstTransition != nullptr) {
- delete firstTransition;
- }
- if (stdRule != nullptr) {
- delete stdRule;
- }
- if (dstRule != nullptr) {
- delete dstRule;
- }
- clearTransitionRules();
- }
- /*
- * Lazy transition rules initializer
- *
- * Note On the removal of UMTX_CHECK from checkTransitionRules():
- *
- * It would be faster to have a UInitOnce as part of a SimpleTimeZone object,
- * which would avoid needing to lock a mutex to check the initialization state.
- * But we can't easily because simpletz.h is a public header, and including
- * a UInitOnce as a member of SimpleTimeZone would publicly expose internal ICU headers.
- *
- * Alternatively we could have a pointer to a UInitOnce in the SimpleTimeZone object,
- * allocate it in the constructors. This would be a more intrusive change, but doable
- * if performance turns out to be an issue.
- */
- void
- SimpleTimeZone::checkTransitionRules(UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return;
- }
- static UMutex gLock;
- umtx_lock(&gLock);
- if (!transitionRulesInitialized) {
- SimpleTimeZone *ncThis = const_cast<SimpleTimeZone*>(this);
- ncThis->initTransitionRules(status);
- }
- umtx_unlock(&gLock);
- }
- void
- SimpleTimeZone::initTransitionRules(UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
- if (transitionRulesInitialized) {
- return;
- }
- deleteTransitionRules();
- UnicodeString tzid;
- getID(tzid);
- if (useDaylight) {
- DateTimeRule* dtRule;
- DateTimeRule::TimeRuleType timeRuleType;
- UDate firstStdStart, firstDstStart;
- // Create a TimeZoneRule for daylight saving time
- timeRuleType = (startTimeMode == STANDARD_TIME) ? DateTimeRule::STANDARD_TIME :
- ((startTimeMode == UTC_TIME) ? DateTimeRule::UTC_TIME : DateTimeRule::WALL_TIME);
- switch (startMode) {
- case DOM_MODE:
- dtRule = new DateTimeRule(startMonth, startDay, startTime, timeRuleType);
- break;
- case DOW_IN_MONTH_MODE:
- dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, startTime, timeRuleType);
- break;
- case DOW_GE_DOM_MODE:
- dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, true, startTime, timeRuleType);
- break;
- case DOW_LE_DOM_MODE:
- dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, false, startTime, timeRuleType);
- break;
- default:
- status = U_INVALID_STATE_ERROR;
- return;
- }
- // Check for Null pointer
- if (dtRule == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- // For now, use ID + "(DST)" as the name
- dstRule = new AnnualTimeZoneRule(tzid+UnicodeString(DST_STR), getRawOffset(), getDSTSavings(),
- dtRule, startYear, AnnualTimeZoneRule::MAX_YEAR);
-
- // Check for Null pointer
- if (dstRule == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- deleteTransitionRules();
- return;
- }
-
- // Calculate the first DST start time
- dstRule->getFirstStart(getRawOffset(), 0, firstDstStart);
- // Create a TimeZoneRule for standard time
- timeRuleType = (endTimeMode == STANDARD_TIME) ? DateTimeRule::STANDARD_TIME :
- ((endTimeMode == UTC_TIME) ? DateTimeRule::UTC_TIME : DateTimeRule::WALL_TIME);
- switch (endMode) {
- case DOM_MODE:
- dtRule = new DateTimeRule(endMonth, endDay, endTime, timeRuleType);
- break;
- case DOW_IN_MONTH_MODE:
- dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, endTime, timeRuleType);
- break;
- case DOW_GE_DOM_MODE:
- dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, true, endTime, timeRuleType);
- break;
- case DOW_LE_DOM_MODE:
- dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, false, endTime, timeRuleType);
- break;
- }
-
- // Check for Null pointer
- if (dtRule == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- deleteTransitionRules();
- return;
- }
- // For now, use ID + "(STD)" as the name
- stdRule = new AnnualTimeZoneRule(tzid+UnicodeString(STD_STR), getRawOffset(), 0,
- dtRule, startYear, AnnualTimeZoneRule::MAX_YEAR);
-
- //Check for Null pointer
- if (stdRule == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- deleteTransitionRules();
- return;
- }
- // Calculate the first STD start time
- stdRule->getFirstStart(getRawOffset(), dstRule->getDSTSavings(), firstStdStart);
- // Create a TimeZoneRule for initial time
- if (firstStdStart < firstDstStart) {
- initialRule = new InitialTimeZoneRule(tzid+UnicodeString(DST_STR), getRawOffset(), dstRule->getDSTSavings());
- if (initialRule == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- deleteTransitionRules();
- return;
- }
- firstTransition = new TimeZoneTransition(firstStdStart, *initialRule, *stdRule);
- } else {
- initialRule = new InitialTimeZoneRule(tzid+UnicodeString(STD_STR), getRawOffset(), 0);
- if (initialRule == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- deleteTransitionRules();
- return;
- }
- firstTransition = new TimeZoneTransition(firstDstStart, *initialRule, *dstRule);
- }
- if (firstTransition == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- deleteTransitionRules();
- return;
- }
-
- } else {
- // Create a TimeZoneRule for initial time
- initialRule = new InitialTimeZoneRule(tzid, getRawOffset(), 0);
- // Check for null pointer.
- if (initialRule == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- deleteTransitionRules();
- return;
- }
- }
- transitionRulesInitialized = true;
- }
- int32_t
- SimpleTimeZone::countTransitionRules(UErrorCode& /*status*/) const {
- return (useDaylight) ? 2 : 0;
- }
- void
- SimpleTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
- const TimeZoneRule* trsrules[],
- int32_t& trscount,
- UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return;
- }
- checkTransitionRules(status);
- if (U_FAILURE(status)) {
- return;
- }
- initial = initialRule;
- int32_t cnt = 0;
- if (stdRule != nullptr) {
- if (cnt < trscount) {
- trsrules[cnt++] = stdRule;
- }
- if (cnt < trscount) {
- trsrules[cnt++] = dstRule;
- }
- }
- trscount = cnt;
- }
- U_NAMESPACE_END
- #endif /* #if !UCONFIG_NO_FORMATTING */
- //eof
|