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

    const InitialTimeZoneRule *orgini;
    const TimeZoneRule **orgtrs = NULL;
    TimeZoneTransition tzt;
    UBool avail;
    UVector *orgRules = NULL;
    int32_t ruleCount;
    TimeZoneRule *r = NULL;
    UBool *done = NULL;
    InitialTimeZoneRule *res_initial = NULL;
    UVector *filteredRules = NULL;
    UnicodeString name;
    int32_t i;
    UDate time, t;
    UDate *newTimes = NULL;
    UDate firstStart;
    UBool bFinalStd = FALSE, bFinalDst = FALSE;

    // Original transition rules
    ruleCount = countTransitionRules(status);
    if (U_FAILURE(status)) {
        return;
    }
    orgRules = new UVector(ruleCount, status);
    if (U_FAILURE(status)) {
        return;
    }
    orgtrs = (const TimeZoneRule**)uprv_malloc(sizeof(TimeZoneRule*)*ruleCount);
    if (orgtrs == NULL) {
        status = U_MEMORY_ALLOCATION_ERROR;
        goto error;
    }
    getTimeZoneRules(orgini, orgtrs, ruleCount, status);
    if (U_FAILURE(status)) {
        goto error;
    }
    for (i = 0; i < ruleCount; i++) {
        orgRules->addElement(orgtrs[i]->clone(), status);
        if (U_FAILURE(status)) {
            goto error;
        }
    }
    uprv_free(orgtrs);
    orgtrs = NULL;

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

    done = (UBool*)uprv_malloc(sizeof(UBool)*ruleCount);
    if (done == NULL) {
        status = U_MEMORY_ALLOCATION_ERROR;
        goto error;
    }
    filteredRules = new UVector(status);
    if (U_FAILURE(status)) {
        goto error;
    }

    // Create initial rule
    tzt.getTo()->getName(name);
    res_initial = new InitialTimeZoneRule(name, tzt.getTo()->getRawOffset(),
        tzt.getTo()->getDSTSavings());

    // Mark rules which does not need to be processed
    for (i = 0; i < ruleCount; i++) {
        r = (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;
        }
        time = tzt.getTime();
 
        const TimeZoneRule *toRule = tzt.getTo();
        for (i = 0; i < ruleCount; i++) {
            r = (TimeZoneRule*)orgRules->elementAt(i);
            if (*r == *toRule) {
                break;
            }
        }
        if (i >= ruleCount) {
            // This case should never happen
            status = U_INVALID_STATE_ERROR;
            goto error;
        }
        if (done[i]) {
            continue;
        }
        if (toRule->getDynamicClassID() == TimeArrayTimeZoneRule::getStaticClassID()) {
            TimeArrayTimeZoneRule *tar = (TimeArrayTimeZoneRule*)toRule;

            // 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
                    filteredRules->addElement(tar->clone(), status);
                    if (U_FAILURE(status)) {
                        goto error;
                    }
                } else {
                    // Colllect 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;
                        }
                    }
                    int32_t asize = startTimes - idx;
                    if (asize > 0) {
                        newTimes = (UDate*)uprv_malloc(sizeof(UDate) * asize);
                        if (newTimes == NULL) {
                            status = U_MEMORY_ALLOCATION_ERROR;
                            goto error;
                        }
                        for (int32_t newidx = 0; newidx < asize; newidx++) {
                            tar->getStartTimeAt(idx + newidx, newTimes[newidx]);
                            if (U_FAILURE(status)) {
                                uprv_free(newTimes);
                                newTimes = NULL;
                                goto error;
                            }
                        }
                        tar->getName(name);
                        TimeArrayTimeZoneRule *newTar = new TimeArrayTimeZoneRule(name,
                            tar->getRawOffset(), tar->getDSTSavings(), newTimes, asize, timeType);
                        uprv_free(newTimes);
                        filteredRules->addElement(newTar, status);
                        if (U_FAILURE(status)) {
                            goto error;
                        }
                    }
                }
            }
        } else if (toRule->getDynamicClassID() == AnnualTimeZoneRule::getStaticClassID()) {
            AnnualTimeZoneRule *ar = (AnnualTimeZoneRule*)toRule;
            ar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart);
            if (firstStart == tzt.getTime()) {
                // Just add the rule as is
                filteredRules->addElement(ar->clone(), status);
                if (U_FAILURE(status)) {
                    goto error;
                }
            } else {
                // Calculate the transition year
                int32_t year, month, dom, dow, doy, mid;
                Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid);
                // Re-create the rule
                ar->getName(name);
                AnnualTimeZoneRule *newAr = new AnnualTimeZoneRule(name, ar->getRawOffset(), ar->getDSTSavings(),
                    *(ar->getRule()), year, ar->getEndYear());
                filteredRules->addElement(newAr, status);
                if (U_FAILURE(status)) {
                    goto error;
                }
            }
            // 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
    if (orgRules != NULL) {
        while (!orgRules->isEmpty()) {
            r = (TimeZoneRule*)orgRules->orphanElementAt(0);
            delete r;
        }
        delete orgRules;
    }
    if (done != NULL) {
        uprv_free(done);
    }

    initial = res_initial;
    transitionRules = filteredRules;
    return;

