]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/ucal.cpp
ICU-551.51.4.tar.gz
[apple/icu.git] / icuSources / i18n / ucal.cpp
index 2a8db94b99a5cc3ace8a157a695e94d0c04c9b8f..01f8cfabb7d68517854ee7b96798e9df50ad80bf 100644 (file)
@@ -1,16 +1,18 @@
 /*
 *******************************************************************************
 /*
 *******************************************************************************
-*   Copyright (C) 1996-2012, International Business Machines
+*   Copyright (C) 1996-2015, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 *******************************************************************************
 */
 
 *   Corporation and others.  All Rights Reserved.
 *******************************************************************************
 */
 
-#include <typeinfo>  // for 'typeid' to work
+#include "utypeinfo.h"  // for 'typeid' to work
 
 #include "unicode/utypes.h"
 
 #if !UCONFIG_NO_FORMATTING
 
 
 #include "unicode/utypes.h"
 
 #if !UCONFIG_NO_FORMATTING
 
+#include <stdlib.h> // Apple addition for uacal_getDayPeriod
+
 #include "unicode/ucal.h"
 #include "unicode/uloc.h"
 #include "unicode/calendar.h"
 #include "unicode/ucal.h"
 #include "unicode/uloc.h"
 #include "unicode/calendar.h"
@@ -19,6 +21,7 @@
 #include "unicode/simpletz.h"
 #include "unicode/ustring.h"
 #include "unicode/strenum.h"
 #include "unicode/simpletz.h"
 #include "unicode/ustring.h"
 #include "unicode/strenum.h"
+#include "unicode/localpointer.h"
 #include "cmemory.h"
 #include "cstring.h"
 #include "ustrenum.h"
 #include "cmemory.h"
 #include "cstring.h"
 #include "ustrenum.h"
@@ -199,6 +202,21 @@ ucal_setTimeZone(    UCalendar*      cal,
   }
 }
 
   }
 }
 
+U_CAPI int32_t U_EXPORT2
+ucal_getTimeZoneID(const UCalendar *cal,
+                   UChar *result,
+                   int32_t resultLength,
+                   UErrorCode *status)
+{
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+    const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
+    UnicodeString id;
+    tz.getID(id);
+    return id.extract(result, resultLength, *status);
+}
+
 U_CAPI int32_t U_EXPORT2
 ucal_getTimeZoneDisplayName(const     UCalendar*                 cal,
                     UCalendarDisplayNameType     type,
 U_CAPI int32_t U_EXPORT2
 ucal_getTimeZoneDisplayName(const     UCalendar*                 cal,
                     UCalendarDisplayNameType     type,
@@ -642,6 +660,11 @@ static const char * const CAL_TYPES[] = {
         "coptic",
         "ethiopic",
         "ethiopic-amete-alem",
         "coptic",
         "ethiopic",
         "ethiopic-amete-alem",
+        "iso8601",
+        "dangi",
+        "islamic-umalqura",
+        "islamic-tbla",
+        "islamic-rgsa",
         NULL
 };
 
         NULL
 };
 
@@ -727,4 +750,247 @@ ucal_getKeywordValuesForLocale(const char * /* key */, const char* locale, UBool
     return en;
 }
 
     return en;
 }
 
