tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ucal.cpp (25708B)


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