Coverage Report

Created: 2025-06-13 06:34

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