]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/ucal.cpp
ICU-551.51.4.tar.gz
[apple/icu.git] / icuSources / i18n / ucal.cpp
CommitLineData
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
31U_NAMESPACE_USE
32
33static 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
51U_CAPI UEnumeration* U_EXPORT2
52ucal_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
58U_CAPI UEnumeration* U_EXPORT2
59ucal_openTimeZones(UErrorCode* ec) {
729e4ab9 60 return uenum_openFromStringEnumeration(TimeZone::createEnumeration(), ec);
b75a7d8f
A
61}
62
63U_CAPI UEnumeration* U_EXPORT2
64ucal_openCountryTimeZones(const char* country, UErrorCode* ec) {
729e4ab9 65 return uenum_openFromStringEnumeration(TimeZone::createEnumeration(country), ec);
b75a7d8f
A
66}
67
68U_CAPI int32_t U_EXPORT2
69ucal_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
85U_CAPI void U_EXPORT2
86ucal_setDefaultTimeZone(const UChar* zoneID, UErrorCode* ec) {
87 TimeZone* zone = _createTimeZone(zoneID, -1, ec);
88 if (zone != NULL) {
89 TimeZone::adoptDefault(zone);
90 }
91}
92
93U_CAPI int32_t U_EXPORT2
94ucal_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
123U_CAPI UDate U_EXPORT2
124ucal_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 132U_CAPI UCalendar* U_EXPORT2
46f4442e
A
133ucal_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
164U_CAPI void U_EXPORT2
165ucal_close(UCalendar *cal)
166{
167
168 delete (Calendar*) cal;
169}
170
46f4442e
A
171U_CAPI UCalendar* U_EXPORT2
172ucal_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
187U_CAPI void U_EXPORT2
188ucal_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
205U_CAPI int32_t U_EXPORT2
206ucal_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
220U_CAPI int32_t U_EXPORT2
221ucal_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
260U_CAPI UBool U_EXPORT2
261ucal_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 269U_CAPI void U_EXPORT2
73c04bcf 270ucal_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 292U_CAPI UDate U_EXPORT2
73c04bcf 293ucal_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
314U_CAPI int32_t U_EXPORT2
315ucal_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
341U_CAPI void U_EXPORT2
342ucal_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
370U_CAPI const char* U_EXPORT2
371ucal_getAvailable(int32_t index)
372{
373
46f4442e 374 return uloc_getAvailable(index);
b75a7d8f
A
375}
376
377U_CAPI int32_t U_EXPORT2
378ucal_countAvailable()
379{
380
46f4442e 381 return uloc_countAvailable();
b75a7d8f
A
382}
383
384U_CAPI UDate U_EXPORT2
385ucal_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
394U_CAPI void U_EXPORT2
395ucal_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?
405U_CAPI void U_EXPORT2
406ucal_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?
419U_CAPI void U_EXPORT2
420ucal_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
434U_CAPI UBool U_EXPORT2
435ucal_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
442U_CAPI void U_EXPORT2
443ucal_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
454U_CAPI void U_EXPORT2
455ucal_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
466U_CAPI int32_t U_EXPORT2
467ucal_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
477U_CAPI void U_EXPORT2
478ucal_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
486U_CAPI UBool U_EXPORT2
487ucal_isSet( const UCalendar* cal,
46f4442e 488 UCalendarDateFields field)
b75a7d8f
A
489{
490
46f4442e 491 return ((Calendar*)cal)->isSet(field);
b75a7d8f
A
492}
493
494U_CAPI void U_EXPORT2
495ucal_clearField( UCalendar* cal,
46f4442e 496 UCalendarDateFields field)
b75a7d8f
A
497{
498
46f4442e 499 ((Calendar*)cal)->clear(field);
b75a7d8f
A
500}
501
502U_CAPI void U_EXPORT2
503ucal_clear(UCalendar* calendar)
504{
505
46f4442e 506 ((Calendar*)calendar)->clear();
b75a7d8f
A
507}
508
509U_CAPI int32_t U_EXPORT2
510ucal_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
547U_CAPI const char * U_EXPORT2
548ucal_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
559U_CAPI const char * U_EXPORT2
560ucal_getTZDataVersion(UErrorCode* status)
561{
562 return TimeZone::getTZDataVersion(*status);
563}
564
565U_CAPI int32_t U_EXPORT2
566ucal_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
591U_CAPI const char * U_EXPORT2
592ucal_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
600U_CAPI UCalendarWeekdayType U_EXPORT2
601ucal_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
609U_CAPI int32_t U_EXPORT2
610ucal_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
618U_CAPI UBool U_EXPORT2
619ucal_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
627U_CAPI int32_t U_EXPORT2
628ucal_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
639static 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
649static 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
671U_CAPI UEnumeration* U_EXPORT2
672ucal_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
753U_CAPI UBool U_EXPORT2
754ucal_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
777U_CAPI int32_t U_EXPORT2
778ucal_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
795U_CAPI int32_t U_EXPORT2
796ucal_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
814typedef struct {
815 const char* name;
816 UADayPeriod value;
817} DayPeriodNameToValue;
818
819static 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
832static 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
844typedef struct {
845 int32_t startHour;
846 int32_t startMin;
847 UADayPeriod value;
848} DayPeriodEntry;
849
850int 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
861enum { kSetNameMaxLen = 8, kBoundaryTimeMaxLen = 6, kDayPeriodEntriesMax = 12 };
862
863U_CAPI UADayPeriod U_EXPORT2
864uacal_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 */