Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/intl/icu/source/i18n/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 21 kB image not shown  

Quelle  basictz.cpp   Sprache: C

 
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
* Copyright (C) 2007-2013, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*/


#include "unicode/utypes.h"

#if !UCONFIG_NO_FORMATTING

#include "unicode/basictz.h"
#include "gregoimp.h"
#include "uvector.h"
#include "cmemory.h"

U_NAMESPACE_BEGIN

#define MILLIS_PER_YEAR (365*24*60*60*1000.0)

BasicTimeZone::BasicTimeZone()
: TimeZone() {
}

BasicTimeZone::BasicTimeZone(const UnicodeString &id)
: TimeZone(id) {
}

BasicTimeZone::BasicTimeZone(const BasicTimeZone& source)
: TimeZone(source) {
}

BasicTimeZone::~BasicTimeZone() {
}

UBool
BasicTimeZone::hasEquivalentTransitions(const BasicTimeZone& tz, UDate start, UDate end,
                                        UBool ignoreDstAmount, UErrorCode& status) const {
    if (U_FAILURE(status)) {
        return false;
    }
    if (hasSameRules(tz)) {
        return true;
    }
    // Check the offsets at the start time
    int32_t raw1, raw2, dst1, dst2;
    getOffset(start, false, raw1, dst1, status);
    if (U_FAILURE(status)) {
        return false;
    }
    tz.getOffset(start, false, raw2, dst2, status);
    if (U_FAILURE(status)) {
        return false;
    }
    if (ignoreDstAmount) {
        if ((raw1 + dst1 != raw2 + dst2)
            || (dst1 != 0 && dst2 == 0)
            || (dst1 == 0 && dst2 != 0)) {
            return false;
        }
    } else {
        if (raw1 != raw2 || dst1 != dst2) {
            return false;
        }            
    }
    // Check transitions in the range
    UDate time = start;
    TimeZoneTransition tr1, tr2;
    while (true) {
        UBool avail1 = getNextTransition(time, false, tr1);
        UBool avail2 = tz.getNextTransition(time, false, tr2);

        if (ignoreDstAmount) {
            // Skip a transition which only differ the amount of DST savings
            while (true) {
                if (avail1
                        && tr1.getTime() <= end
                        && (tr1.getFrom()->getRawOffset() + tr1.getFrom()->getDSTSavings()
                                == tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings())
                        && (tr1.getFrom()->getDSTSavings() != 0 && tr1.getTo()->getDSTSavings() != 0)) {
                    getNextTransition(tr1.getTime(), false, tr1);
                } else {
                    break;
                }
            }
            while (true) {
                if (avail2
                        && tr2.getTime() <= end
                        && (tr2.getFrom()->getRawOffset() + tr2.getFrom()->getDSTSavings()
                                == tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings())
                        && (tr2.getFrom()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() != 0)) {
                    tz.getNextTransition(tr2.getTime(), false, tr2);
                } else {
                    break;
                }
            }
        }

        UBool inRange1 = (avail1 && tr1.getTime() <= end);
        UBool inRange2 = (avail2 && tr2.getTime() <= end);
        if (!inRange1 && !inRange2) {
            // No more transition in the range
            break;
        }
        if (!inRange1 || !inRange2) {
            return false;
        }
        if (tr1.getTime() != tr2.getTime()) {
            return false;
        }
        if (ignoreDstAmount) {
            if (tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings()
                        != tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings()
                    || (tr1.getTo()->getDSTSavings() != 0 &&  tr2.getTo()->getDSTSavings() == 0)
                    || (tr1.getTo()->getDSTSavings() == 0 &&  tr2.getTo()->getDSTSavings() != 0)) {
                return false;
            }
        } else {
            if (tr1.getTo()->getRawOffset() != tr2.getTo()->getRawOffset() ||
                tr1.getTo()->getDSTSavings() != tr2.getTo()->getDSTSavings()) {
                return false;
            }
        }
        time = tr1.getTime();
    }
    return true;
}

