From bc8ee5cca6174ce77df1c6520900499f03a5d000 Mon Sep 17 00:00:00 2001 From: Yoshito Umaoka Date: Thu, 9 Aug 2012 21:29:53 +0000 Subject: [PATCH] ICU-9452 Fixed calendar add issue with the Samoa Dec 2011 24 hour transition. X-SVN-Rev: 32141 --- icu4c/source/i18n/calendar.cpp | 17 +++++++--- icu4c/source/test/intltest/calregts.cpp | 44 +++++++++++++++++++++++++ icu4c/source/test/intltest/calregts.h | 1 + 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/icu4c/source/i18n/calendar.cpp b/icu4c/source/i18n/calendar.cpp index 2e5560f2a51..fa4f83b9bdd 100644 --- a/icu4c/source/i18n/calendar.cpp +++ b/icu4c/source/i18n/calendar.cpp @@ -2005,10 +2005,19 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status // danger of adjusting into a different day. To avoid // this we make the adjustment only if it actually // maintains the hour. - double t = internalGetTime(); - setTimeInMillis(t + prevOffset - newOffset, status); - if (get(UCAL_HOUR_OF_DAY, status) != hour) { - setTimeInMillis(t, status); + + // When the difference of the previous UTC offset and + // the new UTC offset exceeds 1 full day, we do not want + // to roll over/back the date. For now, this only happens + // in Samoa (Pacific/Apia) on Dec 30, 2011. See ticket:9452. + int32_t adjAmount = prevOffset - newOffset; + adjAmount = adjAmount >= 0 ? adjAmount % (int32_t)kOneDay : -(-adjAmount % (int32_t)kOneDay); + if (adjAmount != 0) { + double t = internalGetTime(); + setTimeInMillis(t + adjAmount, status); + if (get(UCAL_HOUR_OF_DAY, status) != hour) { + setTimeInMillis(t, status); + } } } } diff --git a/icu4c/source/test/intltest/calregts.cpp b/icu4c/source/test/intltest/calregts.cpp index 7d05e096ddc..b60c8b62fd0 100644 --- a/icu4c/source/test/intltest/calregts.cpp +++ b/icu4c/source/test/intltest/calregts.cpp @@ -87,6 +87,7 @@ CalendarRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* & CASE(47,TestT8057); CASE(48,TestT8596); CASE(49,Test9019); + CASE(50,TestT9452); default: name = ""; break; } } @@ -2898,4 +2899,47 @@ void CalendarRegressionTest::TestT8596(void) { delete gc; } +// Test case for ticket 9452 +// Calendar addition fall onto the missing date - 2011-12-30 in Samoa +void CalendarRegressionTest::TestT9452(void) { + UErrorCode status = U_ZERO_ERROR; + GregorianCalendar cal(TimeZone::createTimeZone("Pacific/Apia"), status); + failure(status, "initializing GregorianCalendar"); + + SimpleDateFormat sdf(UnicodeString("y-MM-dd'T'HH:mm:ssZZZZZ"), status); + failure(status, "initializing SimpleDateFormat"); + sdf.setCalendar(cal); + + UnicodeString dstr; + + // Set date to 2011-12-29 00:00 + cal.clear(); + cal.set(2011, UCAL_DECEMBER, 29, 0, 0, 0); + + UDate d = cal.getTime(status); + failure(status, "getTime for initial date"); + sdf.format(d, dstr); + logln(UnicodeString("Initial date: ") + dstr); + + // Add 1 day + cal.add(UCAL_DATE, 1, status); + failure(status, "add 1 day"); + d = cal.getTime(status); + failure(status, "getTime after +1 day"); + dstr.remove(); + sdf.format(d, dstr); + logln(UnicodeString("+1 day: ") + dstr); + assertEquals("Add 1 day", UnicodeString("2011-12-31T00:00:00+14:00"), dstr); + + // Subtract 1 day + cal.add(UCAL_DATE, -1, status); + failure(status, "subtract 1 day"); + d = cal.getTime(status); + failure(status, "getTime after -1 day"); + dstr.remove(); + sdf.format(d, dstr); + logln(UnicodeString("-1 day: ") + dstr); + assertEquals("Subtract 1 day", UnicodeString("2011-12-29T00:00:00-10:00"), dstr); +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/test/intltest/calregts.h b/icu4c/source/test/intltest/calregts.h index 294d3345df1..c099d2bbaff 100644 --- a/icu4c/source/test/intltest/calregts.h +++ b/icu4c/source/test/intltest/calregts.h @@ -74,6 +74,7 @@ public: void TestDeprecates(void); void TestT8596(void); void Test9019(void); + void TestT9452(void); void printdate(GregorianCalendar *cal, const char *string); void dowTest(UBool lenient) ;