示例#1
0
void
RuleBasedTimeZone::completeConst(UErrorCode& status) const {
    if (U_FAILURE(status)) {
        return;
    }
    umtx_lock(&gLock);
    if (!fUpToDate) {
        RuleBasedTimeZone *ncThis = const_cast<RuleBasedTimeZone*>(this);
        ncThis->complete(status);
    }
    umtx_unlock(&gLock);
}
示例#2
0
/**
 * The time zone used for performing astronomical computations for
 * Dangi calendar. In Korea various timezones have been used historically 
 * (cf. http://www.math.snu.ac.kr/~kye/others/lunar.html): 
 *  
 *            - 1908/04/01: GMT+8 
 * 1908/04/01 - 1911/12/31: GMT+8.5 
 * 1912/01/01 - 1954/03/20: GMT+9 
 * 1954/03/21 - 1961/08/09: GMT+8.5 
 * 1961/08/10 -           : GMT+9 
 *  
 * Note that, in 1908-1911, the government did not apply the timezone change 
 * but used GMT+8. In addition, 1954-1961's timezone change does not affect 
 * the lunar date calculation. Therefore, the following simpler rule works: 
 *   
 * -1911: GMT+8 
 * 1912-: GMT+9 
 *  
 * Unfortunately, our astronomer's approximation doesn't agree with the 
 * references (http://www.math.snu.ac.kr/~kye/others/lunar.html and 
 * http://astro.kasi.re.kr/Life/ConvertSolarLunarForm.aspx?MenuID=115) 
 * in 1897/7/30. So the following ad hoc fix is used here: 
 *  
 *     -1896: GMT+8 
 *      1897: GMT+7 
 * 1898-1911: GMT+8 
 * 1912-    : GMT+9 
 */
