/** * Default constructor. Creates a time zone with an empty ID and * a fixed GMT offset of zero.
*/ /*OlsonTimeZone::OlsonTimeZone() : finalYear(INT32_MAX), finalMillis(DBL_MAX), finalZone(0), transitionRulesInitialized(false) { clearTransitionRules(); constructEmpty();
}*/
/** * Construct a GMT+0 zone with no transitions. This is done when a * constructor fails so the resultant object is well-behaved.
*/ void OlsonTimeZone::constructEmpty() {
canonicalID = nullptr;
/** * Construct from a resource bundle * @param top the top-level zoneinfo resource bundle. This is used * to lookup the rule that `res' may refer to, if there is one. * @param res the resource bundle of the zone to be constructed * @param ec input-output error code
*/
OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top, const UResourceBundle* res, const UnicodeString& tzid,
UErrorCode& ec) :
BasicTimeZone(tzid), finalZone(nullptr)
{
clearTransitionRules();
U_DEBUG_TZ_MSG(("OlsonTimeZone(%s)\n", ures_getKey((UResourceBundle*)res))); if ((top == nullptr || res == nullptr) && U_SUCCESS(ec)) {
ec = U_ILLEGAL_ARGUMENT_ERROR;
} if (U_SUCCESS(ec)) { // TODO -- clean up -- Doesn't work if res points to an alias // // TODO remove nonconst casts below when ures_* API is fixed // setID(ures_getKey((UResourceBundle*) res)); // cast away const
int32_t len;
StackUResourceBundle r;
// Pre-32bit second transitions
ures_getByKey(res, kTRANSPRE32, r.getAlias(), &ec);
transitionTimesPre32 = ures_getIntVector(r.getAlias(), &len, &ec);
transitionCountPre32 = static_cast<int16_t>(len >> 1); if (ec == U_MISSING_RESOURCE_ERROR) { // No pre-32bit transitions
transitionTimesPre32 = nullptr;
transitionCountPre32 = 0;
ec = U_ZERO_ERROR;
} elseif (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) {
ec = U_INVALID_FORMAT_ERROR;
}
// Post-32bit second transitions
ures_getByKey(res, kTRANSPOST32, r.getAlias(), &ec);
transitionTimesPost32 = ures_getIntVector(r.getAlias(), &len, &ec);
transitionCountPost32 = static_cast<int16_t>(len >> 1); if (ec == U_MISSING_RESOURCE_ERROR) { // No pre-32bit transitions
transitionTimesPost32 = nullptr;
transitionCountPost32 = 0;
ec = U_ZERO_ERROR;
} elseif (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) {
ec = U_INVALID_FORMAT_ERROR;
}
// Type offsets list must be of even size, with size >= 2
ures_getByKey(res, kTYPEOFFSETS, r.getAlias(), &ec);
typeOffsets = ures_getIntVector(r.getAlias(), &len, &ec); if (U_SUCCESS(ec) && (len < 2 || len > 0x7FFE || (len & 1) != 0)) {
ec = U_INVALID_FORMAT_ERROR;
}
typeCount = static_cast<int16_t>(len) >> 1;
// Type map data must be of the same size as the transition count
typeMapData = nullptr; if (transitionCount() > 0) {
ures_getByKey(res, kTYPEMAP, r.getAlias(), &ec);
typeMapData = ures_getBinary(r.getAlias(), &len, &ec); if (ec == U_MISSING_RESOURCE_ERROR) { // no type mapping data
ec = U_INVALID_FORMAT_ERROR;
} elseif (U_SUCCESS(ec) && len != transitionCount()) {
ec = U_INVALID_FORMAT_ERROR;
}
}
// Process final rule and data, if any if (U_SUCCESS(ec)) { const char16_t *ruleIdUStr = ures_getStringByKey(res, kFINALRULE, &len, &ec);
ures_getByKey(res, kFINALRAW, r.getAlias(), &ec);
int32_t ruleRaw = ures_getInt(r.getAlias(), &ec);
ures_getByKey(res, kFINALYEAR, r.getAlias(), &ec);
int32_t ruleYear = ures_getInt(r.getAlias(), &ec); if (U_SUCCESS(ec)) {
UnicodeString ruleID(true, ruleIdUStr, len);
UResourceBundle *rule = TimeZone::loadRule(top, ruleID, nullptr, ec); const int32_t *ruleData = ures_getIntVector(rule, &len, &ec); if (U_SUCCESS(ec) && len == 11) {
UnicodeString emptyStr;
finalZone = new SimpleTimeZone(
ruleRaw * U_MILLIS_PER_SECOND,
emptyStr, static_cast<int8_t>(ruleData[0]), static_cast<int8_t>(ruleData[1]), static_cast<int8_t>(ruleData[2]),
ruleData[3] * U_MILLIS_PER_SECOND, static_cast<SimpleTimeZone::TimeMode>(ruleData[4]), static_cast<int8_t>(ruleData[5]), static_cast<int8_t>(ruleData[6]), static_cast<int8_t>(ruleData[7]),
ruleData[8] * U_MILLIS_PER_SECOND, static_cast<SimpleTimeZone::TimeMode>(ruleData[9]),
ruleData[10] * U_MILLIS_PER_SECOND, ec); if (finalZone == nullptr) {
ec = U_MEMORY_ALLOCATION_ERROR;
} else {
finalStartYear = ruleYear;
// Note: Setting finalStartYear to the finalZone is problematic. When a date is around // year boundary, SimpleTimeZone may return false result when DST is observed at the // beginning of year. We could apply safe margin (day or two), but when one of recurrent // rules falls around year boundary, it could return false result. Without setting the // start year, finalZone works fine around the year boundary of the start year.
// finalZone->setStartYear(finalStartYear);
// Compute the millis for Jan 1, 0:00 GMT of the finalYear
// Note: finalStartMillis is used for detecting either if // historic transition data or finalZone to be used. In an // extreme edge case - for example, two transitions fall into // small windows of time around the year boundary, this may // result incorrect offset computation. But I think it will // never happen practically. Yoshito - Feb 20, 2010
finalStartMillis = Grego::fieldsToDay(finalStartYear, 0, 1) * U_MILLIS_PER_DAY;
}
} else {
ec = U_INVALID_FORMAT_ERROR;
}
ures_close(rule);
} elseif (ec == U_MISSING_RESOURCE_ERROR) { // No final zone
ec = U_ZERO_ERROR;
}
}
// initialize canonical ID
canonicalID = ZoneMeta::getCanonicalCLDRID(tzid, ec);
}
/** * TimeZone API.
*/ void OlsonTimeZone::setRawOffset(int32_t /*offsetMillis*/) { // We don't support this operation, since OlsonTimeZones are // immutable (except for the ID, which is in the base class).
// Maximum absolute offset in seconds (86400 seconds = 1 day) // getHistoricalOffset uses this constant as safety margin of // quick zone transition checking. #define MAX_OFFSET_SECONDS 86400
if (transCount > 0) { double sec = uprv_floor(date / U_MILLIS_PER_SECOND); if (!local && sec < transitionTimeInSeconds(0)) { // Before the first transition time
rawoff = initialRawOffset() * U_MILLIS_PER_SECOND;
dstoff = initialDstOffset() * U_MILLIS_PER_SECOND;
} else { // Linear search from the end is the fastest approach, since // most lookups will happen at/near the end.
int16_t transIdx; for (transIdx = transCount - 1; transIdx >= 0; transIdx--) {
int64_t transition = transitionTimeInSeconds(transIdx);
if (offsetAfter - offsetBefore >= 0) { // Positive transition, which makes a non-existing local time range if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd)
|| ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
transition += offsetBefore;
} elseif (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst)
|| ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
transition += offsetAfter;
} elseif ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) {
transition += offsetBefore;
} else { // Interprets the time with rule before the transition, // default for non-existing time range
transition += offsetAfter;
}
} else { // Negative transition, which makes a duplicated local time range if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd)
|| ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
transition += offsetAfter;
} elseif (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst)
|| ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
transition += offsetBefore;
} elseif ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) {
transition += offsetBefore;
} else { // Interprets the time with rule after the transition, // default for duplicated local time range
transition += offsetAfter;
}
}
} if (sec >= transition) { break;
}
} // transIdx could be -1 when local=true
rawoff = rawOffsetAt(transIdx) * U_MILLIS_PER_SECOND;
dstoff = dstOffsetAt(transIdx) * U_MILLIS_PER_SECOND;
}
} else { // No transitions, single pair of offsets only
rawoff = initialRawOffset() * U_MILLIS_PER_SECOND;
dstoff = initialDstOffset() * U_MILLIS_PER_SECOND;
}
U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst) - raw=%d, dst=%d\n",
date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt, rawoff, dstoff));
}
/** * TimeZone API.
*/
UBool OlsonTimeZone::useDaylightTime() const { // If DST was observed in 1942 (for example) but has never been // observed from 1943 to the present, most clients will expect // this method to return false. This method determines whether // DST is in use in the current year (at any point in the year) // and returns true if so.
UDate current = uprv_getUTCtime(); if (finalZone != nullptr && current >= finalStartMillis) { return finalZone->useDaylightTime();
}
int32_t year, month, dom, dow, doy, mid;
UErrorCode status = U_ZERO_ERROR;
Grego::timeToFields(current, year, month, dom, dow, doy, mid, status);
U_ASSERT(U_SUCCESS(status)); if (U_FAILURE(status)) returnfalse; // If error, just return false.
// Find start of this year, and start of next year double start = Grego::fieldsToDay(year, 0, 1) * SECONDS_PER_DAY; double limit = Grego::fieldsToDay(year+1, 0, 1) * SECONDS_PER_DAY;
// Return true if DST is observed at any time during the current // year. for (int16_t i = 0; i < transitionCount(); ++i) { double transition = static_cast<double>(transitionTimeInSeconds(i)); if (transition >= limit) { break;
} if ((transition >= start && dstOffsetAt(i) != 0)
|| (transition > start && dstOffsetAt(i - 1) != 0)) { returntrue;
}
} returnfalse;
}
int32_t
OlsonTimeZone::getDSTSavings() const{ if (finalZone != nullptr){ return finalZone->getDSTSavings();
} return TimeZone::getDSTSavings();
} /** * TimeZone API.
*/
UBool OlsonTimeZone::inDaylightTime(UDate date, UErrorCode& ec) const {
int32_t raw, dst;
getOffset(date, false, raw, dst, ec); return dst != 0;
}
UBool
OlsonTimeZone::hasSameRules(const TimeZone &other) const { if (this == &other) { returntrue;
} const OlsonTimeZone* z = dynamic_cast<const OlsonTimeZone*>(&other); if (z == nullptr) { returnfalse;
}
// [sic] pointer comparison: typeMapData points into // memory-mapped or DLL space, so if two zones have the same // pointer, they are equal. if (typeMapData == z->typeMapData) { returntrue;
}
// If the pointers are not equal, the zones may still // be equal if their rules and transitions are equal if ((finalZone == nullptr && z->finalZone != nullptr)
|| (finalZone != nullptr && z->finalZone == nullptr)
|| (finalZone != nullptr && z->finalZone != nullptr && *finalZone != *z->finalZone)) { returnfalse;
}
// We probably no longer need to check the first "real" transition // here, because the new tzcode remove such transitions already. // For now, keeping this code for just in case. Feb 19, 2010 Yoshito
firstTZTransitionIdx = 0; for (transitionIdx = 0; transitionIdx < transCount; transitionIdx++) { if (typeMapData[transitionIdx] != 0) { // type 0 is the initial type break;
}
firstTZTransitionIdx++;
} if (transitionIdx == transCount) { // Actually no transitions...
} else { // Build historic rule array
UDate* times = static_cast<UDate*>(uprv_malloc(sizeof(UDate) * transCount)); /* large enough to store all transition times */ if (times == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
deleteTransitionRules(); return;
} for (typeIdx = 0; typeIdx < typeCount; typeIdx++) { // Gather all start times for each pair of offsets
int32_t nTimes = 0; for (transitionIdx = firstTZTransitionIdx; transitionIdx < transCount; transitionIdx++) { if (typeIdx == static_cast<int16_t>(typeMapData[transitionIdx])) {
UDate tt = static_cast<UDate>(transitionTime(transitionIdx)); if (finalZone == nullptr || tt <= finalStartMillis) { // Exclude transitions after finalMillis
times[nTimes++] = tt;
}
}
} if (nTimes > 0) { // Create a TimeArrayTimeZoneRule
raw = typeOffsets[typeIdx << 1] * U_MILLIS_PER_SECOND;
dst = typeOffsets[(typeIdx << 1) + 1] * U_MILLIS_PER_SECOND; if (historicRules == nullptr) {
historicRuleCount = typeCount;
historicRules = static_cast<TimeArrayTimeZoneRule**>(uprv_malloc(sizeof(TimeArrayTimeZoneRule*) * historicRuleCount)); if (historicRules == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
deleteTransitionRules();
uprv_free(times); return;
} for (int i = 0; i < historicRuleCount; i++) { // Initialize TimeArrayTimeZoneRule pointers as nullptr
historicRules[i] = nullptr;
}
}
historicRules[typeIdx] = new TimeArrayTimeZoneRule((dst == 0 ? stdName : dstName),
raw, dst, times, nTimes, DateTimeRule::UTC_TIME); // Check for memory allocation error if (historicRules[typeIdx] == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
deleteTransitionRules(); return;
}
}
}
uprv_free(times);
// Create initial transition
typeIdx = static_cast<int16_t>(typeMapData[firstTZTransitionIdx]);
firstTZTransition = new TimeZoneTransition(static_cast<UDate>(transitionTime(firstTZTransitionIdx)),
*initialRule, *historicRules[typeIdx]); // Check to make sure firstTZTransition was created. if (firstTZTransition == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
deleteTransitionRules(); return;
}
}
} if (finalZone != nullptr) { // Get the first occurrence of final rule starts
UDate startTime = static_cast<UDate>(finalStartMillis);
TimeZoneRule *firstFinalRule = nullptr;
if (finalZone->useDaylightTime()) { /* * Note: When an OlsonTimeZone is constructed, we should set the final year * as the start year of finalZone. However, the boundary condition used for * getting offset from finalZone has some problems. * For now, we do not set the valid start year when the construction time * and create a clone and set the start year when extracting rules.
*/
finalZoneWithStartYear = finalZone->clone(); // Check to make sure finalZone was actually cloned. if (finalZoneWithStartYear == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
deleteTransitionRules(); return;
}
finalZoneWithStartYear->setStartYear(finalStartYear);
TimeZoneTransition tzt;
finalZoneWithStartYear->getNextTransition(startTime, false, tzt);
firstFinalRule = tzt.getTo()->clone(); // Check to make sure firstFinalRule received proper clone. if (firstFinalRule == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
deleteTransitionRules(); return;
}
startTime = tzt.getTime();
} else { // final rule with no transitions
finalZoneWithStartYear = finalZone->clone(); // Check to make sure finalZone was actually cloned. if (finalZoneWithStartYear == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
deleteTransitionRules(); return;
}
finalZone->getID(tzid);
firstFinalRule = new TimeArrayTimeZoneRule(tzid,
finalZone->getRawOffset(), 0, &startTime, 1, DateTimeRule::UTC_TIME); // Check firstFinalRule was properly created. if (firstFinalRule == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
deleteTransitionRules(); return;
}
}
TimeZoneRule *prevRule = nullptr; if (transCount > 0) {
prevRule = historicRules[typeMapData[transCount - 1]];
} if (prevRule == nullptr) { // No historic transitions, but only finalZone available
prevRule = initialRule;
}
firstFinalTZTransition = new TimeZoneTransition(); // Check to make sure firstFinalTZTransition was created before dereferencing if (firstFinalTZTransition == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
deleteTransitionRules(); return;
}
firstFinalTZTransition->setTime(startTime);
firstFinalTZTransition->adoptFrom(prevRule->clone());
firstFinalTZTransition->adoptTo(firstFinalRule);
}
}
UBool
OlsonTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
UErrorCode status = U_ZERO_ERROR;
checkTransitionRules(status); if (U_FAILURE(status)) { returnfalse;
}
if (finalZone != nullptr) { if (inclusive && base == firstFinalTZTransition->getTime()) {
result = *firstFinalTZTransition; returntrue;
} elseif (base >= firstFinalTZTransition->getTime()) { if (finalZone->useDaylightTime()) { //return finalZone->getNextTransition(base, inclusive, result); return finalZoneWithStartYear->getNextTransition(base, inclusive, result);
} else { // No more transitions returnfalse;
}
}
} if (historicRules != nullptr) { // Find a historical transition
int16_t transCount = transitionCount();
int16_t ttidx = transCount - 1; for (; ttidx >= firstTZTransitionIdx; ttidx--) {
UDate t = static_cast<UDate>(transitionTime(ttidx)); if (base > t || (!inclusive && base == t)) { break;
}
} if (ttidx == transCount - 1) { if (firstFinalTZTransition != nullptr) {
result = *firstFinalTZTransition; returntrue;
} else { returnfalse;
}
} elseif (ttidx < firstTZTransitionIdx) {
result = *firstTZTransition; returntrue;
} else { // Create a TimeZoneTransition
TimeZoneRule *to = historicRules[typeMapData[ttidx + 1]];
TimeZoneRule *from = historicRules[typeMapData[ttidx]];
UDate startTime = static_cast<UDate>(transitionTime(ttidx + 1));
// The transitions loaded from zoneinfo.res may contain non-transition data
UnicodeString fromName, toName;
from->getName(fromName);
to->getName(toName); if (fromName == toName && from->getRawOffset() == to->getRawOffset()
&& from->getDSTSavings() == to->getDSTSavings()) { return getNextTransition(startTime, false, result);
}
result.setTime(startTime);
result.adoptFrom(from->clone());
result.adoptTo(to->clone()); returntrue;
}
} returnfalse;
}
UBool
OlsonTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
UErrorCode status = U_ZERO_ERROR;
checkTransitionRules(status); if (U_FAILURE(status)) { returnfalse;
}
if (finalZone != nullptr) { if (inclusive && base == firstFinalTZTransition->getTime()) {
result = *firstFinalTZTransition; returntrue;
} elseif (base > firstFinalTZTransition->getTime()) { if (finalZone->useDaylightTime()) { //return finalZone->getPreviousTransition(base, inclusive, result); return finalZoneWithStartYear->getPreviousTransition(base, inclusive, result);
} else {
result = *firstFinalTZTransition; returntrue;
}
}
}
if (historicRules != nullptr) { // Find a historical transition
int16_t ttidx = transitionCount() - 1; for (; ttidx >= firstTZTransitionIdx; ttidx--) {
UDate t = static_cast<UDate>(transitionTime(ttidx)); if (base > t || (inclusive && base == t)) { break;
}
} if (ttidx < firstTZTransitionIdx) { // No more transitions returnfalse;
} elseif (ttidx == firstTZTransitionIdx) {
result = *firstTZTransition; returntrue;
} else { // Create a TimeZoneTransition
TimeZoneRule *to = historicRules[typeMapData[ttidx]];
TimeZoneRule *from = historicRules[typeMapData[ttidx-1]];
UDate startTime = static_cast<UDate>(transitionTime(ttidx));
// The transitions loaded from zoneinfo.res may contain non-transition data
UnicodeString fromName, toName;
from->getName(fromName);
to->getName(toName); if (fromName == toName && from->getRawOffset() == to->getRawOffset()
&& from->getDSTSavings() == to->getDSTSavings()) { return getPreviousTransition(startTime, false, result);
}
result.setTime(startTime);
result.adoptFrom(from->clone());
result.adoptTo(to->clone()); returntrue;
}
} returnfalse;
}
int32_t
OlsonTimeZone::countTransitionRules(UErrorCode& status) const { if (U_FAILURE(status)) { return 0;
}
checkTransitionRules(status); if (U_FAILURE(status)) { return 0;
}
int32_t count = 0; if (historicRules != nullptr) { // historicRules may contain null entries when original zoneinfo data // includes non transition data. for (int32_t i = 0; i < historicRuleCount; i++) { if (historicRules[i] != nullptr) {
count++;
}
}
} if (finalZone != nullptr) { if (finalZone->useDaylightTime()) {
count += 2;
} else {
count++;
}
} return count;
}
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.