/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 */  |