1 /*
2 *******************************************************************************
3 * Copyright (C) 1996-2016, 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 #include "ulocimp.h"
29
30 U_NAMESPACE_USE
31
32 static TimeZone*
_createTimeZone(const UChar * zoneID,int32_t len,UErrorCode * ec)33 _createTimeZone(const UChar* zoneID, int32_t len, UErrorCode* ec) {
34 TimeZone* zone = NULL;
35 if (ec!=NULL && U_SUCCESS(*ec)) {
36 // Note that if zoneID is invalid, we get back GMT. This odd
37 // behavior is by design and goes back to the JDK. The only
38 // failure we will see is a memory allocation failure.
39 int32_t l = (len<0 ? u_strlen(zoneID) : len);
40 UnicodeString zoneStrID;
41 zoneStrID.setTo((UBool)(len < 0), zoneID, l); /* temporary read-only alias */
42 zone = TimeZone::createTimeZone(zoneStrID);
43 if (zone == NULL) {
44 *ec = U_MEMORY_ALLOCATION_ERROR;
45 }
46 }
47 return zone;
48 }
49
50 U_CAPI UEnumeration* U_EXPORT2
ucal_openTimeZoneIDEnumeration(USystemTimeZoneType zoneType,const char * region,const int32_t * rawOffset,UErrorCode * ec)51 ucal_openTimeZoneIDEnumeration(USystemTimeZoneType zoneType, const char* region,
52 const int32_t* rawOffset, UErrorCode* ec) {
53 return uenum_openFromStringEnumeration(TimeZone::createTimeZoneIDEnumeration(
54 zoneType, region, rawOffset, *ec), ec);
55 }
56
57 U_CAPI UEnumeration* U_EXPORT2
ucal_openTimeZones(UErrorCode * ec)58 ucal_openTimeZones(UErrorCode* ec) {
59 return uenum_openFromStringEnumeration(TimeZone::createEnumeration(), ec);
60 }
61
62 U_CAPI UEnumeration* U_EXPORT2
ucal_openCountryTimeZones(const char * country,UErrorCode * ec)63 ucal_openCountryTimeZones(const char* country, UErrorCode* ec) {
64 return uenum_openFromStringEnumeration(TimeZone::createEnumeration(country), ec);
65 }
66
67 U_CAPI int32_t U_EXPORT2
ucal_getDefaultTimeZone(UChar * result,int32_t resultCapacity,UErrorCode * ec)68 ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec) {
69 int32_t len = 0;
70 if (ec!=NULL && U_SUCCESS(*ec)) {
71 TimeZone* zone = TimeZone::createDefault();
72 if (zone == NULL) {
73 *ec = U_MEMORY_ALLOCATION_ERROR;
74 } else {
75 UnicodeString id;
76 zone->getID(id);
77 delete zone;
78 len = id.extract(result, resultCapacity, *ec);
79 }
80 }
81 return len;
82 }
83
84 U_CAPI void U_EXPORT2
ucal_setDefaultTimeZone(const UChar * zoneID,UErrorCode * ec)85 ucal_setDefaultTimeZone(const UChar* zoneID, UErrorCode* ec) {
86 TimeZone* zone = _createTimeZone(zoneID, -1, ec);
87 if (zone != NULL) {
88 TimeZone::adoptDefault(zone);
89 }
90 }
91
92 U_CAPI int32_t U_EXPORT2
ucal_getDSTSavings(const UChar * zoneID,UErrorCode * ec)93 ucal_getDSTSavings(const UChar* zoneID, UErrorCode* ec) {
94 int32_t result = 0;
95 TimeZone* zone = _createTimeZone(zoneID, -1, ec);
96 if (U_SUCCESS(*ec)) {
97 SimpleTimeZone* stz = dynamic_cast<SimpleTimeZone*>(zone);
98 if (stz != NULL) {
99 result = stz->getDSTSavings();
100 } else {
101 // Since there is no getDSTSavings on TimeZone, we use a
102 // heuristic: Starting with the current time, march
103 // forwards for one year, looking for DST savings.
104 // Stepping by weeks is sufficient.
105 UDate d = Calendar::getNow();
106 for (int32_t i=0; i<53; ++i, d+=U_MILLIS_PER_DAY*7.0) {
107 int32_t raw, dst;
108 zone->getOffset(d, FALSE, raw, dst, *ec);
109 if (U_FAILURE(*ec)) {
110 break;
111 } else if (dst != 0) {
112 result = dst;
113 break;
114 }
115 }
116 }
117 }
118 delete zone;
119 return result;
120 }
121
122 U_CAPI UDate U_EXPORT2
ucal_getNow()123 ucal_getNow()
124 {
125
126 return Calendar::getNow();
127 }
128
129 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
130
131 U_CAPI UCalendar* U_EXPORT2
ucal_open(const UChar * zoneID,int32_t len,const char * locale,UCalendarType caltype,UErrorCode * status)132 ucal_open( const UChar* zoneID,
133 int32_t len,
134 const char* locale,
135 UCalendarType caltype,
136 UErrorCode* status)
137 {
138
139 if(U_FAILURE(*status)) return 0;
140
141 TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault()
142 : _createTimeZone(zoneID, len, status);
143
144 if (U_FAILURE(*status)) {
145 return NULL;
146 }
147
148 if ( caltype == UCAL_GREGORIAN ) {
149 char localeBuf[ULOC_LOCALE_IDENTIFIER_CAPACITY];
150 if ( locale == NULL ) {
151 locale = uloc_getDefault();
152 }
153 uprv_strncpy(localeBuf, locale, ULOC_LOCALE_IDENTIFIER_CAPACITY);
154 uloc_setKeywordValue("calendar", "gregorian", localeBuf, ULOC_LOCALE_IDENTIFIER_CAPACITY, status);
155 if (U_FAILURE(*status)) {
156 return NULL;
157 }
158 return (UCalendar*)Calendar::createInstance(zone, Locale(localeBuf), *status);
159 }
160 return (UCalendar*)Calendar::createInstance(zone, Locale(locale), *status);
161 }
162
163 U_CAPI void U_EXPORT2
ucal_close(UCalendar * cal)164 ucal_close(UCalendar *cal)
165 {
166
167 delete (Calendar*) cal;
168 }
169
170 U_CAPI UCalendar* U_EXPORT2
ucal_clone(const UCalendar * cal,UErrorCode * status)171 ucal_clone(const UCalendar* cal,
172 UErrorCode* status)
173 {
174 if(U_FAILURE(*status)) return 0;
175
176 Calendar* res = ((Calendar*)cal)->clone();
177
178 if(res == 0) {
179 *status = U_MEMORY_ALLOCATION_ERROR;
180 return 0;
181 }
182
183 return (UCalendar*) res;
184 }
185
186 U_CAPI void U_EXPORT2
ucal_setTimeZone(UCalendar * cal,const UChar * zoneID,int32_t len,UErrorCode * status)187 ucal_setTimeZone( UCalendar* cal,
188 const UChar* zoneID,
189 int32_t len,
190 UErrorCode *status)
191 {
192
193 if(U_FAILURE(*status))
194 return;
195
196 TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault()
197 : _createTimeZone(zoneID, len, status);
198
199 if (zone != NULL) {
200 ((Calendar*)cal)->adoptTimeZone(zone);
201 }
202 }
203
204 U_CAPI int32_t U_EXPORT2
ucal_getTimeZoneID(const UCalendar * cal,UChar * result,int32_t resultLength,UErrorCode * status)205 ucal_getTimeZoneID(const UCalendar *cal,
206 UChar *result,
207 int32_t resultLength,
208 UErrorCode *status)
209 {
210 if (U_FAILURE(*status)) {
211 return 0;
212 }
213 const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
214 UnicodeString id;
215 tz.getID(id);
216 return id.extract(result, resultLength, *status);
217 }
218
219 U_CAPI int32_t U_EXPORT2
ucal_getTimeZoneDisplayName(const UCalendar * cal,UCalendarDisplayNameType type,const char * locale,UChar * result,int32_t resultLength,UErrorCode * status)220 ucal_getTimeZoneDisplayName(const UCalendar* cal,
221 UCalendarDisplayNameType type,
222 const char *locale,
223 UChar* result,
224 int32_t resultLength,
225 UErrorCode* status)
226 {
227
228 if(U_FAILURE(*status)) return -1;
229
230 const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
231 UnicodeString id;
232 if(!(result==NULL && resultLength==0)) {
233 // NULL destination for pure preflighting: empty dummy string
234 // otherwise, alias the destination buffer
235 id.setTo(result, 0, resultLength);
236 }
237
238 switch(type) {
239 case UCAL_STANDARD:
240 tz.getDisplayName(FALSE, TimeZone::LONG, Locale(locale), id);
241 break;
242
243 case UCAL_SHORT_STANDARD:
244 tz.getDisplayName(FALSE, TimeZone::SHORT, Locale(locale), id);
245 break;
246
247 case UCAL_DST:
248 tz.getDisplayName(TRUE, TimeZone::LONG, Locale(locale), id);
249 break;
250
251 case UCAL_SHORT_DST:
252 tz.getDisplayName(TRUE, TimeZone::SHORT, Locale(locale), id);
253 break;
254 }
255
256 return id.extract(result, resultLength, *status);
257 }
258
259 U_CAPI UBool U_EXPORT2
ucal_inDaylightTime(const UCalendar * cal,UErrorCode * status)260 ucal_inDaylightTime( const UCalendar* cal,
261 UErrorCode* status )
262 {
263
264 if(U_FAILURE(*status)) return (UBool) -1;
265 return ((Calendar*)cal)->inDaylightTime(*status);
266 }
267
268 U_CAPI void U_EXPORT2
ucal_setGregorianChange(UCalendar * cal,UDate date,UErrorCode * pErrorCode)269 ucal_setGregorianChange(UCalendar *cal, UDate date, UErrorCode *pErrorCode) {
270 if(U_FAILURE(*pErrorCode)) {
271 return;
272 }
273 Calendar *cpp_cal = (Calendar *)cal;
274 GregorianCalendar *gregocal = dynamic_cast<GregorianCalendar *>(cpp_cal);
275 // Not if(gregocal == NULL) {
276 // because we really want to work only with a GregorianCalendar, not with
277 // its subclasses like BuddhistCalendar.
278 if (cpp_cal == NULL) {
279 // We normally don't check "this" pointers for NULL, but this here avoids
280 // compiler-generated exception-throwing code in case cal == NULL.
281 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
282 return;
283 }
284 if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
285 *pErrorCode = U_UNSUPPORTED_ERROR;
286 return;
287 }
288 gregocal->setGregorianChange(date, *pErrorCode);
289 }
290
291 U_CAPI UDate U_EXPORT2
ucal_getGregorianChange(const UCalendar * cal,UErrorCode * pErrorCode)292 ucal_getGregorianChange(const UCalendar *cal, UErrorCode *pErrorCode) {
293 if(U_FAILURE(*pErrorCode)) {
294 return (UDate)0;
295 }
296 const Calendar *cpp_cal = (const Calendar *)cal;
297 const GregorianCalendar *gregocal = dynamic_cast<const GregorianCalendar *>(cpp_cal);
298 // Not if(gregocal == NULL) {
299 // see comments in ucal_setGregorianChange().
300 if (cpp_cal == NULL) {
301 // We normally don't check "this" pointers for NULL, but this here avoids
302 // compiler-generated exception-throwing code in case cal == NULL.
303 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
304 return (UDate)0;
305 }
306 if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
307 *pErrorCode = U_UNSUPPORTED_ERROR;
308 return (UDate)0;
309 }
310 return gregocal->getGregorianChange();
311 }
312
313 U_CAPI int32_t U_EXPORT2
ucal_getAttribute(const UCalendar * cal,UCalendarAttribute attr)314 ucal_getAttribute( const UCalendar* cal,
315 UCalendarAttribute attr)
316 {
317
318 switch(attr) {
319 case UCAL_LENIENT:
320 return ((Calendar*)cal)->isLenient();
321
322 case UCAL_FIRST_DAY_OF_WEEK:
323 return ((Calendar*)cal)->getFirstDayOfWeek();
324
325 case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK:
326 return ((Calendar*)cal)->getMinimalDaysInFirstWeek();
327
328 case UCAL_REPEATED_WALL_TIME:
329 return ((Calendar*)cal)->getRepeatedWallTimeOption();
330
331 case UCAL_SKIPPED_WALL_TIME:
332 return ((Calendar*)cal)->getSkippedWallTimeOption();
333
334 default:
335 break;
336 }
337 return -1;
338 }
339
340 U_CAPI void U_EXPORT2
ucal_setAttribute(UCalendar * cal,UCalendarAttribute attr,int32_t newValue)341 ucal_setAttribute( UCalendar* cal,
342 UCalendarAttribute attr,
343 int32_t newValue)
344 {
345
346 switch(attr) {
347 case UCAL_LENIENT:
348 ((Calendar*)cal)->setLenient((UBool)newValue);
349 break;
350
351 case UCAL_FIRST_DAY_OF_WEEK:
352 ((Calendar*)cal)->setFirstDayOfWeek((UCalendarDaysOfWeek)newValue);
353 break;
354
355 case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK:
356 ((Calendar*)cal)->setMinimalDaysInFirstWeek((uint8_t)newValue);
357 break;
358
359 case UCAL_REPEATED_WALL_TIME:
360 ((Calendar*)cal)->setRepeatedWallTimeOption((UCalendarWallTimeOption)newValue);
361 break;
362
363 case UCAL_SKIPPED_WALL_TIME:
364 ((Calendar*)cal)->setSkippedWallTimeOption((UCalendarWallTimeOption)newValue);
365 break;
366 }
367 }
368
369 U_CAPI const char* U_EXPORT2
ucal_getAvailable(int32_t index)370 ucal_getAvailable(int32_t index)
371 {
372
373 return uloc_getAvailable(index);
374 }
375
376 U_CAPI int32_t U_EXPORT2
ucal_countAvailable()377 ucal_countAvailable()
378 {
379
380 return uloc_countAvailable();
381 }
382
383 U_CAPI UDate U_EXPORT2
ucal_getMillis(const UCalendar * cal,UErrorCode * status)384 ucal_getMillis( const UCalendar* cal,
385 UErrorCode* status)
386 {
387
388 if(U_FAILURE(*status)) return (UDate) 0;
389
390 return ((Calendar*)cal)->getTime(*status);
391 }
392
393 U_CAPI void U_EXPORT2
ucal_setMillis(UCalendar * cal,UDate dateTime,UErrorCode * status)394 ucal_setMillis( UCalendar* cal,
395 UDate dateTime,
396 UErrorCode* status )
397 {
398 if(U_FAILURE(*status)) return;
399
400 ((Calendar*)cal)->setTime(dateTime, *status);
401 }
402
403 // TBD: why does this take an UErrorCode?
404 U_CAPI void U_EXPORT2
ucal_setDate(UCalendar * cal,int32_t year,int32_t month,int32_t date,UErrorCode * status)405 ucal_setDate( UCalendar* cal,
406 int32_t year,
407 int32_t month,
408 int32_t date,
409 UErrorCode *status)
410 {
411
412 if(U_FAILURE(*status)) return;
413
414 ((Calendar*)cal)->set(year, month, date);
415 }
416
417 // TBD: why does this take an UErrorCode?
418 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)419 ucal_setDateTime( UCalendar* cal,
420 int32_t year,
421 int32_t month,
422 int32_t date,
423 int32_t hour,
424 int32_t minute,
425 int32_t second,
426 UErrorCode *status)
427 {
428 if(U_FAILURE(*status)) return;
429
430 ((Calendar*)cal)->set(year, month, date, hour, minute, second);
431 }
432
433 U_CAPI UBool U_EXPORT2
ucal_equivalentTo(const UCalendar * cal1,const UCalendar * cal2)434 ucal_equivalentTo( const UCalendar* cal1,
435 const UCalendar* cal2)
436 {
437
438 return ((Calendar*)cal1)->isEquivalentTo(*((Calendar*)cal2));
439 }
440
441 U_CAPI void U_EXPORT2
ucal_add(UCalendar * cal,UCalendarDateFields field,int32_t amount,UErrorCode * status)442 ucal_add( UCalendar* cal,
443 UCalendarDateFields field,
444 int32_t amount,
445 UErrorCode* status)
446 {
447
448 if(U_FAILURE(*status)) return;
449
450 ((Calendar*)cal)->add(field, amount, *status);
451 }
452
453 U_CAPI void U_EXPORT2
ucal_roll(UCalendar * cal,UCalendarDateFields field,int32_t amount,UErrorCode * status)454 ucal_roll( UCalendar* cal,
455 UCalendarDateFields field,
456 int32_t amount,
457 UErrorCode* status)
458 {
459
460 if(U_FAILURE(*status)) return;
461
462 ((Calendar*)cal)->roll(field, amount, *status);
463 }
464
465 U_CAPI int32_t U_EXPORT2
ucal_get(const UCalendar * cal,UCalendarDateFields field,UErrorCode * status)466 ucal_get( const UCalendar* cal,
467 UCalendarDateFields field,
468 UErrorCode* status )
469 {
470
471 if(U_FAILURE(*status)) return -1;
472
473 return ((Calendar*)cal)->get(field, *status);
474 }
475
476 U_CAPI void U_EXPORT2
ucal_set(UCalendar * cal,UCalendarDateFields field,int32_t value)477 ucal_set( UCalendar* cal,
478 UCalendarDateFields field,
479 int32_t value)
480 {
481
482 ((Calendar*)cal)->set(field, value);
483 }
484
485 U_CAPI UBool U_EXPORT2
ucal_isSet(const UCalendar * cal,UCalendarDateFields field)486 ucal_isSet( const UCalendar* cal,
487 UCalendarDateFields field)
488 {
489
490 return ((Calendar*)cal)->isSet(field);
491 }
492
493 U_CAPI void U_EXPORT2
ucal_clearField(UCalendar * cal,UCalendarDateFields field)494 ucal_clearField( UCalendar* cal,
495 UCalendarDateFields field)
496 {
497
498 ((Calendar*)cal)->clear(field);
499 }
500
501 U_CAPI void U_EXPORT2
ucal_clear(UCalendar * calendar)502 ucal_clear(UCalendar* calendar)
503 {
504
505 ((Calendar*)calendar)->clear();
506 }
507
508 U_CAPI int32_t U_EXPORT2
ucal_getLimit(const UCalendar * cal,UCalendarDateFields field,UCalendarLimitType type,UErrorCode * status)509 ucal_getLimit( const UCalendar* cal,
510 UCalendarDateFields field,
511 UCalendarLimitType type,
512 UErrorCode *status)
513 {
514
515 if(status==0 || U_FAILURE(*status)) {
516 return -1;
517 }
518
519 switch(type) {
520 case UCAL_MINIMUM:
521 return ((Calendar*)cal)->getMinimum(field);
522
523 case UCAL_MAXIMUM:
524 return ((Calendar*)cal)->getMaximum(field);
525
526 case UCAL_GREATEST_MINIMUM:
527 return ((Calendar*)cal)->getGreatestMinimum(field);
528
529 case UCAL_LEAST_MAXIMUM:
530 return ((Calendar*)cal)->getLeastMaximum(field);
531
532 case UCAL_ACTUAL_MINIMUM:
533 return ((Calendar*)cal)->getActualMinimum(field,
534 *status);
535
536 case UCAL_ACTUAL_MAXIMUM:
537 return ((Calendar*)cal)->getActualMaximum(field,
538 *status);
539
540 default:
541 break;
542 }
543 return -1;
544 }
545
546 U_CAPI const char * U_EXPORT2
ucal_getLocaleByType(const UCalendar * cal,ULocDataLocaleType type,UErrorCode * status)547 ucal_getLocaleByType(const UCalendar *cal, ULocDataLocaleType type, UErrorCode* status)
548 {
549 if (cal == NULL) {
550 if (U_SUCCESS(*status)) {
551 *status = U_ILLEGAL_ARGUMENT_ERROR;
552 }
553 return NULL;
554 }
555 return ((Calendar*)cal)->getLocaleID(type, *status);
556 }
557
558 U_CAPI const char * U_EXPORT2
ucal_getTZDataVersion(UErrorCode * status)559 ucal_getTZDataVersion(UErrorCode* status)
560 {
561 return TimeZone::getTZDataVersion(*status);
562 }
563
564 U_CAPI int32_t U_EXPORT2
ucal_getCanonicalTimeZoneID(const UChar * id,int32_t len,UChar * result,int32_t resultCapacity,UBool * isSystemID,UErrorCode * status)565 ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len,
566 UChar* result, int32_t resultCapacity, UBool *isSystemID, UErrorCode* status) {
567 if(status == 0 || U_FAILURE(*status)) {
568 return 0;
569 }
570 if (isSystemID) {
571 *isSystemID = FALSE;
572 }
573 if (id == 0 || len == 0 || result == 0 || resultCapacity <= 0) {
574 *status = U_ILLEGAL_ARGUMENT_ERROR;
575 return 0;
576 }
577 int32_t reslen = 0;
578 UnicodeString canonical;
579 UBool systemID = FALSE;
580 TimeZone::getCanonicalID(UnicodeString(id, len), canonical, systemID, *status);
581 if (U_SUCCESS(*status)) {
582 if (isSystemID) {
583 *isSystemID = systemID;
584 }
585 reslen = canonical.extract(result, resultCapacity, *status);
586 }
587 return reslen;
588 }
589
590 U_CAPI const char * U_EXPORT2
ucal_getType(const UCalendar * cal,UErrorCode * status)591 ucal_getType(const UCalendar *cal, UErrorCode* status)
592 {
593 if (U_FAILURE(*status)) {
594 return NULL;
595 }
596 return ((Calendar*)cal)->getType();
597 }
598
599 U_CAPI UCalendarWeekdayType U_EXPORT2
ucal_getDayOfWeekType(const UCalendar * cal,UCalendarDaysOfWeek dayOfWeek,UErrorCode * status)600 ucal_getDayOfWeekType(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode* status)
601 {
602 if (U_FAILURE(*status)) {
603 return UCAL_WEEKDAY;
604 }
605 return ((Calendar*)cal)->getDayOfWeekType(dayOfWeek, *status);
606 }
607
608 U_CAPI int32_t U_EXPORT2
ucal_getWeekendTransition(const UCalendar * cal,UCalendarDaysOfWeek dayOfWeek,UErrorCode * status)609 ucal_getWeekendTransition(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode *status)
610 {
611 if (U_FAILURE(*status)) {
612 return 0;
613 }
614 return ((Calendar*)cal)->getWeekendTransition(dayOfWeek, *status);
615 }
616
617 U_CAPI UBool U_EXPORT2
ucal_isWeekend(const UCalendar * cal,UDate date,UErrorCode * status)618 ucal_isWeekend(const UCalendar *cal, UDate date, UErrorCode *status)
619 {
620 if (U_FAILURE(*status)) {
621 return FALSE;
622 }
623 return ((Calendar*)cal)->isWeekend(date, *status);
624 }
625
626 U_CAPI int32_t U_EXPORT2
ucal_getFieldDifference(UCalendar * cal,UDate target,UCalendarDateFields field,UErrorCode * status)627 ucal_getFieldDifference(UCalendar* cal, UDate target,
628 UCalendarDateFields field,
629 UErrorCode* status )
630 {
631 if (U_FAILURE(*status)) {
632 return 0;
633 }
634 return ((Calendar*)cal)->fieldDifference(target, field, *status);
635 }
636
637
638 static const UEnumeration defaultKeywordValues = {
639 NULL,
640 NULL,
641 ulist_close_keyword_values_iterator,
642 ulist_count_keyword_values,
643 uenum_unextDefault,
644 ulist_next_keyword_value,
645 ulist_reset_keyword_values_iterator
646 };
647
648 static const char * const CAL_TYPES[] = {
649 "gregorian",
650 "japanese",
651 "buddhist",
652 "roc",
653 "persian",
654 "islamic-civil",
655 "islamic",
656 "hebrew",
657 "chinese",
658 "indian",
659 "coptic",
660 "ethiopic",
661 "ethiopic-amete-alem",
662 "iso8601",
663 "dangi",
664 "islamic-umalqura",
665 "islamic-tbla",
666 "islamic-rgsa",
667 NULL
668 };
669
670 U_CAPI UEnumeration* U_EXPORT2
ucal_getKeywordValuesForLocale(const char *,const char * locale,UBool commonlyUsed,UErrorCode * status)671 ucal_getKeywordValuesForLocale(const char * /* key */, const char* locale, UBool commonlyUsed, UErrorCode *status) {
672 // Resolve region
673 char prefRegion[ULOC_COUNTRY_CAPACITY];
674 (void)ulocimp_getRegionForSupplementalData(locale, TRUE, prefRegion, sizeof(prefRegion), status);
675
676 // Read preferred calendar values from supplementalData calendarPreference
677 UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", status);
678 ures_getByKey(rb, "calendarPreferenceData", rb, status);
679 UResourceBundle *order = ures_getByKey(rb, prefRegion, NULL, status);
680 if (*status == U_MISSING_RESOURCE_ERROR && rb != NULL) {
681 *status = U_ZERO_ERROR;
682 order = ures_getByKey(rb, "001", NULL, status);
683 }
684
685 // Create a list of calendar type strings
686 UList *values = NULL;
687 if (U_SUCCESS(*status)) {
688 values = ulist_createEmptyList(status);
689 if (U_SUCCESS(*status)) {
690 for (int i = 0; i < ures_getSize(order); i++) {
691 int32_t len;
692 const UChar *type = ures_getStringByIndex(order, i, &len, status);
693 char *caltype = (char*)uprv_malloc(len + 1);
694 if (caltype == NULL) {
695 *status = U_MEMORY_ALLOCATION_ERROR;
696 break;
697 }
698 u_UCharsToChars(type, caltype, len);
699 *(caltype + len) = 0;
700
701 ulist_addItemEndList(values, caltype, TRUE, status);
702 if (U_FAILURE(*status)) {
703 break;
704 }
705 }
706
707 if (U_SUCCESS(*status) && !commonlyUsed) {
708 // If not commonlyUsed, add other available values
709 for (int32_t i = 0; CAL_TYPES[i] != NULL; i++) {
710 if (!ulist_containsString(values, CAL_TYPES[i], (int32_t)uprv_strlen(CAL_TYPES[i]))) {
711 ulist_addItemEndList(values, CAL_TYPES[i], FALSE, status);
712 if (U_FAILURE(*status)) {
713 break;
714 }
715 }
716 }
717 }
718 if (U_FAILURE(*status)) {
719 ulist_deleteList(values);
720 values = NULL;
721 }
722 }
723 }
724
725 ures_close(order);
726 ures_close(rb);
727
728 if (U_FAILURE(*status) || values == NULL) {
729 return NULL;
730 }
731
732 // Create string enumeration
733 UEnumeration *en = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
734 if (en == NULL) {
735 *status = U_MEMORY_ALLOCATION_ERROR;
736 ulist_deleteList(values);
737 return NULL;
738 }
739 ulist_resetList(values);
740 memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
741 en->context = values;
742 return en;
743 }
744
745 U_CAPI UBool U_EXPORT2
ucal_getTimeZoneTransitionDate(const UCalendar * cal,UTimeZoneTransitionType type,UDate * transition,UErrorCode * status)746 ucal_getTimeZoneTransitionDate(const UCalendar* cal, UTimeZoneTransitionType type,
747 UDate* transition, UErrorCode* status)
748 {
749 if (U_FAILURE(*status)) {
750 return FALSE;
751 }
752 UDate base = ((Calendar*)cal)->getTime(*status);
753 const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
754 const BasicTimeZone * btz = dynamic_cast<const BasicTimeZone *>(&tz);
755 if (btz != NULL && U_SUCCESS(*status)) {
756 TimeZoneTransition tzt;
757 UBool inclusive = (type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE || type == UCAL_TZ_TRANSITION_PREVIOUS_INCLUSIVE);
758 UBool result = (type == UCAL_TZ_TRANSITION_NEXT || type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE)?
759 btz->getNextTransition(base, inclusive, tzt):
760 btz->getPreviousTransition(base, inclusive, tzt);
761 if (result) {
762 *transition = tzt.getTime();
763 return TRUE;
764 }
765 }
766 return FALSE;
767 }
768
769 U_CAPI int32_t U_EXPORT2
ucal_getWindowsTimeZoneID(const UChar * id,int32_t len,UChar * winid,int32_t winidCapacity,UErrorCode * status)770 ucal_getWindowsTimeZoneID(const UChar* id, int32_t len, UChar* winid, int32_t winidCapacity, UErrorCode* status) {
771 if (U_FAILURE(*status)) {
772 return 0;
773 }
774
775 int32_t resultLen = 0;
776 UnicodeString resultWinID;
777
778 TimeZone::getWindowsID(UnicodeString(id, len), resultWinID, *status);
779 if (U_SUCCESS(*status) && resultWinID.length() > 0) {
780 resultLen = resultWinID.length();
781 resultWinID.extract(winid, winidCapacity, *status);
782 }
783
784 return resultLen;
785 }
786
787 U_CAPI int32_t U_EXPORT2
ucal_getTimeZoneIDForWindowsID(const UChar * winid,int32_t len,const char * region,UChar * id,int32_t idCapacity,UErrorCode * status)788 ucal_getTimeZoneIDForWindowsID(const UChar* winid, int32_t len, const char* region, UChar* id, int32_t idCapacity, UErrorCode* status) {
789 if (U_FAILURE(*status)) {
790 return 0;
791 }
792
793 int32_t resultLen = 0;
794 UnicodeString resultID;
795
796 TimeZone::getIDForWindowsID(UnicodeString(winid, len), region, resultID, *status);
797 if (U_SUCCESS(*status) && resultID.length() > 0) {
798 resultLen = resultID.length();
799 resultID.extract(id, idCapacity, *status);
800 }
801
802 return resultLen;
803 }
804
805 #endif /* #if !UCONFIG_NO_FORMATTING */
806