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