• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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