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 */