void
BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,
        AnnualTimeZoneRule*& std, AnnualTimeZoneRule*& dst, UErrorCode& status) const {
    initial = nullptr;
    std = nullptr;
    dst = nullptr;
    if (U_FAILURE(status)) {
        return;
    }
    int32_t initialRaw, initialDst;
    UnicodeString initialName;

    AnnualTimeZoneRule *ar1 = nullptr;
    AnnualTimeZoneRule *ar2 = nullptr;
    UnicodeString name;

    UBool avail;
    TimeZoneTransition tr;
    // Get the next transition
    avail = getNextTransition(date, false, tr);
    if (avail) {
        tr.getFrom()->getName(initialName);
        initialRaw = tr.getFrom()->getRawOffset();
        initialDst = tr.getFrom()->getDSTSavings();

        // Check if the next transition is either DST->STD or STD->DST and
        // within roughly 1 year from the specified date
        UDate nextTransitionTime = tr.getTime();
        if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
              || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
            && (date + MILLIS_PER_YEAR > nextTransitionTime)) {
 
            int32_t year, month, dom, dow, doy, mid;
            UDate d;

            // Get local wall time for the next transition time
            Grego::timeToFields(nextTransitionTime + initialRaw + initialDst,
                year, month, dom, dow, doy, mid, status);
            if (U_FAILURE(status)) return;
            int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
            // Create DOW rule
            DateTimeRule *dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
            tr.getTo()->getName(name);

            // Note:  SimpleTimeZone does not support raw offset change.
            // So we always use raw offset of the given time for the rule,
            // even raw offset is changed.  This will result that the result
            // zone to return wrong offset after the transition.
            // When we encounter such case, we do not inspect next next
            // transition for another rule.
            ar1 = new AnnualTimeZoneRule(name, initialRaw, tr.getTo()->getDSTSavings(),
                dtr, year, AnnualTimeZoneRule::MAX_YEAR);

            if (tr.getTo()->getRawOffset() == initialRaw) {
                // Get the next next transition
                avail = getNextTransition(nextTransitionTime, false, tr);
                if (avail) {
                    // Check if the next next transition is either DST->STD or STD->DST
                    // and within roughly 1 year from the next transition
                    if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
                          || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
                         && nextTransitionTime + MILLIS_PER_YEAR > tr.getTime()) {

                        // Get local wall time for the next transition time
                        Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
                            year, month, dom, dow, doy, mid, status);
                        if (U_FAILURE(status)) return;
                        weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
                        // Generate another DOW rule
                        dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
                        tr.getTo()->getName(name);
                        ar2 = new AnnualTimeZoneRule(name, tr.getTo()->getRawOffset(), tr.getTo()->getDSTSavings(),
                            dtr, year - 1, AnnualTimeZoneRule::MAX_YEAR);

                        // Make sure this rule can be applied to the specified date
                        avail = ar2->getPreviousStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), true, d);
                        if (!avail || d > date
                                || initialRaw != tr.getTo()->getRawOffset()
                                || initialDst != tr.getTo()->getDSTSavings()) {
                            // We cannot use this rule as the second transition rule
                            delete ar2;
                            ar2 = nullptr;
                        }
                    }
                }
            }
            if (ar2 == nullptr) {
                // Try previous transition
                avail = getPreviousTransition(date, true, tr);
                if (avail) {
                    // Check if the previous transition is either DST->STD or STD->DST.
                    // The actual transition time does not matter here.
                    if ((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
                        || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) {

                        // Generate another DOW rule
                        Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
                            year, month, dom, dow, doy, mid, status);
                        if (U_FAILURE(status)) return;
                        weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
                        dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
                        tr.getTo()->getName(name);

                        // second rule raw/dst offsets should match raw/dst offsets
                        // at the given time
                        ar2 = new AnnualTimeZoneRule(name, initialRaw, initialDst,
                            dtr, ar1->getStartYear() - 1, AnnualTimeZoneRule::MAX_YEAR);

                        // Check if this rule start after the first rule after the specified date
                        avail = ar2->getNextStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), false, d);
                        if (!avail || d <= nextTransitionTime) {
                            // We cannot use this rule as the second transition rule
                            delete ar2;
                            ar2 = nullptr;
                        }
                    }
                }
            }
            if (ar2 == nullptr) {
                // Cannot find a good pair of AnnualTimeZoneRule
                delete ar1;
                ar1 = nullptr;
            } else {
                // The initial rule should represent the rule before the previous transition
                ar1->getName(initialName);
                initialRaw = ar1->getRawOffset();
                initialDst = ar1->getDSTSavings();
            }
        }
    }
    else {
        // Try the previous one
        avail = getPreviousTransition(date, true, tr);
        if (avail) {
            tr.getTo()->getName(initialName);
            initialRaw = tr.getTo()->getRawOffset();
            initialDst = tr.getTo()->getDSTSavings();
        } else {
            // No transitions in the past.  Just use the current offsets
            getOffset(date, false, initialRaw, initialDst, status);
            if (U_FAILURE(status)) {
                return;
            }
        }
    }
    // Set the initial rule
    initial = new InitialTimeZoneRule(initialName, initialRaw, initialDst);

    // Set the standard and daylight saving rules
    if (ar1 != nullptr && ar2 != nullptr) {
        if (ar1->getDSTSavings() != 0) {
            dst = ar1;
            std = ar2;
        } else {
            std = ar1;
            dst = ar2;
        }
    }
}

