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