static void U_CALLCONV initDangiCalZoneAstroCalc(void) {
    U_ASSERT(gDangiCalendarZoneAstroCalc == NULL);
    const UDate millis1897[] = { (UDate)((1897 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here
    const UDate millis1898[] = { (UDate)((1898 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here
    const UDate millis1912[] = { (UDate)((1912 - 1970) * 365 * kOneDay) }; // this doesn't create an issue for 1911/12/20
    InitialTimeZoneRule* initialTimeZone = new InitialTimeZoneRule(UNICODE_STRING_SIMPLE("GMT+8"), 8*kOneHour, 0);
    TimeZoneRule* rule1897 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1897"), 7*kOneHour, 0, millis1897, 1, DateTimeRule::STANDARD_TIME);
    TimeZoneRule* rule1898to1911 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1898-1911"), 8*kOneHour, 0, millis1898, 1, DateTimeRule::STANDARD_TIME);
    TimeZoneRule* ruleFrom1912 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1912-"), 9*kOneHour, 0, millis1912, 1, DateTimeRule::STANDARD_TIME);
    UErrorCode status = U_ZERO_ERROR;
    RuleBasedTimeZone* dangiCalZoneAstroCalc = new RuleBasedTimeZone(UNICODE_STRING_SIMPLE("KOREA_ZONE"), initialTimeZone); // adopts initialTimeZone
    dangiCalZoneAstroCalc->addTransitionRule(rule1897, status); // adopts rule1897
    dangiCalZoneAstroCalc->addTransitionRule(rule1898to1911, status);
    dangiCalZoneAstroCalc->addTransitionRule(ruleFrom1912, status);
    dangiCalZoneAstroCalc->complete(status);
    if (U_SUCCESS(status)) {
        gDangiCalendarZoneAstroCalc = dangiCalZoneAstroCalc;
    } else {
        delete dangiCalZoneAstroCalc;
        gDangiCalendarZoneAstroCalc = NULL;
    }
    ucln_i18n_registerCleanup(UCLN_I18N_DANGI_CALENDAR, calendar_dangi_cleanup);
}
/*
 * Testing getOffset APIs around rule transition by local standard/wall time.
 */
void
TimeZoneOffsetLocalTest::TestGetOffsetAroundTransition() {
    const int32_t NUM_DATES = 10;
    const int32_t NUM_TIMEZONES = 3;

    const int32_t HOUR = 60*60*1000;
    const int32_t MINUTE = 60*1000;

    const int32_t DATES[NUM_DATES][6] = {
        {2006, UCAL_APRIL, 2, 1, 30, 1*HOUR+30*MINUTE},
        {2006, UCAL_APRIL, 2, 2, 00, 2*HOUR},
        {2006, UCAL_APRIL, 2, 2, 30, 2*HOUR+30*MINUTE},
        {2006, UCAL_APRIL, 2, 3, 00, 3*HOUR},
        {2006, UCAL_APRIL, 2, 3, 30, 3*HOUR+30*MINUTE},
        {2006, UCAL_OCTOBER, 29, 0, 30, 0*HOUR+30*MINUTE},
        {2006, UCAL_OCTOBER, 29, 1, 00, 1*HOUR},
        {2006, UCAL_OCTOBER, 29, 1, 30, 1*HOUR+30*MINUTE},
        {2006, UCAL_OCTOBER, 29, 2, 00, 2*HOUR},
        {2006, UCAL_OCTOBER, 29, 2, 30, 2*HOUR+30*MINUTE},
    };

    // Expected offsets by int32_t getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
    // uint8_t dayOfWeek, int32_t millis, UErrorCode& status)
    const int32_t OFFSETS1[NUM_DATES] = {
        // April 2, 2006
        -8*HOUR,
        -7*HOUR,
        -7*HOUR,
        -7*HOUR,
        -7*HOUR,

        // October 29, 2006
        -7*HOUR,
        -8*HOUR,
        -8*HOUR,
        -8*HOUR,
        -8*HOUR,
    };

    // Expected offsets by void getOffset(UDate date, UBool local, int32_t& rawOffset,
    // int32_t& dstOffset, UErrorCode& ec) with local=TRUE
    // or void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
    // int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) with
    // nonExistingTimeOpt=kStandard/duplicatedTimeOpt=kStandard
    const int32_t OFFSETS2[NUM_DATES][2] = {
        // April 2, 2006
        {-8*HOUR, 0},
        {-8*HOUR, 0},
        {-8*HOUR, 0},
        {-8*HOUR, 1*HOUR},
        {-8*HOUR, 1*HOUR},

        // Oct 29, 2006
        {-8*HOUR, 1*HOUR},
        {-8*HOUR, 0},
        {-8*HOUR, 0},
        {-8*HOUR, 0},
        {-8*HOUR, 0},
    };

    // Expected offsets by void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt,
    // int32_t duplicatedTimeOpt, int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) with
    // nonExistingTimeOpt=kDaylight/duplicatedTimeOpt=kDaylight
    const int32_t OFFSETS3[][2] = {
        // April 2, 2006
        {-8*HOUR, 0},
        {-8*HOUR, 1*HOUR},
        {-8*HOUR, 1*HOUR},
        {-8*HOUR, 1*HOUR},
        {-8*HOUR, 1*HOUR},

        // October 29, 2006
        {-8*HOUR, 1*HOUR},
        {-8*HOUR, 1*HOUR},
        {-8*HOUR, 1*HOUR},
        {-8*HOUR, 0},
        {-8*HOUR, 0},
    };

    UErrorCode status = U_ZERO_ERROR;

    int32_t rawOffset, dstOffset;
    TimeZone* utc = TimeZone::createTimeZone("UTC");
    Calendar* cal = Calendar::createInstance(*utc, status);
    if (U_FAILURE(status)) {
        errln("Calendar::createInstance failed");
        return;
    }
    cal->clear();

    // Set up TimeZone objects - OlsonTimeZone, SimpleTimeZone and RuleBasedTimeZone
    BasicTimeZone *TESTZONES[NUM_TIMEZONES];

    TESTZONES[0] = (BasicTimeZone*)TimeZone::createTimeZone("America/Los_Angeles");
    TESTZONES[1] = new SimpleTimeZone(-8*HOUR, "Simple Pacific Time",
                                        UCAL_APRIL, 1, UCAL_SUNDAY, 2*HOUR,
                                        UCAL_OCTOBER, -1, UCAL_SUNDAY, 2*HOUR, status);
    if (U_FAILURE(status)) {
        errln("SimpleTimeZone constructor failed");
        return;
    }

    InitialTimeZoneRule *ir = new InitialTimeZoneRule(
            "Pacific Standard Time", // Initial time Name
            -8*HOUR,        // Raw offset
            0*HOUR);        // DST saving amount

    RuleBasedTimeZone *rbPT = new RuleBasedTimeZone("Rule based Pacific Time", ir);

    DateTimeRule *dtr;
    AnnualTimeZoneRule *atzr;
    const int32_t STARTYEAR = 2000;

    dtr = new DateTimeRule(UCAL_APRIL, 1, UCAL_SUNDAY,
                        2*HOUR, DateTimeRule::WALL_TIME); // 1st Sunday in April, at 2AM wall time
    atzr = new AnnualTimeZoneRule("Pacific Daylight Time",
            -8*HOUR /* rawOffset */, 1*HOUR /* dstSavings */, dtr,
            STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
    rbPT->addTransitionRule(atzr, status);
    if (U_FAILURE(status)) {
        errln("Could not add DST start rule to the RuleBasedTimeZone rbPT");
        return;
    }

    dtr = new DateTimeRule(UCAL_OCTOBER, -1, UCAL_SUNDAY,
                        2*HOUR, DateTimeRule::WALL_TIME); // last Sunday in October, at 2AM wall time
    atzr = new AnnualTimeZoneRule("Pacific Standard Time",
            -8*HOUR /* rawOffset */, 0 /* dstSavings */, dtr,
            STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
    rbPT->addTransitionRule(atzr, status);
    if (U_FAILURE(status)) {
        errln("Could not add STD start rule to the RuleBasedTimeZone rbPT");
        return;
    }

    rbPT->complete(status);
    if (U_FAILURE(status)) {
        errln("complete() failed for RuleBasedTimeZone rbPT");
        return;
    }

    TESTZONES[2] = rbPT;

    // Calculate millis
    UDate MILLIS[NUM_DATES];
    for (int32_t i = 0; i < NUM_DATES; i++) {
        cal->clear();
        cal->set(DATES[i][0], DATES[i][1], DATES[i][2], DATES[i][3], DATES[i][4]);
        MILLIS[i] = cal->getTime(status);
        if (U_FAILURE(status)) {
            errln("cal->getTime failed");
            return;
        }
    }

    SimpleDateFormat df(UnicodeString("yyyy-MM-dd HH:mm:ss"), status);
    if (U_FAILURE(status)) {
        errln("Failed to initialize a SimpleDateFormat");
    }
    df.setTimeZone(*utc);
    UnicodeString dateStr;

    // Test getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
    // uint8_t dayOfWeek, int32_t millis, UErrorCode& status)
    for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
        for (int32_t d = 0; d < NUM_DATES; d++) {
            status = U_ZERO_ERROR;
            int32_t offset = TESTZONES[i]->getOffset(GregorianCalendar::AD, DATES[d][0], DATES[d][1], DATES[d][2],
                                                UCAL_SUNDAY, DATES[d][5], status);
            if (U_FAILURE(status)) {
                errln((UnicodeString)"getOffset(era,year,month,day,dayOfWeek,millis,status) failed for TESTZONES[" + i + "]");
            } else if (offset != OFFSETS1[d]) {
                dateStr.remove();
                df.format(MILLIS[d], dateStr);
                errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
                        + dateStr + "(standard) - Got: " + offset + " Expected: " + OFFSETS1[d]);
            }
        }
    }

    // Test getOffset(UDate date, UBool local, int32_t& rawOffset,
    // int32_t& dstOffset, UErrorCode& ec) with local = TRUE
    for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
        for (int32_t m = 0; m < NUM_DATES; m++) {
            status = U_ZERO_ERROR;
            TESTZONES[i]->getOffset(MILLIS[m], TRUE, rawOffset, dstOffset, status);
            if (U_FAILURE(status)) {
                errln((UnicodeString)"getOffset(date,local,rawOfset,dstOffset,ec) failed for TESTZONES[" + i + "]");
            } else if (rawOffset != OFFSETS2[m][0] || dstOffset != OFFSETS2[m][1]) {
                dateStr.remove();
                df.format(MILLIS[m], dateStr);
                errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
                        + dateStr + "(wall) - Got: "
                        + rawOffset + "/" + dstOffset
                        + " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]);
            }
        }
    }

    // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
    // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
    // with nonExistingTimeOpt=kStandard/duplicatedTimeOpt=kStandard
    for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
        for (int m = 0; m < NUM_DATES; m++) {
            status = U_ZERO_ERROR;
            TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kStandard, BasicTimeZone::kStandard,
                rawOffset, dstOffset, status);
            if (U_FAILURE(status)) {
                errln((UnicodeString)"getOffsetFromLocal with kStandard/kStandard failed for TESTZONES[" + i + "]");
            } else if (rawOffset != OFFSETS2[m][0] || dstOffset != OFFSETS2[m][1]) {
                dateStr.remove();
                df.format(MILLIS[m], dateStr);
                errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
                        + dateStr + "(wall/kStandard/kStandard) - Got: "
                        + rawOffset + "/" + dstOffset
                        + " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]);
            }
        }
    }

    // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
    // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
    // with nonExistingTimeOpt=kDaylight/duplicatedTimeOpt=kDaylight
    for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
        for (int m = 0; m < NUM_DATES; m++) {
            status = U_ZERO_ERROR;
            TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kDaylight, BasicTimeZone::kDaylight,
                rawOffset, dstOffset, status);
            if (U_FAILURE(status)) {
                errln((UnicodeString)"getOffsetFromLocal with kDaylight/kDaylight failed for TESTZONES[" + i + "]");
            } else if (rawOffset != OFFSETS3[m][0] || dstOffset != OFFSETS3[m][1]) {
                dateStr.remove();
                df.format(MILLIS[m], dateStr);
                errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
                        + dateStr + "(wall/kDaylight/kDaylight) - Got: "
                        + rawOffset + "/" + dstOffset
                        + " Expected: " + OFFSETS3[m][0] + "/" + OFFSETS3[m][1]);
            }
        }
    }

    // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
    // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
    // with nonExistingTimeOpt=kFormer/duplicatedTimeOpt=kLatter
    for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
        for (int m = 0; m < NUM_DATES; m++) {
            status = U_ZERO_ERROR;
            TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kFormer, BasicTimeZone::kLatter,
                rawOffset, dstOffset, status);
            if (U_FAILURE(status)) {
                errln((UnicodeString)"getOffsetFromLocal with kFormer/kLatter failed for TESTZONES[" + i + "]");
            } else if (rawOffset != OFFSETS2[m][0] || dstOffset != OFFSETS2[m][1]) {
                dateStr.remove();
                df.format(MILLIS[m], dateStr);
                errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
                        + dateStr + "(wall/kFormer/kLatter) - Got: "
                        + rawOffset + "/" + dstOffset
                        + " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]);
            }
        }
    }

    // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
    // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
    // with nonExistingTimeOpt=kLatter/duplicatedTimeOpt=kFormer
    for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
        for (int m = 0; m < NUM_DATES; m++) {
            status = U_ZERO_ERROR;
            TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kLatter, BasicTimeZone::kFormer,
                rawOffset, dstOffset, status);
            if (U_FAILURE(status)) {
                errln((UnicodeString)"getOffsetFromLocal with kLatter/kFormer failed for TESTZONES[" + i + "]");
            } else if (rawOffset != OFFSETS3[m][0] || dstOffset != OFFSETS3[m][1]) {
                dateStr.remove();
                df.format(MILLIS[m], dateStr);
                errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
                        + dateStr + "(wall/kLatter/kFormer) - Got: "
                        + rawOffset + "/" + dstOffset
                        + " Expected: " + OFFSETS3[m][0] + "/" + OFFSETS3[m][1]);
            }
        }
    }

    for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
        delete TESTZONES[i];
    }
    delete utc;
    delete cal;
}