void
BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial,
                                     UVector*& transitionRules, UErrorCode& status) const {
    if (U_FAILURE(status)) {
        return;
    }

    const InitialTimeZoneRule *orgini;
    TimeZoneTransition tzt;
    bool avail;
    int32_t ruleCount;
    TimeZoneRule *r = nullptr;
    UnicodeString name;
    int32_t i;
    UDate time, t;
    UDate firstStart;
    UBool bFinalStd = false, bFinalDst = false;

    initial = nullptr;
    transitionRules = nullptr;

    // Original transition rules
    ruleCount = countTransitionRules(status);
    if (U_FAILURE(status)) {
        return;
    }
    LocalPointer<UVector> orgRules(
        new UVector(uprv_deleteUObject, nullptr, ruleCount, status), status);
    if (U_FAILURE(status)) {
        return;
    }
    LocalMemory<const TimeZoneRule *> orgtrs(
        static_cast<const TimeZoneRule **>(uprv_malloc(sizeof(TimeZoneRule*)*ruleCount)));
    if (orgtrs.isNull()) {
        status = U_MEMORY_ALLOCATION_ERROR;
        return;
    }
    getTimeZoneRules(orgini, &orgtrs[0], ruleCount, status);
    if (U_FAILURE(status)) {
        return;
    }
    for (i = 0; i < ruleCount; i++) {
        LocalPointer<TimeZoneRule> lpRule(orgtrs[i]->clone(), status);
        orgRules->adoptElement(lpRule.orphan(), status);
        if (U_FAILURE(status)) {
            return;
        }
    }

    avail = getPreviousTransition(start, true, tzt);
    if (!avail) {
        // No need to filter out rules only applicable to time before the start
        initial = orgini->clone();
        if (initial == nullptr) {
            status = U_MEMORY_ALLOCATION_ERROR;
            return;
        }
        transitionRules = orgRules.orphan();
        return;
    }

    LocalMemory<bool> done(static_cast<bool *>(uprv_malloc(sizeof(bool)*ruleCount)));
    if (done.isNull()) {
        status = U_MEMORY_ALLOCATION_ERROR;
        return;
    }
    LocalPointer<UVector> filteredRules(
        new UVector(uprv_deleteUObject, nullptr, status), status);
    if (U_FAILURE(status)) {
        return;
    }

    // Create initial rule
    tzt.getTo()->getName(name);
    LocalPointer<InitialTimeZoneRule> res_initial(
        new InitialTimeZoneRule(name, tzt.getTo()->getRawOffset(), tzt.getTo()->getDSTSavings()), status);
    if (U_FAILURE(status)) {
        return;
    }

    // Mark rules which does not need to be processed
    for (i = 0; i < ruleCount; i++) {
        r = static_cast<TimeZoneRule*>(orgRules->elementAt(i));
        avail = r->getNextStart(start, res_initial->getRawOffset(), res_initial->getDSTSavings(), false, time);
        done[i] = !avail;
    }

    time = start;
    while (!bFinalStd || !bFinalDst) {
        avail = getNextTransition(time, false, tzt);
        if (!avail) {
            break;
        }
        UDate updatedTime = tzt.getTime();
        if (updatedTime == time) {
            // Can get here if rules for start & end of daylight time have exactly
            // the same time.  
            // TODO:  fix getNextTransition() to prevent it?
            status = U_INVALID_STATE_ERROR;
            return;
        }
        time = updatedTime;
 
        const TimeZoneRule *toRule = tzt.getTo();
        for (i = 0; i < ruleCount; i++) {
            r = static_cast<TimeZoneRule*>(orgRules->elementAt(i));
            if (*r == *toRule) {
                break;
            }
        }
        if (i >= ruleCount) {
            // This case should never happen
            status = U_INVALID_STATE_ERROR;
            return;
        }
        if (done[i]) {
            continue;
        }
        const TimeArrayTimeZoneRule *tar = dynamic_cast<const TimeArrayTimeZoneRule *>(toRule);
        const AnnualTimeZoneRule *ar;
        if (tar != nullptr) {
            // Get the previous raw offset and DST savings before the very first start time
            TimeZoneTransition tzt0;
            t = start;
            while (true) {
                avail = getNextTransition(t, false, tzt0);
                if (!avail) {
                    break;
                }
                if (*(tzt0.getTo()) == *tar) {
                    break;
                }
                t = tzt0.getTime();
            }
            if (avail) {
                // Check if the entire start times to be added
                tar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart);
                if (firstStart > start) {
                    // Just add the rule as is
                    LocalPointer<TimeArrayTimeZoneRule> lpTar(tar->clone(), status);
                    filteredRules->adoptElement(lpTar.orphan(), status);
                    if (U_FAILURE(status)) {
                        return;
                    }
                } else {
                    // Collect transitions after the start time
                    int32_t startTimes;
                    DateTimeRule::TimeRuleType timeType;
                    int32_t idx;

                    startTimes = tar->countStartTimes();
                    timeType = tar->getTimeType();
                    for (idx = 0; idx < startTimes; idx++) {
                        tar->getStartTimeAt(idx, t);
                        if (timeType == DateTimeRule::STANDARD_TIME) {
                            t -= tzt.getFrom()->getRawOffset();
                        }
                        if (timeType == DateTimeRule::WALL_TIME) {
                            t -= tzt.getFrom()->getDSTSavings();
                        }
                        if (t > start) {
                            break;
                        }
                    }
                    if (U_FAILURE(status)) {
                        return;
                    }
                    int32_t asize = startTimes - idx;
                    if (asize > 0) {
                        LocalMemory<UDate> newTimes(static_cast<UDate *>(uprv_malloc(sizeof(UDate) * asize)));
                        if (newTimes.isNull()) {
                            status = U_MEMORY_ALLOCATION_ERROR;
                            return;
                        }
                        for (int32_t newidx = 0; newidx < asize; newidx++) {
                            tar->getStartTimeAt(idx + newidx, newTimes[newidx]);
                        }
                        tar->getName(name);
                        LocalPointer<TimeArrayTimeZoneRule> newTar(new TimeArrayTimeZoneRule(
                                name, tar->getRawOffset(), tar->getDSTSavings(), &newTimes[0], asize, timeType), status);
                        filteredRules->adoptElement(newTar.orphan(), status);
                        if (U_FAILURE(status)) {
                            return;
                        }
                    }
                }
            }
        } else if ((ar = dynamic_cast<const AnnualTimeZoneRule *>(toRule)) != nullptr) {
            ar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart);
            if (firstStart == tzt.getTime()) {
                // Just add the rule as is
                LocalPointer<AnnualTimeZoneRule> arClone(ar->clone(), status);
                filteredRules->adoptElement(arClone.orphan(), status);
                if (U_FAILURE(status)) {
                    return;
                }
            } else {
                // Calculate the transition year
                int32_t year, month, dom, dow, doy, mid;
                Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid, status);
                if (U_FAILURE(status)) {
                    return;
                }
                // Re-create the rule
                ar->getName(name);
                LocalPointer<AnnualTimeZoneRule> newAr(new AnnualTimeZoneRule(name, ar->getRawOffset(), ar->getDSTSavings(),
                    *(ar->getRule()), year, ar->getEndYear()), status);
                filteredRules->adoptElement(newAr.orphan(), status);
                if (U_FAILURE(status)) {
                    return;
                }
            }
            // check if this is a final rule
            if (ar->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
                // After bot final standard and dst rules are processed,
                // exit this while loop.
                if (ar->getDSTSavings() == 0) {
                    bFinalStd = true;
                } else {
                    bFinalDst = true;
                }
            }
        }
        done[i] = true;
    }

    // Set the results
    initial = res_initial.orphan();
    transitionRules = filteredRules.orphan();
}

void
BasicTimeZone::getOffsetFromLocal(UDate /*date*/, UTimeZoneLocalOption /*nonExistingTimeOpt*/,
                                  UTimeZoneLocalOption /*duplicatedTimeOpt*/,
                                  int32_t& /*rawOffset*/, int32_t& /*dstOffset*/,
                                  UErrorCode& status) const {
    if (U_FAILURE(status)) {
        return;
    }
    status = U_UNSUPPORTED_ERROR;
}

void BasicTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
                                       int32_t& rawOffset, int32_t& dstOffset,
                                       UErrorCode& status) const {
    getOffsetFromLocal(date, static_cast<UTimeZoneLocalOption>(nonExistingTimeOpt),
                       static_cast<UTimeZoneLocalOption>(duplicatedTimeOpt), rawOffset, dstOffset, status);
}

U_NAMESPACE_END

#endif /* #if !UCONFIG_NO_FORMATTING */

//eof

Messung V0.5
C=89 H=92 G=90

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.