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