]>
Commit | Line | Data |
---|---|---|
b75a7d8f A |
1 | /* |
2 | ******************************************************************************* | |
b331163b | 3 | * Copyright (C) 1996-2015, International Business Machines |
b75a7d8f A |
4 | * Corporation and others. All Rights Reserved. |
5 | ******************************************************************************* | |
6 | */ | |
7 | ||
51004dcb | 8 | #include "utypeinfo.h" // for 'typeid' to work |
729e4ab9 | 9 | |
b75a7d8f A |
10 | #include "unicode/utypes.h" |
11 | ||
12 | #if !UCONFIG_NO_FORMATTING | |
13 | ||
b331163b A |
14 | #include <stdlib.h> // Apple addition for uacal_getDayPeriod |
15 | ||
b75a7d8f A |
16 | #include "unicode/ucal.h" |
17 | #include "unicode/uloc.h" | |
18 | #include "unicode/calendar.h" | |
19 | #include "unicode/timezone.h" | |
73c04bcf | 20 | #include "unicode/gregocal.h" |
b75a7d8f A |
21 | #include "unicode/simpletz.h" |
22 | #include "unicode/ustring.h" | |
23 | #include "unicode/strenum.h" | |
51004dcb | 24 | #include "unicode/localpointer.h" |
b75a7d8f | 25 | #include "cmemory.h" |
46f4442e | 26 | #include "cstring.h" |
b75a7d8f | 27 | #include "ustrenum.h" |
729e4ab9 A |
28 | #include "uenumimp.h" |
29 | #include "ulist.h" | |
b75a7d8f A |
30 | |
31 | U_NAMESPACE_USE | |
32 | ||
33 | static TimeZone* | |
34 | _createTimeZone(const UChar* zoneID, int32_t len, UErrorCode* ec) { | |
35 | TimeZone* zone = NULL; | |
36 | if (ec!=NULL && U_SUCCESS(*ec)) { | |
37 | // Note that if zoneID is invalid, we get back GMT. This odd | |
38 | // behavior is by design and goes back to the JDK. The only | |
39 | // failure we will see is a memory allocation failure. | |
40 | int32_t l = (len<0 ? u_strlen(zoneID) : len); | |
374ca955 A |
41 | UnicodeString zoneStrID; |
42 | zoneStrID.setTo((UBool)(len < 0), zoneID, l); /* temporary read-only alias */ | |
43 | zone = TimeZone::createTimeZone(zoneStrID); | |
b75a7d8f A |
44 | if (zone == NULL) { |
45 | *ec = U_MEMORY_ALLOCATION_ERROR; | |
46 | } | |
47 | } | |
48 | return zone; | |
49 | } | |
50 | ||
4388f060 A |
51 | U_CAPI UEnumeration* U_EXPORT2 |
52 | ucal_openTimeZoneIDEnumeration(USystemTimeZoneType zoneType, const char* region, | |
53 | const int32_t* rawOffset, UErrorCode* ec) { | |
54 | return uenum_openFromStringEnumeration(TimeZone::createTimeZoneIDEnumeration( | |
55 | zoneType, region, rawOffset, *ec), ec); | |
56 | } | |
57 | ||
b75a7d8f A |
58 | U_CAPI UEnumeration* U_EXPORT2 |
59 | ucal_openTimeZones(UErrorCode* ec) { | |
729e4ab9 | 60 | return uenum_openFromStringEnumeration(TimeZone::createEnumeration(), ec); |
b75a7d8f A |
61 | } |
62 | ||
63 | U_CAPI UEnumeration* U_EXPORT2 | |
64 | ucal_openCountryTimeZones(const char* country, UErrorCode* ec) { | |
729e4ab9 | 65 | return uenum_openFromStringEnumeration(TimeZone::createEnumeration(country), ec); |
b75a7d8f A |
66 | } |
67 | ||
68 | U_CAPI int32_t U_EXPORT2 | |
69 | ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec) { | |
70 | int32_t len = 0; | |
71 | if (ec!=NULL && U_SUCCESS(*ec)) { | |
72 | TimeZone* zone = TimeZone::createDefault(); | |
73 | if (zone == NULL) { | |
74 | *ec = U_MEMORY_ALLOCATION_ERROR; | |
75 | } else { | |
76 | UnicodeString id; | |
77 | zone->getID(id); | |
78 | delete zone; | |
79 | len = id.extract(result, resultCapacity, *ec); | |
80 | } | |
81 | } | |
82 | return len; | |
83 | } | |
84 | ||
85 | U_CAPI void U_EXPORT2 | |
86 | ucal_setDefaultTimeZone(const UChar* zoneID, UErrorCode* ec) { | |
87 | TimeZone* zone = _createTimeZone(zoneID, -1, ec); | |
88 | if (zone != NULL) { | |
89 | TimeZone::adoptDefault(zone); | |
90 | } | |
91 | } | |
92 | ||
93 | U_CAPI int32_t U_EXPORT2 | |
94 | ucal_getDSTSavings(const UChar* zoneID, UErrorCode* ec) { | |
95 | int32_t result = 0; | |
96 | TimeZone* zone = _createTimeZone(zoneID, -1, ec); | |
374ca955 | 97 | if (U_SUCCESS(*ec)) { |
729e4ab9 A |
98 | SimpleTimeZone* stz = dynamic_cast<SimpleTimeZone*>(zone); |
99 | if (stz != NULL) { | |
100 | result = stz->getDSTSavings(); | |
374ca955 A |
101 | } else { |
102 | // Since there is no getDSTSavings on TimeZone, we use a | |
103 | // heuristic: Starting with the current time, march | |
104 | // forwards for one year, looking for DST savings. | |
105 | // Stepping by weeks is sufficient. | |
106 | UDate d = Calendar::getNow(); | |
107 | for (int32_t i=0; i<53; ++i, d+=U_MILLIS_PER_DAY*7.0) { | |
108 | int32_t raw, dst; | |
109 | zone->getOffset(d, FALSE, raw, dst, *ec); | |
110 | if (U_FAILURE(*ec)) { | |
111 | break; | |
112 | } else if (dst != 0) { | |
113 | result = dst; | |
114 | break; | |
115 | } | |
116 | } | |
117 | } | |
b75a7d8f A |
118 | } |
119 | delete zone; | |
120 | return result; | |
121 | } | |
122 | ||
b75a7d8f A |
123 | U_CAPI UDate U_EXPORT2 |
124 | ucal_getNow() | |
125 | { | |
126 | ||
127 | return Calendar::getNow(); | |
128 | } | |
129 | ||
46f4442e A |
130 | #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY) |
131 | ||
b75a7d8f | 132 | U_CAPI UCalendar* U_EXPORT2 |
46f4442e A |
133 | ucal_open( const UChar* zoneID, |
134 | int32_t len, | |
135 | const char* locale, | |
136 | UCalendarType caltype, | |
137 | UErrorCode* status) | |
b75a7d8f A |
138 | { |
139 | ||
140 | if(U_FAILURE(*status)) return 0; | |
141 | ||
142 | TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault() | |
143 | : _createTimeZone(zoneID, len, status); | |
144 | ||
145 | if (U_FAILURE(*status)) { | |
146 | return NULL; | |
147 | } | |
46f4442e A |
148 | |
149 | if ( caltype == UCAL_GREGORIAN ) { | |
150 | char localeBuf[ULOC_LOCALE_IDENTIFIER_CAPACITY]; | |
729e4ab9 A |
151 | if ( locale == NULL ) { |
152 | locale = uloc_getDefault(); | |
153 | } | |
46f4442e A |
154 | uprv_strncpy(localeBuf, locale, ULOC_LOCALE_IDENTIFIER_CAPACITY); |
155 | uloc_setKeywordValue("calendar", "gregorian", localeBuf, ULOC_LOCALE_IDENTIFIER_CAPACITY, status); | |
156 | if (U_FAILURE(*status)) { | |
157 | return NULL; | |
158 | } | |
159 | return (UCalendar*)Calendar::createInstance(zone, Locale(localeBuf), *status); | |
160 | } | |
b75a7d8f A |
161 | return (UCalendar*)Calendar::createInstance(zone, Locale(locale), *status); |
162 | } | |
163 | ||
164 | U_CAPI void U_EXPORT2 | |
165 | ucal_close(UCalendar *cal) | |
166 | { | |
167 | ||
168 | delete (Calendar*) cal; | |
169 | } | |
170 | ||
46f4442e A |
171 | U_CAPI UCalendar* U_EXPORT2 |
172 | ucal_clone(const UCalendar* cal, | |
173 | UErrorCode* status) | |
174 | { | |
175 | if(U_FAILURE(*status)) return 0; | |
176 | ||
177 | Calendar* res = ((Calendar*)cal)->clone(); | |
178 | ||
179 | if(res == 0) { | |
180 | *status = U_MEMORY_ALLOCATION_ERROR; | |
181 | return 0; | |
182 | } | |
183 | ||
184 | return (UCalendar*) res; | |
185 | } | |
186 | ||
b75a7d8f A |
187 | U_CAPI void U_EXPORT2 |
188 | ucal_setTimeZone( UCalendar* cal, | |
189 | const UChar* zoneID, | |
190 | int32_t len, | |
191 | UErrorCode *status) | |
192 | { | |
193 | ||
194 | if(U_FAILURE(*status)) | |
195 | return; | |
196 | ||
197 | TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault() | |
198 | : _createTimeZone(zoneID, len, status); | |
199 | ||
200 | if (zone != NULL) { | |
201 | ((Calendar*)cal)->adoptTimeZone(zone); | |
202 | } | |
203 | } | |
204 | ||
51004dcb A |
205 | U_CAPI int32_t U_EXPORT2 |
206 | ucal_getTimeZoneID(const UCalendar *cal, | |
207 | UChar *result, | |
208 | int32_t resultLength, | |
209 | UErrorCode *status) | |
210 | { | |
211 | if (U_FAILURE(*status)) { | |
212 | return 0; | |
213 | } | |
214 | const TimeZone& tz = ((Calendar*)cal)->getTimeZone(); | |
215 | UnicodeString id; | |
216 | tz.getID(id); | |
217 | return id.extract(result, resultLength, *status); | |
218 | } | |
219 | ||
b75a7d8f A |
220 | U_CAPI int32_t U_EXPORT2 |
221 | ucal_getTimeZoneDisplayName(const UCalendar* cal, | |
222 | UCalendarDisplayNameType type, | |
223 | const char *locale, | |
224 | UChar* result, | |
225 | int32_t resultLength, | |
226 | UErrorCode* status) | |
227 | { | |
228 | ||
46f4442e | 229 | if(U_FAILURE(*status)) return -1; |
b75a7d8f | 230 | |
46f4442e A |
231 | const TimeZone& tz = ((Calendar*)cal)->getTimeZone(); |
232 | UnicodeString id; | |
233 | if(!(result==NULL && resultLength==0)) { | |
234 | // NULL destination for pure preflighting: empty dummy string | |
235 | // otherwise, alias the destination buffer | |
236 | id.setTo(result, 0, resultLength); | |
237 | } | |
b75a7d8f | 238 | |
46f4442e | 239 | switch(type) { |
b75a7d8f | 240 | case UCAL_STANDARD: |
46f4442e A |
241 | tz.getDisplayName(FALSE, TimeZone::LONG, Locale(locale), id); |
242 | break; | |
b75a7d8f A |
243 | |
244 | case UCAL_SHORT_STANDARD: | |
46f4442e A |
245 | tz.getDisplayName(FALSE, TimeZone::SHORT, Locale(locale), id); |
246 | break; | |
b75a7d8f A |
247 | |
248 | case UCAL_DST: | |
46f4442e A |
249 | tz.getDisplayName(TRUE, TimeZone::LONG, Locale(locale), id); |
250 | break; | |
b75a7d8f A |
251 | |
252 | case UCAL_SHORT_DST: | |
46f4442e A |
253 | tz.getDisplayName(TRUE, TimeZone::SHORT, Locale(locale), id); |
254 | break; | |
255 | } | |
b75a7d8f | 256 | |
46f4442e | 257 | return id.extract(result, resultLength, *status); |
b75a7d8f A |
258 | } |
259 | ||
260 | U_CAPI UBool U_EXPORT2 | |
261 | ucal_inDaylightTime( const UCalendar* cal, | |
46f4442e | 262 | UErrorCode* status ) |
b75a7d8f A |
263 | { |
264 | ||
46f4442e A |
265 | if(U_FAILURE(*status)) return (UBool) -1; |
266 | return ((Calendar*)cal)->inDaylightTime(*status); | |
b75a7d8f A |
267 | } |
268 | ||
46f4442e | 269 | U_CAPI void U_EXPORT2 |
73c04bcf | 270 | ucal_setGregorianChange(UCalendar *cal, UDate date, UErrorCode *pErrorCode) { |
46f4442e A |
271 | if(U_FAILURE(*pErrorCode)) { |
272 | return; | |
273 | } | |
274 | Calendar *cpp_cal = (Calendar *)cal; | |
729e4ab9 A |
275 | GregorianCalendar *gregocal = dynamic_cast<GregorianCalendar *>(cpp_cal); |
276 | // Not if(gregocal == NULL) { | |
277 | // because we really want to work only with a GregorianCalendar, not with | |
278 | // its subclasses like BuddhistCalendar. | |
4388f060 A |
279 | if (cpp_cal == NULL) { |
280 | // We normally don't check "this" pointers for NULL, but this here avoids | |
281 | // compiler-generated exception-throwing code in case cal == NULL. | |
282 | *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR; | |
283 | return; | |
284 | } | |
729e4ab9 | 285 | if(typeid(*cpp_cal) != typeid(GregorianCalendar)) { |
46f4442e A |
286 | *pErrorCode = U_UNSUPPORTED_ERROR; |
287 | return; | |
288 | } | |
729e4ab9 | 289 | gregocal->setGregorianChange(date, *pErrorCode); |
73c04bcf A |
290 | } |
291 | ||
46f4442e | 292 | U_CAPI UDate U_EXPORT2 |
73c04bcf | 293 | ucal_getGregorianChange(const UCalendar *cal, UErrorCode *pErrorCode) { |
46f4442e A |
294 | if(U_FAILURE(*pErrorCode)) { |
295 | return (UDate)0; | |
296 | } | |
729e4ab9 A |
297 | const Calendar *cpp_cal = (const Calendar *)cal; |
298 | const GregorianCalendar *gregocal = dynamic_cast<const GregorianCalendar *>(cpp_cal); | |
299 | // Not if(gregocal == NULL) { | |
300 | // see comments in ucal_setGregorianChange(). | |
4388f060 A |
301 | if (cpp_cal == NULL) { |
302 | // We normally don't check "this" pointers for NULL, but this here avoids | |
303 | // compiler-generated exception-throwing code in case cal == NULL. | |
304 | *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR; | |
305 | return (UDate)0; | |
306 | } | |
729e4ab9 | 307 | if(typeid(*cpp_cal) != typeid(GregorianCalendar)) { |
46f4442e A |
308 | *pErrorCode = U_UNSUPPORTED_ERROR; |
309 | return (UDate)0; | |
310 | } | |
729e4ab9 | 311 | return gregocal->getGregorianChange(); |
73c04bcf A |
312 | } |
313 | ||
b75a7d8f A |
314 | U_CAPI int32_t U_EXPORT2 |
315 | ucal_getAttribute( const UCalendar* cal, | |
46f4442e | 316 | UCalendarAttribute attr) |
b75a7d8f A |
317 | { |
318 | ||
46f4442e | 319 | switch(attr) { |
b75a7d8f | 320 | case UCAL_LENIENT: |
46f4442e A |
321 | return ((Calendar*)cal)->isLenient(); |
322 | ||
b75a7d8f | 323 | case UCAL_FIRST_DAY_OF_WEEK: |
46f4442e A |
324 | return ((Calendar*)cal)->getFirstDayOfWeek(); |
325 | ||
b75a7d8f | 326 | case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK: |
46f4442e | 327 | return ((Calendar*)cal)->getMinimalDaysInFirstWeek(); |
b75a7d8f | 328 | |
4388f060 A |
329 | case UCAL_REPEATED_WALL_TIME: |
330 | return ((Calendar*)cal)->getRepeatedWallTimeOption(); | |
331 | ||
332 | case UCAL_SKIPPED_WALL_TIME: | |
333 | return ((Calendar*)cal)->getSkippedWallTimeOption(); | |
334 | ||
b75a7d8f | 335 | default: |
46f4442e A |
336 | break; |
337 | } | |
338 | return -1; | |
b75a7d8f A |
339 | } |
340 | ||
341 | U_CAPI void U_EXPORT2 | |
342 | ucal_setAttribute( UCalendar* cal, | |
46f4442e A |
343 | UCalendarAttribute attr, |
344 | int32_t newValue) | |
b75a7d8f A |
345 | { |
346 | ||
46f4442e | 347 | switch(attr) { |
b75a7d8f | 348 | case UCAL_LENIENT: |
46f4442e A |
349 | ((Calendar*)cal)->setLenient((UBool)newValue); |
350 | break; | |
351 | ||
b75a7d8f | 352 | case UCAL_FIRST_DAY_OF_WEEK: |
46f4442e A |
353 | ((Calendar*)cal)->setFirstDayOfWeek((UCalendarDaysOfWeek)newValue); |
354 | break; | |
355 | ||
b75a7d8f | 356 | case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK: |
46f4442e A |
357 | ((Calendar*)cal)->setMinimalDaysInFirstWeek((uint8_t)newValue); |
358 | break; | |
4388f060 A |
359 | |
360 | case UCAL_REPEATED_WALL_TIME: | |
361 | ((Calendar*)cal)->setRepeatedWallTimeOption((UCalendarWallTimeOption)newValue); | |
362 | break; | |
363 | ||
364 | case UCAL_SKIPPED_WALL_TIME: | |
365 | ((Calendar*)cal)->setSkippedWallTimeOption((UCalendarWallTimeOption)newValue); | |
366 | break; | |
46f4442e | 367 | } |
b75a7d8f A |
368 | } |
369 | ||
370 | U_CAPI const char* U_EXPORT2 | |
371 | ucal_getAvailable(int32_t index) | |
372 | { | |
373 | ||
46f4442e | 374 | return uloc_getAvailable(index); |
b75a7d8f A |
375 | } |
376 | ||
377 | U_CAPI int32_t U_EXPORT2 | |
378 | ucal_countAvailable() | |
379 | { | |
380 | ||
46f4442e | 381 | return uloc_countAvailable(); |
b75a7d8f A |
382 | } |
383 | ||
384 | U_CAPI UDate U_EXPORT2 | |
385 | ucal_getMillis( const UCalendar* cal, | |
46f4442e | 386 | UErrorCode* status) |
b75a7d8f A |
387 | { |
388 | ||
46f4442e | 389 | if(U_FAILURE(*status)) return (UDate) 0; |
b75a7d8f | 390 | |
46f4442e | 391 | return ((Calendar*)cal)->getTime(*status); |
b75a7d8f A |
392 | } |
393 | ||
394 | U_CAPI void U_EXPORT2 | |
395 | ucal_setMillis( UCalendar* cal, | |
46f4442e A |
396 | UDate dateTime, |
397 | UErrorCode* status ) | |
b75a7d8f | 398 | { |
46f4442e | 399 | if(U_FAILURE(*status)) return; |
b75a7d8f | 400 | |
46f4442e | 401 | ((Calendar*)cal)->setTime(dateTime, *status); |
b75a7d8f A |
402 | } |
403 | ||
404 | // TBD: why does this take an UErrorCode? | |
405 | U_CAPI void U_EXPORT2 | |
406 | ucal_setDate( UCalendar* cal, | |
46f4442e A |
407 | int32_t year, |
408 | int32_t month, | |
409 | int32_t date, | |
410 | UErrorCode *status) | |
b75a7d8f A |
411 | { |
412 | ||
46f4442e | 413 | if(U_FAILURE(*status)) return; |
b75a7d8f | 414 | |
46f4442e | 415 | ((Calendar*)cal)->set(year, month, date); |
b75a7d8f A |
416 | } |
417 | ||
418 | // TBD: why does this take an UErrorCode? | |
419 | U_CAPI void U_EXPORT2 | |
420 | ucal_setDateTime( UCalendar* cal, | |
46f4442e A |
421 | int32_t year, |
422 | int32_t month, | |
423 | int32_t date, | |
424 | int32_t hour, | |
425 | int32_t minute, | |
426 | int32_t second, | |
427 | UErrorCode *status) | |
b75a7d8f | 428 | { |
46f4442e | 429 | if(U_FAILURE(*status)) return; |
b75a7d8f | 430 | |
46f4442e | 431 | ((Calendar*)cal)->set(year, month, date, hour, minute, second); |
b75a7d8f A |
432 | } |
433 | ||
434 | U_CAPI UBool U_EXPORT2 | |
435 | ucal_equivalentTo( const UCalendar* cal1, | |
46f4442e | 436 | const UCalendar* cal2) |
b75a7d8f A |
437 | { |
438 | ||
46f4442e | 439 | return ((Calendar*)cal1)->isEquivalentTo(*((Calendar*)cal2)); |
b75a7d8f A |
440 | } |
441 | ||
442 | U_CAPI void U_EXPORT2 | |
443 | ucal_add( UCalendar* cal, | |
46f4442e A |
444 | UCalendarDateFields field, |
445 | int32_t amount, | |
446 | UErrorCode* status) | |
b75a7d8f A |
447 | { |
448 | ||
46f4442e | 449 | if(U_FAILURE(*status)) return; |
b75a7d8f | 450 | |
46f4442e | 451 | ((Calendar*)cal)->add(field, amount, *status); |
b75a7d8f A |
452 | } |
453 | ||
454 | U_CAPI void U_EXPORT2 | |
455 | ucal_roll( UCalendar* cal, | |
46f4442e A |
456 | UCalendarDateFields field, |
457 | int32_t amount, | |
458 | UErrorCode* status) | |
b75a7d8f A |
459 | { |
460 | ||
46f4442e | 461 | if(U_FAILURE(*status)) return; |
b75a7d8f | 462 | |
46f4442e | 463 | ((Calendar*)cal)->roll(field, amount, *status); |
b75a7d8f A |
464 | } |
465 | ||
466 | U_CAPI int32_t U_EXPORT2 | |
467 | ucal_get( const UCalendar* cal, | |
46f4442e A |
468 | UCalendarDateFields field, |
469 | UErrorCode* status ) | |
b75a7d8f A |
470 | { |
471 | ||
46f4442e | 472 | if(U_FAILURE(*status)) return -1; |
b75a7d8f | 473 | |
46f4442e | 474 | return ((Calendar*)cal)->get(field, *status); |
b75a7d8f A |
475 | } |
476 | ||
477 | U_CAPI void U_EXPORT2 | |
478 | ucal_set( UCalendar* cal, | |
46f4442e A |
479 | UCalendarDateFields field, |
480 | int32_t value) | |
b75a7d8f A |
481 | { |
482 | ||
46f4442e | 483 | ((Calendar*)cal)->set(field, value); |
b75a7d8f A |
484 | } |
485 | ||
486 | U_CAPI UBool U_EXPORT2 | |
487 | ucal_isSet( const UCalendar* cal, | |
46f4442e | 488 | UCalendarDateFields field) |
b75a7d8f A |
489 | { |
490 | ||
46f4442e | 491 | return ((Calendar*)cal)->isSet(field); |
b75a7d8f A |
492 | } |
493 | ||
494 | U_CAPI void U_EXPORT2 | |
495 | ucal_clearField( UCalendar* cal, | |
46f4442e | 496 | UCalendarDateFields field) |
b75a7d8f A |
497 | { |
498 | ||
46f4442e | 499 | ((Calendar*)cal)->clear(field); |
b75a7d8f A |
500 | } |
501 | ||
502 | U_CAPI void U_EXPORT2 | |
503 | ucal_clear(UCalendar* calendar) | |
504 | { | |
505 | ||
46f4442e | 506 | ((Calendar*)calendar)->clear(); |
b75a7d8f A |
507 | } |
508 | ||
509 | U_CAPI int32_t U_EXPORT2 | |
510 | ucal_getLimit( const UCalendar* cal, | |
46f4442e A |
511 | UCalendarDateFields field, |
512 | UCalendarLimitType type, | |
513 | UErrorCode *status) | |
b75a7d8f A |
514 | { |
515 | ||
46f4442e A |
516 | if(status==0 || U_FAILURE(*status)) { |
517 | return -1; | |
518 | } | |
519 | ||
520 | switch(type) { | |
b75a7d8f | 521 | case UCAL_MINIMUM: |
46f4442e | 522 | return ((Calendar*)cal)->getMinimum(field); |
b75a7d8f A |
523 | |
524 | case UCAL_MAXIMUM: | |
46f4442e | 525 | return ((Calendar*)cal)->getMaximum(field); |
b75a7d8f A |
526 | |
527 | case UCAL_GREATEST_MINIMUM: | |
46f4442e | 528 | return ((Calendar*)cal)->getGreatestMinimum(field); |
b75a7d8f A |
529 | |
530 | case UCAL_LEAST_MAXIMUM: | |
46f4442e | 531 | return ((Calendar*)cal)->getLeastMaximum(field); |
b75a7d8f A |
532 | |
533 | case UCAL_ACTUAL_MINIMUM: | |
46f4442e A |
534 | return ((Calendar*)cal)->getActualMinimum(field, |
535 | *status); | |
b75a7d8f A |
536 | |
537 | case UCAL_ACTUAL_MAXIMUM: | |
46f4442e A |
538 | return ((Calendar*)cal)->getActualMaximum(field, |
539 | *status); | |
b75a7d8f A |
540 | |
541 | default: | |
46f4442e A |
542 | break; |
543 | } | |
544 | return -1; | |
b75a7d8f A |
545 | } |
546 | ||
374ca955 A |
547 | U_CAPI const char * U_EXPORT2 |
548 | ucal_getLocaleByType(const UCalendar *cal, ULocDataLocaleType type, UErrorCode* status) | |
549 | { | |
550 | if (cal == NULL) { | |
551 | if (U_SUCCESS(*status)) { | |
552 | *status = U_ILLEGAL_ARGUMENT_ERROR; | |
553 | } | |
554 | return NULL; | |
555 | } | |
556 | return ((Calendar*)cal)->getLocaleID(type, *status); | |
557 | } | |
558 | ||
46f4442e A |
559 | U_CAPI const char * U_EXPORT2 |
560 | ucal_getTZDataVersion(UErrorCode* status) | |
561 | { | |
562 | return TimeZone::getTZDataVersion(*status); | |
563 | } | |
564 | ||
565 | U_CAPI int32_t U_EXPORT2 | |
566 | ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len, | |
567 | UChar* result, int32_t resultCapacity, UBool *isSystemID, UErrorCode* status) { | |
568 | if(status == 0 || U_FAILURE(*status)) { | |
569 | return 0; | |
570 | } | |
571 | if (isSystemID) { | |
572 | *isSystemID = FALSE; | |
573 | } | |
574 | if (id == 0 || len == 0 || result == 0 || resultCapacity <= 0) { | |
575 | *status = U_ILLEGAL_ARGUMENT_ERROR; | |
576 | return 0; | |
577 | } | |
578 | int32_t reslen = 0; | |
579 | UnicodeString canonical; | |
580 | UBool systemID = FALSE; | |
581 | TimeZone::getCanonicalID(UnicodeString(id, len), canonical, systemID, *status); | |
582 | if (U_SUCCESS(*status)) { | |
583 | if (isSystemID) { | |
584 | *isSystemID = systemID; | |
585 | } | |
586 | reslen = canonical.extract(result, resultCapacity, *status); | |
587 | } | |
588 | return reslen; | |
589 | } | |
590 | ||
591 | U_CAPI const char * U_EXPORT2 | |
592 | ucal_getType(const UCalendar *cal, UErrorCode* status) | |
593 | { | |
594 | if (U_FAILURE(*status)) { | |
595 | return NULL; | |
596 | } | |
597 | return ((Calendar*)cal)->getType(); | |
598 | } | |
599 | ||
729e4ab9 A |
600 | U_CAPI UCalendarWeekdayType U_EXPORT2 |
601 | ucal_getDayOfWeekType(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode* status) | |
602 | { | |
603 | if (U_FAILURE(*status)) { | |
604 | return UCAL_WEEKDAY; | |
605 | } | |
606 | return ((Calendar*)cal)->getDayOfWeekType(dayOfWeek, *status); | |
607 | } | |
608 | ||
609 | U_CAPI int32_t U_EXPORT2 | |
610 | ucal_getWeekendTransition(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode *status) | |
611 | { | |
612 | if (U_FAILURE(*status)) { | |
613 | return 0; | |
614 | } | |
615 | return ((Calendar*)cal)->getWeekendTransition(dayOfWeek, *status); | |
616 | } | |
617 | ||
618 | U_CAPI UBool U_EXPORT2 | |
619 | ucal_isWeekend(const UCalendar *cal, UDate date, UErrorCode *status) | |
46f4442e | 620 | { |
729e4ab9 A |
621 | if (U_FAILURE(*status)) { |
622 | return FALSE; | |
623 | } | |
624 | return ((Calendar*)cal)->isWeekend(date, *status); | |
625 | } | |
626 | ||
627 | U_CAPI int32_t U_EXPORT2 | |
628 | ucal_getFieldDifference(UCalendar* cal, UDate target, | |
629 | UCalendarDateFields field, | |
630 | UErrorCode* status ) | |
631 | { | |
632 | if (U_FAILURE(*status)) { | |
633 | return 0; | |
634 | } | |
635 | return ((Calendar*)cal)->fieldDifference(target, field, *status); | |
636 | } | |
637 | ||
638 | ||
639 | static const UEnumeration defaultKeywordValues = { | |
640 | NULL, | |
641 | NULL, | |
642 | ulist_close_keyword_values_iterator, | |
643 | ulist_count_keyword_values, | |
644 | uenum_unextDefault, | |
645 | ulist_next_keyword_value, | |
646 | ulist_reset_keyword_values_iterator | |
647 | }; | |
648 | ||
649 | static const char * const CAL_TYPES[] = { | |
650 | "gregorian", | |
651 | "japanese", | |
652 | "buddhist", | |
653 | "roc", | |
654 | "persian", | |
655 | "islamic-civil", | |
656 | "islamic", | |
657 | "hebrew", | |
658 | "chinese", | |
659 | "indian", | |
660 | "coptic", | |
661 | "ethiopic", | |
662 | "ethiopic-amete-alem", | |
57a6839d A |
663 | "iso8601", |
664 | "dangi", | |
665 | "islamic-umalqura", | |
666 | "islamic-tbla", | |
667 | "islamic-rgsa", | |
729e4ab9 A |
668 | NULL |
669 | }; | |
670 | ||
671 | U_CAPI UEnumeration* U_EXPORT2 | |
672 | ucal_getKeywordValuesForLocale(const char * /* key */, const char* locale, UBool commonlyUsed, UErrorCode *status) { | |
673 | // Resolve region | |
674 | char prefRegion[ULOC_FULLNAME_CAPACITY] = ""; | |
675 | int32_t prefRegionLength = 0; | |
676 | prefRegionLength = uloc_getCountry(locale, prefRegion, sizeof(prefRegion), status); | |
677 | if (prefRegionLength == 0) { | |
678 | char loc[ULOC_FULLNAME_CAPACITY] = ""; | |
4388f060 | 679 | uloc_addLikelySubtags(locale, loc, sizeof(loc), status); |
729e4ab9 A |
680 | |
681 | prefRegionLength = uloc_getCountry(loc, prefRegion, sizeof(prefRegion), status); | |
682 | } | |
683 | ||
684 | // Read preferred calendar values from supplementalData calendarPreference | |
685 | UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", status); | |
686 | ures_getByKey(rb, "calendarPreferenceData", rb, status); | |
687 | UResourceBundle *order = ures_getByKey(rb, prefRegion, NULL, status); | |
688 | if (*status == U_MISSING_RESOURCE_ERROR && rb != NULL) { | |
689 | *status = U_ZERO_ERROR; | |
690 | order = ures_getByKey(rb, "001", NULL, status); | |
691 | } | |
692 | ||
693 | // Create a list of calendar type strings | |
694 | UList *values = NULL; | |
695 | if (U_SUCCESS(*status)) { | |
696 | values = ulist_createEmptyList(status); | |
697 | if (U_SUCCESS(*status)) { | |
698 | for (int i = 0; i < ures_getSize(order); i++) { | |
699 | int32_t len; | |
700 | const UChar *type = ures_getStringByIndex(order, i, &len, status); | |
701 | char *caltype = (char*)uprv_malloc(len + 1); | |
702 | if (caltype == NULL) { | |
703 | *status = U_MEMORY_ALLOCATION_ERROR; | |
704 | break; | |
705 | } | |
706 | u_UCharsToChars(type, caltype, len); | |
707 | *(caltype + len) = 0; | |
708 | ||
709 | ulist_addItemEndList(values, caltype, TRUE, status); | |
710 | if (U_FAILURE(*status)) { | |
711 | break; | |
712 | } | |
713 | } | |
714 | ||
715 | if (U_SUCCESS(*status) && !commonlyUsed) { | |
716 | // If not commonlyUsed, add other available values | |
717 | for (int32_t i = 0; CAL_TYPES[i] != NULL; i++) { | |
718 | if (!ulist_containsString(values, CAL_TYPES[i], (int32_t)uprv_strlen(CAL_TYPES[i]))) { | |
719 | ulist_addItemEndList(values, CAL_TYPES[i], FALSE, status); | |
720 | if (U_FAILURE(*status)) { | |
721 | break; | |
722 | } | |
723 | } | |
724 | } | |
725 | } | |
726 | if (U_FAILURE(*status)) { | |
727 | ulist_deleteList(values); | |
728 | values = NULL; | |
729 | } | |
730 | } | |
731 | } | |
732 | ||
733 | ures_close(order); | |
734 | ures_close(rb); | |
735 | ||
736 | if (U_FAILURE(*status) || values == NULL) { | |
737 | return NULL; | |
738 | } | |
739 | ||
740 | // Create string enumeration | |
741 | UEnumeration *en = (UEnumeration*)uprv_malloc(sizeof(UEnumeration)); | |
742 | if (en == NULL) { | |
743 | *status = U_MEMORY_ALLOCATION_ERROR; | |
744 | ulist_deleteList(values); | |
745 | return NULL; | |
746 | } | |
747 | ulist_resetList(values); | |
748 | memcpy(en, &defaultKeywordValues, sizeof(UEnumeration)); | |
749 | en->context = values; | |
750 | return en; | |
46f4442e A |
751 | } |
752 | ||
51004dcb A |
753 | U_CAPI UBool U_EXPORT2 |
754 | ucal_getTimeZoneTransitionDate(const UCalendar* cal, UTimeZoneTransitionType type, | |
755 | UDate* transition, UErrorCode* status) | |
756 | { | |
757 | if (U_FAILURE(*status)) { | |
758 | return FALSE; | |
759 | } | |
760 | UDate base = ((Calendar*)cal)->getTime(*status); | |
761 | const TimeZone& tz = ((Calendar*)cal)->getTimeZone(); | |
762 | const BasicTimeZone * btz = dynamic_cast<const BasicTimeZone *>(&tz); | |
763 | if (btz != NULL && U_SUCCESS(*status)) { | |
764 | TimeZoneTransition tzt; | |
765 | UBool inclusive = (type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE || type == UCAL_TZ_TRANSITION_PREVIOUS_INCLUSIVE); | |
766 | UBool result = (type == UCAL_TZ_TRANSITION_NEXT || type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE)? | |
767 | btz->getNextTransition(base, inclusive, tzt): | |
768 | btz->getPreviousTransition(base, inclusive, tzt); | |
769 | if (result) { | |
770 | *transition = tzt.getTime(); | |
771 | return TRUE; | |
772 | } | |
773 | } | |
774 | return FALSE; | |
775 | } | |
776 | ||
57a6839d A |
777 | U_CAPI int32_t U_EXPORT2 |
778 | ucal_getWindowsTimeZoneID(const UChar* id, int32_t len, UChar* winid, int32_t winidCapacity, UErrorCode* status) { | |
779 | if (U_FAILURE(*status)) { | |
780 | return 0; | |
781 | } | |
782 | ||
783 | int32_t resultLen = 0; | |
784 | UnicodeString resultWinID; | |
785 | ||
786 | TimeZone::getWindowsID(UnicodeString(id, len), resultWinID, *status); | |
787 | if (U_SUCCESS(*status) && resultWinID.length() > 0) { | |
788 | resultLen = resultWinID.length(); | |
789 | resultWinID.extract(winid, winidCapacity, *status); | |
790 | } | |
791 | ||
792 | return resultLen; | |
793 | } | |
794 | ||
795 | U_CAPI int32_t U_EXPORT2 | |
796 | ucal_getTimeZoneIDForWindowsID(const UChar* winid, int32_t len, const char* region, UChar* id, int32_t idCapacity, UErrorCode* status) { | |
797 | if (U_FAILURE(*status)) { | |
798 | return 0; | |
799 | } | |
800 | ||
801 | int32_t resultLen = 0; | |
802 | UnicodeString resultID; | |
803 | ||
804 | TimeZone::getIDForWindowsID(UnicodeString(winid, len), region, resultID, *status); | |
805 | if (U_SUCCESS(*status) && resultID.length() > 0) { | |
806 | resultLen = resultID.length(); | |
807 | resultID.extract(id, idCapacity, *status); | |
808 | } | |
809 | ||
810 | return resultLen; | |
811 | } | |
812 | ||
b331163b A |
813 | // Apple-specific function uacal_getDayPeriod and helper functions/data |
814 | typedef struct { | |
815 | const char* name; | |
816 | UADayPeriod value; | |
817 | } DayPeriodNameToValue; | |
818 | ||
819 | static const DayPeriodNameToValue dpNameToValue[] = { | |
820 | { "afternoon1", UADAYPERIOD_AFTERNOON1 }, | |
821 | { "afternoon2", UADAYPERIOD_AFTERNOON2 }, | |
822 | { "evening1", UADAYPERIOD_EVENING1 }, | |
823 | { "evening2", UADAYPERIOD_EVENING2 }, | |
824 | { "midnight", UADAYPERIOD_MIDNIGHT }, | |
825 | { "morning1", UADAYPERIOD_MORNING1 }, | |
826 | { "morning2", UADAYPERIOD_MORNING2 }, | |
827 | { "night1", UADAYPERIOD_NIGHT1 }, | |
828 | { "night2", UADAYPERIOD_NIGHT2 }, | |
829 | { "noon", UADAYPERIOD_NOON }, | |
830 | }; | |
831 | ||
832 | static UADayPeriod dayPeriodFromName(const char* name) { | |
833 | const DayPeriodNameToValue * dpNameToValuePtr = dpNameToValue; | |
834 | const DayPeriodNameToValue * dpNameToValueLim = dpNameToValue + UPRV_LENGTHOF(dpNameToValue); | |
835 | // simple linear search, dpNameToValue is small enough | |
836 | for (; dpNameToValuePtr < dpNameToValueLim; dpNameToValuePtr++) { | |
837 | if (uprv_strcmp(name, dpNameToValuePtr->name) == 0) { | |
838 | return dpNameToValuePtr->value; | |
839 | } | |
840 | } | |
841 | return UADAYPERIOD_UNKNOWN; | |
842 | } | |
843 | ||
844 | typedef struct { | |
845 | int32_t startHour; | |
846 | int32_t startMin; | |
847 | UADayPeriod value; | |
848 | } DayPeriodEntry; | |
849 | ||
850 | int CompareDayPeriodEntries(const void* entry1Ptr, const void* entry2Ptr) { | |
851 | const DayPeriodEntry * dpEntry1Ptr = (const DayPeriodEntry *)entry1Ptr; | |
852 | const DayPeriodEntry * dpEntry2Ptr = (const DayPeriodEntry *)entry2Ptr; | |
853 | if (dpEntry1Ptr->startHour < dpEntry2Ptr->startHour) return -1; | |
854 | if (dpEntry1Ptr->startHour > dpEntry2Ptr->startHour) return 1; | |
855 | // here hours are equal | |
856 | if (dpEntry1Ptr->startMin < dpEntry2Ptr->startMin) return -1; | |
857 | if (dpEntry1Ptr->startMin > dpEntry2Ptr->startMin) return 1; | |
858 | return 0; | |
859 | } | |
860 | ||
861 | enum { kSetNameMaxLen = 8, kBoundaryTimeMaxLen = 6, kDayPeriodEntriesMax = 12 }; | |
862 | ||
863 | U_CAPI UADayPeriod U_EXPORT2 | |
864 | uacal_getDayPeriod( const char* locale, | |
865 | int32_t hour, | |
866 | int32_t minute, | |
867 | UBool formatStyle, | |
868 | UErrorCode* status ) { | |
869 | UADayPeriod dayPeriod = UADAYPERIOD_UNKNOWN; | |
870 | DayPeriodEntry dpEntries[kDayPeriodEntriesMax]; | |
871 | int32_t dpEntriesCount = 0; | |
872 | ||
873 | if (U_FAILURE(*status)) { | |
874 | return dayPeriod; | |
875 | } | |
876 | if (hour < 0 || hour > 23 || minute < 0 || minute > 59) { | |
877 | *status = U_ILLEGAL_ARGUMENT_ERROR; | |
878 | return dayPeriod; | |
879 | } | |
880 | // get dayPeriods bundle | |
881 | LocalUResourceBundlePointer rb(ures_openDirect(NULL, "dayPeriods", status)); | |
882 | if (U_FAILURE(*status)) { | |
883 | return dayPeriod; | |
884 | } | |
885 | // get locales/locales_selection subbundle | |
886 | LocalUResourceBundlePointer rbSub(ures_getByKey(rb.getAlias(), formatStyle? "locales": "locales_selection", NULL, status)); | |
887 | if (U_FAILURE(*status)) { | |
888 | return dayPeriod; | |
889 | } | |
890 | // get bundle for language (maps to setName) | |
891 | char lang[ULOC_LANG_CAPACITY] = {0}; | |
892 | if (locale != NULL) { | |
893 | UErrorCode tempStatus = U_ZERO_ERROR; | |
894 | uloc_getLanguage(locale, lang, ULOC_LANG_CAPACITY, &tempStatus); | |
895 | if (U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) { | |
896 | lang[0] = 0; | |
897 | } | |
898 | } | |
899 | if (lang[0] == 0) { | |
900 | uprv_strcpy(lang, "en"); // should be "root" but the data for root is currently missing | |
901 | } | |
902 | LocalUResourceBundlePointer rbLang(ures_getByKey(rbSub.getAlias(), lang, NULL, status)); | |
903 | if (U_FAILURE(*status)) { | |
904 | // should only happen if lang was not [root] en | |
905 | // fallback should be "root" but the data for root is currently missing, use "en" | |
906 | *status = U_ZERO_ERROR; | |
907 | rbLang.adoptInstead(ures_getByKey(rbSub.getAlias(), "en", rbLang.orphan(), status)); | |
908 | } | |
909 | if (U_FAILURE(*status)) { | |
910 | return dayPeriod; | |
911 | } | |
912 | // get setName from language bundle | |
913 | char setName[kSetNameMaxLen] = {0}; | |
914 | int32_t setNameLen = kSetNameMaxLen; | |
915 | ures_getUTF8String(rbLang.getAlias(), setName, &setNameLen, TRUE, status); | |
916 | if (U_FAILURE(*status)) { | |
917 | return dayPeriod; | |
918 | } | |
919 | // get rules subbundle | |
920 | rbSub.adoptInstead(ures_getByKey(rb.getAlias(), "rules", rbSub.orphan(), status)); | |
921 | if (U_FAILURE(*status)) { | |
922 | return dayPeriod; | |
923 | } | |
924 | // get ruleset from rules subbundle | |
925 | rb.adoptInstead(ures_getByKey(rbSub.getAlias(), setName, rb.orphan(), status)); | |
926 | if (U_FAILURE(*status)) { | |
927 | return dayPeriod; | |
928 | } | |
929 | // OK, we should finally have a ruleset (works to here). | |
930 | // Iterate over it to collect entries | |
931 | LocalUResourceBundlePointer rbBound; | |
932 | while (ures_hasNext(rb.getAlias())) { | |
933 | rbSub.adoptInstead(ures_getNextResource(rb.getAlias(), rbSub.orphan(), status)); | |
934 | if (U_FAILURE(*status)) { | |
935 | return dayPeriod; | |
936 | } | |
937 | // rbSub now has the bundle for a particular dayPeriod such as morning1, afternoon2, noon | |
938 | UADayPeriod dpForBundle = dayPeriodFromName(ures_getKey(rbSub.getAlias())); | |
939 | while (ures_hasNext(rbSub.getAlias())) { | |
940 | rbBound.adoptInstead(ures_getNextResource(rbSub.getAlias(), rbBound.orphan(), status)); | |
941 | if (U_FAILURE(*status)) { | |
942 | return dayPeriod; | |
943 | } | |
944 | // rbBound now has the bundle for a particular time period boundary such as at, from, after. | |
945 | // This is either of type URES_STRING (size=1) or of type URES_ARRAY (size > 1) | |
946 | const char *boundaryType = ures_getKey(rbBound.getAlias()); | |
947 | // skip boundaryType "before", it is redundant if we have at, from, after | |
948 | if (uprv_strcmp(boundaryType, "before") == 0) { | |
949 | continue; | |
950 | } | |
951 | int32_t boundaryMinute = (uprv_strcmp(boundaryType, "after") == 0)? 1: 0; | |
952 | int32_t boundaryTimeIndex, boundaryTimeCount = ures_getSize(rbBound.getAlias()); | |
953 | for (boundaryTimeIndex = 0; boundaryTimeIndex < boundaryTimeCount; boundaryTimeIndex++) { | |
954 | char boundaryTimeStr[kBoundaryTimeMaxLen]; | |
955 | int32_t boundaryTimeStrLen = kBoundaryTimeMaxLen; | |
956 | ures_getUTF8StringByIndex(rbBound.getAlias(), boundaryTimeIndex, boundaryTimeStr, &boundaryTimeStrLen, TRUE, status); | |
957 | if (U_FAILURE(*status)) { | |
958 | return dayPeriod; | |
959 | } | |
960 | if (dpEntriesCount < kDayPeriodEntriesMax) { | |
961 | dpEntries[dpEntriesCount].startHour = atoi(boundaryTimeStr); // can depend on POSIX locale (fortunately no decimal sep here) | |
962 | dpEntries[dpEntriesCount].startMin = boundaryMinute; | |
963 | dpEntries[dpEntriesCount].value = dpForBundle; | |
964 | dpEntriesCount++; | |
965 | } | |
966 | } | |
967 | } | |
968 | } | |
969 | if (dpEntriesCount < kDayPeriodEntriesMax) { | |
970 | dpEntries[dpEntriesCount].startHour = 24; | |
971 | dpEntries[dpEntriesCount].startMin = 0; | |
972 | dpEntries[dpEntriesCount].value = UADAYPERIOD_UNKNOWN; | |
973 | dpEntriesCount++; | |
974 | } | |
975 | // We have collected all of the rule data, now sort by time | |
976 | qsort(dpEntries, dpEntriesCount, sizeof(DayPeriodEntry), CompareDayPeriodEntries); | |
977 | // OK, all of the above is what we would do in an "open" function if we were using an | |
978 | // open/use/close model for this; the object would just have the sorted array above. | |
979 | ||
980 | // Now we use the sorted array to find the dayPeriod matching the supplied time. | |
981 | // Only a few entries, linear search OK | |
982 | DayPeriodEntry entryToMatch = { hour, minute, UADAYPERIOD_UNKNOWN }; | |
983 | int32_t dpIndex = 0; | |
984 | while (dpIndex < dpEntriesCount - 1 && CompareDayPeriodEntries(&entryToMatch, &dpEntries[dpIndex + 1]) >= 0) { | |
985 | dpIndex++; | |
986 | } | |
987 | if (CompareDayPeriodEntries(&entryToMatch, &dpEntries[dpIndex]) >= 0) { | |
988 | dayPeriod = dpEntries[dpIndex].value; | |
989 | } | |
990 | ||
991 | return dayPeriod; | |
992 | } | |
993 | ||
994 | ||
57a6839d | 995 | |
b75a7d8f | 996 | #endif /* #if !UCONFIG_NO_FORMATTING */ |