1 /*
2 *******************************************************************************
3 * Copyright (C) 1996-2012, 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*
_createTimeZone(const UChar * zoneID,int32_t len,UErrorCode * ec)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
ucal_openTimeZoneIDEnumeration(USystemTimeZoneType zoneType,const char * region,const int32_t * rawOffset,UErrorCode * ec)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
ucal_openTimeZones(UErrorCode * ec)57 ucal_openTimeZones(UErrorCode* ec) {
58 return uenum_openFromStringEnumeration(TimeZone::createEnumeration(), ec);
59 }
60
61 U_CAPI UEnumeration* U_EXPORT2
ucal_openCountryTimeZones(const char * country,UErrorCode * ec)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
ucal_getDefaultTimeZone(UChar * result,int32_t resultCapacity,UErrorCode * ec)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
ucal_setDefaultTimeZone(const UChar * zoneID,UErrorCode * ec)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
ucal_getDSTSavings(const UChar * zoneID,UErrorCode * ec)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
ucal_getNow()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
ucal_open(const UChar * zoneID,int32_t len,const char * locale,UCalendarType caltype,UErrorCode * status)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
ucal_close(UCalendar * cal)163 ucal_close(UCalendar *cal)
164 {
165
166 delete (Calendar*) cal;
167 }
168
169 U_CAPI UCalendar* U_EXPORT2
ucal_clone(const UCalendar * cal,UErrorCode * status)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
ucal_setTimeZone(UCalendar * cal,const UChar * zoneID,int32_t len,UErrorCode * status)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
ucal_getTimeZoneDisplayName(const UCalendar * cal,UCalendarDisplayNameType type,const char * locale,UChar * result,int32_t resultLength,UErrorCode * status)204 ucal_getTimeZoneDisplayName(const UCalendar* cal,
205 UCalendarDisplayNameType type,
206 const char *locale,
207 UChar* result,
208 int32_t resultLength,
209 UErrorCode* status)
210 {
211
212 if(U_FAILURE(*status)) return -1;
213
214 const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
215 UnicodeString id;
216 if(!(result==NULL && resultLength==0)) {
217 // NULL destination for pure preflighting: empty dummy string
218 // otherwise, alias the destination buffer
219 id.setTo(result, 0, resultLength);
220 }
221
222 switch(type) {
223 case UCAL_STANDARD:
224 tz.getDisplayName(FALSE, TimeZone::LONG, Locale(locale), id);
225 break;
226
227 case UCAL_SHORT_STANDARD:
228 tz.getDisplayName(FALSE, TimeZone::SHORT, Locale(locale), id);
229 break;
230
231 case UCAL_DST:
232 tz.getDisplayName(TRUE, TimeZone::LONG, Locale(locale), id);
233 break;
234
235 case UCAL_SHORT_DST:
236 tz.getDisplayName(TRUE, TimeZone::SHORT, Locale(locale), id);
237 break;
238 }
239
240 return id.extract(result, resultLength, *status);
241 }
242
243 U_CAPI UBool U_EXPORT2
ucal_inDaylightTime(const UCalendar * cal,UErrorCode * status)244 ucal_inDaylightTime( const UCalendar* cal,
245 UErrorCode* status )
246 {
247
248 if(U_FAILURE(*status)) return (UBool) -1;
249 return ((Calendar*)cal)->inDaylightTime(*status);
250 }
251
252 U_CAPI void U_EXPORT2
ucal_setGregorianChange(UCalendar * cal,UDate date,UErrorCode * pErrorCode)253 ucal_setGregorianChange(UCalendar *cal, UDate date, UErrorCode *pErrorCode) {
254 if(U_FAILURE(*pErrorCode)) {
255 return;
256 }
257 Calendar *cpp_cal = (Calendar *)cal;
258 GregorianCalendar *gregocal = dynamic_cast<GregorianCalendar *>(cpp_cal);
259 // Not if(gregocal == NULL) {
260 // because we really want to work only with a GregorianCalendar, not with
261 // its subclasses like BuddhistCalendar.
262 if (cpp_cal == NULL) {
263 // We normally don't check "this" pointers for NULL, but this here avoids
264 // compiler-generated exception-throwing code in case cal == NULL.
265 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
266 return;
267 }
268 if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
269 *pErrorCode = U_UNSUPPORTED_ERROR;
270 return;
271 }
272 gregocal->setGregorianChange(date, *pErrorCode);
273 }
274
275 U_CAPI UDate U_EXPORT2
ucal_getGregorianChange(const UCalendar * cal,UErrorCode * pErrorCode)276 ucal_getGregorianChange(const UCalendar *cal, UErrorCode *pErrorCode) {
277 if(U_FAILURE(*pErrorCode)) {
278 return (UDate)0;
279 }
280 const Calendar *cpp_cal = (const Calendar *)cal;
281 const GregorianCalendar *gregocal = dynamic_cast<const GregorianCalendar *>(cpp_cal);
282 // Not if(gregocal == NULL) {
283 // see comments in ucal_setGregorianChange().
284 if (cpp_cal == NULL) {
285 // We normally don't check "this" pointers for NULL, but this here avoids
286 // compiler-generated exception-throwing code in case cal == NULL.
287 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
288 return (UDate)0;
289 }
290 if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
291 *pErrorCode = U_UNSUPPORTED_ERROR;
292 return (UDate)0;
293 }
294 return gregocal->getGregorianChange();
295 }
296
297 U_CAPI int32_t U_EXPORT2
ucal_getAttribute(const UCalendar * cal,UCalendarAttribute attr)298 ucal_getAttribute( const UCalendar* cal,
299 UCalendarAttribute attr)
300 {
301
302 switch(attr) {
303 case UCAL_LENIENT:
304 return ((Calendar*)cal)->isLenient();
305
306 case UCAL_FIRST_DAY_OF_WEEK:
307 return ((Calendar*)cal)->getFirstDayOfWeek();
308
309 case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK:
310 return ((Calendar*)cal)->getMinimalDaysInFirstWeek();
311
312 case UCAL_REPEATED_WALL_TIME:
313 return ((Calendar*)cal)->getRepeatedWallTimeOption();
314
315 case UCAL_SKIPPED_WALL_TIME:
316 return ((Calendar*)cal)->getSkippedWallTimeOption();
317
318 default:
319 break;
320 }
321 return -1;
322 }
323
324 U_CAPI void U_EXPORT2
ucal_setAttribute(UCalendar * cal,UCalendarAttribute attr,int32_t newValue)325 ucal_setAttribute( UCalendar* cal,
326 UCalendarAttribute attr,
327 int32_t newValue)
328 {
329
330 switch(attr) {
331 case UCAL_LENIENT:
332 ((Calendar*)cal)->setLenient((UBool)newValue);
333 break;
334
335 case UCAL_FIRST_DAY_OF_WEEK:
336 ((Calendar*)cal)->setFirstDayOfWeek((UCalendarDaysOfWeek)newValue);
337 break;
338
339 case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK:
340 ((Calendar*)cal)->setMinimalDaysInFirstWeek((uint8_t)newValue);
341 break;
342
343 case UCAL_REPEATED_WALL_TIME:
344 ((Calendar*)cal)->setRepeatedWallTimeOption((UCalendarWallTimeOption)newValue);
345 break;
346
347 case UCAL_SKIPPED_WALL_TIME:
348 ((Calendar*)cal)->setSkippedWallTimeOption((UCalendarWallTimeOption)newValue);
349 break;
350 }
351 }
352
353 U_CAPI const char* U_EXPORT2
ucal_getAvailable(int32_t index)354 ucal_getAvailable(int32_t index)
355 {
356
357 return uloc_getAvailable(index);
358 }
359
360 U_CAPI int32_t U_EXPORT2
ucal_countAvailable()361 ucal_countAvailable()
362 {
363
364 return uloc_countAvailable();
365 }
366
367 U_CAPI UDate U_EXPORT2
ucal_getMillis(const UCalendar * cal,UErrorCode * status)368 ucal_getMillis( const UCalendar* cal,
369 UErrorCode* status)
370 {
371
372 if(U_FAILURE(*status)) return (UDate) 0;
373
374 return ((Calendar*)cal)->getTime(*status);
375 }
376
377 U_CAPI void U_EXPORT2
ucal_setMillis(UCalendar * cal,UDate dateTime,UErrorCode * status)378 ucal_setMillis( UCalendar* cal,
379 UDate dateTime,
380 UErrorCode* status )
381 {
382 if(U_FAILURE(*status)) return;
383
384 ((Calendar*)cal)->setTime(dateTime, *status);
385 }
386
387 // TBD: why does this take an UErrorCode?
388 U_CAPI void U_EXPORT2
ucal_setDate(UCalendar * cal,int32_t year,int32_t month,int32_t date,UErrorCode * status)389 ucal_setDate( UCalendar* cal,
390 int32_t year,
391 int32_t month,
392 int32_t date,
393 UErrorCode *status)
394 {
395
396 if(U_FAILURE(*status)) return;
397
398 ((Calendar*)cal)->set(year, month, date);
399 }
400
401 // TBD: why does this take an UErrorCode?
402 U_CAPI void U_EXPORT2
ucal_setDateTime(UCalendar * cal,int32_t year,int32_t month,int32_t date,int32_t hour,int32_t minute,int32_t second,UErrorCode * status)403 ucal_setDateTime( UCalendar* cal,
404 int32_t year,
405 int32_t month,
406 int32_t date,
407 int32_t hour,
408 int32_t minute,
409 int32_t second,
410 UErrorCode *status)
411 {
412 if(U_FAILURE(*status)) return;
413
414 ((Calendar*)cal)->set(year, month, date, hour, minute, second);
415 }
416
417 U_CAPI UBool U_EXPORT2
ucal_equivalentTo(const UCalendar * cal1,const UCalendar * cal2)418 ucal_equivalentTo( const UCalendar* cal1,
419 const UCalendar* cal2)
420 {
421
422 return ((Calendar*)cal1)->isEquivalentTo(*((Calendar*)cal2));
423 }
424
425 U_CAPI void U_EXPORT2
ucal_add(UCalendar * cal,UCalendarDateFields field,int32_t amount,UErrorCode * status)426 ucal_add( UCalendar* cal,
427 UCalendarDateFields field,
428 int32_t amount,
429 UErrorCode* status)
430 {
431
432 if(U_FAILURE(*status)) return;
433
434 ((Calendar*)cal)->add(field, amount, *status);
435 }
436
437 U_CAPI void U_EXPORT2
ucal_roll(UCalendar * cal,UCalendarDateFields field,int32_t amount,UErrorCode * status)438 ucal_roll( UCalendar* cal,
439 UCalendarDateFields field,
440 int32_t amount,
441 UErrorCode* status)
442 {
443
444 if(U_FAILURE(*status)) return;
445
446 ((Calendar*)cal)->roll(field, amount, *status);
447 }
448
449 U_CAPI int32_t U_EXPORT2
ucal_get(const UCalendar * cal,UCalendarDateFields field,UErrorCode * status)450 ucal_get( const UCalendar* cal,
451 UCalendarDateFields field,
452 UErrorCode* status )
453 {
454
455 if(U_FAILURE(*status)) return -1;
456
457 return ((Calendar*)cal)->get(field, *status);
458 }
459
460 U_CAPI void U_EXPORT2
ucal_set(UCalendar * cal,UCalendarDateFields field,int32_t value)461 ucal_set( UCalendar* cal,
462 UCalendarDateFields field,
463 int32_t value)
464 {
465
466 ((Calendar*)cal)->set(field, value);
467 }
468
469 U_CAPI UBool U_EXPORT2
ucal_isSet(const UCalendar * cal,UCalendarDateFields field)470 ucal_isSet( const UCalendar* cal,
471 UCalendarDateFields field)
472 {
473
474 return ((Calendar*)cal)->isSet(field);
475 }
476
477 U_CAPI void U_EXPORT2
ucal_clearField(UCalendar * cal,UCalendarDateFields field)478 ucal_clearField( UCalendar* cal,
479 UCalendarDateFields field)
480 {
481
482 ((Calendar*)cal)->clear(field);
483 }
484
485 U_CAPI void U_EXPORT2
ucal_clear(UCalendar * calendar)486 ucal_clear(UCalendar* calendar)
487 {
488
489 ((Calendar*)calendar)->clear();
490 }
491
492 U_CAPI int32_t U_EXPORT2
ucal_getLimit(const UCalendar * cal,UCalendarDateFields field,UCalendarLimitType type,UErrorCode * status)493 ucal_getLimit( const UCalendar* cal,
494 UCalendarDateFields field,
495 UCalendarLimitType type,
496 UErrorCode *status)
497 {
498
499 if(status==0 || U_FAILURE(*status)) {
500 return -1;
501 }
502
503 switch(type) {
504 case UCAL_MINIMUM:
505 return ((Calendar*)cal)->getMinimum(field);
506
507 case UCAL_MAXIMUM:
508 return ((Calendar*)cal)->getMaximum(field);
509
510 case UCAL_GREATEST_MINIMUM:
511 return ((Calendar*)cal)->getGreatestMinimum(field);
512
513 case UCAL_LEAST_MAXIMUM:
514 return ((Calendar*)cal)->getLeastMaximum(field);
515
516 case UCAL_ACTUAL_MINIMUM:
517 return ((Calendar*)cal)->getActualMinimum(field,
518 *status);
519
520 case UCAL_ACTUAL_MAXIMUM:
521 return ((Calendar*)cal)->getActualMaximum(field,
522 *status);
523
524 default:
525 break;
526 }
527 return -1;
528 }
529
530 U_CAPI const char * U_EXPORT2
ucal_getLocaleByType(const UCalendar * cal,ULocDataLocaleType type,UErrorCode * status)531 ucal_getLocaleByType(const UCalendar *cal, ULocDataLocaleType type, UErrorCode* status)
532 {
533 if (cal == NULL) {
534 if (U_SUCCESS(*status)) {
535 *status = U_ILLEGAL_ARGUMENT_ERROR;
536 }
537 return NULL;
538 }
539 return ((Calendar*)cal)->getLocaleID(type, *status);
540 }
541
542 U_CAPI const char * U_EXPORT2
ucal_getTZDataVersion(UErrorCode * status)543 ucal_getTZDataVersion(UErrorCode* status)
544 {
545 return TimeZone::getTZDataVersion(*status);
546 }
547
548 U_CAPI int32_t U_EXPORT2
ucal_getCanonicalTimeZoneID(const UChar * id,int32_t len,UChar * result,int32_t resultCapacity,UBool * isSystemID,UErrorCode * status)549 ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len,
550 UChar* result, int32_t resultCapacity, UBool *isSystemID, UErrorCode* status) {
551 if(status == 0 || U_FAILURE(*status)) {
552 return 0;
553 }
554 if (isSystemID) {
555 *isSystemID = FALSE;
556 }
557 if (id == 0 || len == 0 || result == 0 || resultCapacity <= 0) {
558 *status = U_ILLEGAL_ARGUMENT_ERROR;
559 return 0;
560 }
561 int32_t reslen = 0;
562 UnicodeString canonical;
563 UBool systemID = FALSE;
564 TimeZone::getCanonicalID(UnicodeString(id, len), canonical, systemID, *status);
565 if (U_SUCCESS(*status)) {
566 if (isSystemID) {
567 *isSystemID = systemID;
568 }
569 reslen = canonical.extract(result, resultCapacity, *status);
570 }
571 return reslen;
572 }
573
574 U_CAPI const char * U_EXPORT2
ucal_getType(const UCalendar * cal,UErrorCode * status)575 ucal_getType(const UCalendar *cal, UErrorCode* status)
576 {
577 if (U_FAILURE(*status)) {
578 return NULL;
579 }
580 return ((Calendar*)cal)->getType();
581 }
582
583 U_CAPI UCalendarWeekdayType U_EXPORT2
ucal_getDayOfWeekType(const UCalendar * cal,UCalendarDaysOfWeek dayOfWeek,UErrorCode * status)584 ucal_getDayOfWeekType(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode* status)
585 {
586 if (U_FAILURE(*status)) {
587 return UCAL_WEEKDAY;
588 }
589 return ((Calendar*)cal)->getDayOfWeekType(dayOfWeek, *status);
590 }
591
592 U_CAPI int32_t U_EXPORT2
ucal_getWeekendTransition(const UCalendar * cal,UCalendarDaysOfWeek dayOfWeek,UErrorCode * status)593 ucal_getWeekendTransition(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode *status)
594 {
595 if (U_FAILURE(*status)) {
596 return 0;
597 }
598 return ((Calendar*)cal)->getWeekendTransition(dayOfWeek, *status);
599 }
600
601 U_CAPI UBool U_EXPORT2
ucal_isWeekend(const UCalendar * cal,UDate date,UErrorCode * status)602 ucal_isWeekend(const UCalendar *cal, UDate date, UErrorCode *status)
603 {
604 if (U_FAILURE(*status)) {
605 return FALSE;
606 }
607 return ((Calendar*)cal)->isWeekend(date, *status);
608 }
609
610 U_CAPI int32_t U_EXPORT2
ucal_getFieldDifference(UCalendar * cal,UDate target,UCalendarDateFields field,UErrorCode * status)611 ucal_getFieldDifference(UCalendar* cal, UDate target,
612 UCalendarDateFields field,
613 UErrorCode* status )
614 {
615 if (U_FAILURE(*status)) {
616 return 0;
617 }
618 return ((Calendar*)cal)->fieldDifference(target, field, *status);
619 }
620
621
622 static const UEnumeration defaultKeywordValues = {
623 NULL,
624 NULL,
625 ulist_close_keyword_values_iterator,
626 ulist_count_keyword_values,
627 uenum_unextDefault,
628 ulist_next_keyword_value,
629 ulist_reset_keyword_values_iterator
630 };
631
632 static const char * const CAL_TYPES[] = {
633 "gregorian",
634 "japanese",
635 "buddhist",
636 "roc",
637 "persian",
638 "islamic-civil",
639 "islamic",
640 "hebrew",
641 "chinese",
642 "indian",
643 "coptic",
644 "ethiopic",
645 "ethiopic-amete-alem",
646 NULL
647 };
648
649 U_CAPI UEnumeration* U_EXPORT2
ucal_getKeywordValuesForLocale(const char *,const char * locale,UBool commonlyUsed,UErrorCode * status)650 ucal_getKeywordValuesForLocale(const char * /* key */, const char* locale, UBool commonlyUsed, UErrorCode *status) {
651 // Resolve region
652 char prefRegion[ULOC_FULLNAME_CAPACITY] = "";
653 int32_t prefRegionLength = 0;
654 prefRegionLength = uloc_getCountry(locale, prefRegion, sizeof(prefRegion), status);
655 if (prefRegionLength == 0) {
656 char loc[ULOC_FULLNAME_CAPACITY] = "";
657 uloc_addLikelySubtags(locale, loc, sizeof(loc), status);
658
659 prefRegionLength = uloc_getCountry(loc, prefRegion, sizeof(prefRegion), status);
660 }
661
662 // Read preferred calendar values from supplementalData calendarPreference
663 UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", status);
664 ures_getByKey(rb, "calendarPreferenceData", rb, status);
665 UResourceBundle *order = ures_getByKey(rb, prefRegion, NULL, status);
666 if (*status == U_MISSING_RESOURCE_ERROR && rb != NULL) {
667 *status = U_ZERO_ERROR;
668 order = ures_getByKey(rb, "001", NULL, status);
669 }
670
671 // Create a list of calendar type strings
672 UList *values = NULL;
673 if (U_SUCCESS(*status)) {
674 values = ulist_createEmptyList(status);
675 if (U_SUCCESS(*status)) {
676 for (int i = 0; i < ures_getSize(order); i++) {
677 int32_t len;
678 const UChar *type = ures_getStringByIndex(order, i, &len, status);
679 char *caltype = (char*)uprv_malloc(len + 1);
680 if (caltype == NULL) {
681 *status = U_MEMORY_ALLOCATION_ERROR;
682 break;
683 }
684 u_UCharsToChars(type, caltype, len);
685 *(caltype + len) = 0;
686
687 ulist_addItemEndList(values, caltype, TRUE, status);
688 if (U_FAILURE(*status)) {
689 break;
690 }
691 }
692
693 if (U_SUCCESS(*status) && !commonlyUsed) {
694 // If not commonlyUsed, add other available values
695 for (int32_t i = 0; CAL_TYPES[i] != NULL; i++) {
696 if (!ulist_containsString(values, CAL_TYPES[i], (int32_t)uprv_strlen(CAL_TYPES[i]))) {
697 ulist_addItemEndList(values, CAL_TYPES[i], FALSE, status);
698 if (U_FAILURE(*status)) {
699 break;
700 }
701 }
702 }
703 }
704 if (U_FAILURE(*status)) {
705 ulist_deleteList(values);
706 values = NULL;
707 }
708 }
709 }
710
711 ures_close(order);
712 ures_close(rb);
713
714 if (U_FAILURE(*status) || values == NULL) {
715 return NULL;
716 }
717
718 // Create string enumeration
719 UEnumeration *en = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
720 if (en == NULL) {
721 *status = U_MEMORY_ALLOCATION_ERROR;
722 ulist_deleteList(values);
723 return NULL;
724 }
725 ulist_resetList(values);
726 memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
727 en->context = values;
728 return en;
729 }
730
731 U_CAPI UBool U_EXPORT2
ucal_getTimeZoneTransitionDate(const UCalendar * cal,UTimeZoneTransitionType type,UDate * transition,UErrorCode * status)732 ucal_getTimeZoneTransitionDate(const UCalendar* cal, UTimeZoneTransitionType type,
733 UDate* transition, UErrorCode* status)
734 {
735 if (U_FAILURE(*status)) {
736 return FALSE;
737 }
738 UDate base = ((Calendar*)cal)->getTime(*status);
739 const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
740 const BasicTimeZone * btz = dynamic_cast<const BasicTimeZone *>(&tz);
741 if (btz != NULL && U_SUCCESS(*status)) {
742 TimeZoneTransition tzt;
743 LocalPointer<BasicTimeZone> btzClone(static_cast<BasicTimeZone *>(btz->clone())); // getNext/PreviousTransition are non-const
744 UBool inclusive = (type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE || type == UCAL_TZ_TRANSITION_PREVIOUS_INCLUSIVE);
745 UBool result = (type == UCAL_TZ_TRANSITION_NEXT || type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE)?
746 btzClone->getNextTransition(base, inclusive, tzt):
747 btzClone->getPreviousTransition(base, inclusive, tzt);
748 if (result) {
749 *transition = tzt.getTime();
750 return TRUE;
751 }
752 }
753 return FALSE;
754 }
755
756 #endif /* #if !UCONFIG_NO_FORMATTING */
757