1 /* 2 ******************************************************************************* 3 * Copyright (C) 1996-2010, 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 if ( locale == NULL ) { 139 locale = uloc_getDefault(); 140 } 141 uprv_strncpy(localeBuf, locale, ULOC_LOCALE_IDENTIFIER_CAPACITY); 142 uloc_setKeywordValue("calendar", "gregorian", localeBuf, ULOC_LOCALE_IDENTIFIER_CAPACITY, status); 143 if (U_FAILURE(*status)) { 144 return NULL; 145 } 146 return (UCalendar*)Calendar::createInstance(zone, Locale(localeBuf), *status); 147 } 148 return (UCalendar*)Calendar::createInstance(zone, Locale(locale), *status); 149 } 150 151 U_CAPI void U_EXPORT2 152 ucal_close(UCalendar *cal) 153 { 154 155 delete (Calendar*) cal; 156 } 157 158 U_CAPI UCalendar* U_EXPORT2 159 ucal_clone(const UCalendar* cal, 160 UErrorCode* status) 161 { 162 if(U_FAILURE(*status)) return 0; 163 164 Calendar* res = ((Calendar*)cal)->clone(); 165 166 if(res == 0) { 167 *status = U_MEMORY_ALLOCATION_ERROR; 168 return 0; 169 } 170 171 return (UCalendar*) res; 172 } 173 174 U_CAPI void U_EXPORT2 175 ucal_setTimeZone( UCalendar* cal, 176 const UChar* zoneID, 177 int32_t len, 178 UErrorCode *status) 179 { 180 181 if(U_FAILURE(*status)) 182 return; 183 184 TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault() 185 : _createTimeZone(zoneID, len, status); 186 187 if (zone != NULL) { 188 ((Calendar*)cal)->adoptTimeZone(zone); 189 } 190 } 191 192 U_CAPI int32_t U_EXPORT2 193 ucal_getTimeZoneDisplayName(const UCalendar* cal, 194 UCalendarDisplayNameType type, 195 const char *locale, 196 UChar* result, 197 int32_t resultLength, 198 UErrorCode* status) 199 { 200 201 if(U_FAILURE(*status)) return -1; 202 203 const TimeZone& tz = ((Calendar*)cal)->getTimeZone(); 204 UnicodeString id; 205 if(!(result==NULL && resultLength==0)) { 206 // NULL destination for pure preflighting: empty dummy string 207 // otherwise, alias the destination buffer 208 id.setTo(result, 0, resultLength); 209 } 210 211 switch(type) { 212 case UCAL_STANDARD: 213 tz.getDisplayName(FALSE, TimeZone::LONG, Locale(locale), id); 214 break; 215 216 case UCAL_SHORT_STANDARD: 217 tz.getDisplayName(FALSE, TimeZone::SHORT, Locale(locale), id); 218 break; 219 220 case UCAL_DST: 221 tz.getDisplayName(TRUE, TimeZone::LONG, Locale(locale), id); 222 break; 223 224 case UCAL_SHORT_DST: 225 tz.getDisplayName(TRUE, TimeZone::SHORT, Locale(locale), id); 226 break; 227 } 228 229 return id.extract(result, resultLength, *status); 230 } 231 232 U_CAPI UBool U_EXPORT2 233 ucal_inDaylightTime( const UCalendar* cal, 234 UErrorCode* status ) 235 { 236 237 if(U_FAILURE(*status)) return (UBool) -1; 238 return ((Calendar*)cal)->inDaylightTime(*status); 239 } 240 241 U_CAPI void U_EXPORT2 242 ucal_setGregorianChange(UCalendar *cal, UDate date, UErrorCode *pErrorCode) { 243 if(U_FAILURE(*pErrorCode)) { 244 return; 245 } 246 Calendar *cpp_cal = (Calendar *)cal; 247 if(cpp_cal->getDynamicClassID() != GregorianCalendar::getStaticClassID()) { 248 *pErrorCode = U_UNSUPPORTED_ERROR; 249 return; 250 } 251 ((GregorianCalendar *)cpp_cal)->setGregorianChange(date, *pErrorCode); 252 } 253 254 U_CAPI UDate U_EXPORT2 255 ucal_getGregorianChange(const UCalendar *cal, UErrorCode *pErrorCode) { 256 if(U_FAILURE(*pErrorCode)) { 257 return (UDate)0; 258 } 259 Calendar *cpp_cal = (Calendar *)cal; 260 if(cpp_cal->getDynamicClassID() != GregorianCalendar::getStaticClassID()) { 261 *pErrorCode = U_UNSUPPORTED_ERROR; 262 return (UDate)0; 263 } 264 return ((GregorianCalendar *)cpp_cal)->getGregorianChange(); 265 } 266 267 U_CAPI int32_t U_EXPORT2 268 ucal_getAttribute( const UCalendar* cal, 269 UCalendarAttribute attr) 270 { 271 272 switch(attr) { 273 case UCAL_LENIENT: 274 return ((Calendar*)cal)->isLenient(); 275 276 case UCAL_FIRST_DAY_OF_WEEK: 277 return ((Calendar*)cal)->getFirstDayOfWeek(); 278 279 case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK: 280 return ((Calendar*)cal)->getMinimalDaysInFirstWeek(); 281 282 default: 283 break; 284 } 285 return -1; 286 } 287 288 U_CAPI void U_EXPORT2 289 ucal_setAttribute( UCalendar* cal, 290 UCalendarAttribute attr, 291 int32_t newValue) 292 { 293 294 switch(attr) { 295 case UCAL_LENIENT: 296 ((Calendar*)cal)->setLenient((UBool)newValue); 297 break; 298 299 case UCAL_FIRST_DAY_OF_WEEK: 300 ((Calendar*)cal)->setFirstDayOfWeek((UCalendarDaysOfWeek)newValue); 301 break; 302 303 case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK: 304 ((Calendar*)cal)->setMinimalDaysInFirstWeek((uint8_t)newValue); 305 break; 306 } 307 } 308 309 U_CAPI const char* U_EXPORT2 310 ucal_getAvailable(int32_t index) 311 { 312 313 return uloc_getAvailable(index); 314 } 315 316 U_CAPI int32_t U_EXPORT2 317 ucal_countAvailable() 318 { 319 320 return uloc_countAvailable(); 321 } 322 323 U_CAPI UDate U_EXPORT2 324 ucal_getMillis( const UCalendar* cal, 325 UErrorCode* status) 326 { 327 328 if(U_FAILURE(*status)) return (UDate) 0; 329 330 return ((Calendar*)cal)->getTime(*status); 331 } 332 333 U_CAPI void U_EXPORT2 334 ucal_setMillis( UCalendar* cal, 335 UDate dateTime, 336 UErrorCode* status ) 337 { 338 if(U_FAILURE(*status)) return; 339 340 ((Calendar*)cal)->setTime(dateTime, *status); 341 } 342 343 // TBD: why does this take an UErrorCode? 344 U_CAPI void U_EXPORT2 345 ucal_setDate( UCalendar* cal, 346 int32_t year, 347 int32_t month, 348 int32_t date, 349 UErrorCode *status) 350 { 351 352 if(U_FAILURE(*status)) return; 353 354 ((Calendar*)cal)->set(year, month, date); 355 } 356 357 // TBD: why does this take an UErrorCode? 358 U_CAPI void U_EXPORT2 359 ucal_setDateTime( UCalendar* cal, 360 int32_t year, 361 int32_t month, 362 int32_t date, 363 int32_t hour, 364 int32_t minute, 365 int32_t second, 366 UErrorCode *status) 367 { 368 if(U_FAILURE(*status)) return; 369 370 ((Calendar*)cal)->set(year, month, date, hour, minute, second); 371 } 372 373 U_CAPI UBool U_EXPORT2 374 ucal_equivalentTo( const UCalendar* cal1, 375 const UCalendar* cal2) 376 { 377 378 return ((Calendar*)cal1)->isEquivalentTo(*((Calendar*)cal2)); 379 } 380 381 U_CAPI void U_EXPORT2 382 ucal_add( UCalendar* cal, 383 UCalendarDateFields field, 384 int32_t amount, 385 UErrorCode* status) 386 { 387 388 if(U_FAILURE(*status)) return; 389 390 ((Calendar*)cal)->add(field, amount, *status); 391 } 392 393 U_CAPI void U_EXPORT2 394 ucal_roll( UCalendar* cal, 395 UCalendarDateFields field, 396 int32_t amount, 397 UErrorCode* status) 398 { 399 400 if(U_FAILURE(*status)) return; 401 402 ((Calendar*)cal)->roll(field, amount, *status); 403 } 404 405 U_CAPI int32_t U_EXPORT2 406 ucal_get( const UCalendar* cal, 407 UCalendarDateFields field, 408 UErrorCode* status ) 409 { 410 411 if(U_FAILURE(*status)) return -1; 412 413 return ((Calendar*)cal)->get(field, *status); 414 } 415 416 U_CAPI void U_EXPORT2 417 ucal_set( UCalendar* cal, 418 UCalendarDateFields field, 419 int32_t value) 420 { 421 422 ((Calendar*)cal)->set(field, value); 423 } 424 425 U_CAPI UBool U_EXPORT2 426 ucal_isSet( const UCalendar* cal, 427 UCalendarDateFields field) 428 { 429 430 return ((Calendar*)cal)->isSet(field); 431 } 432 433 U_CAPI void U_EXPORT2 434 ucal_clearField( UCalendar* cal, 435 UCalendarDateFields field) 436 { 437 438 ((Calendar*)cal)->clear(field); 439 } 440 441 U_CAPI void U_EXPORT2 442 ucal_clear(UCalendar* calendar) 443 { 444 445 ((Calendar*)calendar)->clear(); 446 } 447 448 U_CAPI int32_t U_EXPORT2 449 ucal_getLimit( const UCalendar* cal, 450 UCalendarDateFields field, 451 UCalendarLimitType type, 452 UErrorCode *status) 453 { 454 455 if(status==0 || U_FAILURE(*status)) { 456 return -1; 457 } 458 459 switch(type) { 460 case UCAL_MINIMUM: 461 return ((Calendar*)cal)->getMinimum(field); 462 463 case UCAL_MAXIMUM: 464 return ((Calendar*)cal)->getMaximum(field); 465 466 case UCAL_GREATEST_MINIMUM: 467 return ((Calendar*)cal)->getGreatestMinimum(field); 468 469 case UCAL_LEAST_MAXIMUM: 470 return ((Calendar*)cal)->getLeastMaximum(field); 471 472 case UCAL_ACTUAL_MINIMUM: 473 return ((Calendar*)cal)->getActualMinimum(field, 474 *status); 475 476 case UCAL_ACTUAL_MAXIMUM: 477 return ((Calendar*)cal)->getActualMaximum(field, 478 *status); 479 480 default: 481 break; 482 } 483 return -1; 484 } 485 486 U_CAPI const char * U_EXPORT2 487 ucal_getLocaleByType(const UCalendar *cal, ULocDataLocaleType type, UErrorCode* status) 488 { 489 if (cal == NULL) { 490 if (U_SUCCESS(*status)) { 491 *status = U_ILLEGAL_ARGUMENT_ERROR; 492 } 493 return NULL; 494 } 495 return ((Calendar*)cal)->getLocaleID(type, *status); 496 } 497 498 U_CAPI const char * U_EXPORT2 499 ucal_getTZDataVersion(UErrorCode* status) 500 { 501 return TimeZone::getTZDataVersion(*status); 502 } 503 504 U_CAPI int32_t U_EXPORT2 505 ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len, 506 UChar* result, int32_t resultCapacity, UBool *isSystemID, UErrorCode* status) { 507 if(status == 0 || U_FAILURE(*status)) { 508 return 0; 509 } 510 if (isSystemID) { 511 *isSystemID = FALSE; 512 } 513 if (id == 0 || len == 0 || result == 0 || resultCapacity <= 0) { 514 *status = U_ILLEGAL_ARGUMENT_ERROR; 515 return 0; 516 } 517 int32_t reslen = 0; 518 UnicodeString canonical; 519 UBool systemID = FALSE; 520 TimeZone::getCanonicalID(UnicodeString(id, len), canonical, systemID, *status); 521 if (U_SUCCESS(*status)) { 522 if (isSystemID) { 523 *isSystemID = systemID; 524 } 525 reslen = canonical.extract(result, resultCapacity, *status); 526 } 527 return reslen; 528 } 529 530 U_CAPI const char * U_EXPORT2 531 ucal_getType(const UCalendar *cal, UErrorCode* status) 532 { 533 if (U_FAILURE(*status)) { 534 return NULL; 535 } 536 return ((Calendar*)cal)->getType(); 537 } 538 539 U_CAPI UCalendarWeekdayType U_EXPORT2 540 ucal_getDayOfWeekType(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode* status) 541 { 542 if (U_FAILURE(*status)) { 543 return UCAL_WEEKDAY; 544 } 545 return ((Calendar*)cal)->getDayOfWeekType(dayOfWeek, *status); 546 } 547 548 U_CAPI int32_t U_EXPORT2 549 ucal_getWeekendTransition(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode *status) 550 { 551 if (U_FAILURE(*status)) { 552 return 0; 553 } 554 return ((Calendar*)cal)->getWeekendTransition(dayOfWeek, *status); 555 } 556 557 U_CAPI UBool U_EXPORT2 558 ucal_isWeekend(const UCalendar *cal, UDate date, UErrorCode *status) 559 { 560 if (U_FAILURE(*status)) { 561 return FALSE; 562 } 563 return ((Calendar*)cal)->isWeekend(date, *status); 564 } 565 566 567 static const UEnumeration defaultKeywordValues = { 568 NULL, 569 NULL, 570 ulist_close_keyword_values_iterator, 571 ulist_count_keyword_values, 572 uenum_unextDefault, 573 ulist_next_keyword_value, 574 ulist_reset_keyword_values_iterator 575 }; 576 577 static const char * const CAL_TYPES[] = { 578 "gregorian", 579 "japanese", 580 "buddhist", 581 "roc", 582 "persian", 583 "islamic-civil", 584 "islamic", 585 "hebrew", 586 "chinese", 587 "indian", 588 "coptic", 589 "ethiopic", 590 "ethiopic-amete-alem", 591 NULL 592 }; 593 594 U_CAPI UEnumeration* U_EXPORT2 595 ucal_getKeywordValuesForLocale(const char * /* key */, const char* locale, UBool commonlyUsed, UErrorCode *status) { 596 // Resolve region 597 char prefRegion[ULOC_FULLNAME_CAPACITY] = ""; 598 int32_t prefRegionLength = 0; 599 prefRegionLength = uloc_getCountry(locale, prefRegion, sizeof(prefRegion), status); 600 if (prefRegionLength == 0) { 601 char loc[ULOC_FULLNAME_CAPACITY] = ""; 602 int32_t locLength = 0; 603 locLength = uloc_addLikelySubtags(locale, loc, sizeof(loc), status); 604 605 prefRegionLength = uloc_getCountry(loc, prefRegion, sizeof(prefRegion), status); 606 } 607 608 // Read preferred calendar values from supplementalData calendarPreference 609 UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", status); 610 ures_getByKey(rb, "calendarPreferenceData", rb, status); 611 UResourceBundle *order = ures_getByKey(rb, prefRegion, NULL, status); 612 if (*status == U_MISSING_RESOURCE_ERROR && rb != NULL) { 613 *status = U_ZERO_ERROR; 614 order = ures_getByKey(rb, "001", NULL, status); 615 } 616 617 // Create a list of calendar type strings 618 UList *values = NULL; 619 if (U_SUCCESS(*status)) { 620 values = ulist_createEmptyList(status); 621 if (U_SUCCESS(*status)) { 622 for (int i = 0; i < ures_getSize(order); i++) { 623 int32_t len; 624 const UChar *type = ures_getStringByIndex(order, i, &len, status); 625 char *caltype = (char*)uprv_malloc(len + 1); 626 if (caltype == NULL) { 627 *status = U_MEMORY_ALLOCATION_ERROR; 628 break; 629 } 630 u_UCharsToChars(type, caltype, len); 631 *(caltype + len) = 0; 632 633 ulist_addItemEndList(values, caltype, TRUE, status); 634 if (U_FAILURE(*status)) { 635 break; 636 } 637 } 638 639 if (U_SUCCESS(*status) && !commonlyUsed) { 640 // If not commonlyUsed, add other available values 641 for (int32_t i = 0; CAL_TYPES[i] != NULL; i++) { 642 if (!ulist_containsString(values, CAL_TYPES[i], (int32_t)uprv_strlen(CAL_TYPES[i]))) { 643 ulist_addItemEndList(values, CAL_TYPES[i], FALSE, status); 644 if (U_FAILURE(*status)) { 645 break; 646 } 647 } 648 } 649 } 650 if (U_FAILURE(*status)) { 651 ulist_deleteList(values); 652 values = NULL; 653 } 654 } 655 } 656 657 ures_close(order); 658 ures_close(rb); 659 660 if (U_FAILURE(*status) || values == NULL) { 661 return NULL; 662 } 663 664 // Create string enumeration 665 UEnumeration *en = (UEnumeration*)uprv_malloc(sizeof(UEnumeration)); 666 if (en == NULL) { 667 *status = U_MEMORY_ALLOCATION_ERROR; 668 ulist_deleteList(values); 669 return NULL; 670 } 671 ulist_resetList(values); 672 memcpy(en, &defaultKeywordValues, sizeof(UEnumeration)); 673 en->context = values; 674 return en; 675 } 676 677 #endif /* #if !UCONFIG_NO_FORMATTING */ 678