]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/islamcal.cpp
ICU-511.35.tar.gz
[apple/icu.git] / icuSources / i18n / islamcal.cpp
index 47669d39bab31dc092fc662e9dfba8aba6247b5d..6d553787da3b188f97681b6c1a247c55b5a57ff0 100644 (file)
@@ -1,6 +1,6 @@
 /*
 ******************************************************************************
-* Copyright (C) 2003-2008, International Business Machines Corporation
+* Copyright (C) 2003-2012, International Business Machines Corporation
 * and others. All Rights Reserved.
 ******************************************************************************
 *
@@ -51,9 +51,9 @@ static void debug_islamcal_msg(const char *pat, ...)
 
 // --- The cache --
 // cache of months
-static UMTX astroLock = 0;  // pod bay door lock
-static U_NAMESPACE_QUALIFIER CalendarCache *gMonthCache = NULL;
-static U_NAMESPACE_QUALIFIER CalendarAstronomer *gIslamicCalendarAstro = NULL;
+static UMutex astroLock = U_MUTEX_INITIALIZER;  // pod bay door lock
+static icu::CalendarCache *gMonthCache = NULL;
+static icu::CalendarAstronomer *gIslamicCalendarAstro = NULL;
 
 U_CDECL_BEGIN
 static UBool calendar_islamic_cleanup(void) {
@@ -65,7 +65,6 @@ static UBool calendar_islamic_cleanup(void) {
         delete gIslamicCalendarAstro;
         gIslamicCalendarAstro = NULL;
     }
-    umtx_destroy(&astroLock);
     return TRUE;
 }
 U_CDECL_END
@@ -141,6 +140,10 @@ UBool IslamicCalendar::isCivil() {
 // Note: Current IslamicCalendar implementation does not work
 // well with negative years.
 
+// TODO: In some cases the current ICU Islamic calendar implementation shows
+// a month as having 31 days. Since date parsing now uses range checks based
+// on the table below, we need to change the range for last day of month to
+// include 31 as a workaround until the implementation is fixed.
 static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
     // Minimum  Greatest    Least  Maximum
     //           Minimum  Maximum
@@ -149,7 +152,7 @@ static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
     {        0,        0,       11,       11}, // MONTH
     {        1,        1,       50,       51}, // WEEK_OF_YEAR
     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH
-    {        1,        1,       29,       31}, // DAY_OF_MONTH (**** SB 30 ****)
+    {        1,        1,       29,       31}, // DAY_OF_MONTH - 31 to workaround for cal implementation bug, should be 30
     {        1,        1,      354,      355}, // DAY_OF_YEAR
     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
     {       -1,       -1,        5,        5}, // DAY_OF_WEEK_IN_MONTH
@@ -194,7 +197,7 @@ UBool IslamicCalendar::civilLeapYear(int32_t year)
 */
 int32_t IslamicCalendar::yearStart(int32_t year) {
     if (civil == CIVIL) {
-        return (year-1)*354 + Math::floorDivide((3+11*year),30);
+        return (year-1)*354 + ClockMath::floorDivide((3+11*year),30);
     } else {
         return trueMonthStart(12*(year-1));
     }
@@ -210,7 +213,7 @@ int32_t IslamicCalendar::yearStart(int32_t year) {
 int32_t IslamicCalendar::monthStart(int32_t year, int32_t month) const {
     if (civil == CIVIL) {
         return (int32_t)uprv_ceil(29.5*month)
-            + (year-1)*354 + (int32_t)Math::floorDivide((3+11*year),30);
+            + (year-1)*354 + (int32_t)ClockMath::floorDivide((3+11*year),30);
     } else {
         return trueMonthStart(12*(year-1) + month);
     }
@@ -232,7 +235,7 @@ int32_t IslamicCalendar::trueMonthStart(int32_t month) const
     if (start==0) {
         // Make a guess at when the month started, using the average length
         UDate origin = HIJRA_MILLIS 
-            + uprv_floor(month * CalendarAstronomer::SYNODIC_MONTH - 1) * kOneDay;
+            + uprv_floor(month * CalendarAstronomer::SYNODIC_MONTH) * kOneDay;
 
         // moonAge will fail due to memory allocation error
         double age = moonAge(origin, status);
@@ -260,7 +263,7 @@ int32_t IslamicCalendar::trueMonthStart(int32_t month) const
                 }
             } while (age < 0);
         }
-        start = (int32_t)Math::floorDivide((origin - HIJRA_MILLIS), (double)kOneDay) + 1;
+        start = (int32_t)ClockMath::floorDivide((origin - HIJRA_MILLIS), (double)kOneDay) + 1;
         CalendarCache::put(&gMonthCache, month, start, status);
     }
 trueMonthStartEnd :
