/*
*******************************************************************************
-* Copyright (C) 1996-2006, International Business Machines
+* Copyright (C) 1996-2012, International Business Machines
* Corporation and others. All Rights Reserved.
*******************************************************************************
*/
#include "unicode/dtfmtsym.h"
#include "unicode/ustring.h"
#include "cpputils.h"
+#include "reldtfmt.h"
+#include "umutex.h"
U_NAMESPACE_USE
+/**
+ * Verify that fmt is a SimpleDateFormat. Invalid error if not.
+ * @param fmt the UDateFormat, definitely a DateFormat, maybe something else
+ * @param status error code, will be set to failure if there is a familure or the fmt is NULL.
+ */
+static void verifyIsSimpleDateFormat(const UDateFormat* fmt, UErrorCode *status) {
+ if(U_SUCCESS(*status) &&
+ dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))==NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+}
+
+// This mirrors the correspondence between the
+// SimpleDateFormat::fgPatternIndexToDateFormatField and
+// SimpleDateFormat::fgPatternIndexToCalendarField arrays.
+static UCalendarDateFields gDateFieldMapping[] = {
+ UCAL_ERA, // UDAT_ERA_FIELD = 0
+ UCAL_YEAR, // UDAT_YEAR_FIELD = 1
+ UCAL_MONTH, // UDAT_MONTH_FIELD = 2
+ UCAL_DATE, // UDAT_DATE_FIELD = 3
+ UCAL_HOUR_OF_DAY, // UDAT_HOUR_OF_DAY1_FIELD = 4
+ UCAL_HOUR_OF_DAY, // UDAT_HOUR_OF_DAY0_FIELD = 5
+ UCAL_MINUTE, // UDAT_MINUTE_FIELD = 6
+ UCAL_SECOND, // UDAT_SECOND_FIELD = 7
+ UCAL_MILLISECOND, // UDAT_FRACTIONAL_SECOND_FIELD = 8
+ UCAL_DAY_OF_WEEK, // UDAT_DAY_OF_WEEK_FIELD = 9
+ UCAL_DAY_OF_YEAR, // UDAT_DAY_OF_YEAR_FIELD = 10
+ UCAL_DAY_OF_WEEK_IN_MONTH, // UDAT_DAY_OF_WEEK_IN_MONTH_FIELD = 11
+ UCAL_WEEK_OF_YEAR, // UDAT_WEEK_OF_YEAR_FIELD = 12
+ UCAL_WEEK_OF_MONTH, // UDAT_WEEK_OF_MONTH_FIELD = 13
+ UCAL_AM_PM, // UDAT_AM_PM_FIELD = 14
+ UCAL_HOUR, // UDAT_HOUR1_FIELD = 15
+ UCAL_HOUR, // UDAT_HOUR0_FIELD = 16
+ UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_FIELD = 17
+ UCAL_YEAR_WOY, // UDAT_YEAR_WOY_FIELD = 18
+ UCAL_DOW_LOCAL, // UDAT_DOW_LOCAL_FIELD = 19
+ UCAL_EXTENDED_YEAR, // UDAT_EXTENDED_YEAR_FIELD = 20
+ UCAL_JULIAN_DAY, // UDAT_JULIAN_DAY_FIELD = 21
+ UCAL_MILLISECONDS_IN_DAY, // UDAT_MILLISECONDS_IN_DAY_FIELD = 22
+ UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_RFC_FIELD = 23
+ // UCAL_DST_OFFSET also
+ UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_GENERIC_FIELD = 24
+ UCAL_DOW_LOCAL, // UDAT_STANDALONE_DAY_FIELD = 25
+ UCAL_MONTH, // UDAT_STANDALONE_MONTH_FIELD = 26
+ UCAL_MONTH, // UDAT_QUARTER_FIELD = 27
+ UCAL_MONTH, // UDAT_STANDALONE_QUARTER_FIELD = 28
+ UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_SPECIAL_FIELD = 29
+ UCAL_YEAR, // UDAT_YEAR_NAME_FIELD = 30
+ UCAL_FIELD_COUNT, // UDAT_FIELD_COUNT = 31
+ // UCAL_IS_LEAP_MONTH is not the target of a mapping
+};
+
+U_CAPI UCalendarDateFields U_EXPORT2
+udat_toCalendarDateField(UDateFormatField field) {
+ return gDateFieldMapping[field];
+}
+
+/* For now- one opener. */
+static UDateFormatOpener gOpener = NULL;
+
+U_INTERNAL void U_EXPORT2
+udat_registerOpener(UDateFormatOpener opener, UErrorCode *status)
+{
+ if(U_FAILURE(*status)) return;
+ umtx_lock(NULL);
+ if(gOpener==NULL) {
+ gOpener = opener;
+ } else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ umtx_unlock(NULL);
+}
+
+U_INTERNAL UDateFormatOpener U_EXPORT2
+udat_unregisterOpener(UDateFormatOpener opener, UErrorCode *status)
+{
+ if(U_FAILURE(*status)) return NULL;
+ UDateFormatOpener oldOpener = NULL;
+ umtx_lock(NULL);
+ if(gOpener==NULL || gOpener!=opener) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ oldOpener=gOpener;
+ gOpener=NULL;
+ }
+ umtx_unlock(NULL);
+ return oldOpener;
+}
+
+
+
U_CAPI UDateFormat* U_EXPORT2
udat_open(UDateFormatStyle timeStyle,
UDateFormatStyle dateStyle,
if(U_FAILURE(*status)) {
return 0;
}
+ if(gOpener!=NULL) { // if it's registered
+ fmt = (DateFormat*) (*gOpener)(timeStyle,dateStyle,locale,tzID,tzIDLength,pattern,patternLength,status);
+ if(fmt!=NULL) {
+ return (UDateFormat*)fmt;
+ } // else fall through.
+ }
if(timeStyle != UDAT_IGNORE) {
if(locale == 0) {
fmt = DateFormat::createDateTimeInstance((DateFormat::EStyle)dateStyle,
{
if(U_FAILURE(*status)) return 0;
- Format *res = ((SimpleDateFormat*)fmt)->clone();
+ Format *res = ((DateFormat*)fmt)->clone();
if(res == 0) {
*status = U_MEMORY_ALLOCATION_ERROR;
udat_get2DigitYearStart( const UDateFormat *fmt,
UErrorCode *status)
{
+ verifyIsSimpleDateFormat(fmt, status);
if(U_FAILURE(*status)) return (UDate)0;
return ((SimpleDateFormat*)fmt)->get2DigitYearStart(*status);
}
UDate d,
UErrorCode *status)
{
+ verifyIsSimpleDateFormat(fmt, status);
if(U_FAILURE(*status)) return;
((SimpleDateFormat*)fmt)->set2DigitYearStart(d, *status);
}
res.setTo(result, 0, resultLength);
}
- if(localized)
- ((SimpleDateFormat*)fmt)->toLocalizedPattern(res, *status);
- else
- ((SimpleDateFormat*)fmt)->toPattern(res);
+ const DateFormat *df=reinterpret_cast<const DateFormat *>(fmt);
+ const SimpleDateFormat *sdtfmt=dynamic_cast<const SimpleDateFormat *>(df);
+ const RelativeDateFormat *reldtfmt;
+ if (sdtfmt!=NULL) {
+ if(localized)
+ sdtfmt->toLocalizedPattern(res, *status);
+ else
+ sdtfmt->toPattern(res);
+ } else if (!localized && (reldtfmt=dynamic_cast<const RelativeDateFormat *>(df))!=NULL) {
+ reldtfmt->toPattern(res, *status);
+ } else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
return res.extract(result, resultLength, *status);
}
-// TBD: should this take an UErrorCode?
+// TODO: should this take an UErrorCode?
+// A: Yes. Of course.
U_CAPI void U_EXPORT2
udat_applyPattern( UDateFormat *format,
UBool localized,
const UnicodeString pat((UBool)(patternLength == -1), pattern, patternLength);
UErrorCode status = U_ZERO_ERROR;
+ verifyIsSimpleDateFormat(format, &status);
+ if(U_FAILURE(status)) {
+ return;
+ }
+
if(localized)
((SimpleDateFormat*)format)->applyLocalizedPattern(pat, status);
else
int32_t resultLength,
UErrorCode *status)
{
- if(U_FAILURE(*status)) return -1;
-
- const DateFormatSymbols *syms =
- ((SimpleDateFormat*)fmt)->getDateFormatSymbols();
+ const DateFormatSymbols *syms;
+ const SimpleDateFormat* sdtfmt;
+ const RelativeDateFormat* rdtfmt;
+ if ((sdtfmt = dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
+ syms = sdtfmt->getDateFormatSymbols();
+ } else if ((rdtfmt = dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
+ syms = rdtfmt->getDateFormatSymbols();
+ } else {
+ return -1;
+ }
int32_t count;
const UnicodeString *res = NULL;
return 0;
}
+// TODO: also needs an errorCode.
U_CAPI int32_t U_EXPORT2
udat_countSymbols( const UDateFormat *fmt,
UDateFormatSymbolType type)
{
- const DateFormatSymbols *syms =
- ((SimpleDateFormat*)fmt)->getDateFormatSymbols();
+ const DateFormatSymbols *syms;
+ const SimpleDateFormat* sdtfmt;
+ const RelativeDateFormat* rdtfmt;
+ if ((sdtfmt = dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
+ syms = sdtfmt->getDateFormatSymbols();
+ } else if ((rdtfmt = dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
+ syms = rdtfmt->getDateFormatSymbols();
+ } else {
+ return 0;
+ }
int32_t count = 0;
switch(type) {
int32_t valueLength,
UErrorCode *status)
{
-
+ verifyIsSimpleDateFormat(format, status);
if(U_FAILURE(*status)) return;
DateFormatSymbols *syms = (DateFormatSymbols *)((SimpleDateFormat *)format)->getDateFormatSymbols();
}
return ((Format*)fmt)->getLocaleID(type, *status);
}
+
+
+U_CAPI void U_EXPORT2
+udat_setDefaultContext(UDateFormat* fmt,
+ UDateFormatContextType type, UDateFormatContextValue value,
+ UErrorCode* status)
+{
+ verifyIsSimpleDateFormat(fmt, status);
+ if (U_FAILURE(*status)) {
+ return;
+ }
+ ((SimpleDateFormat*)fmt)->setDefaultContext(type, value, *status);
+}
+
+U_CAPI int32_t U_EXPORT2
+udat_getDefaultContext(UDateFormat* fmt,
+ UDateFormatContextType type,
+ UErrorCode* status)
+{
+ verifyIsSimpleDateFormat(fmt, status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ return ((SimpleDateFormat*)fmt)->getDefaultContext(type, *status);
+}
+
+
+/**
+ * Verify that fmt is a RelativeDateFormat. Invalid error if not.
+ * @param fmt the UDateFormat, definitely a DateFormat, maybe something else
+ * @param status error code, will be set to failure if there is a familure or the fmt is NULL.
+ */
+static void verifyIsRelativeDateFormat(const UDateFormat* fmt, UErrorCode *status) {
+ if(U_SUCCESS(*status) &&
+ dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))==NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+}
+
+
+U_CAPI int32_t U_EXPORT2
+udat_toPatternRelativeDate(const UDateFormat *fmt,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status)
+{
+ verifyIsRelativeDateFormat(fmt, status);
+ if(U_FAILURE(*status)) return -1;
+
+ UnicodeString datePattern;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ datePattern.setTo(result, 0, resultLength);
+ }
+ ((RelativeDateFormat*)fmt)->toPatternDate(datePattern, *status);
+ return datePattern.extract(result, resultLength, *status);
+}
+
+U_CAPI int32_t U_EXPORT2
+udat_toPatternRelativeTime(const UDateFormat *fmt,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status)
+{
+ verifyIsRelativeDateFormat(fmt, status);
+ if(U_FAILURE(*status)) return -1;
+
+ UnicodeString timePattern;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ timePattern.setTo(result, 0, resultLength);
+ }
+ ((RelativeDateFormat*)fmt)->toPatternTime(timePattern, *status);
+ return timePattern.extract(result, resultLength, *status);
+}
+
+U_CAPI void U_EXPORT2
+udat_applyPatternRelative(UDateFormat *format,
+ const UChar *datePattern,
+ int32_t datePatternLength,
+ const UChar *timePattern,
+ int32_t timePatternLength,
+ UErrorCode *status)
+{
+ verifyIsRelativeDateFormat(format, status);
+ if(U_FAILURE(*status)) return;
+ const UnicodeString datePat((UBool)(datePatternLength == -1), datePattern, datePatternLength);
+ const UnicodeString timePat((UBool)(timePatternLength == -1), timePattern, timePatternLength);
+ ((RelativeDateFormat*)format)->applyPatterns(datePat, timePat, *status);
+}
+
#endif /* #if !UCONFIG_NO_FORMATTING */