+U_CAPI UBool U_EXPORT2 
+ucal_getTimeZoneTransitionDate(const UCalendar* cal, UTimeZoneTransitionType type,
+                               UDate* transition, UErrorCode* status)
+{
+    if (U_FAILURE(*status)) {
+        return FALSE;
+    }
+    UDate base = ((Calendar*)cal)->getTime(*status);
+    const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
+    const BasicTimeZone * btz = dynamic_cast<const BasicTimeZone *>(&tz);
+    if (btz != NULL && U_SUCCESS(*status)) {
+        TimeZoneTransition tzt;
+        UBool inclusive = (type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE || type == UCAL_TZ_TRANSITION_PREVIOUS_INCLUSIVE);
+        UBool result = (type == UCAL_TZ_TRANSITION_NEXT || type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE)?
+                        btz->getNextTransition(base, inclusive, tzt):
+                        btz->getPreviousTransition(base, inclusive, tzt);
+        if (result) {
+            *transition = tzt.getTime();
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucal_getWindowsTimeZoneID(const UChar* id, int32_t len, UChar* winid, int32_t winidCapacity, UErrorCode* status) {
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    int32_t resultLen = 0;
+    UnicodeString resultWinID;
+
+    TimeZone::getWindowsID(UnicodeString(id, len), resultWinID, *status);
+    if (U_SUCCESS(*status) && resultWinID.length() > 0) {
+        resultLen = resultWinID.length();
+        resultWinID.extract(winid, winidCapacity, *status);
+    }
+
+    return resultLen;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucal_getTimeZoneIDForWindowsID(const UChar* winid, int32_t len, const char* region, UChar* id, int32_t idCapacity, UErrorCode* status) {
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    int32_t resultLen = 0;
+    UnicodeString resultID;
+
+    TimeZone::getIDForWindowsID(UnicodeString(winid, len), region, resultID, *status);
+    if (U_SUCCESS(*status) && resultID.length() > 0) {
+        resultLen = resultID.length();
+        resultID.extract(id, idCapacity, *status);
+    }
+
+    return resultLen;
+}
+
+// Apple-specific function uacal_getDayPeriod and helper functions/data
+typedef struct {
+    const char* name;
+    UADayPeriod value;
+} DayPeriodNameToValue;
+
+static const DayPeriodNameToValue dpNameToValue[] = {
+    { "afternoon1", UADAYPERIOD_AFTERNOON1 },
+    { "afternoon2", UADAYPERIOD_AFTERNOON2 },
+    { "evening1",   UADAYPERIOD_EVENING1   },
+    { "evening2",   UADAYPERIOD_EVENING2   },
+    { "midnight",   UADAYPERIOD_MIDNIGHT   },
+    { "morning1",   UADAYPERIOD_MORNING1   },
+    { "morning2",   UADAYPERIOD_MORNING2   },
+    { "night1",     UADAYPERIOD_NIGHT1     },
+    { "night2",     UADAYPERIOD_NIGHT2     },
+    { "noon",       UADAYPERIOD_NOON       },
+};
+
+static UADayPeriod dayPeriodFromName(const char* name) {
+    const DayPeriodNameToValue * dpNameToValuePtr = dpNameToValue;
+    const DayPeriodNameToValue * dpNameToValueLim = dpNameToValue +  UPRV_LENGTHOF(dpNameToValue);
+    // simple linear search, dpNameToValue is small enough
+    for (; dpNameToValuePtr < dpNameToValueLim; dpNameToValuePtr++) {
+        if (uprv_strcmp(name, dpNameToValuePtr->name) == 0) {
+            return dpNameToValuePtr->value;
+        }
+    }
+    return UADAYPERIOD_UNKNOWN;
+}
+
+typedef struct {
+    int32_t startHour;
+    int32_t startMin;
+    UADayPeriod value;
+} DayPeriodEntry;
+
+int CompareDayPeriodEntries(const void* entry1Ptr, const void* entry2Ptr) {
+    const DayPeriodEntry * dpEntry1Ptr = (const DayPeriodEntry *)entry1Ptr;
+    const DayPeriodEntry * dpEntry2Ptr = (const DayPeriodEntry *)entry2Ptr;
+    if (dpEntry1Ptr->startHour < dpEntry2Ptr->startHour) return -1;
+    if (dpEntry1Ptr->startHour > dpEntry2Ptr->startHour) return 1;
+    // here hours are equal
+    if (dpEntry1Ptr->startMin < dpEntry2Ptr->startMin) return -1;
+    if (dpEntry1Ptr->startMin > dpEntry2Ptr->startMin) return 1;
+    return 0;
+}
+
+enum { kSetNameMaxLen = 8, kBoundaryTimeMaxLen = 6, kDayPeriodEntriesMax = 12 };
+
+U_CAPI UADayPeriod U_EXPORT2
+uacal_getDayPeriod( const char* locale,
+                    int32_t     hour,
+                    int32_t     minute,
+                    UBool       formatStyle,
+                    UErrorCode* status ) {
+    UADayPeriod dayPeriod = UADAYPERIOD_UNKNOWN;
+    DayPeriodEntry dpEntries[kDayPeriodEntriesMax];
+    int32_t dpEntriesCount = 0;
+
+    if (U_FAILURE(*status)) {
+        return dayPeriod;
+    }
+    if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return dayPeriod;
+    }
+    // get dayPeriods bundle
+    LocalUResourceBundlePointer rb(ures_openDirect(NULL, "dayPeriods", status));
+    if (U_FAILURE(*status)) {
+        return dayPeriod;
+    }
+    // get locales/locales_selection subbundle
+    LocalUResourceBundlePointer rbSub(ures_getByKey(rb.getAlias(), formatStyle? "locales": "locales_selection", NULL, status));
+    if (U_FAILURE(*status)) {
+        return dayPeriod;
+    }
+    // get bundle for language (maps to setName)
+    char lang[ULOC_LANG_CAPACITY] = {0};
+    if (locale != NULL) {
+        UErrorCode tempStatus = U_ZERO_ERROR;
+        uloc_getLanguage(locale, lang, ULOC_LANG_CAPACITY, &tempStatus);
+        if (U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) {
+            lang[0] = 0;
+        }
+    }
+    if (lang[0] == 0) {
+        uprv_strcpy(lang, "en"); // should be "root" but the data for root is currently missing
+    }
+    LocalUResourceBundlePointer rbLang(ures_getByKey(rbSub.getAlias(), lang, NULL, status));
+    if (U_FAILURE(*status)) {
+        // should only happen if lang was not [root] en
+        // fallback should be "root" but the data for root is currently missing, use "en"
+        *status = U_ZERO_ERROR;
+        rbLang.adoptInstead(ures_getByKey(rbSub.getAlias(), "en", rbLang.orphan(), status));
+    }
+    if (U_FAILURE(*status)) {
+        return dayPeriod;
+    }
+    // get setName from language bundle
+    char setName[kSetNameMaxLen] = {0};
+    int32_t setNameLen = kSetNameMaxLen;
+    ures_getUTF8String(rbLang.getAlias(), setName, &setNameLen, TRUE, status);
+    if (U_FAILURE(*status)) {
+        return dayPeriod;
+    }
+    // get rules subbundle
+    rbSub.adoptInstead(ures_getByKey(rb.getAlias(), "rules", rbSub.orphan(), status));
+    if (U_FAILURE(*status)) {
+        return dayPeriod;
+    }
+    // get ruleset from rules subbundle
+    rb.adoptInstead(ures_getByKey(rbSub.getAlias(), setName, rb.orphan(), status));
+    if (U_FAILURE(*status)) {
+        return dayPeriod;
+    }
+    // OK, we should finally have a ruleset (works to here).
+    // Iterate over it to collect entries
+    LocalUResourceBundlePointer rbBound;
+    while (ures_hasNext(rb.getAlias())) {
+        rbSub.adoptInstead(ures_getNextResource(rb.getAlias(), rbSub.orphan(), status));
+        if (U_FAILURE(*status)) {
+            return dayPeriod;
+        }
+        // rbSub now has the bundle for a particular dayPeriod such as morning1, afternoon2, noon
+        UADayPeriod dpForBundle = dayPeriodFromName(ures_getKey(rbSub.getAlias()));
+        while (ures_hasNext(rbSub.getAlias())) {
+            rbBound.adoptInstead(ures_getNextResource(rbSub.getAlias(), rbBound.orphan(), status));
+            if (U_FAILURE(*status)) {
+                return dayPeriod;
+            }
+            // rbBound now has the bundle for a particular time period boundary such as at, from, after.
+            // This is either of type URES_STRING (size=1) or of type URES_ARRAY (size > 1)
+            const char *boundaryType = ures_getKey(rbBound.getAlias());
+            // skip boundaryType "before", it is redundant if we have at, from, after
+            if (uprv_strcmp(boundaryType, "before") == 0) {
+                continue;
+            }
+            int32_t boundaryMinute = (uprv_strcmp(boundaryType, "after") == 0)? 1: 0;
+            int32_t boundaryTimeIndex, boundaryTimeCount = ures_getSize(rbBound.getAlias());
+            for (boundaryTimeIndex = 0; boundaryTimeIndex < boundaryTimeCount; boundaryTimeIndex++) {
+                char boundaryTimeStr[kBoundaryTimeMaxLen];
+                int32_t boundaryTimeStrLen = kBoundaryTimeMaxLen;
+                ures_getUTF8StringByIndex(rbBound.getAlias(), boundaryTimeIndex, boundaryTimeStr, &boundaryTimeStrLen, TRUE, status);
+                if (U_FAILURE(*status)) {
+                    return dayPeriod;
+                }
+                if (dpEntriesCount < kDayPeriodEntriesMax) {
+                    dpEntries[dpEntriesCount].startHour = atoi(boundaryTimeStr); // can depend on POSIX locale (fortunately no decimal sep here)
+                    dpEntries[dpEntriesCount].startMin = boundaryMinute;
+                    dpEntries[dpEntriesCount].value = dpForBundle;
+                    dpEntriesCount++;
+                }
+            }
+        }
+    }
+    if (dpEntriesCount < kDayPeriodEntriesMax) {
+        dpEntries[dpEntriesCount].startHour = 24;
+        dpEntries[dpEntriesCount].startMin = 0;
+        dpEntries[dpEntriesCount].value = UADAYPERIOD_UNKNOWN;
+        dpEntriesCount++;
+    }
+    // We have collected all of the rule data, now sort by time
+    qsort(dpEntries, dpEntriesCount, sizeof(DayPeriodEntry), CompareDayPeriodEntries);
+    // OK, all of the above is what we would do in an "open" function if we were using an
+    // open/use/close model for this; the object would just have the sorted array above.
+    
+    // Now we use the sorted array to find the dayPeriod matching the supplied time.
+    // Only a few entries, linear search OK
+    DayPeriodEntry entryToMatch = { hour, minute, UADAYPERIOD_UNKNOWN };
+    int32_t dpIndex = 0;
+    while (dpIndex < dpEntriesCount - 1 && CompareDayPeriodEntries(&entryToMatch, &dpEntries[dpIndex + 1]) >= 0) {
+        dpIndex++;
+    }
+    if (CompareDayPeriodEntries(&entryToMatch, &dpEntries[dpIndex]) >= 0) {
+        dayPeriod = dpEntries[dpIndex].value;
+    }
+
+    return dayPeriod;
+}
+
+
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
 #endif /* #if !UCONFIG_NO_FORMATTING */