Home | History | Annotate | Download | only in i18n
      1 /*
      2 *******************************************************************************
      3 *   Copyright (C) 1996-2013, International Business Machines
      4 *   Corporation and others.  All Rights Reserved.
      5 *******************************************************************************
      6 */
      7 
      8 #include "utypeinfo.h"  // for 'typeid' to work
      9 
     10 #include "unicode/utypes.h"
     11 
     12 #if !UCONFIG_NO_FORMATTING
     13 
     14 #include "unicode/ucal.h"
     15 #include "unicode/uloc.h"
     16 #include "unicode/calendar.h"
     17 #include "unicode/timezone.h"
     18 #include "unicode/gregocal.h"
     19 #include "unicode/simpletz.h"
     20 #include "unicode/ustring.h"
     21 #include "unicode/strenum.h"
     22 #include "unicode/localpointer.h"
     23 #include "cmemory.h"
     24 #include "cstring.h"
     25 #include "ustrenum.h"
     26 #include "uenumimp.h"
     27 #include "ulist.h"
     28 
     29 U_NAMESPACE_USE
     30 
     31 static TimeZone*
     32 _createTimeZone(const UChar* zoneID, int32_t len, UErrorCode* ec) {
     33     TimeZone* zone = NULL;
     34     if (ec!=NULL && U_SUCCESS(*ec)) {
     35         // Note that if zoneID is invalid, we get back GMT. This odd
     36         // behavior is by design and goes back to the JDK. The only
     37         // failure we will see is a memory allocation failure.
     38         int32_t l = (len<0 ? u_strlen(zoneID) : len);
     39         UnicodeString zoneStrID;
     40         zoneStrID.setTo((UBool)(len < 0), zoneID, l); /* temporary read-only alias */
     41         zone = TimeZone::createTimeZone(zoneStrID);
     42         if (zone == NULL) {
     43             *ec = U_MEMORY_ALLOCATION_ERROR;
     44         }
     45     }
     46     return zone;
     47 }
     48 
     49 U_CAPI UEnumeration* U_EXPORT2
     50 ucal_openTimeZoneIDEnumeration(USystemTimeZoneType zoneType, const char* region,
     51                                 const int32_t* rawOffset, UErrorCode* ec) {
     52     return uenum_openFromStringEnumeration(TimeZone::createTimeZoneIDEnumeration(
     53         zoneType, region, rawOffset, *ec), ec);
     54 }
     55 
     56 U_CAPI UEnumeration* U_EXPORT2
     57 ucal_openTimeZones(UErrorCode* ec) {
     58     return uenum_openFromStringEnumeration(TimeZone::createEnumeration(), ec);
     59 }
     60 
     61 U_CAPI UEnumeration* U_EXPORT2
     62 ucal_openCountryTimeZones(const char* country, UErrorCode* ec) {
     63     return uenum_openFromStringEnumeration(TimeZone::createEnumeration(country), ec);
     64 }
     65 
     66 U_CAPI int32_t U_EXPORT2
     67 ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec) {
     68     int32_t len = 0;
     69     if (ec!=NULL && U_SUCCESS(*ec)) {
     70         TimeZone* zone = TimeZone::createDefault();
     71         if (zone == NULL) {
     72             *ec = U_MEMORY_ALLOCATION_ERROR;
     73         } else {
     74             UnicodeString id;
     75             zone->getID(id);
     76             delete zone;
     77             len = id.extract(result, resultCapacity, *ec);
     78         }
     79     }
     80     return len;
     81 }
     82 
     83 U_CAPI void U_EXPORT2
     84 ucal_setDefaultTimeZone(const UChar* zoneID, UErrorCode* ec) {
     85     TimeZone* zone = _createTimeZone(zoneID, -1, ec);
     86     if (zone != NULL) {
     87         TimeZone::adoptDefault(zone);
     88     }
     89 }
     90 
     91 U_CAPI int32_t U_EXPORT2
     92 ucal_getDSTSavings(const UChar* zoneID, UErrorCode* ec) {
     93     int32_t result = 0;
     94     TimeZone* zone = _createTimeZone(zoneID, -1, ec);
     95     if (U_SUCCESS(*ec)) {
     96         SimpleTimeZone* stz = dynamic_cast<SimpleTimeZone*>(zone);
     97         if (stz != NULL) {
     98             result = stz->getDSTSavings();
     99         } else {
    100             // Since there is no getDSTSavings on TimeZone, we use a
    101             // heuristic: Starting with the current time, march
    102             // forwards for one year, looking for DST savings.
    103             // Stepping by weeks is sufficient.
    104             UDate d = Calendar::getNow();
    105             for (int32_t i=0; i<53; ++i, d+=U_MILLIS_PER_DAY*7.0) {
    106                 int32_t raw, dst;
    107                 zone->getOffset(d, FALSE, raw, dst, *ec);
    108                 if (U_FAILURE(*ec)) {
    109                     break;
    110                 } else if (dst != 0) {
    111                     result = dst;
    112                     break;
    113                 }
    114             }
    115         }
    116     }
    117     delete zone;
    118     return result;
    119 }
    120 
    121 U_CAPI UDate  U_EXPORT2
    122 ucal_getNow()
    123 {
    124 
    125   return Calendar::getNow();
    126 }
    127 
    128 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
    129 
    130 U_CAPI UCalendar*  U_EXPORT2
    131 ucal_open(  const UChar*  zoneID,
    132             int32_t       len,
    133             const char*   locale,
    134             UCalendarType caltype,
    135             UErrorCode*   status)
    136 {
    137 
    138   if(U_FAILURE(*status)) return 0;
    139 
    140   TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault()
    141       : _createTimeZone(zoneID, len, status);
    142 
    143   if (U_FAILURE(*status)) {
    144       return NULL;
    145   }
    146 
    147   if ( caltype == UCAL_GREGORIAN ) {
    148       char  localeBuf[ULOC_LOCALE_IDENTIFIER_CAPACITY];
    149       if ( locale == NULL ) {
    150           locale = uloc_getDefault();
    151       }
    152       uprv_strncpy(localeBuf, locale, ULOC_LOCALE_IDENTIFIER_CAPACITY);
    153       uloc_setKeywordValue("calendar", "gregorian", localeBuf, ULOC_LOCALE_IDENTIFIER_CAPACITY, status);
    154       if (U_FAILURE(*status)) {
    155           return NULL;
    156       }
    157       return (UCalendar*)Calendar::createInstance(zone, Locale(localeBuf), *status);
    158   }
    159   return (UCalendar*)Calendar::createInstance(zone, Locale(locale), *status);
    160 }
    161 
    162 U_CAPI void U_EXPORT2
    163 ucal_close(UCalendar *cal)
    164 {
    165 
    166   delete (Calendar*) cal;
    167 }
    168 
    169 U_CAPI UCalendar* U_EXPORT2
    170 ucal_clone(const UCalendar* cal,
    171            UErrorCode*      status)
    172 {
    173   if(U_FAILURE(*status)) return 0;
    174 
    175   Calendar* res = ((Calendar*)cal)->clone();
    176 
    177   if(res == 0) {
    178     *status = U_MEMORY_ALLOCATION_ERROR;
    179     return 0;
    180   }
    181 
    182   return (UCalendar*) res;
    183 }
    184 
    185 U_CAPI void  U_EXPORT2
    186 ucal_setTimeZone(    UCalendar*      cal,
    187             const    UChar*            zoneID,
    188             int32_t        len,
    189             UErrorCode *status)
    190 {
    191 
    192   if(U_FAILURE(*status))
    193     return;
    194 
    195   TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault()
    196       : _createTimeZone(zoneID, len, status);
    197 
    198   if (zone != NULL) {
    199       ((Calendar*)cal)->adoptTimeZone(zone);
    200   }
    201 }
    202 
    203 U_CAPI int32_t U_EXPORT2
    204 ucal_getTimeZoneID(const UCalendar *cal,
    205                    UChar *result,
    206                    int32_t resultLength,
    207                    UErrorCode *status)
    208 {
    209     if (U_FAILURE(*status)) {
    210         return 0;
    211     }
    212     const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
    213     UnicodeString id;
    214     tz.getID(id);
    215     return id.extract(result, resultLength, *status);
    216 }
    217 
    218 U_CAPI int32_t U_EXPORT2
    219 ucal_getTimeZoneDisplayName(const     UCalendar*                 cal,
    220                     UCalendarDisplayNameType     type,
    221                     const char             *locale,
    222                     UChar*                  result,
    223                     int32_t                 resultLength,
    224                     UErrorCode*             status)
    225 {
    226 
    227     if(U_FAILURE(*status)) return -1;
    228 
    229     const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
    230     UnicodeString id;
    231     if(!(result==NULL && resultLength==0)) {
    232         // NULL destination for pure preflighting: empty dummy string
    233         // otherwise, alias the destination buffer
    234         id.setTo(result, 0, resultLength);
    235     }
    236 
    237     switch(type) {
    238   case UCAL_STANDARD:
    239       tz.getDisplayName(FALSE, TimeZone::LONG, Locale(locale), id);
    240       break;
    241 
    242   case UCAL_SHORT_STANDARD:
    243       tz.getDisplayName(FALSE, TimeZone::SHORT, Locale(locale), id);
    244       break;
    245 
    246   case UCAL_DST:
    247       tz.getDisplayName(TRUE, TimeZone::LONG, Locale(locale), id);
    248       break;
    249 
    250   case UCAL_SHORT_DST:
    251       tz.getDisplayName(TRUE, TimeZone::SHORT, Locale(locale), id);
    252       break;
    253     }
    254 
    255     return id.extract(result, resultLength, *status);
    256 }
    257 
    258 U_CAPI UBool  U_EXPORT2
    259 ucal_inDaylightTime(    const    UCalendar*      cal,
    260                     UErrorCode*     status )
    261 {
    262 
    263     if(U_FAILURE(*status)) return (UBool) -1;
    264     return ((Calendar*)cal)->inDaylightTime(*status);
    265 }
    266 
    267 U_CAPI void U_EXPORT2
    268 ucal_setGregorianChange(UCalendar *cal, UDate date, UErrorCode *pErrorCode) {
    269     if(U_FAILURE(*pErrorCode)) {
    270         return;
    271     }
    272     Calendar *cpp_cal = (Calendar *)cal;
    273     GregorianCalendar *gregocal = dynamic_cast<GregorianCalendar *>(cpp_cal);
    274     // Not if(gregocal == NULL) {
    275     // because we really want to work only with a GregorianCalendar, not with
    276     // its subclasses like BuddhistCalendar.
    277     if (cpp_cal == NULL) {
    278         // We normally don't check "this" pointers for NULL, but this here avoids
    279         // compiler-generated exception-throwing code in case cal == NULL.
    280         *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
    281         return;
    282     }
    283     if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
    284         *pErrorCode = U_UNSUPPORTED_ERROR;
    285         return;
    286     }
    287     gregocal->setGregorianChange(date, *pErrorCode);
    288 }
    289 
    290 U_CAPI UDate U_EXPORT2
    291 ucal_getGregorianChange(const UCalendar *cal, UErrorCode *pErrorCode) {
    292     if(U_FAILURE(*pErrorCode)) {
    293         return (UDate)0;
    294     }
    295     const Calendar *cpp_cal = (const Calendar *)cal;
    296     const GregorianCalendar *gregocal = dynamic_cast<const GregorianCalendar *>(cpp_cal);
    297     // Not if(gregocal == NULL) {
    298     // see comments in ucal_setGregorianChange().
    299     if (cpp_cal == NULL) {
    300         // We normally don't check "this" pointers for NULL, but this here avoids
    301         // compiler-generated exception-throwing code in case cal == NULL.
    302         *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
    303         return (UDate)0;
    304     }
    305     if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
    306         *pErrorCode = U_UNSUPPORTED_ERROR;
    307         return (UDate)0;
    308     }
    309     return gregocal->getGregorianChange();
    310 }
    311 
    312 U_CAPI int32_t U_EXPORT2
    313 ucal_getAttribute(    const    UCalendar*              cal,
    314                   UCalendarAttribute      attr)
    315 {
    316 
    317     switch(attr) {
    318   case UCAL_LENIENT:
    319       return ((Calendar*)cal)->isLenient();
    320 
    321   case UCAL_FIRST_DAY_OF_WEEK:
    322       return ((Calendar*)cal)->getFirstDayOfWeek();
    323 
    324   case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK:
    325       return ((Calendar*)cal)->getMinimalDaysInFirstWeek();
    326 
    327   case UCAL_REPEATED_WALL_TIME:
    328       return ((Calendar*)cal)->getRepeatedWallTimeOption();
    329 
    330   case UCAL_SKIPPED_WALL_TIME:
    331       return ((Calendar*)cal)->getSkippedWallTimeOption();
    332 
    333   default:
    334       break;
    335     }
    336     return -1;
    337 }
    338 
    339 U_CAPI void U_EXPORT2
    340 ucal_setAttribute(      UCalendar*              cal,
    341                   UCalendarAttribute      attr,
    342                   int32_t                 newValue)
    343 {
    344 
    345     switch(attr) {
    346   case UCAL_LENIENT:
    347       ((Calendar*)cal)->setLenient((UBool)newValue);
    348       break;
    349 
    350   case UCAL_FIRST_DAY_OF_WEEK:
    351       ((Calendar*)cal)->setFirstDayOfWeek((UCalendarDaysOfWeek)newValue);
    352       break;
    353 
    354   case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK:
    355       ((Calendar*)cal)->setMinimalDaysInFirstWeek((uint8_t)newValue);
    356       break;
    357 
    358   case UCAL_REPEATED_WALL_TIME:
    359       ((Calendar*)cal)->setRepeatedWallTimeOption((UCalendarWallTimeOption)newValue);
    360       break;
    361 
    362   case UCAL_SKIPPED_WALL_TIME:
    363       ((Calendar*)cal)->setSkippedWallTimeOption((UCalendarWallTimeOption)newValue);
    364       break;
    365     }
    366 }
    367 
    368 U_CAPI const char* U_EXPORT2
    369 ucal_getAvailable(int32_t index)
    370 {
    371 
    372     return uloc_getAvailable(index);
    373 }
    374 
    375 U_CAPI int32_t U_EXPORT2
    376 ucal_countAvailable()
    377 {
    378 
    379     return uloc_countAvailable();
    380 }
    381 
    382 U_CAPI UDate  U_EXPORT2
    383 ucal_getMillis(    const    UCalendar*      cal,
    384                UErrorCode*     status)
    385 {
    386 
    387     if(U_FAILURE(*status)) return (UDate) 0;
    388 
    389     return ((Calendar*)cal)->getTime(*status);
    390 }
    391 
    392 U_CAPI void  U_EXPORT2
    393 ucal_setMillis(        UCalendar*      cal,
    394                UDate           dateTime,
    395                UErrorCode*     status )
    396 {
    397     if(U_FAILURE(*status)) return;
    398 
    399     ((Calendar*)cal)->setTime(dateTime, *status);
    400 }
    401 
    402 // TBD: why does this take an UErrorCode?
    403 U_CAPI void  U_EXPORT2
    404 ucal_setDate(        UCalendar*        cal,
    405              int32_t            year,
    406              int32_t            month,
    407              int32_t            date,
    408              UErrorCode        *status)
    409 {
    410 
    411     if(U_FAILURE(*status)) return;
    412 
    413     ((Calendar*)cal)->set(year, month, date);
    414 }
    415 
    416 // TBD: why does this take an UErrorCode?
    417 U_CAPI void  U_EXPORT2
    418 ucal_setDateTime(    UCalendar*        cal,
    419                  int32_t            year,
    420                  int32_t            month,
    421                  int32_t            date,
    422                  int32_t            hour,
    423                  int32_t            minute,
    424                  int32_t            second,
    425                  UErrorCode        *status)
    426 {
    427     if(U_FAILURE(*status)) return;
    428 
    429     ((Calendar*)cal)->set(year, month, date, hour, minute, second);
    430 }
    431 
    432 U_CAPI UBool  U_EXPORT2
    433 ucal_equivalentTo(    const UCalendar*      cal1,
    434                   const UCalendar*      cal2)
    435 {
    436 
    437     return ((Calendar*)cal1)->isEquivalentTo(*((Calendar*)cal2));
    438 }
    439 
    440 U_CAPI void  U_EXPORT2
    441 ucal_add(    UCalendar*                cal,
    442          UCalendarDateFields        field,
    443          int32_t                    amount,
    444          UErrorCode*                status)
    445 {
    446 
    447     if(U_FAILURE(*status)) return;
    448 
    449     ((Calendar*)cal)->add(field, amount, *status);
    450 }
    451 
    452 U_CAPI void  U_EXPORT2
    453 ucal_roll(        UCalendar*            cal,
    454           UCalendarDateFields field,
    455           int32_t                amount,
    456           UErrorCode*            status)
    457 {
    458 
    459     if(U_FAILURE(*status)) return;
    460 
    461     ((Calendar*)cal)->roll(field, amount, *status);
    462 }
    463 
    464 U_CAPI int32_t  U_EXPORT2
    465 ucal_get(    const    UCalendar*                cal,
    466          UCalendarDateFields        field,
    467          UErrorCode*                status )
    468 {
    469 
    470     if(U_FAILURE(*status)) return -1;
    471 
    472     return ((Calendar*)cal)->get(field, *status);
    473 }
    474 
    475 U_CAPI void  U_EXPORT2
    476 ucal_set(    UCalendar*                cal,
    477          UCalendarDateFields        field,
    478          int32_t                    value)
    479 {
    480 
    481     ((Calendar*)cal)->set(field, value);
    482 }
    483 
    484 U_CAPI UBool  U_EXPORT2
    485 ucal_isSet(    const    UCalendar*                cal,
    486            UCalendarDateFields        field)
    487 {
    488 
    489     return ((Calendar*)cal)->isSet(field);
    490 }
    491 
    492 U_CAPI void  U_EXPORT2
    493 ucal_clearField(    UCalendar*            cal,
    494                 UCalendarDateFields field)
    495 {
    496 
    497     ((Calendar*)cal)->clear(field);
    498 }
    499 
    500 U_CAPI void  U_EXPORT2
    501 ucal_clear(UCalendar* calendar)
    502 {
    503 
    504     ((Calendar*)calendar)->clear();
    505 }
    506 
    507 U_CAPI int32_t  U_EXPORT2
    508 ucal_getLimit(    const    UCalendar*              cal,
    509               UCalendarDateFields     field,
    510               UCalendarLimitType      type,
    511               UErrorCode        *status)
    512 {
    513 
    514     if(status==0 || U_FAILURE(*status)) {
    515         return -1;
    516     }
    517 
    518     switch(type) {
    519   case UCAL_MINIMUM:
    520       return ((Calendar*)cal)->getMinimum(field);
    521 
    522   case UCAL_MAXIMUM:
    523       return ((Calendar*)cal)->getMaximum(field);
    524 
    525   case UCAL_GREATEST_MINIMUM:
    526       return ((Calendar*)cal)->getGreatestMinimum(field);
    527 
    528   case UCAL_LEAST_MAXIMUM:
    529       return ((Calendar*)cal)->getLeastMaximum(field);
    530 
    531   case UCAL_ACTUAL_MINIMUM:
    532       return ((Calendar*)cal)->getActualMinimum(field,
    533           *status);
    534 
    535   case UCAL_ACTUAL_MAXIMUM:
    536       return ((Calendar*)cal)->getActualMaximum(field,
    537           *status);
    538 
    539   default:
    540       break;
    541     }
    542     return -1;
    543 }
    544 
    545 U_CAPI const char * U_EXPORT2
    546 ucal_getLocaleByType(const UCalendar *cal, ULocDataLocaleType type, UErrorCode* status)
    547 {
    548     if (cal == NULL) {
    549         if (U_SUCCESS(*status)) {
    550             *status = U_ILLEGAL_ARGUMENT_ERROR;
    551         }
    552         return NULL;
    553     }
    554     return ((Calendar*)cal)->getLocaleID(type, *status);
    555 }
    556 
    557 U_CAPI const char * U_EXPORT2
    558 ucal_getTZDataVersion(UErrorCode* status)
    559 {
    560     return TimeZone::getTZDataVersion(*status);
    561 }
    562 
    563 U_CAPI int32_t U_EXPORT2
    564 ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len,
    565                             UChar* result, int32_t resultCapacity, UBool *isSystemID, UErrorCode* status) {
    566     if(status == 0 || U_FAILURE(*status)) {
    567         return 0;
    568     }
    569     if (isSystemID) {
    570         *isSystemID = FALSE;
    571     }
    572     if (id == 0 || len == 0 || result == 0 || resultCapacity <= 0) {
    573         *status = U_ILLEGAL_ARGUMENT_ERROR;
    574         return 0;
    575     }
    576     int32_t reslen = 0;
    577     UnicodeString canonical;
    578     UBool systemID = FALSE;
    579     TimeZone::getCanonicalID(UnicodeString(id, len), canonical, systemID, *status);
    580     if (U_SUCCESS(*status)) {
    581         if (isSystemID) {
    582             *isSystemID = systemID;
    583         }
    584         reslen = canonical.extract(result, resultCapacity, *status);
    585     }
    586     return reslen;
    587 }
    588 
    589 U_CAPI const char * U_EXPORT2
    590 ucal_getType(const UCalendar *cal, UErrorCode* status)
    591 {
    592     if (U_FAILURE(*status)) {
    593         return NULL;
    594     }
    595     return ((Calendar*)cal)->getType();
    596 }
    597 
    598 U_CAPI UCalendarWeekdayType U_EXPORT2
    599 ucal_getDayOfWeekType(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode* status)
    600 {
    601     if (U_FAILURE(*status)) {
    602         return UCAL_WEEKDAY;
    603     }
    604     return ((Calendar*)cal)->getDayOfWeekType(dayOfWeek, *status);
    605 }
    606 
    607 U_CAPI int32_t U_EXPORT2
    608 ucal_getWeekendTransition(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode *status)
    609 {
    610     if (U_FAILURE(*status)) {
    611         return 0;
    612     }
    613     return ((Calendar*)cal)->getWeekendTransition(dayOfWeek, *status);
    614 }
    615 
    616 U_CAPI UBool U_EXPORT2
    617 ucal_isWeekend(const UCalendar *cal, UDate date, UErrorCode *status)
    618 {
    619     if (U_FAILURE(*status)) {
    620         return FALSE;
    621     }
    622     return ((Calendar*)cal)->isWeekend(date, *status);
    623 }
    624 
    625 U_CAPI int32_t  U_EXPORT2
    626 ucal_getFieldDifference(UCalendar* cal, UDate target,
    627                         UCalendarDateFields field,
    628                         UErrorCode* status )
    629 {
    630     if (U_FAILURE(*status)) {
    631         return 0;
    632     }
    633     return ((Calendar*)cal)->fieldDifference(target, field, *status);
    634 }
    635 
    636 
    637 static const UEnumeration defaultKeywordValues = {
    638     NULL,
    639     NULL,
    640     ulist_close_keyword_values_iterator,
    641     ulist_count_keyword_values,
    642     uenum_unextDefault,
    643     ulist_next_keyword_value,
    644     ulist_reset_keyword_values_iterator
    645 };
    646 
    647 static const char * const CAL_TYPES[] = {
    648         "gregorian",
    649         "japanese",
    650         "buddhist",
    651         "roc",
    652         "persian",
    653         "islamic-civil",
    654         "islamic",
    655         "hebrew",
    656         "chinese",
    657         "indian",
    658         "coptic",
    659         "ethiopic",
    660         "ethiopic-amete-alem",
    661         NULL
    662 };
    663 
    664 U_CAPI UEnumeration* U_EXPORT2
    665 ucal_getKeywordValuesForLocale(const char * /* key */, const char* locale, UBool commonlyUsed, UErrorCode *status) {
    666     // Resolve region
    667     char prefRegion[ULOC_FULLNAME_CAPACITY] = "";
    668     int32_t prefRegionLength = 0;
    669     prefRegionLength = uloc_getCountry(locale, prefRegion, sizeof(prefRegion), status);
    670     if (prefRegionLength == 0) {
    671         char loc[ULOC_FULLNAME_CAPACITY] = "";
    672         uloc_addLikelySubtags(locale, loc, sizeof(loc), status);
    673 
    674         prefRegionLength = uloc_getCountry(loc, prefRegion, sizeof(prefRegion), status);
    675     }
    676 
    677     // Read preferred calendar values from supplementalData calendarPreference
    678     UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", status);
    679     ures_getByKey(rb, "calendarPreferenceData", rb, status);
    680     UResourceBundle *order = ures_getByKey(rb, prefRegion, NULL, status);
    681     if (*status == U_MISSING_RESOURCE_ERROR && rb != NULL) {
    682         *status = U_ZERO_ERROR;
    683         order = ures_getByKey(rb, "001", NULL, status);
    684     }
    685 
    686     // Create a list of calendar type strings
    687     UList *values = NULL;
    688     if (U_SUCCESS(*status)) {
    689         values = ulist_createEmptyList(status);
    690         if (U_SUCCESS(*status)) {
    691             for (int i = 0; i < ures_getSize(order); i++) {
    692                 int32_t len;
    693                 const UChar *type = ures_getStringByIndex(order, i, &len, status);
    694                 char *caltype = (char*)uprv_malloc(len + 1);
    695                 if (caltype == NULL) {
    696                     *status = U_MEMORY_ALLOCATION_ERROR;
    697                     break;
    698                 }
    699                 u_UCharsToChars(type, caltype, len);
    700                 *(caltype + len) = 0;
    701 
    702                 ulist_addItemEndList(values, caltype, TRUE, status);
    703                 if (U_FAILURE(*status)) {
    704                     break;
    705                 }
    706             }
    707 
    708             if (U_SUCCESS(*status) && !commonlyUsed) {
    709                 // If not commonlyUsed, add other available values
    710                 for (int32_t i = 0; CAL_TYPES[i] != NULL; i++) {
    711                     if (!ulist_containsString(values, CAL_TYPES[i], (int32_t)uprv_strlen(CAL_TYPES[i]))) {
    712                         ulist_addItemEndList(values, CAL_TYPES[i], FALSE, status);
    713                         if (U_FAILURE(*status)) {
    714                             break;
    715                         }
    716                     }
    717                 }
    718             }
    719             if (U_FAILURE(*status)) {
    720                 ulist_deleteList(values);
    721                 values = NULL;
    722             }
    723         }
    724     }
    725 
    726     ures_close(order);
    727     ures_close(rb);
    728 
    729     if (U_FAILURE(*status) || values == NULL) {
    730         return NULL;
    731     }
    732 
    733     // Create string enumeration
    734     UEnumeration *en = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
    735     if (en == NULL) {
    736         *status = U_MEMORY_ALLOCATION_ERROR;
    737         ulist_deleteList(values);
    738         return NULL;
    739     }
    740     ulist_resetList(values);
    741     memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
    742     en->context = values;
    743     return en;
    744 }
    745 
    746 U_CAPI UBool U_EXPORT2
    747 ucal_getTimeZoneTransitionDate(const UCalendar* cal, UTimeZoneTransitionType type,
    748                                UDate* transition, UErrorCode* status)
    749 {
    750     if (U_FAILURE(*status)) {
    751         return FALSE;
    752     }
    753     UDate base = ((Calendar*)cal)->getTime(*status);
    754     const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
    755     const BasicTimeZone * btz = dynamic_cast<const BasicTimeZone *>(&tz);
    756     if (btz != NULL && U_SUCCESS(*status)) {
    757         TimeZoneTransition tzt;
    758         UBool inclusive = (type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE || type == UCAL_TZ_TRANSITION_PREVIOUS_INCLUSIVE);
    759         UBool result = (type == UCAL_TZ_TRANSITION_NEXT || type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE)?
    760                         btz->getNextTransition(base, inclusive, tzt):
    761                         btz->getPreviousTransition(base, inclusive, tzt);
    762         if (result) {
    763             *transition = tzt.getTime();
    764             return TRUE;
    765         }
    766     }
    767     return FALSE;
    768 }
    769 
    770 #endif /* #if !UCONFIG_NO_FORMATTING */
    771