@@ -397,7 +400,7 @@ void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status)
 
     if (civil == CIVIL) {
         // Use the civil calendar approximation, which is just arithmetic
-        year  = (int)Math::floorDivide( (double)(30 * days + 10646) , 10631.0 );
+        year  = (int)ClockMath::floorDivide( (double)(30 * days + 10646) , 10631.0 );
         month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 );
         month = month<11?month:11;
         startDate = monthStart(year, month);
@@ -405,14 +408,14 @@ void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status)
         // Guess at the number of elapsed full months since the epoch
         int32_t months = (int32_t)uprv_floor((double)days / CalendarAstronomer::SYNODIC_MONTH);
 
-        startDate = uprv_floor(months * CalendarAstronomer::SYNODIC_MONTH - 1);
+        startDate = uprv_floor(months * CalendarAstronomer::SYNODIC_MONTH);
 
         double age = moonAge(internalGetTime(), status);
         if (U_FAILURE(status)) {
                status = U_MEMORY_ALLOCATION_ERROR;
                return;
         }
-        if ( days - startDate >= 28 && age > 0) {
+        if ( days - startDate >= 25 && age > 0) {
             // If we're near the end of the month, assume next month and search backwards
             months++;
         }
@@ -517,27 +520,24 @@ IslamicCalendar::initializeSystemDefaultCentury()
     // initialize systemDefaultCentury and systemDefaultCenturyYear based
     // on the current time.  They'll be set to 80 years before
     // the current time.
-    // No point in locking as it should be idempotent.
-    if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
+    UErrorCode status = U_ZERO_ERROR;
+    IslamicCalendar calendar(Locale("@calendar=islamic-civil"),status);
+    if (U_SUCCESS(status))
     {
-        UErrorCode status = U_ZERO_ERROR;
-        IslamicCalendar calendar(Locale("@calendar=islamic-civil"),status);
-        if (U_SUCCESS(status))
+        calendar.setTime(Calendar::getNow(), status);
+        calendar.add(UCAL_YEAR, -80, status);
+        UDate    newStart =  calendar.getTime(status);
+        int32_t  newYear  =  calendar.get(UCAL_YEAR, status);
+        umtx_lock(NULL);
+        if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
         {
-            calendar.setTime(Calendar::getNow(), status);
-            calendar.add(UCAL_YEAR, -80, status);
-            UDate    newStart =  calendar.getTime(status);
-            int32_t  newYear  =  calendar.get(UCAL_YEAR, status);
-            {
-                umtx_lock(NULL);
-                fgSystemDefaultCenturyStart = newStart;
-                fgSystemDefaultCenturyStartYear = newYear;
-                umtx_unlock(NULL);
-            }
+            fgSystemDefaultCenturyStartYear = newYear;
+            fgSystemDefaultCenturyStart = newStart;
         }
-        // We have no recourse upon failure unless we want to propagate the failure
-        // out.
+        umtx_unlock(NULL);
     }
+    // We have no recourse upon failure unless we want to propagate the failure
+    // out.
 }
 
 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicCalendar)