2 *******************************************************************************
3 * Copyright (C) 1996-2013, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 *******************************************************************************
8 #include "utypeinfo.h" // 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"
22 #include "unicode/localpointer.h"
32 _createTimeZone(const UChar
* zoneID
, int32_t len
, UErrorCode
* ec
) {
33 TimeZone
* zone
= NULL
;
34 if (ec
!=NULL
&& U_SUCCESS(*ec
)) {
35 // Note that if zoneID is invalid, we get back GMT. This odd
36 // behavior is by design and goes back to the JDK. The only
37 // failure we will see is a memory allocation failure.
38 int32_t l
= (len
<0 ? u_strlen(zoneID
) : len
);
39 UnicodeString zoneStrID
;
40 zoneStrID
.setTo((UBool
)(len
< 0), zoneID
, l
); /* temporary read-only alias */
41 zone
= TimeZone::createTimeZone(zoneStrID
);
43 *ec
= U_MEMORY_ALLOCATION_ERROR
;
49 U_CAPI UEnumeration
* U_EXPORT2
50 ucal_openTimeZoneIDEnumeration(USystemTimeZoneType zoneType
, const char* region
,
51 const int32_t* rawOffset
, UErrorCode
* ec
) {
52 return uenum_openFromStringEnumeration(TimeZone::createTimeZoneIDEnumeration(
53 zoneType
, region
, rawOffset
, *ec
), ec
);
56 U_CAPI UEnumeration
* U_EXPORT2
57 ucal_openTimeZones(UErrorCode
* ec
) {
58 return uenum_openFromStringEnumeration(TimeZone::createEnumeration(), ec
);
61 U_CAPI UEnumeration
* U_EXPORT2
62 ucal_openCountryTimeZones(const char* country
, UErrorCode
* ec
) {
63 return uenum_openFromStringEnumeration(TimeZone::createEnumeration(country
), ec
);
66 U_CAPI
int32_t U_EXPORT2
67 ucal_getDefaultTimeZone(UChar
* result
, int32_t resultCapacity
, UErrorCode
* ec
) {
69 if (ec
!=NULL
&& U_SUCCESS(*ec
)) {
70 TimeZone
* zone
= TimeZone::createDefault();
72 *ec
= U_MEMORY_ALLOCATION_ERROR
;
77 len
= id
.extract(result
, resultCapacity
, *ec
);
84 ucal_setDefaultTimeZone(const UChar
* zoneID
, UErrorCode
* ec
) {
85 TimeZone
* zone
= _createTimeZone(zoneID
, -1, ec
);
87 TimeZone::adoptDefault(zone
);
91 U_CAPI
int32_t U_EXPORT2
92 ucal_getDSTSavings(const UChar
* zoneID
, UErrorCode
* ec
) {
94 TimeZone
* zone
= _createTimeZone(zoneID
, -1, ec
);
96 SimpleTimeZone
* stz
= dynamic_cast<SimpleTimeZone
*>(zone
);
98 result
= stz
->getDSTSavings();
100 // Since there is no getDSTSavings on TimeZone, we use a
101 // heuristic: Starting with the current time, march
102 // forwards for one year, looking for DST savings.
103 // Stepping by weeks is sufficient.
104 UDate d
= Calendar::getNow();
105 for (int32_t i
=0; i
<53; ++i
, d
+=U_MILLIS_PER_DAY
*7.0) {
107 zone
->getOffset(d
, FALSE
, raw
, dst
, *ec
);
108 if (U_FAILURE(*ec
)) {
110 } else if (dst
!= 0) {
121 U_CAPI UDate U_EXPORT2
125 return Calendar::getNow();
128 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
130 U_CAPI UCalendar
* U_EXPORT2
131 ucal_open( const UChar
* zoneID
,
134 UCalendarType caltype
,
138 if(U_FAILURE(*status
)) return 0;
140 TimeZone
* zone
= (zoneID
==NULL
) ? TimeZone::createDefault()
141 : _createTimeZone(zoneID
, len
, status
);
143 if (U_FAILURE(*status
)) {
147 if ( caltype
== UCAL_GREGORIAN
) {
148 char localeBuf
[ULOC_LOCALE_IDENTIFIER_CAPACITY
];
149 if ( locale
== NULL
) {
150 locale
= uloc_getDefault();
152 uprv_strncpy(localeBuf
, locale
, ULOC_LOCALE_IDENTIFIER_CAPACITY
);
153 uloc_setKeywordValue("calendar", "gregorian", localeBuf
, ULOC_LOCALE_IDENTIFIER_CAPACITY
, status
);
154 if (U_FAILURE(*status
)) {
157 return (UCalendar
*)Calendar::createInstance(zone
, Locale(localeBuf
), *status
);
159 return (UCalendar
*)Calendar::createInstance(zone
, Locale(locale
), *status
);
162 U_CAPI
void U_EXPORT2
163 ucal_close(UCalendar
*cal
)
166 delete (Calendar
*) cal
;
169 U_CAPI UCalendar
* U_EXPORT2
170 ucal_clone(const UCalendar
* cal
,
173 if(U_FAILURE(*status
)) return 0;
175 Calendar
* res
= ((Calendar
*)cal
)->clone();
178 *status
= U_MEMORY_ALLOCATION_ERROR
;
182 return (UCalendar
*) res
;
185 U_CAPI
void U_EXPORT2
186 ucal_setTimeZone( UCalendar
* cal
,
192 if(U_FAILURE(*status
))
195 TimeZone
* zone
= (zoneID
==NULL
) ? TimeZone::createDefault()
196 : _createTimeZone(zoneID
, len
, status
);
199 ((Calendar
*)cal
)->adoptTimeZone(zone
);
203 U_CAPI
int32_t U_EXPORT2
204 ucal_getTimeZoneID(const UCalendar
*cal
,
206 int32_t resultLength
,
209 if (U_FAILURE(*status
)) {
212 const TimeZone
& tz
= ((Calendar
*)cal
)->getTimeZone();
215 return id
.extract(result
, resultLength
, *status
);
218 U_CAPI
int32_t U_EXPORT2
219 ucal_getTimeZoneDisplayName(const UCalendar
* cal
,
220 UCalendarDisplayNameType type
,
223 int32_t resultLength
,
227 if(U_FAILURE(*status
)) return -1;
229 const TimeZone
& tz
= ((Calendar
*)cal
)->getTimeZone();
231 if(!(result
==NULL
&& resultLength
==0)) {
232 // NULL destination for pure preflighting: empty dummy string
233 // otherwise, alias the destination buffer
234 id
.setTo(result
, 0, resultLength
);
239 tz
.getDisplayName(FALSE
, TimeZone::LONG
, Locale(locale
), id
);
242 case UCAL_SHORT_STANDARD
:
243 tz
.getDisplayName(FALSE
, TimeZone::SHORT
, Locale(locale
), id
);
247 tz
.getDisplayName(TRUE
, TimeZone::LONG
, Locale(locale
), id
);
251 tz
.getDisplayName(TRUE
, TimeZone::SHORT
, Locale(locale
), id
);
255 return id
.extract(result
, resultLength
, *status
);
258 U_CAPI UBool U_EXPORT2
259 ucal_inDaylightTime( const UCalendar
* cal
,
263 if(U_FAILURE(*status
)) return (UBool
) -1;
264 return ((Calendar
*)cal
)->inDaylightTime(*status
);
267 U_CAPI
void U_EXPORT2
268 ucal_setGregorianChange(UCalendar
*cal
, UDate date
, UErrorCode
*pErrorCode
) {
269 if(U_FAILURE(*pErrorCode
)) {
272 Calendar
*cpp_cal
= (Calendar
*)cal
;
273 GregorianCalendar
*gregocal
= dynamic_cast<GregorianCalendar
*>(cpp_cal
);
274 // Not if(gregocal == NULL) {
275 // because we really want to work only with a GregorianCalendar, not with
276 // its subclasses like BuddhistCalendar.
277 if (cpp_cal
== NULL
) {
278 // We normally don't check "this" pointers for NULL, but this here avoids
279 // compiler-generated exception-throwing code in case cal == NULL.
280 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
283 if(typeid(*cpp_cal
) != typeid(GregorianCalendar
)) {
284 *pErrorCode
= U_UNSUPPORTED_ERROR
;
287 gregocal
->setGregorianChange(date
, *pErrorCode
);
290 U_CAPI UDate U_EXPORT2
291 ucal_getGregorianChange(const UCalendar
*cal
, UErrorCode
*pErrorCode
) {
292 if(U_FAILURE(*pErrorCode
)) {
295 const Calendar
*cpp_cal
= (const Calendar
*)cal
;
296 const GregorianCalendar
*gregocal
= dynamic_cast<const GregorianCalendar
*>(cpp_cal
);
297 // Not if(gregocal == NULL) {
298 // see comments in ucal_setGregorianChange().
299 if (cpp_cal
== NULL
) {
300 // We normally don't check "this" pointers for NULL, but this here avoids
301 // compiler-generated exception-throwing code in case cal == NULL.
302 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
305 if(typeid(*cpp_cal
) != typeid(GregorianCalendar
)) {
306 *pErrorCode
= U_UNSUPPORTED_ERROR
;
309 return gregocal
->getGregorianChange();
312 U_CAPI
int32_t U_EXPORT2
313 ucal_getAttribute( const UCalendar
* cal
,
314 UCalendarAttribute attr
)
319 return ((Calendar
*)cal
)->isLenient();
321 case UCAL_FIRST_DAY_OF_WEEK
:
322 return ((Calendar
*)cal
)->getFirstDayOfWeek();
324 case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK
:
325 return ((Calendar
*)cal
)->getMinimalDaysInFirstWeek();
327 case UCAL_REPEATED_WALL_TIME
:
328 return ((Calendar
*)cal
)->getRepeatedWallTimeOption();
330 case UCAL_SKIPPED_WALL_TIME
:
331 return ((Calendar
*)cal
)->getSkippedWallTimeOption();
339 U_CAPI
void U_EXPORT2
340 ucal_setAttribute( UCalendar
* cal
,
341 UCalendarAttribute attr
,
347 ((Calendar
*)cal
)->setLenient((UBool
)newValue
);
350 case UCAL_FIRST_DAY_OF_WEEK
:
351 ((Calendar
*)cal
)->setFirstDayOfWeek((UCalendarDaysOfWeek
)newValue
);
354 case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK
:
355 ((Calendar
*)cal
)->setMinimalDaysInFirstWeek((uint8_t)newValue
);
358 case UCAL_REPEATED_WALL_TIME
:
359 ((Calendar
*)cal
)->setRepeatedWallTimeOption((UCalendarWallTimeOption
)newValue
);
362 case UCAL_SKIPPED_WALL_TIME
:
363 ((Calendar
*)cal
)->setSkippedWallTimeOption((UCalendarWallTimeOption
)newValue
);
368 U_CAPI
const char* U_EXPORT2
369 ucal_getAvailable(int32_t index
)
372 return uloc_getAvailable(index
);
375 U_CAPI
int32_t U_EXPORT2
376 ucal_countAvailable()
379 return uloc_countAvailable();
382 U_CAPI UDate U_EXPORT2
383 ucal_getMillis( const UCalendar
* cal
,
387 if(U_FAILURE(*status
)) return (UDate
) 0;
389 return ((Calendar
*)cal
)->getTime(*status
);
392 U_CAPI
void U_EXPORT2
393 ucal_setMillis( UCalendar
* cal
,
397 if(U_FAILURE(*status
)) return;
399 ((Calendar
*)cal
)->setTime(dateTime
, *status
);
402 // TBD: why does this take an UErrorCode?
403 U_CAPI
void U_EXPORT2
404 ucal_setDate( UCalendar
* cal
,
411 if(U_FAILURE(*status
)) return;
413 ((Calendar
*)cal
)->set(year
, month
, date
);
416 // TBD: why does this take an UErrorCode?
417 U_CAPI
void U_EXPORT2
418 ucal_setDateTime( UCalendar
* cal
,
427 if(U_FAILURE(*status
)) return;
429 ((Calendar
*)cal
)->set(year
, month
, date
, hour
, minute
, second
);
432 U_CAPI UBool U_EXPORT2
433 ucal_equivalentTo( const UCalendar
* cal1
,
434 const UCalendar
* cal2
)
437 return ((Calendar
*)cal1
)->isEquivalentTo(*((Calendar
*)cal2
));
440 U_CAPI
void U_EXPORT2
441 ucal_add( UCalendar
* cal
,
442 UCalendarDateFields field
,
447 if(U_FAILURE(*status
)) return;
449 ((Calendar
*)cal
)->add(field
, amount
, *status
);
452 U_CAPI
void U_EXPORT2
453 ucal_roll( UCalendar
* cal
,
454 UCalendarDateFields field
,
459 if(U_FAILURE(*status
)) return;
461 ((Calendar
*)cal
)->roll(field
, amount
, *status
);
464 U_CAPI
int32_t U_EXPORT2
465 ucal_get( const UCalendar
* cal
,
466 UCalendarDateFields field
,
470 if(U_FAILURE(*status
)) return -1;
472 return ((Calendar
*)cal
)->get(field
, *status
);
475 U_CAPI
void U_EXPORT2
476 ucal_set( UCalendar
* cal
,
477 UCalendarDateFields field
,
481 ((Calendar
*)cal
)->set(field
, value
);
484 U_CAPI UBool U_EXPORT2
485 ucal_isSet( const UCalendar
* cal
,
486 UCalendarDateFields field
)
489 return ((Calendar
*)cal
)->isSet(field
);
492 U_CAPI
void U_EXPORT2
493 ucal_clearField( UCalendar
* cal
,
494 UCalendarDateFields field
)
497 ((Calendar
*)cal
)->clear(field
);
500 U_CAPI
void U_EXPORT2
501 ucal_clear(UCalendar
* calendar
)
504 ((Calendar
*)calendar
)->clear();
507 U_CAPI
int32_t U_EXPORT2
508 ucal_getLimit( const UCalendar
* cal
,
509 UCalendarDateFields field
,
510 UCalendarLimitType type
,
514 if(status
==0 || U_FAILURE(*status
)) {
520 return ((Calendar
*)cal
)->getMinimum(field
);
523 return ((Calendar
*)cal
)->getMaximum(field
);
525 case UCAL_GREATEST_MINIMUM
:
526 return ((Calendar
*)cal
)->getGreatestMinimum(field
);
528 case UCAL_LEAST_MAXIMUM
:
529 return ((Calendar
*)cal
)->getLeastMaximum(field
);
531 case UCAL_ACTUAL_MINIMUM
:
532 return ((Calendar
*)cal
)->getActualMinimum(field
,
535 case UCAL_ACTUAL_MAXIMUM
:
536 return ((Calendar
*)cal
)->getActualMaximum(field
,
545 U_CAPI
const char * U_EXPORT2
546 ucal_getLocaleByType(const UCalendar
*cal
, ULocDataLocaleType type
, UErrorCode
* status
)
549 if (U_SUCCESS(*status
)) {
550 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
554 return ((Calendar
*)cal
)->getLocaleID(type
, *status
);
557 U_CAPI
const char * U_EXPORT2
558 ucal_getTZDataVersion(UErrorCode
* status
)
560 return TimeZone::getTZDataVersion(*status
);
563 U_CAPI
int32_t U_EXPORT2
564 ucal_getCanonicalTimeZoneID(const UChar
* id
, int32_t len
,
565 UChar
* result
, int32_t resultCapacity
, UBool
*isSystemID
, UErrorCode
* status
) {
566 if(status
== 0 || U_FAILURE(*status
)) {
572 if (id
== 0 || len
== 0 || result
== 0 || resultCapacity
<= 0) {
573 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
577 UnicodeString canonical
;
578 UBool systemID
= FALSE
;
579 TimeZone::getCanonicalID(UnicodeString(id
, len
), canonical
, systemID
, *status
);
580 if (U_SUCCESS(*status
)) {
582 *isSystemID
= systemID
;
584 reslen
= canonical
.extract(result
, resultCapacity
, *status
);
589 U_CAPI
const char * U_EXPORT2
590 ucal_getType(const UCalendar
*cal
, UErrorCode
* status
)
592 if (U_FAILURE(*status
)) {
595 return ((Calendar
*)cal
)->getType();
598 U_CAPI UCalendarWeekdayType U_EXPORT2
599 ucal_getDayOfWeekType(const UCalendar
*cal
, UCalendarDaysOfWeek dayOfWeek
, UErrorCode
* status
)
601 if (U_FAILURE(*status
)) {
604 return ((Calendar
*)cal
)->getDayOfWeekType(dayOfWeek
, *status
);
607 U_CAPI
int32_t U_EXPORT2
608 ucal_getWeekendTransition(const UCalendar
*cal
, UCalendarDaysOfWeek dayOfWeek
, UErrorCode
*status
)
610 if (U_FAILURE(*status
)) {
613 return ((Calendar
*)cal
)->getWeekendTransition(dayOfWeek
, *status
);
616 U_CAPI UBool U_EXPORT2
617 ucal_isWeekend(const UCalendar
*cal
, UDate date
, UErrorCode
*status
)
619 if (U_FAILURE(*status
)) {
622 return ((Calendar
*)cal
)->isWeekend(date
, *status
);
625 U_CAPI
int32_t U_EXPORT2
626 ucal_getFieldDifference(UCalendar
* cal
, UDate target
,
627 UCalendarDateFields field
,
630 if (U_FAILURE(*status
)) {
633 return ((Calendar
*)cal
)->fieldDifference(target
, field
, *status
);
637 static const UEnumeration defaultKeywordValues
= {
640 ulist_close_keyword_values_iterator
,
641 ulist_count_keyword_values
,
643 ulist_next_keyword_value
,
644 ulist_reset_keyword_values_iterator
647 static const char * const CAL_TYPES
[] = {
660 "ethiopic-amete-alem",
664 U_CAPI UEnumeration
* U_EXPORT2
665 ucal_getKeywordValuesForLocale(const char * /* key */, const char* locale
, UBool commonlyUsed
, UErrorCode
*status
) {
667 char prefRegion
[ULOC_FULLNAME_CAPACITY
] = "";
668 int32_t prefRegionLength
= 0;
669 prefRegionLength
= uloc_getCountry(locale
, prefRegion
, sizeof(prefRegion
), status
);
670 if (prefRegionLength
== 0) {
671 char loc
[ULOC_FULLNAME_CAPACITY
] = "";
672 uloc_addLikelySubtags(locale
, loc
, sizeof(loc
), status
);
674 prefRegionLength
= uloc_getCountry(loc
, prefRegion
, sizeof(prefRegion
), status
);
677 // Read preferred calendar values from supplementalData calendarPreference
678 UResourceBundle
*rb
= ures_openDirect(NULL
, "supplementalData", status
);
679 ures_getByKey(rb
, "calendarPreferenceData", rb
, status
);
680 UResourceBundle
*order
= ures_getByKey(rb
, prefRegion
, NULL
, status
);
681 if (*status
== U_MISSING_RESOURCE_ERROR
&& rb
!= NULL
) {
682 *status
= U_ZERO_ERROR
;
683 order
= ures_getByKey(rb
, "001", NULL
, status
);
686 // Create a list of calendar type strings
687 UList
*values
= NULL
;
688 if (U_SUCCESS(*status
)) {
689 values
= ulist_createEmptyList(status
);
690 if (U_SUCCESS(*status
)) {
691 for (int i
= 0; i
< ures_getSize(order
); i
++) {
693 const UChar
*type
= ures_getStringByIndex(order
, i
, &len
, status
);
694 char *caltype
= (char*)uprv_malloc(len
+ 1);
695 if (caltype
== NULL
) {
696 *status
= U_MEMORY_ALLOCATION_ERROR
;
699 u_UCharsToChars(type
, caltype
, len
);
700 *(caltype
+ len
) = 0;
702 ulist_addItemEndList(values
, caltype
, TRUE
, status
);
703 if (U_FAILURE(*status
)) {
708 if (U_SUCCESS(*status
) && !commonlyUsed
) {
709 // If not commonlyUsed, add other available values
710 for (int32_t i
= 0; CAL_TYPES
[i
] != NULL
; i
++) {
711 if (!ulist_containsString(values
, CAL_TYPES
[i
], (int32_t)uprv_strlen(CAL_TYPES
[i
]))) {
712 ulist_addItemEndList(values
, CAL_TYPES
[i
], FALSE
, status
);
713 if (U_FAILURE(*status
)) {
719 if (U_FAILURE(*status
)) {
720 ulist_deleteList(values
);
729 if (U_FAILURE(*status
) || values
== NULL
) {
733 // Create string enumeration
734 UEnumeration
*en
= (UEnumeration
*)uprv_malloc(sizeof(UEnumeration
));
736 *status
= U_MEMORY_ALLOCATION_ERROR
;
737 ulist_deleteList(values
);
740 ulist_resetList(values
);
741 memcpy(en
, &defaultKeywordValues
, sizeof(UEnumeration
));
742 en
->context
= values
;
746 U_CAPI UBool U_EXPORT2
747 ucal_getTimeZoneTransitionDate(const UCalendar
* cal
, UTimeZoneTransitionType type
,
748 UDate
* transition
, UErrorCode
* status
)
750 if (U_FAILURE(*status
)) {
753 UDate base
= ((Calendar
*)cal
)->getTime(*status
);
754 const TimeZone
& tz
= ((Calendar
*)cal
)->getTimeZone();
755 const BasicTimeZone
* btz
= dynamic_cast<const BasicTimeZone
*>(&tz
);
756 if (btz
!= NULL
&& U_SUCCESS(*status
)) {
757 TimeZoneTransition tzt
;
758 UBool inclusive
= (type
== UCAL_TZ_TRANSITION_NEXT_INCLUSIVE
|| type
== UCAL_TZ_TRANSITION_PREVIOUS_INCLUSIVE
);
759 UBool result
= (type
== UCAL_TZ_TRANSITION_NEXT
|| type
== UCAL_TZ_TRANSITION_NEXT_INCLUSIVE
)?
760 btz
->getNextTransition(base
, inclusive
, tzt
):
761 btz
->getPreviousTransition(base
, inclusive
, tzt
);
763 *transition
= tzt
.getTime();
770 #endif /* #if !UCONFIG_NO_FORMATTING */