2 *******************************************************************************
3 * Copyright (C) 1996-2011, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 *******************************************************************************
8 #include <typeinfo> // for 'typeid' to work
10 #include "unicode/utypes.h"
12 #if !UCONFIG_NO_FORMATTING
14 #include "unicode/ucal.h"
15 #include "unicode/uloc.h"
16 #include "unicode/calendar.h"
17 #include "unicode/timezone.h"
18 #include "unicode/gregocal.h"
19 #include "unicode/simpletz.h"
20 #include "unicode/ustring.h"
21 #include "unicode/strenum.h"
31 _createTimeZone(const UChar
* zoneID
, int32_t len
, UErrorCode
* ec
) {
32 TimeZone
* zone
= NULL
;
33 if (ec
!=NULL
&& U_SUCCESS(*ec
)) {
34 // Note that if zoneID is invalid, we get back GMT. This odd
35 // behavior is by design and goes back to the JDK. The only
36 // failure we will see is a memory allocation failure.
37 int32_t l
= (len
<0 ? u_strlen(zoneID
) : len
);
38 UnicodeString zoneStrID
;
39 zoneStrID
.setTo((UBool
)(len
< 0), zoneID
, l
); /* temporary read-only alias */
40 zone
= TimeZone::createTimeZone(zoneStrID
);
42 *ec
= U_MEMORY_ALLOCATION_ERROR
;
48 U_CAPI UEnumeration
* U_EXPORT2
49 ucal_openTimeZones(UErrorCode
* ec
) {
50 return uenum_openFromStringEnumeration(TimeZone::createEnumeration(), ec
);
53 U_CAPI UEnumeration
* U_EXPORT2
54 ucal_openCountryTimeZones(const char* country
, UErrorCode
* ec
) {
55 return uenum_openFromStringEnumeration(TimeZone::createEnumeration(country
), ec
);
58 U_CAPI
int32_t U_EXPORT2
59 ucal_getDefaultTimeZone(UChar
* result
, int32_t resultCapacity
, UErrorCode
* ec
) {
61 if (ec
!=NULL
&& U_SUCCESS(*ec
)) {
62 TimeZone
* zone
= TimeZone::createDefault();
64 *ec
= U_MEMORY_ALLOCATION_ERROR
;
69 len
= id
.extract(result
, resultCapacity
, *ec
);
76 ucal_setDefaultTimeZone(const UChar
* zoneID
, UErrorCode
* ec
) {
77 TimeZone
* zone
= _createTimeZone(zoneID
, -1, ec
);
79 TimeZone::adoptDefault(zone
);
83 U_CAPI
int32_t U_EXPORT2
84 ucal_getDSTSavings(const UChar
* zoneID
, UErrorCode
* ec
) {
86 TimeZone
* zone
= _createTimeZone(zoneID
, -1, ec
);
88 SimpleTimeZone
* stz
= dynamic_cast<SimpleTimeZone
*>(zone
);
90 result
= stz
->getDSTSavings();
92 // Since there is no getDSTSavings on TimeZone, we use a
93 // heuristic: Starting with the current time, march
94 // forwards for one year, looking for DST savings.
95 // Stepping by weeks is sufficient.
96 UDate d
= Calendar::getNow();
97 for (int32_t i
=0; i
<53; ++i
, d
+=U_MILLIS_PER_DAY
*7.0) {
99 zone
->getOffset(d
, FALSE
, raw
, dst
, *ec
);
100 if (U_FAILURE(*ec
)) {
102 } else if (dst
!= 0) {
113 U_CAPI UDate U_EXPORT2
117 return Calendar::getNow();
120 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
122 U_CAPI UCalendar
* U_EXPORT2
123 ucal_open( const UChar
* zoneID
,
126 UCalendarType caltype
,
130 if(U_FAILURE(*status
)) return 0;
132 TimeZone
* zone
= (zoneID
==NULL
) ? TimeZone::createDefault()
133 : _createTimeZone(zoneID
, len
, status
);
135 if (U_FAILURE(*status
)) {
139 if ( caltype
== UCAL_GREGORIAN
) {
140 char localeBuf
[ULOC_LOCALE_IDENTIFIER_CAPACITY
];
141 if ( locale
== NULL
) {
142 locale
= uloc_getDefault();
144 uprv_strncpy(localeBuf
, locale
, ULOC_LOCALE_IDENTIFIER_CAPACITY
);
145 uloc_setKeywordValue("calendar", "gregorian", localeBuf
, ULOC_LOCALE_IDENTIFIER_CAPACITY
, status
);
146 if (U_FAILURE(*status
)) {
149 return (UCalendar
*)Calendar::createInstance(zone
, Locale(localeBuf
), *status
);
151 return (UCalendar
*)Calendar::createInstance(zone
, Locale(locale
), *status
);
154 U_CAPI
void U_EXPORT2
155 ucal_close(UCalendar
*cal
)
158 delete (Calendar
*) cal
;
161 U_CAPI UCalendar
* U_EXPORT2
162 ucal_clone(const UCalendar
* cal
,
165 if(U_FAILURE(*status
)) return 0;
167 Calendar
* res
= ((Calendar
*)cal
)->clone();
170 *status
= U_MEMORY_ALLOCATION_ERROR
;
174 return (UCalendar
*) res
;
177 U_CAPI
void U_EXPORT2
178 ucal_setTimeZone( UCalendar
* cal
,
184 if(U_FAILURE(*status
))
187 TimeZone
* zone
= (zoneID
==NULL
) ? TimeZone::createDefault()
188 : _createTimeZone(zoneID
, len
, status
);
191 ((Calendar
*)cal
)->adoptTimeZone(zone
);
195 U_CAPI
int32_t U_EXPORT2
196 ucal_getTimeZoneDisplayName(const UCalendar
* cal
,
197 UCalendarDisplayNameType type
,
200 int32_t resultLength
,
204 if(U_FAILURE(*status
)) return -1;
206 const TimeZone
& tz
= ((Calendar
*)cal
)->getTimeZone();
208 if(!(result
==NULL
&& resultLength
==0)) {
209 // NULL destination for pure preflighting: empty dummy string
210 // otherwise, alias the destination buffer
211 id
.setTo(result
, 0, resultLength
);
216 tz
.getDisplayName(FALSE
, TimeZone::LONG
, Locale(locale
), id
);
219 case UCAL_SHORT_STANDARD
:
220 tz
.getDisplayName(FALSE
, TimeZone::SHORT
, Locale(locale
), id
);
224 tz
.getDisplayName(TRUE
, TimeZone::LONG
, Locale(locale
), id
);
228 tz
.getDisplayName(TRUE
, TimeZone::SHORT
, Locale(locale
), id
);
232 return id
.extract(result
, resultLength
, *status
);
235 U_CAPI UBool U_EXPORT2
236 ucal_inDaylightTime( const UCalendar
* cal
,
240 if(U_FAILURE(*status
)) return (UBool
) -1;
241 return ((Calendar
*)cal
)->inDaylightTime(*status
);
244 U_CAPI
void U_EXPORT2
245 ucal_setGregorianChange(UCalendar
*cal
, UDate date
, UErrorCode
*pErrorCode
) {
246 if(U_FAILURE(*pErrorCode
)) {
249 Calendar
*cpp_cal
= (Calendar
*)cal
;
250 GregorianCalendar
*gregocal
= dynamic_cast<GregorianCalendar
*>(cpp_cal
);
251 // Not if(gregocal == NULL) {
252 // because we really want to work only with a GregorianCalendar, not with
253 // its subclasses like BuddhistCalendar.
254 if(typeid(*cpp_cal
) != typeid(GregorianCalendar
)) {
255 *pErrorCode
= U_UNSUPPORTED_ERROR
;
258 gregocal
->setGregorianChange(date
, *pErrorCode
);
261 U_CAPI UDate U_EXPORT2
262 ucal_getGregorianChange(const UCalendar
*cal
, UErrorCode
*pErrorCode
) {
263 if(U_FAILURE(*pErrorCode
)) {
266 const Calendar
*cpp_cal
= (const Calendar
*)cal
;
267 const GregorianCalendar
*gregocal
= dynamic_cast<const GregorianCalendar
*>(cpp_cal
);
268 // Not if(gregocal == NULL) {
269 // see comments in ucal_setGregorianChange().
270 if(typeid(*cpp_cal
) != typeid(GregorianCalendar
)) {
271 *pErrorCode
= U_UNSUPPORTED_ERROR
;
274 return gregocal
->getGregorianChange();
277 U_CAPI
int32_t U_EXPORT2
278 ucal_getAttribute( const UCalendar
* cal
,
279 UCalendarAttribute attr
)
284 return ((Calendar
*)cal
)->isLenient();
286 case UCAL_FIRST_DAY_OF_WEEK
:
287 return ((Calendar
*)cal
)->getFirstDayOfWeek();
289 case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK
:
290 return ((Calendar
*)cal
)->getMinimalDaysInFirstWeek();
298 U_CAPI
void U_EXPORT2
299 ucal_setAttribute( UCalendar
* cal
,
300 UCalendarAttribute attr
,
306 ((Calendar
*)cal
)->setLenient((UBool
)newValue
);
309 case UCAL_FIRST_DAY_OF_WEEK
:
310 ((Calendar
*)cal
)->setFirstDayOfWeek((UCalendarDaysOfWeek
)newValue
);
313 case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK
:
314 ((Calendar
*)cal
)->setMinimalDaysInFirstWeek((uint8_t)newValue
);
319 U_CAPI
const char* U_EXPORT2
320 ucal_getAvailable(int32_t index
)
323 return uloc_getAvailable(index
);
326 U_CAPI
int32_t U_EXPORT2
327 ucal_countAvailable()
330 return uloc_countAvailable();
333 U_CAPI UDate U_EXPORT2
334 ucal_getMillis( const UCalendar
* cal
,
338 if(U_FAILURE(*status
)) return (UDate
) 0;
340 return ((Calendar
*)cal
)->getTime(*status
);
343 U_CAPI
void U_EXPORT2
344 ucal_setMillis( UCalendar
* cal
,
348 if(U_FAILURE(*status
)) return;
350 ((Calendar
*)cal
)->setTime(dateTime
, *status
);
353 // TBD: why does this take an UErrorCode?
354 U_CAPI
void U_EXPORT2
355 ucal_setDate( UCalendar
* cal
,
362 if(U_FAILURE(*status
)) return;
364 ((Calendar
*)cal
)->set(year
, month
, date
);
367 // TBD: why does this take an UErrorCode?
368 U_CAPI
void U_EXPORT2
369 ucal_setDateTime( UCalendar
* cal
,
378 if(U_FAILURE(*status
)) return;
380 ((Calendar
*)cal
)->set(year
, month
, date
, hour
, minute
, second
);
383 U_CAPI UBool U_EXPORT2
384 ucal_equivalentTo( const UCalendar
* cal1
,
385 const UCalendar
* cal2
)
388 return ((Calendar
*)cal1
)->isEquivalentTo(*((Calendar
*)cal2
));
391 U_CAPI
void U_EXPORT2
392 ucal_add( UCalendar
* cal
,
393 UCalendarDateFields field
,
398 if(U_FAILURE(*status
)) return;
400 ((Calendar
*)cal
)->add(field
, amount
, *status
);
403 U_CAPI
void U_EXPORT2
404 ucal_roll( UCalendar
* cal
,
405 UCalendarDateFields field
,
410 if(U_FAILURE(*status
)) return;
412 ((Calendar
*)cal
)->roll(field
, amount
, *status
);
415 U_CAPI
int32_t U_EXPORT2
416 ucal_get( const UCalendar
* cal
,
417 UCalendarDateFields field
,
421 if(U_FAILURE(*status
)) return -1;
423 return ((Calendar
*)cal
)->get(field
, *status
);
426 U_CAPI
void U_EXPORT2
427 ucal_set( UCalendar
* cal
,
428 UCalendarDateFields field
,
432 ((Calendar
*)cal
)->set(field
, value
);
435 U_CAPI UBool U_EXPORT2
436 ucal_isSet( const UCalendar
* cal
,
437 UCalendarDateFields field
)
440 return ((Calendar
*)cal
)->isSet(field
);
443 U_CAPI
void U_EXPORT2
444 ucal_clearField( UCalendar
* cal
,
445 UCalendarDateFields field
)
448 ((Calendar
*)cal
)->clear(field
);
451 U_CAPI
void U_EXPORT2
452 ucal_clear(UCalendar
* calendar
)
455 ((Calendar
*)calendar
)->clear();
458 U_CAPI
int32_t U_EXPORT2
459 ucal_getLimit( const UCalendar
* cal
,
460 UCalendarDateFields field
,
461 UCalendarLimitType type
,
465 if(status
==0 || U_FAILURE(*status
)) {
471 return ((Calendar
*)cal
)->getMinimum(field
);
474 return ((Calendar
*)cal
)->getMaximum(field
);
476 case UCAL_GREATEST_MINIMUM
:
477 return ((Calendar
*)cal
)->getGreatestMinimum(field
);
479 case UCAL_LEAST_MAXIMUM
:
480 return ((Calendar
*)cal
)->getLeastMaximum(field
);
482 case UCAL_ACTUAL_MINIMUM
:
483 return ((Calendar
*)cal
)->getActualMinimum(field
,
486 case UCAL_ACTUAL_MAXIMUM
:
487 return ((Calendar
*)cal
)->getActualMaximum(field
,
496 U_CAPI
const char * U_EXPORT2
497 ucal_getLocaleByType(const UCalendar
*cal
, ULocDataLocaleType type
, UErrorCode
* status
)
500 if (U_SUCCESS(*status
)) {
501 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
505 return ((Calendar
*)cal
)->getLocaleID(type
, *status
);
508 U_CAPI
const char * U_EXPORT2
509 ucal_getTZDataVersion(UErrorCode
* status
)
511 return TimeZone::getTZDataVersion(*status
);
514 U_CAPI
int32_t U_EXPORT2
515 ucal_getCanonicalTimeZoneID(const UChar
* id
, int32_t len
,
516 UChar
* result
, int32_t resultCapacity
, UBool
*isSystemID
, UErrorCode
* status
) {
517 if(status
== 0 || U_FAILURE(*status
)) {
523 if (id
== 0 || len
== 0 || result
== 0 || resultCapacity
<= 0) {
524 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
528 UnicodeString canonical
;
529 UBool systemID
= FALSE
;
530 TimeZone::getCanonicalID(UnicodeString(id
, len
), canonical
, systemID
, *status
);
531 if (U_SUCCESS(*status
)) {
533 *isSystemID
= systemID
;
535 reslen
= canonical
.extract(result
, resultCapacity
, *status
);
540 U_CAPI
const char * U_EXPORT2
541 ucal_getType(const UCalendar
*cal
, UErrorCode
* status
)
543 if (U_FAILURE(*status
)) {
546 return ((Calendar
*)cal
)->getType();
549 U_CAPI UCalendarWeekdayType U_EXPORT2
550 ucal_getDayOfWeekType(const UCalendar
*cal
, UCalendarDaysOfWeek dayOfWeek
, UErrorCode
* status
)
552 if (U_FAILURE(*status
)) {
555 return ((Calendar
*)cal
)->getDayOfWeekType(dayOfWeek
, *status
);
558 U_CAPI
int32_t U_EXPORT2
559 ucal_getWeekendTransition(const UCalendar
*cal
, UCalendarDaysOfWeek dayOfWeek
, UErrorCode
*status
)
561 if (U_FAILURE(*status
)) {
564 return ((Calendar
*)cal
)->getWeekendTransition(dayOfWeek
, *status
);
567 U_CAPI UBool U_EXPORT2
568 ucal_isWeekend(const UCalendar
*cal
, UDate date
, UErrorCode
*status
)
570 if (U_FAILURE(*status
)) {
573 return ((Calendar
*)cal
)->isWeekend(date
, *status
);
576 U_CAPI
int32_t U_EXPORT2
577 ucal_getFieldDifference(UCalendar
* cal
, UDate target
,
578 UCalendarDateFields field
,
581 if (U_FAILURE(*status
)) {
584 return ((Calendar
*)cal
)->fieldDifference(target
, field
, *status
);
588 static const UEnumeration defaultKeywordValues
= {
591 ulist_close_keyword_values_iterator
,
592 ulist_count_keyword_values
,
594 ulist_next_keyword_value
,
595 ulist_reset_keyword_values_iterator
598 static const char * const CAL_TYPES
[] = {
611 "ethiopic-amete-alem",
615 U_CAPI UEnumeration
* U_EXPORT2
616 ucal_getKeywordValuesForLocale(const char * /* key */, const char* locale
, UBool commonlyUsed
, UErrorCode
*status
) {
618 char prefRegion
[ULOC_FULLNAME_CAPACITY
] = "";
619 int32_t prefRegionLength
= 0;
620 prefRegionLength
= uloc_getCountry(locale
, prefRegion
, sizeof(prefRegion
), status
);
621 if (prefRegionLength
== 0) {
622 char loc
[ULOC_FULLNAME_CAPACITY
] = "";
623 int32_t locLength
= 0;
624 locLength
= uloc_addLikelySubtags(locale
, loc
, sizeof(loc
), status
);
626 prefRegionLength
= uloc_getCountry(loc
, prefRegion
, sizeof(prefRegion
), status
);
629 // Read preferred calendar values from supplementalData calendarPreference
630 UResourceBundle
*rb
= ures_openDirect(NULL
, "supplementalData", status
);
631 ures_getByKey(rb
, "calendarPreferenceData", rb
, status
);
632 UResourceBundle
*order
= ures_getByKey(rb
, prefRegion
, NULL
, status
);
633 if (*status
== U_MISSING_RESOURCE_ERROR
&& rb
!= NULL
) {
634 *status
= U_ZERO_ERROR
;
635 order
= ures_getByKey(rb
, "001", NULL
, status
);
638 // Create a list of calendar type strings
639 UList
*values
= NULL
;
640 if (U_SUCCESS(*status
)) {
641 values
= ulist_createEmptyList(status
);
642 if (U_SUCCESS(*status
)) {
643 for (int i
= 0; i
< ures_getSize(order
); i
++) {
645 const UChar
*type
= ures_getStringByIndex(order
, i
, &len
, status
);
646 char *caltype
= (char*)uprv_malloc(len
+ 1);
647 if (caltype
== NULL
) {
648 *status
= U_MEMORY_ALLOCATION_ERROR
;
651 u_UCharsToChars(type
, caltype
, len
);
652 *(caltype
+ len
) = 0;
654 ulist_addItemEndList(values
, caltype
, TRUE
, status
);
655 if (U_FAILURE(*status
)) {
660 if (U_SUCCESS(*status
) && !commonlyUsed
) {
661 // If not commonlyUsed, add other available values
662 for (int32_t i
= 0; CAL_TYPES
[i
] != NULL
; i
++) {
663 if (!ulist_containsString(values
, CAL_TYPES
[i
], (int32_t)uprv_strlen(CAL_TYPES
[i
]))) {
664 ulist_addItemEndList(values
, CAL_TYPES
[i
], FALSE
, status
);
665 if (U_FAILURE(*status
)) {
671 if (U_FAILURE(*status
)) {
672 ulist_deleteList(values
);
681 if (U_FAILURE(*status
) || values
== NULL
) {
685 // Create string enumeration
686 UEnumeration
*en
= (UEnumeration
*)uprv_malloc(sizeof(UEnumeration
));
688 *status
= U_MEMORY_ALLOCATION_ERROR
;
689 ulist_deleteList(values
);
692 ulist_resetList(values
);
693 memcpy(en
, &defaultKeywordValues
, sizeof(UEnumeration
));
694 en
->context
= values
;
698 #endif /* #if !UCONFIG_NO_FORMATTING */