From c42e57a06c26ded74e6301ddf3c5626867c480a5 Mon Sep 17 00:00:00 2001 From: Scott Russell Date: Tue, 17 Sep 2013 16:55:02 +0000 Subject: [PATCH] ICU-10249 Implement new islamic calendar variants tbla, rgsa X-SVN-Rev: 34354 --- icu4c/source/i18n/calendar.cpp | 8 ++++-- icu4c/source/i18n/islamcal.cpp | 16 +++++++---- icu4c/source/i18n/islamcal.h | 15 ++++++++-- icu4c/source/test/intltest/caltest.cpp | 38 +++++++++++++++++++++++++- icu4c/source/test/intltest/caltest.h | 1 + 5 files changed, 66 insertions(+), 12 deletions(-) diff --git a/icu4c/source/i18n/calendar.cpp b/icu4c/source/i18n/calendar.cpp index c7609320277..27825c04a2c 100644 --- a/icu4c/source/i18n/calendar.cpp +++ b/icu4c/source/i18n/calendar.cpp @@ -323,9 +323,14 @@ static Calendar *createStandardCalendar(ECalType calType, const Locale &loc, UEr case CALTYPE_PERSIAN: cal = new PersianCalendar(loc, status); break; + case CALTYPE_ISLAMIC_TBLA: + cal = new IslamicCalendar(loc, status, IslamicCalendar::TBLA); + break; case CALTYPE_ISLAMIC_CIVIL: cal = new IslamicCalendar(loc, status, IslamicCalendar::CIVIL); break; + case CALTYPE_ISLAMIC_RGSA: + // default any region specific not handled individually to islamic case CALTYPE_ISLAMIC: cal = new IslamicCalendar(loc, status, IslamicCalendar::ASTRONOMICAL); break; @@ -358,9 +363,6 @@ static Calendar *createStandardCalendar(ECalType calType, const Locale &loc, UEr case CALTYPE_DANGI: cal = new DangiCalendar(loc, status); break; - case CALTYPE_ISLAMIC_TBLA: - case CALTYPE_ISLAMIC_RGSA: - // Need to add handling for these, meanwhile fall through to default default: status = U_UNSUPPORTED_ERROR; } diff --git a/icu4c/source/i18n/islamcal.cpp b/icu4c/source/i18n/islamcal.cpp index fec702799db..59de71335fa 100644 --- a/icu4c/source/i18n/islamcal.cpp +++ b/icu4c/source/i18n/islamcal.cpp @@ -82,6 +82,8 @@ const char *IslamicCalendar::getType() const { return "islamic-civil"; } else if(civil==ASTRONOMICAL){ return "islamic"; + } else if(civil==TBLA){ + return "islamic-tbla"; } else { return "islamic-umalqura"; } @@ -198,7 +200,7 @@ UBool IslamicCalendar::civilLeapYear(int32_t year) * from the Hijri epoch, origin 0. */ int32_t IslamicCalendar::yearStart(int32_t year) const{ - if (civil == CIVIL || + if (civil == CIVIL || civil == TBLA || (civil == UMALQURA && year < UMALQURA_YEAR_START)) { return (year-1)*354 + ClockMath::floorDivide((3+11*year),30); @@ -222,7 +224,7 @@ int32_t IslamicCalendar::yearStart(int32_t year) const{ * @param year The hijri month, 0-based */ int32_t IslamicCalendar::monthStart(int32_t year, int32_t month) const { - if (civil == CIVIL) { + if (civil == CIVIL || civil == TBLA) { return (int32_t)uprv_ceil(29.5*month) + (year-1)*354 + (int32_t)ClockMath::floorDivide((3+11*year),30); } else if(civil==ASTRONOMICAL){ @@ -340,7 +342,7 @@ int32_t IslamicCalendar::handleGetMonthLength(int32_t extendedYear, int32_t mont int32_t length = 0; - if (civil == CIVIL || + if (civil == CIVIL || civil == TBLA || (civil == UMALQURA && (extendedYearUMALQURA_YEAR_END)) ) { length = 29 + (month+1) % 2; if (month == DHU_AL_HIJJAH && civilLeapYear(extendedYear)) { @@ -360,7 +362,7 @@ int32_t IslamicCalendar::handleGetMonthLength(int32_t extendedYear, int32_t mont * @draft ICU 2.4 */ int32_t IslamicCalendar::handleGetYearLength(int32_t extendedYear) const { - if (civil == CIVIL || + if (civil == CIVIL || civil == TBLA || (civil == UMALQURA && (extendedYearUMALQURA_YEAR_END)) ) { return 354 + (civilLeapYear(extendedYear) ? 1 : 0); } else if(civil == ASTRONOMICAL){ @@ -422,9 +424,11 @@ int32_t IslamicCalendar::handleGetExtendedYear() { void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) { int32_t year, month, dayOfMonth, dayOfYear; UDate startDate; - int32_t days = julianDay - 1948440; + int32_t days = julianDay - CIVIL_EPOC; - if (civil == CIVIL) { + if (civil == CIVIL || civil == TBLA) { + if(civil == TBLA) + days = julianDay - ASTRONOMICAL_EPOC; // Use the civil calendar approximation, which is just arithmetic year = (int)ClockMath::floorDivide( (double)(30 * days + 10646) , 10631.0 ); month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 ); diff --git a/icu4c/source/i18n/islamcal.h b/icu4c/source/i18n/islamcal.h index 507e135d73d..b37e8169cb2 100644 --- a/icu4c/source/i18n/islamcal.h +++ b/icu4c/source/i18n/islamcal.h @@ -94,7 +94,8 @@ class U_I18N_API IslamicCalendar : public Calendar { enum ECivil { ASTRONOMICAL, CIVIL, - UMALQURA + UMALQURA, + TBLA }; /** @@ -178,7 +179,6 @@ class U_I18N_API IslamicCalendar : public Calendar { }; - //------------------------------------------------------------------------- // Constructors... //------------------------------------------------------------------------- @@ -441,6 +441,17 @@ class U_I18N_API IslamicCalendar : public Calendar { static const int32_t UMALQURA_YEAR_END = 1480; + /** + * Friday EPOC + */ + static const int32_t CIVIL_EPOC = 1948440; + + /** + * Thursday EPOC + */ + static const int32_t ASTRONOMICAL_EPOC = 1948439; + + static const int getUmalqura_MonthLength(int i, int j){ static const int UMALQURA_MONTHLENGTH[] = { diff --git a/icu4c/source/test/intltest/caltest.cpp b/icu4c/source/test/intltest/caltest.cpp index 1c47540838e..30f98e8c73d 100644 --- a/icu4c/source/test/intltest/caltest.cpp +++ b/icu4c/source/test/intltest/caltest.cpp @@ -3,7 +3,6 @@ * Copyright (c) 1997-2013, International Business Machines Corporation * and others. All Rights Reserved. ************************************************************************/ - #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING @@ -286,6 +285,13 @@ void CalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name, logln("Test8449---"); logln(""); Test8449(); } + break; + case 32: + name = "Test10249"; + if(exec) { + logln("Test10249---"); logln(""); + Test10249(); + } break; default: name = ""; break; } @@ -2844,6 +2850,36 @@ void CalendarTest::Test8449() { delete tstCal; } +void CalendarTest::Test10249() { + UErrorCode status = U_ZERO_ERROR; + Locale islamicLoc("ar_SA@calendar=islamic-civil"); + Locale tblaLoc("ar_SA@calendar=islamic-tbla"); + SimpleDateFormat* formatter = new SimpleDateFormat("yyyy-MM-dd", Locale::getUS(), status); + UDate date = formatter->parse("1975-05-06", status); + + Calendar* tstCal = Calendar::createInstance(islamicLoc, status); + tstCal->setTime(date, status); + int32_t is_day = tstCal->get(UCAL_DAY_OF_MONTH,status); + int32_t is_month = tstCal->get(UCAL_MONTH,status); + int32_t is_year = tstCal->get(UCAL_YEAR,status); + TEST_CHECK_STATUS; + delete tstCal; + + tstCal = Calendar::createInstance(tblaLoc, status); + tstCal->setTime(date, status); + int32_t tbla_day = tstCal->get(UCAL_DAY_OF_MONTH,status); + int32_t tbla_month = tstCal->get(UCAL_MONTH,status); + int32_t tbla_year = tstCal->get(UCAL_YEAR,status); + TEST_CHECK_STATUS; + + if(tbla_month != is_month || tbla_year != is_year) + errln("unexpected difference between islamic and tbla month %d : %d and/or year %d : %d",tbla_month,is_month,tbla_year,is_year); + + if(tbla_day - is_day != 1) + errln("unexpected day difference between islamic and tbla: %d : %d ",tbla_day,is_day); + delete tstCal; + delete formatter; +} #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/test/intltest/caltest.h b/icu4c/source/test/intltest/caltest.h index 7686767ee0a..1d028095bb1 100644 --- a/icu4c/source/test/intltest/caltest.h +++ b/icu4c/source/test/intltest/caltest.h @@ -220,6 +220,7 @@ public: // package void Test3785(void); void Test1624(void); void Test8449(void); + void Test10249(void); /** * Test the time stamp array recalculation during heavy Calendar usage