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