// 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};
// Called by TimeZone::createDefault(), then clone() inside a Mutex - be careful.
SimpleTimeZone::SimpleTimeZone(const SimpleTimeZone &source)
: BasicTimeZone(source)
{
*this = source;
}
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; return0;
}
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);
}
// 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(static_cast<int8_t>(month), static_cast<int8_t>(monthLength), static_cast<int8_t>(prevMonthLength),
static_cast<int8_t>(day), static_cast<int8_t>(dayOfWeek), millis,
startTimeMode == UTC_TIME ? -rawOffset : 0,
startMode, startMonth, startDayOfWeek,
startDay, startTime);
int32_t endCompare = 0;
/* We don't always have to compute endCompare. For many instances, *startCompareisenoughtodetermineifweareinDSTornot.Inthe *northernhemisphere,ifwearebeforethestartrule,wecan'thave *DST.Inthesouthernhemisphere,ifweareafterthestartrule,we *musthaveDST.Thisisreflectedinthewaythenextifstatement
* (not the one immediately following) short circuits. */ if(southern != (startCompare >= 0)) {
endCompare = compareToRule(static_cast<int8_t>(month), static_cast<int8_t>(monthLength), static_cast<int8_t>(prevMonthLength),
static_cast<int8_t>(day), static_cast<int8_t>(dayOfWeek), millis,
endTimeMode == WALL_TIME ? dstSavings :
(endTimeMode == UTC_TIME ? -rawOffset : 0),
endMode, endMonth, endDayOfWeek,
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;
// 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) {
Grego::timeToFields(date, year, month, dom, dow, millis, status); if (U_FAILURE(status)) return;
savingsDST = getOffset(GregorianCalendar::AD, year, month, dom,
static_cast<uint8_t>(dow), millis,
Grego::monthLength(year, month),
status) - rawOffsetGMT;
}
}
// -------------------------------------
/** *Compareagivendateintheyeartoarule.Return1,0,or-1,depending *onwhetherthedateisafter,equalto,orbeforetheruledate.The *millisarecompareddirectlyagainsttheruleMillis,soany *standard-daylightadjustmentsmustbehandledbythecaller. * *@return1ifthedateisaftertheruledate,-1ifthedateisbefore *theruledate,or0ifthedateisequaltotheruledate.
*/
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 = static_cast<int8_t>(1 + (dayOfWeek % 7)); // dayOfWeek is one-based if (dayOfMonth > monthLen) {
dayOfMonth = 1; /* When incrementing the month, it is desirable to overflow *fromDECEMBERtoDECEMBER+1,sinceweusetheresultto *compareagainstarealmonth.Wraparoundofthevalue
* leads to bug 4173604. */
++month;
}
} while (millis < 0) {
millis += U_MILLIS_PER_DAY;
--dayOfMonth;
dayOfWeek = static_cast<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; elseif (month > ruleMonth) return1;
// 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_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; elseif (dayOfMonth > ruleDayOfMonth) return1;
// ...and if they're equal, we compare times if (millis < ruleMillis) return -1; elseif (millis > ruleMillis) return1; elsereturn0;
}
/** *OverridesTimeZone *QueriesifthegivendateisinDaylightSavingsTime.
*/
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)) returnfalse;
GregorianCalendar *gc = new GregorianCalendar(*this, status); /* test for nullptr */ if (gc == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR; returnfalse;
}
gc->setTime(date, status);
UBool result = gc->inDaylightTime(status); delete gc; return result;
}
//---------------------------------------------------------------------- // 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. //----------------------------------------------------------------------
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;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.