error:
    if (orgtrs != NULL) {
        uprv_free(orgtrs);
    }
    if (orgRules != NULL) {
        while (!orgRules->isEmpty()) {
            r = (TimeZoneRule*)orgRules->orphanElementAt(0);
            delete r;
        }
        delete orgRules;
    }
    if (done != NULL) {
        uprv_free(done);
    }

    initial = NULL;
    transitionRules = NULL;
}
static UBool getSystemTimeInformation(TimeZone *tz, SYSTEMTIME &daylightDate, SYSTEMTIME &standardDate, int32_t &bias, int32_t &daylightBias, int32_t &standardBias) {
    UErrorCode status = U_ZERO_ERROR;
    UBool result = TRUE;
    BasicTimeZone *btz = (BasicTimeZone*)tz; // we should check type
    InitialTimeZoneRule *initial = NULL;
    AnnualTimeZoneRule *std = NULL, *dst = NULL;

    btz->getSimpleRulesNear(uprv_getUTCtime(), initial, std, dst, status);
    if (U_SUCCESS(status)) {
        if (std == NULL || dst == NULL) {
            bias = -1 * (initial->getRawOffset()/60000);
            daylightBias = 0;
            // Do not use DST.  Set 0 to all stadardDate/daylightDate fields
            standardDate.wYear = standardDate.wMonth  = standardDate.wDayOfWeek = standardDate.wDay = 
            standardDate.wHour = standardDate.wMinute = standardDate.wSecond    = standardDate.wMilliseconds = 0;
            daylightDate.wYear = daylightDate.wMonth  = daylightDate.wDayOfWeek = daylightDate.wDay =
            daylightDate.wHour = daylightDate.wMinute = daylightDate.wSecond    = daylightDate.wMilliseconds = 0;
        } else {
            U_ASSERT(std->getRule()->getDateRuleType() == DateTimeRule::DOW);
            U_ASSERT(dst->getRule()->getDateRuleType() == DateTimeRule::DOW);

            bias = -1 * (std->getRawOffset()/60000);
            daylightBias = -1 * (dst->getDSTSavings()/60000);
            // Always use DOW type rule
            int32_t hour, min, sec, mil;
            standardDate.wYear = 0;
            standardDate.wMonth = std->getRule()->getRuleMonth() + 1;
            standardDate.wDay = std->getRule()->getRuleWeekInMonth();
            if (standardDate.wDay < 0) {
                standardDate.wDay = 5;
            }
            standardDate.wDayOfWeek = std->getRule()->getRuleDayOfWeek() - 1;

            mil = std->getRule()->getRuleMillisInDay();
            hour = mil/3600000;
            mil %= 3600000;
            min = mil/60000;
            mil %= 60000;
            sec = mil/1000;
            mil %= 1000;

            standardDate.wHour = hour;
            standardDate.wMinute = min;
            standardDate.wSecond = sec;
            standardDate.wMilliseconds = mil;

            daylightDate.wYear = 0;
            daylightDate.wMonth = dst->getRule()->getRuleMonth() + 1;
            daylightDate.wDay = dst->getRule()->getRuleWeekInMonth();
            if (daylightDate.wDay < 0) {
                daylightDate.wDay = 5;
            }
            daylightDate.wDayOfWeek = dst->getRule()->getRuleDayOfWeek() - 1;

            mil = dst->getRule()->getRuleMillisInDay();
            hour = mil/3600000;
            mil %= 3600000;
            min = mil/60000;
            mil %= 60000;
            sec = mil/1000;
            mil %= 1000;

            daylightDate.wHour = hour;
            daylightDate.wMinute = min;
            daylightDate.wSecond = sec;
            daylightDate.wMilliseconds = mil;
        }
    } else {
        result = FALSE;
    }

    delete initial;
    delete std;
    delete dst;

    return result;
}