Coverage Report

Created: 2025-06-24 06:43

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