From caafcceb8f7900c804134b8360bc9df275ebe3b6 Mon Sep 17 00:00:00 2001 From: Ram Viswanadha Date: Fri, 4 Nov 2005 21:57:24 +0000 Subject: [PATCH] ICU-4912 synchronize with ICU4J X-SVN-Rev: 18758 --- icu4c/source/i18n/dtfmtsym.cpp | 2 + icu4c/source/i18n/olsontz.cpp | 13 +- icu4c/source/i18n/olsontz.h | 4 +- icu4c/source/i18n/simpletz.cpp | 7 +- icu4c/source/i18n/timezone.cpp | 31 +++-- icu4c/source/i18n/unicode/timezone.h | 18 ++- icu4c/source/test/intltest/calregts.cpp | 10 ++ icu4c/source/test/intltest/dtfmttst.cpp | 17 ++- icu4c/source/test/intltest/intltest.vcproj | 6 +- icu4c/source/test/intltest/tzbdtest.cpp | 108 +++++++++++++-- icu4c/source/test/intltest/tzbdtest.h | 5 +- icu4c/source/test/intltest/tzregts.cpp | 151 ++++++++++++++++++++- icu4c/source/test/intltest/tzregts.h | 5 +- icu4c/source/test/intltest/tztest.cpp | 19 ++- icu4c/source/test/intltest/tztest.h | 4 +- 15 files changed, 359 insertions(+), 41 deletions(-) diff --git a/icu4c/source/i18n/dtfmtsym.cpp b/icu4c/source/i18n/dtfmtsym.cpp index ecb7d0ce89..f694789ff6 100644 --- a/icu4c/source/i18n/dtfmtsym.cpp +++ b/icu4c/source/i18n/dtfmtsym.cpp @@ -1765,6 +1765,8 @@ DateFormatSymbols::getZoneID(const UnicodeString& zid, UnicodeString& result, UE } } } + }else{ + result.setTo(zid); } return result; } diff --git a/icu4c/source/i18n/olsontz.cpp b/icu4c/source/i18n/olsontz.cpp index d31fa4d30b..792a996b18 100644 --- a/icu4c/source/i18n/olsontz.cpp +++ b/icu4c/source/i18n/olsontz.cpp @@ -473,7 +473,18 @@ UBool OlsonTimeZone::useDaylightTime() const { } return FALSE; } - +inline int32_t OlsonTimeZone::getDSTSavings() const{ + if(finalZone!=NULL){ + return finalZone->getDSTSavings(); + } + // return super->getDSTSavings(); + // this is basically identical to implementation in + // superclass timezone + if (useDaylightTime()) { + return 3600000; + } + return 0; +} /** * TimeZone API. */ diff --git a/icu4c/source/i18n/olsontz.h b/icu4c/source/i18n/olsontz.h index ef19ee2a22..4728b82ade 100644 --- a/icu4c/source/i18n/olsontz.h +++ b/icu4c/source/i18n/olsontz.h @@ -1,6 +1,6 @@ /* ********************************************************************** -* Copyright (c) 2003-2004, International Business Machines +* Copyright (c) 2003-2005, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** * Author: Alan Liu @@ -209,6 +209,8 @@ class U_I18N_API OlsonTimeZone: public TimeZone { */ virtual UBool inDaylightTime(UDate date, UErrorCode& ec) const; + virtual inline int32_t getDSTSavings() const; + protected: /** * Default constructor. Creates a time zone with an empty ID and diff --git a/icu4c/source/i18n/simpletz.cpp b/icu4c/source/i18n/simpletz.cpp index 393d339d28..111ca43f54 100644 --- a/icu4c/source/i18n/simpletz.cpp +++ b/icu4c/source/i18n/simpletz.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 1997-2003, International Business Machines Corporation and * +* Copyright (C) 1997-2005, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -27,6 +27,7 @@ #include "unicode/simpletz.h" #include "unicode/gregocal.h" +#include "unicode/smpdtfmt.h" U_NAMESPACE_BEGIN @@ -822,7 +823,7 @@ SimpleTimeZone::decodeStartRule(UErrorCode& status) status = U_ILLEGAL_ARGUMENT_ERROR; return; } - } else if (startDay > STATICMONTHLENGTH[startMonth]) { + } else if (startDay<1 || startDay > STATICMONTHLENGTH[startMonth]) { status = U_ILLEGAL_ARGUMENT_ERROR; return; } @@ -877,7 +878,7 @@ SimpleTimeZone::decodeEndRule(UErrorCode& status) status = U_ILLEGAL_ARGUMENT_ERROR; return; } - } else if (endDay > STATICMONTHLENGTH[endMonth]) { + } else if (endDay<1 || endDay > STATICMONTHLENGTH[endMonth]) { status = U_ILLEGAL_ARGUMENT_ERROR; return; } diff --git a/icu4c/source/i18n/timezone.cpp b/icu4c/source/i18n/timezone.cpp index 79ecf4feef..42200e475b 100644 --- a/icu4c/source/i18n/timezone.cpp +++ b/icu4c/source/i18n/timezone.cpp @@ -1073,7 +1073,15 @@ TimeZone::getDisplayName(UBool daylight, EDisplayType style, UnicodeString& resu { return getDisplayName(daylight,style, Locale::getDefault(), result); } - +//-------------------------------------- +inline int32_t +TimeZone::getDSTSavings()const { + if (useDaylightTime()) { + return 3600000; + } + return 0; +} +//--------------------------------------- UnicodeString& TimeZone::getDisplayName(UBool daylight, EDisplayType style, const Locale& locale, UnicodeString& result) const { @@ -1100,14 +1108,17 @@ TimeZone::getDisplayName(UBool daylight, EDisplayType style, const Locale& local // and hence the same display name. // We don't cache these because they're small and cheap to create. UnicodeString tempID; - SimpleTimeZone *tz = daylight ? - // For the pure-DST zone, we use JANUARY and DECEMBER - - new SimpleTimeZone(getRawOffset(), getID(tempID), - UCAL_JANUARY , 1, 0, 0, - UCAL_DECEMBER , 31, 0, U_MILLIS_PER_DAY, status) : - new SimpleTimeZone(getRawOffset(), getID(tempID)); - + SimpleTimeZone *tz = NULL; + if(daylight && useDaylightTime()){ + // For the pure-DST zone, we use JANUARY and DECEMBER + int savings = getDSTSavings(); + tz = new SimpleTimeZone(getRawOffset(), getID(tempID), + UCAL_JANUARY, 1, 0, 0, + UCAL_FEBRUARY, 1, 0, 0, + savings, status); + }else{ + tz = new SimpleTimeZone(getRawOffset(), getID(tempID)); + } format.applyPattern(style == LONG ? ZZZZ_STR : Z_STR); Calendar *myCalendar = (Calendar*)format.getCalendar(); myCalendar->setTimeZone(*tz); // copy @@ -1115,7 +1126,7 @@ TimeZone::getDisplayName(UBool daylight, EDisplayType style, const Locale& local delete tz; FieldPosition pos(FieldPosition::DONT_CARE); - return format.format(UDate(196262345678.), result, pos); // Must use a valid date here. + return format.format(UDate(864000000L), result, pos); // Must use a valid date here. } diff --git a/icu4c/source/i18n/unicode/timezone.h b/icu4c/source/i18n/unicode/timezone.h index 1d4e4bbe1b..861a03bf96 100644 --- a/icu4c/source/i18n/unicode/timezone.h +++ b/icu4c/source/i18n/unicode/timezone.h @@ -602,7 +602,23 @@ public: * @stable ICU 2.0 */ virtual UClassID getDynamicClassID(void) const = 0; - + + /** + * Returns the amount of time to be added to local standard time + * to get local wall clock time. + *

+ * The default implementation always returns 3600000 milliseconds + * (i.e., one hour) if this time zone observes Daylight Saving + * Time. Otherwise, 0 (zero) is returned. + *

+ * If an underlying TimeZone implementation subclass supports + * historical Daylight Saving Time changes, this method returns + * the known latest daylight saving value. + * + * @return the amount of saving time in milliseconds + * @draft ICU 3.6 + */ + virtual inline int32_t getDSTSavings() const; protected: /** diff --git a/icu4c/source/test/intltest/calregts.cpp b/icu4c/source/test/intltest/calregts.cpp index d38bf8a947..b515cf8f48 100644 --- a/icu4c/source/test/intltest/calregts.cpp +++ b/icu4c/source/test/intltest/calregts.cpp @@ -215,6 +215,16 @@ CalendarRegressionTest::test4031502() UErrorCode status = U_ZERO_ERROR; StringEnumeration* ids = TimeZone::createEnumeration(); UBool bad = FALSE; + TimeZone* tz =TimeZone::createTimeZone("Asia/Riyadh87"); + failure(status, "new TimeZone"); + GregorianCalendar *cl = new GregorianCalendar(tz, status); + failure(status, "new GregorianCalendar"); + cl->clear(); + cl->set(1900, 15, 5, 5, 8, 13); + cl->get(UCAL_HOUR, status); + failure(status, "cl->get(UCAL_HOUR, status)"); + status = U_ZERO_ERROR; + delete tz; for (int32_t i=0; icount(status); ++i) { TimeZone *zone = TimeZone::createTimeZone(*ids->snext(status)); GregorianCalendar *cal = new GregorianCalendar(zone, status); diff --git a/icu4c/source/test/intltest/dtfmttst.cpp b/icu4c/source/test/intltest/dtfmttst.cpp index a75653a0f2..a1d94e5cdc 100644 --- a/icu4c/source/test/intltest/dtfmttst.cpp +++ b/icu4c/source/test/intltest/dtfmttst.cpp @@ -176,6 +176,9 @@ DateFormatTest::TestEquals() if (!(*fmtA == *fmtB)) errln((UnicodeString)"FAIL"); delete fmtA; delete fmtB; + + TimeZone* test = TimeZone::createTimeZone("PDT"); + delete test; } // ------------------------------------- @@ -191,13 +194,21 @@ DateFormatTest::TestTwoDigitYearDSTParse(void) SimpleDateFormat *fmt = new SimpleDateFormat((UnicodeString)"dd-MMM-yy h:mm:ss 'o''clock' a z", Locale::getEnglish(), status); //DateFormat* fmt = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL, Locale::ENGLISH); UnicodeString* s = new UnicodeString("03-Apr-04 2:20:47 o'clock AM PST", ""); - int32_t hour = 2; - + TimeZone* defaultTZ = TimeZone::createDefault(); + TimeZone* PST = TimeZone::createTimeZone("PST"); + int32_t defaultOffset = defaultTZ->getRawOffset(); + int32_t PSTOffset = PST->getRawOffset(); + int32_t hour = 2 + (defaultOffset - PSTOffset) / (60*60*1000); + // hour is the expected hour of day, in units of seconds + hour = ((hour < 0) ? hour + 24 : hour) * 60*60; + UnicodeString str; UDate d = fmt->parse(*s, status); logln(*s + " P> " + ((DateFormat*)fullFmt)->format(d, str)); int32_t y, m, day, hr, min, sec; dateToFields(d, y, m, day, hr, min, sec); + hour += defaultTZ->inDaylightTime(d, status) ? 1 : 0; + hr = hr*60*60; if (hr != hour) errln((UnicodeString)"FAIL: Should parse to hour " + hour + " but got " + hr); @@ -207,6 +218,8 @@ DateFormatTest::TestTwoDigitYearDSTParse(void) delete s; delete fmt; delete fullFmt; + delete PST; + delete defaultTZ; } // ------------------------------------- diff --git a/icu4c/source/test/intltest/intltest.vcproj b/icu4c/source/test/intltest/intltest.vcproj index f77e64ce03..3e90beeb0e 100644 --- a/icu4c/source/test/intltest/intltest.vcproj +++ b/icu4c/source/test/intltest/intltest.vcproj @@ -362,6 +362,9 @@ + + @@ -384,9 +387,6 @@ - - diff --git a/icu4c/source/test/intltest/tzbdtest.cpp b/icu4c/source/test/intltest/tzbdtest.cpp index 66e0f24a17..6e305f458f 100644 --- a/icu4c/source/test/intltest/tzbdtest.cpp +++ b/icu4c/source/test/intltest/tzbdtest.cpp @@ -1,6 +1,6 @@ /*********************************************************************** * COPYRIGHT: - * Copyright (c) 1997-2004, International Business Machines Corporation + * Copyright (c) 1997-2005, International Business Machines Corporation * and others. All Rights Reserved. ***********************************************************************/ @@ -193,13 +193,19 @@ TimeZoneBoundaryTest::verifyDST(UDate d, TimeZone* time_zone, UBool expUseDaylig logln("-- Verifying time " + dateToString(d) + " in zone " + time_zone->getID(str)); if (time_zone->inDaylightTime(d, status) == expInDaylightTime) logln(UnicodeString("PASS: inDaylightTime = ") + (time_zone->inDaylightTime(d, status)?"true":"false")); - else errln(UnicodeString("FAIL: inDaylightTime = ") + (time_zone->inDaylightTime(d, status)?"true":"false")); - if (failure(status, "TimeZone::inDaylightTime")) return; + else + errln(UnicodeString("FAIL: inDaylightTime = ") + (time_zone->inDaylightTime(d, status)?"true":"false")); + if (failure(status, "TimeZone::inDaylightTime")) + return; if (time_zone->useDaylightTime() == expUseDaylightTime) logln(UnicodeString("PASS: useDaylightTime = ") + (time_zone->useDaylightTime()?"true":"false")); - else errln(UnicodeString("FAIL: useDaylightTime = ") + (time_zone->useDaylightTime()?"true":"false")); - if (time_zone->getRawOffset() == expZoneOffset) logln(UnicodeString("PASS: getRawOffset() = ") + (expZoneOffset / ONE_HOUR)); - else errln(UnicodeString("FAIL: getRawOffset() = ") + (time_zone->getRawOffset() / ONE_HOUR) + "; expected " + (expZoneOffset / ONE_HOUR)); + else + errln(UnicodeString("FAIL: useDaylightTime = ") + (time_zone->useDaylightTime()?"true":"false")); + if (time_zone->getRawOffset() == expZoneOffset) + logln(UnicodeString("PASS: getRawOffset() = ") + (expZoneOffset / ONE_HOUR)); + else + errln(UnicodeString("FAIL: getRawOffset() = ") + (time_zone->getRawOffset() / ONE_HOUR) + "; expected " + (expZoneOffset / ONE_HOUR)); + GregorianCalendar *gc = new GregorianCalendar(time_zone->clone(), status); gc->setTime(d, status); if (failure(status, "GregorianCalendar::setTime")) return; @@ -215,7 +221,52 @@ TimeZoneBoundaryTest::verifyDST(UDate d, TimeZone* time_zone, UBool expUseDaylig } // ------------------------------------- - +/** + * Check that the given year/month/dom/hour maps to and from the + * given epochHours. This verifies the functioning of the + * calendar and time zone in conjunction with one another, + * including the calendar time->fields and fields->time and + * the time zone getOffset method. + * + * @param epochHours hours after Jan 1 1970 0:00 GMT. + */ +void TimeZoneBoundaryTest::verifyMapping(Calendar& cal, int year, int month, int dom, int hour, + double epochHours) { + double H = 3600000.0; + UErrorCode status = U_ZERO_ERROR; + cal.clear(); + cal.set(year, month, dom, hour, 0, 0); + UDate e = cal.getTime(status)/ H; + UDate ed = (epochHours * H); + if (e == epochHours) { + logln(UnicodeString("Ok: ") + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " + + e + " (" + ed + ")"); + } else { + errln(UnicodeString("FAIL: ") + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " + + e + " (" + (e * H) + ")" + + ", expected " + epochHours + " (" + ed + ")"); + } + cal.setTime(ed, status); + if (cal.get(UCAL_YEAR, status) == year && + cal.get(UCAL_MONTH, status) == month && + cal.get(UCAL_DATE, status) == dom && + cal.get(UCAL_MILLISECONDS_IN_DAY, status) == hour * 3600000) { + logln(UnicodeString("Ok: ") + epochHours + " (" + ed + ") => " + + cal.get(UCAL_YEAR, status) + "/" + + (cal.get(UCAL_MONTH, status)+1) + "/" + + cal.get(UCAL_DATE, status) + " " + + cal.get(UCAL_MILLISECOND, status)/H); + } else { + errln(UnicodeString("FAIL: ") + epochHours + " (" + ed + ") => " + + cal.get(UCAL_YEAR, status) + "/" + + (cal.get(UCAL_MONTH, status)+1) + "/" + + cal.get(UCAL_DATE, status) + " " + + cal.get(UCAL_MILLISECOND, status)/H + + ", expected " + year + "/" + (month+1) + "/" + dom + + " " + hour); + } +} + /** * Test the behavior of SimpleTimeZone at the transition into and out of DST. * Use a binary search to find boundaries. @@ -223,6 +274,47 @@ TimeZoneBoundaryTest::verifyDST(UDate d, TimeZone* time_zone, UBool expUseDaylig void TimeZoneBoundaryTest::TestBoundaries() { + UErrorCode status = U_ZERO_ERROR; + TimeZone* pst = TimeZone::createTimeZone("PST"); + Calendar* tempcal = Calendar::createInstance(pst, status); + if(U_SUCCESS(status)){ + verifyMapping(*tempcal, 1997, Calendar::APRIL, 3, 0, 238904.0); + verifyMapping(*tempcal, 1997, Calendar::APRIL, 4, 0, 238928.0); + verifyMapping(*tempcal, 1997, Calendar::APRIL, 5, 0, 238952.0); + verifyMapping(*tempcal, 1997, Calendar::APRIL, 5, 23, 238975.0); + verifyMapping(*tempcal, 1997, Calendar::APRIL, 6, 0, 238976.0); + verifyMapping(*tempcal, 1997, Calendar::APRIL, 6, 1, 238977.0); + verifyMapping(*tempcal, 1997, Calendar::APRIL, 6, 3, 238978.0); + }else{ + errln("Could not create calendar. Error: %s", u_errorName(status)); + } + TimeZone* utc = TimeZone::createTimeZone("UTC"); + Calendar* utccal = Calendar::createInstance(utc, status); + if(U_SUCCESS(status)){ + verifyMapping(*utccal, 1997, Calendar::APRIL, 6, 0, 238968.0); + }else{ + errln("Could not create calendar. Error: %s", u_errorName(status)); + } + TimeZone* save = TimeZone::createDefault(); + TimeZone::setDefault(*pst); + + // DST changeover for PST is 4/6/1997 at 2 hours past midnight + // at 238978.0 epoch hours. + tempcal->clear(); + tempcal->set(1997, Calendar::APRIL, 6); + UDate d = tempcal->getTime(status); + + // i is minutes past midnight standard time + for (int i=-120; i<=180; i+=60) + { + UBool inDST = (i >= 120); + tempcal->setTime(d + i*60*1000, status); + verifyDST(tempcal->getTime(status),pst, TRUE, inDST, -8*ONE_HOUR,inDST ? -7*ONE_HOUR : -8*ONE_HOUR); + } + TimeZone::setDefault(*save); + delete utccal; + delete tempcal; + #if 1 { logln("--- Test a ---"); @@ -292,7 +384,7 @@ TimeZoneBoundaryTest::testUsingBinarySearch(SimpleTimeZone* tz, UDate d, UDate e UBool startsInDST = tz->inDaylightTime(d, status); if (failure(status, "SimpleTimeZone::inDaylightTime")) return; if (tz->inDaylightTime(max, status) == startsInDST) { - logln("Error: inDaylightTime(" + dateToString(max) + ") != " + ((!startsInDST)?"true":"false")); + errln("Error: inDaylightTime(" + dateToString(max) + ") != " + ((!startsInDST)?"true":"false")); } if (failure(status, "SimpleTimeZone::inDaylightTime")) return; while ((max - min) > INTERVAL) { diff --git a/icu4c/source/test/intltest/tzbdtest.h b/icu4c/source/test/intltest/tzbdtest.h index f58beb6256..ecc867c9fa 100644 --- a/icu4c/source/test/intltest/tzbdtest.h +++ b/icu4c/source/test/intltest/tzbdtest.h @@ -1,6 +1,6 @@ /******************************************************************** * COPYRIGHT: - * Copyright (c) 1997-2001, International Business Machines Corporation and + * Copyright (c) 1997-2005, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ @@ -79,7 +79,8 @@ public: // package * Use a stepwise march to find boundaries. */ virtual void TestStepwise(void); - + void verifyMapping(Calendar& cal, int year, int month, int dom, int hour, + double epochHours) ; private: const UDate ONE_SECOND; const UDate ONE_MINUTE; diff --git a/icu4c/source/test/intltest/tzregts.cpp b/icu4c/source/test/intltest/tzregts.cpp index b13947873a..c1844141a4 100644 --- a/icu4c/source/test/intltest/tzregts.cpp +++ b/icu4c/source/test/intltest/tzregts.cpp @@ -1,6 +1,6 @@ /******************************************************************** * COPYRIGHT: - * Copyright (c) 1997-2003, International Business Machines Corporation and + * Copyright (c) 1997-2005, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ @@ -18,7 +18,8 @@ // ***************************************************************************** // class TimeZoneRegressionTest // ***************************************************************************** - +/* length of an array */ +#define ARRAY_LENGTH(array) (sizeof(array)/sizeof(array[0])) #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break void @@ -44,7 +45,8 @@ TimeZoneRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* & CASE(14, TestJ186); CASE(15, TestJ449); CASE(16, TestJDK12API); - + CASE(17, Test4176686); + CASE(18, Test4184229); default: name = ""; break; } } @@ -871,16 +873,16 @@ TimeZoneRegressionTest::Test4162593() // Must construct the Date object AFTER setting the default zone int32_t *p = (int32_t*)DATA_INT[j]; UDate d = CalendarRegressionTest::makeDate(p[0], p[1], p[2], p[3], p[4]); - UBool transitionExpected = DATA_BOOL[j]; + UBool transitionExpected = DATA_BOOL[j]; UnicodeString temp; logln(tz->getID(temp) + ":"); for (int32_t i = 0; i < 4; ++i) { FieldPosition pos(0); zone[i].remove(); - zone[i] = fmt->format(d, zone[i], pos); + zone[i] = fmt->format(d+ i*ONE_HOUR, zone[i], pos); logln(UnicodeString("") + i + ": " + d + " / " + zone[i]); - d += (double) ONE_HOUR; + //d += (double) ONE_HOUR; } if(zone[0] == zone[1] && (zone[1] == zone[2]) != transitionExpected && @@ -896,6 +898,72 @@ TimeZoneRegressionTest::Test4162593() delete DATA_TZ[0]; } + /** + * getDisplayName doesn't work with unusual savings/offsets. + */ +void TimeZoneRegressionTest::Test4176686() { + // Construct a zone that does not observe DST but + // that does have a DST savings (which should be ignored). + UErrorCode status = U_ZERO_ERROR; + int32_t offset = 90 * 60000; // 1:30 + SimpleTimeZone* z1 = new SimpleTimeZone(offset, "_std_zone_"); + z1->setDSTSavings(45 * 60000, status); // 0:45 + + // Construct a zone that observes DST for the first 6 months. + SimpleTimeZone* z2 = new SimpleTimeZone(offset, "_dst_zone_"); + z2->setDSTSavings(45 * 60000, status); // 0:45 + z2->setStartRule(UCAL_JANUARY, 1, 0, status); + z2->setEndRule(UCAL_JULY, 1, 0, status); + + // Also check DateFormat + DateFormat* fmt1 = new SimpleDateFormat(UnicodeString("z"), status); + fmt1->setTimeZone(*z1); // Format uses standard zone + DateFormat* fmt2 = new SimpleDateFormat(UnicodeString("z"), status); + fmt2->setTimeZone(*z2); // Format uses DST zone + Calendar* tempcal = Calendar::createInstance(status); + tempcal->clear(); + tempcal->set(1970, UCAL_FEBRUARY, 1); + UDate dst = tempcal->getTime(status); // Time in DST + tempcal->set(1970, UCAL_AUGUST, 1); + UDate std = tempcal->getTime(status); // Time in standard + + // Description, Result, Expected Result + UnicodeString a,b,c,d,e,f,g,h,i,j,k,l; + UnicodeString DATA[] = { + "z1->getDisplayName(false, SHORT)/std zone", + z1->getDisplayName(FALSE, TimeZone::SHORT, a), "GMT+01:30", + "z1->getDisplayName(false, LONG)/std zone", + z1->getDisplayName(FALSE, TimeZone::LONG, b), "GMT+01:30", + "z1->getDisplayName(true, SHORT)/std zone", + z1->getDisplayName(TRUE, TimeZone::SHORT, c), "GMT+01:30", + "z1->getDisplayName(true, LONG)/std zone", + z1->getDisplayName(TRUE, TimeZone::LONG, d ), "GMT+01:30", + "z2->getDisplayName(false, SHORT)/dst zone", + z2->getDisplayName(FALSE, TimeZone::SHORT, e), "GMT+01:30", + "z2->getDisplayName(false, LONG)/dst zone", + z2->getDisplayName(FALSE, TimeZone::LONG, f ), "GMT+01:30", + "z2->getDisplayName(true, SHORT)/dst zone", + z2->getDisplayName(TRUE, TimeZone::SHORT, g), "GMT+02:15", + "z2->getDisplayName(true, LONG)/dst zone", + z2->getDisplayName(TRUE, TimeZone::LONG, h ), "GMT+02:15", + "DateFormat.format(std)/std zone", fmt1->format(std, i), "GMT+01:30", + "DateFormat.format(dst)/std zone", fmt1->format(dst, j), "GMT+01:30", + "DateFormat.format(std)/dst zone", fmt2->format(std, k), "GMT+01:30", + "DateFormat.format(dst)/dst zone", fmt2->format(dst, l), "GMT+02:15", + }; + + for (int i=0; i " + DATA[i+1] + ", exp " + DATA[i+2]); + } + } + delete z1; + delete z2; + delete fmt1; + delete fmt2; + delete tempcal; +} + /** * Make sure setStartRule and setEndRule set the DST savings to nonzero * if it was zero. @@ -1050,5 +1118,76 @@ TimeZoneRegressionTest::TestJDK12API() delete pst; delete cst; } +/** + * SimpleTimeZone allows invalid DOM values. + */ +void TimeZoneRegressionTest::Test4184229() { + SimpleTimeZone* zone = NULL; + UErrorCode status = U_ZERO_ERROR; + zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 0, status); + if(U_SUCCESS(status)){ + errln("Failed. No exception has been thrown for DOM -1 startDay"); + }else{ + logln("(a) " + UnicodeString( u_errorName(status))); + } + status = U_ZERO_ERROR; + delete zone; + + zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, status); + if(U_SUCCESS(status)){ + errln("Failed. No exception has been thrown for DOM -1 endDay"); + }else{ + logln("(b) " + UnicodeString(u_errorName(status))); + } + status = U_ZERO_ERROR; + delete zone; + + zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 1000, status); + if(U_SUCCESS(status)){ + errln("Failed. No exception has been thrown for DOM -1 startDay+savings"); + }else{ + logln("(c) " + UnicodeString(u_errorName(status))); + } + status = U_ZERO_ERROR; + delete zone; + zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, 1000, status); + if(U_SUCCESS(status)){ + errln("Failed. No exception has been thrown for DOM -1 endDay+ savings"); + }else{ + logln("(d) " + UnicodeString(u_errorName(status))); + } + status = U_ZERO_ERROR; + delete zone; + // Make a valid constructor call for subsequent tests. + zone = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 0, 1, 0, 0, status); + + zone->setStartRule(0, -1, 0, 0, status); + if(U_SUCCESS(status)){ + errln("Failed. No exception has been thrown for DOM -1 setStartRule +savings"); + } else{ + logln("(e) " + UnicodeString(u_errorName(status))); + } + zone->setStartRule(0, -1, 0, status); + if(U_SUCCESS(status)){ + errln("Failed. No exception has been thrown for DOM -1 setStartRule"); + } else{ + logln("(f) " + UnicodeString(u_errorName(status))); + } + + zone->setEndRule(0, -1, 0, 0, status); + if(U_SUCCESS(status)){ + errln("Failed. No exception has been thrown for DOM -1 setEndRule+savings"); + } else{ + logln("(g) " + UnicodeString(u_errorName(status))); + } + + zone->setEndRule(0, -1, 0, status); + if(U_SUCCESS(status)){ + errln("Failed. No exception has been thrown for DOM -1 setEndRule"); + } else{ + logln("(h) " + UnicodeString(u_errorName(status))); + } + delete zone; +} #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/test/intltest/tzregts.h b/icu4c/source/test/intltest/tzregts.h index 5fefadb747..6b5500c953 100644 --- a/icu4c/source/test/intltest/tzregts.h +++ b/icu4c/source/test/intltest/tzregts.h @@ -1,6 +1,6 @@ /******************************************************************** * COPYRIGHT: - * Copyright (c) 1998-2001, International Business Machines Corporation and + * Copyright (c) 1998-2005, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ @@ -41,10 +41,11 @@ public: void Test4154650(void); void Test4154525(void); void Test4162593(void); + void Test4176686(void); void TestJ186(void); void TestJ449(void); void TestJDK12API(void); - + void Test4184229(void); UBool checkCalendar314(GregorianCalendar *testCal, TimeZone *testTZ); diff --git a/icu4c/source/test/intltest/tztest.cpp b/icu4c/source/test/intltest/tztest.cpp index 9ec3b8e09f..176f967796 100644 --- a/icu4c/source/test/intltest/tztest.cpp +++ b/icu4c/source/test/intltest/tztest.cpp @@ -48,6 +48,7 @@ void TimeZoneTest::runIndexedTest( int32_t index, UBool exec, const char* &name, CASE(11,TestHistorical); CASE(12,TestEquivalentIDs); CASE(13, TestAliasedNames); + CASE(14, TestFractionalDST); default: name = ""; break; } } @@ -776,7 +777,7 @@ void TimeZoneTest::TestCustomParse() kData[] = { // ID Expected offset in minutes - //"GMT", kUnparseable, Isn't custom. Can't test it here. [returns normal GMT] + //{"GMT", kUnparseable}, //Isn't custom. Can't test it here. [returns normal GMT] {"GMT-YOUR.AD.HERE", kUnparseable}, // {"GMT0", kUnparseable}, // ICU 2.8: An Olson zone ID // {"GMT+0", (0)}, // ICU 2.8: An Olson zone ID @@ -1334,6 +1335,22 @@ TimeZoneTest::TestAlternateRules() + (offset / U_MILLIS_PER_HOUR) + " hours."); } +void TimeZoneTest::TestFractionalDST() { + const char* tzName = "Australia/Lord_Howe"; // 30 min offset + TimeZone* tz_icu = TimeZone::createTimeZone(tzName); + int dst_icu = tz_icu->getDSTSavings(); + UnicodeString id; + int32_t expected = 1800000; + if (expected != dst_icu) { + errln(UnicodeString("java reports dst savings of ") + expected + + " but icu reports " + dst_icu + + " for tz " + tz_icu->getID(id)); + } else { + logln(UnicodeString("both java and icu report dst savings of ") + expected + " for tz " + tz_icu->getID(id)); + } + delete tz_icu; +} + /** * Test country code support. Jitterbug 776. */ diff --git a/icu4c/source/test/intltest/tztest.h b/icu4c/source/test/intltest/tztest.h index 5e24930bb4..6aa70343ff 100644 --- a/icu4c/source/test/intltest/tztest.h +++ b/icu4c/source/test/intltest/tztest.h @@ -84,7 +84,9 @@ public: void TestEquivalentIDs(void); void TestAliasedNames(void); - + + void TestFractionalDST(void); + static const UDate INTERVAL; private: