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