includes new getter/setter API per TC discussion.
*fp = *(other.fp);
dtMatcher->copyFrom(other.dtMatcher->skeleton);
*distanceInfo = *(other.distanceInfo);
- dateTimeFormat = other.dateTimeFormat;
+ for (int32_t style = UDAT_FULL; style <= UDAT_SHORT; style++) {
+ dateTimeFormat[style] = other.dateTimeFormat[style];
+ }
decimal = other.decimal;
- // NUL-terminate for the C API.
- dateTimeFormat.getTerminatedBuffer();
+ for (int32_t style = UDAT_FULL; style <= UDAT_SHORT; style++) {
+ dateTimeFormat[style].getTerminatedBuffer(); // NUL-terminate for the C API.
+ }
decimal.getTerminatedBuffer();
delete skipMatcher;
if ( other.skipMatcher == nullptr ) {
return true;
}
if ((pLocale==other.pLocale) && (patternMap->equals(*other.patternMap)) &&
- (dateTimeFormat==other.dateTimeFormat) && (decimal==other.decimal)) {
+ (decimal==other.decimal)) {
+ for (int32_t style = UDAT_FULL; style <= UDAT_SHORT; style++) {
+ if (dateTimeFormat[style] != other.dateTimeFormat[style]) {
+ return false;
+ }
+ }
for ( int32_t i=0 ; i<UDATPG_FIELD_COUNT; ++i ) {
if (appendItemFormats[i] != other.appendItemFormats[i]) {
return false;
}
resultPattern.remove();
status = U_ZERO_ERROR;
- dtFormat=getDateTimeFormat();
+ // determine which dateTimeFormat to use
+ PtnSkeleton* reqSkeleton = dtMatcher->getSkeletonPtr();
+ UDateFormatStyle style = UDAT_SHORT;
+ int32_t monthFieldLen = reqSkeleton->baseOriginal.getFieldLength(UDATPG_MONTH_FIELD);
+ if (monthFieldLen == 4) {
+ if (reqSkeleton->baseOriginal.getFieldLength(UDATPG_WEEKDAY_FIELD) > 0) {
+ style = UDAT_FULL;
+ } else {
+ style = UDAT_LONG;
+ }
+ } else if (monthFieldLen == 3) {
+ style = UDAT_MEDIUM;
+ }
+ // and now use it to compose date and time
+ dtFormat=getDateTimeFormat(style, status);
SimpleFormatter(dtFormat, 2, 2, status).format(timePattern, datePattern, resultPattern, status);
return resultPattern;
}
void
DateTimePatternGenerator::setDateTimeFormat(const UnicodeString& dtFormat) {
- dateTimeFormat = dtFormat;
- // NUL-terminate for the C API.
- dateTimeFormat.getTerminatedBuffer();
+ UErrorCode status = U_ZERO_ERROR;
+ for (int32_t style = UDAT_FULL; style <= UDAT_SHORT; style++) {
+ setDateTimeFormat((UDateFormatStyle)style, dtFormat, status);
+ }
}
const UnicodeString&
DateTimePatternGenerator::getDateTimeFormat() const {
- return dateTimeFormat;
+ UErrorCode status = U_ZERO_ERROR;
+ return getDateTimeFormat(UDAT_MEDIUM, status);
+}
+
+void
+DateTimePatternGenerator::setDateTimeFormat(UDateFormatStyle style, const UnicodeString& dtFormat, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (style < UDAT_FULL || style > UDAT_SHORT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ dateTimeFormat[style] = dtFormat;
+ // Note for the following: getTerminatedBuffer() can re-allocate the UnicodeString
+ // buffer so we do this here before clients request a const ref to the UnicodeString
+ // or its buffer.
+ dateTimeFormat[style].getTerminatedBuffer(); // NUL-terminate for the C API.
+}
+
+const UnicodeString&
+DateTimePatternGenerator::getDateTimeFormat(UDateFormatStyle style, UErrorCode& status) const {
+ static const UnicodeString emptyString = UNICODE_STRING_SIMPLE("");
+ if (U_FAILURE(status)) {
+ return emptyString;
+ }
+ if (style < UDAT_FULL || style > UDAT_SHORT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return emptyString;
+ }
+ return dateTimeFormat[style];
}
void
}
if (U_FAILURE(status)) { return; }
- if (ures_getSize(dateTimePatterns.getAlias()) <= DateFormat::kDateTime)
+ if (ures_getSize(dateTimePatterns.getAlias()) <= DateFormat::kDateTimeOffset + DateFormat::kShort)
{
status = U_INVALID_FORMAT_ERROR;
return;
}
- resStr = ures_getStringByIndex(dateTimePatterns.getAlias(), (int32_t)DateFormat::kDateTime, &resStrLen, &status);
- setDateTimeFormat(UnicodeString(TRUE, resStr, resStrLen));
+ for (int32_t style = UDAT_FULL; style <= UDAT_SHORT; style++) {
+ resStr = ures_getStringByIndex(dateTimePatterns.getAlias(), (int32_t)DateFormat::kDateTimeOffset + style, &resStrLen, &status);
+ setDateTimeFormat((UDateFormatStyle)style, UnicodeString(TRUE, resStr, resStrLen), status);
+ }
}
void
U_CAPI const UChar * U_EXPORT2
udatpg_getDateTimeFormat(const UDateTimePatternGenerator *dtpg,
int32_t *pLength) {
- const UnicodeString &result=((const DateTimePatternGenerator *)dtpg)->getDateTimeFormat();
- if(pLength!=NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ return udatpg_getDateTimeFormatForStyle(dtpg, UDAT_MEDIUM, pLength, &status);
+}
+
+U_CAPI void U_EXPORT2
+udatpg_setDateTimeFormatForStyle(UDateTimePatternGenerator *udtpg,
+ UDateFormatStyle style,
+ const UChar *dateTimeFormat, int32_t length,
+ UErrorCode *pErrorCode) {
+ if (U_FAILURE(*pErrorCode)) {
+ return;
+ } else if (dateTimeFormat==nullptr) {
+ *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ DateTimePatternGenerator *dtpg = reinterpret_cast<DateTimePatternGenerator *>(udtpg);
+ UnicodeString dtFormatString((UBool)(length<0), dateTimeFormat, length);
+ dtpg->setDateTimeFormat(style, dtFormatString, *pErrorCode);
+}
+
+U_CAPI const UChar* U_EXPORT2
+udatpg_getDateTimeFormatForStyle(const UDateTimePatternGenerator *udtpg,
+ UDateFormatStyle style, int32_t *pLength,
+ UErrorCode *pErrorCode) {
+ static const UChar emptyString[] = { (UChar)0 };
+ if (U_FAILURE(*pErrorCode)) {
+ if (pLength !=nullptr) {
+ *pLength = 0;
+ }
+ return emptyString;
+ }
+ const DateTimePatternGenerator *dtpg = reinterpret_cast<const DateTimePatternGenerator *>(udtpg);
+ const UnicodeString &result = dtpg->getDateTimeFormat(style, *pErrorCode);
+ if (pLength != nullptr) {
*pLength=result.length();
}
+ // Note: The UnicodeString for the dateTimeFormat string in the DateTimePatternGenerator
+ // was NUL-terminated what it was set, to avoid doing it here which could re-allocate
+ // the buffe and affect and cont references to the string or its buffer.
return result.getBuffer();
-}
+ }
U_CAPI void U_EXPORT2
udatpg_setDecimal(UDateTimePatternGenerator *dtpg,
* for those two skeletons, so the result is put together with this pattern,
* resulting in "d-MMM h:mm".
*
+ * There are four DateTimeFormats in a DateTimePatternGenerator object,
+ * corresponding to date styles UDAT_FULL..UDAT_SHORT. This method sets
+ * all of them to the specified pattern. To set them individually, see
+ * setDateTimeFormat(UDateFormatStyle style, ...).
+ *
* @param dateTimeFormat
* message format pattern, here {1} will be replaced by the date
* pattern and {0} will be replaced by the time pattern.
/**
* Getter corresponding to setDateTimeFormat.
+ *
+ * There are four DateTimeFormats in a DateTimePatternGenerator object,
+ * corresponding to date styles UDAT_FULL..UDAT_SHORT. This method gets
+ * the style for UDAT_MEDIUM (the default). To get them individually, see
+ * getDateTimeFormat(UDateFormatStyle style).
+ *
* @return DateTimeFormat.
* @stable ICU 3.8
*/
const UnicodeString& getDateTimeFormat() const;
+#if !UCONFIG_NO_FORMATTING
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * dateTimeFormats are message patterns used to compose combinations of date
+ * and time patterns. There are four length styles, corresponding to the
+ * inferred style of the date pattern; these are UDateFormatStyle values:
+ * - UDAT_FULL (for date pattern with weekday and long month), else
+ * - UDAT_LONG (for a date pattern with long month), else
+ * - UDAT_MEDIUM (for a date pattern with abbreviated month), else
+ * - UDAT_SHORT (for any other date pattern).
+ * For details on dateTimeFormats, see
+ * https://www.unicode.org/reports/tr35/tr35-dates.html#dateTimeFormats.
+ * The default pattern in the root locale for all styles is "{1} {0}".
+ *
+ * @param style
+ * one of DateFormat.FULL..DateFormat.SHORT. Error if out of range.
+ * @param dateTimeFormat
+ * the new dateTimeFormat to set for the the specified style
+ * @param status
+ * in/out parameter; if no failure status is already set,
+ * it will be set according to result of the function (e.g.
+ * U_ILLEGAL_ARGUMENT_ERROR for style out of range).
+ * @draft ICU 71
+ */
+ void setDateTimeFormat(UDateFormatStyle style, const UnicodeString& dateTimeFormat,
+ UErrorCode& status);
+
+ /**
+ * Getter corresponding to setDateTimeFormat.
+ *
+ * @param style
+ * one of UDAT_FULL..UDAT_SHORT. Error if out of range.
+ * @param status
+ * in/out parameter; if no failure status is already set,
+ * it will be set according to result of the function (e.g.
+ * U_ILLEGAL_ARGUMENT_ERROR for style out of range).
+ * @return
+ * the current dateTimeFormat for the the specified style, or
+ * empty string in case of error. The UnicodeString reference,
+ * or the contents of the string, may no longer be valid if
+ * setDateTimeFormat is called, or the DateTimePatternGenerator
+ * object is deleted.
+ * @draft ICU 71
+ */
+ const UnicodeString& getDateTimeFormat(UDateFormatStyle style,
+ UErrorCode& status) const;
+#endif /* U_HIDE_DRAFT_API */
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
/**
* Return the best pattern matching the input skeleton. It is guaranteed to
* have all of the fields in the skeleton.
UnicodeString appendItemFormats[UDATPG_FIELD_COUNT];
// TODO(ticket:13619): [3] -> UDATPG_WIDTH_COUNT
UnicodeString fieldDisplayNames[UDATPG_FIELD_COUNT][3];
- UnicodeString dateTimeFormat;
+ UnicodeString dateTimeFormat[4];
UnicodeString decimal;
DateTimeMatcher *skipMatcher;
Hashtable *fAvailableFormatKeyHash;
* for those two skeletons, so the result is put together with this pattern,
* resulting in "d-MMM h:mm".
*
+ * There are four DateTimeFormats in a UDateTimePatternGenerator object,
+ * corresponding to date styles UDAT_FULL..UDAT_SHORT. This method sets
+ * all of them to the specified pattern. To set them individually, see
+ * udatpg_setDateTimeFormatForStyle.
+ *
* @param dtpg a pointer to UDateTimePatternGenerator.
* @param dtFormat
* message format pattern, here {1} will be replaced by the date
/**
* Getter corresponding to setDateTimeFormat.
+ *
+ * There are four DateTimeFormats in a UDateTimePatternGenerator object,
+ * corresponding to date styles UDAT_FULL..UDAT_SHORT. This method gets
+ * the style for UDAT_MEDIUM (the default). To get them individually, see
+ * udatpg_getDateTimeFormatForStyle.
+ *
* @param dtpg a pointer to UDateTimePatternGenerator.
* @param pLength A pointer that will receive the length of the format
* @return dateTimeFormat.
udatpg_getDateTimeFormat(const UDateTimePatternGenerator *dtpg,
int32_t *pLength);
+#if !UCONFIG_NO_FORMATTING
+#ifndef U_HIDE_DRAFT_API
+/**
+ * dateTimeFormats are message patterns used to compose combinations of date
+ * and time patterns. There are four length styles, corresponding to the
+ * inferred style of the date pattern; these are UDateFormatStyle values:
+ * - UDAT_FULL (for date pattern with weekday and long month), else
+ * - UDAT_LONG (for a date pattern with long month), else
+ * - UDAT_MEDIUM (for a date pattern with abbreviated month), else
+ * - UDAT_SHORT (for any other date pattern).
+ * For details on dateTimeFormats, see
+ * https://www.unicode.org/reports/tr35/tr35-dates.html#dateTimeFormats.
+ * The default pattern in the root locale for all styles is "{1} {0}".
+ *
+ * @param udtpg
+ * a pointer to the UDateTimePatternGenerator
+ * @param style
+ * one of UDAT_FULL..UDAT_SHORT. Error if out of range.
+ * @param dateTimeFormat
+ * the new dateTimeFormat to set for the the specified style
+ * @param length
+ * the length of dateTimeFormat, or -1 if unknown and pattern
+ * is null-terminated
+ * @param pErrorCode
+ * a pointer to the UErrorCode (in/out parameter); if no failure
+ * status is already set, it will be set according to result of the
+ * function (e.g. U_ILLEGAL_ARGUMENT_ERROR for style out of range).
+ * @draft ICU 71
+ */
+U_CAPI void U_EXPORT2
+udatpg_setDateTimeFormatForStyle(UDateTimePatternGenerator *udtpg,
+ UDateFormatStyle style,
+ const UChar *dateTimeFormat, int32_t length,
+ UErrorCode *pErrorCode);
+
+/**
+ * Getter corresponding to udatpg_setDateTimeFormatForStyle.
+ *
+ * @param udtpg
+ * a pointer to the UDateTimePatternGenerator
+ * @param style
+ * one of UDAT_FULL..UDAT_SHORT. Error if out of range.
+ * @param pLength
+ * a pointer that will receive the length of the format. May be NULL
+ * if length is not desired.
+ * @param pErrorCode
+ * a pointer to the UErrorCode (in/out parameter); if no failure
+ * status is already set, it will be set according to result of the
+ * function (e.g. U_ILLEGAL_ARGUMENT_ERROR for style out of range).
+ * @return
+ * pointer to the current dateTimeFormat (0 terminated) for the specified
+ * style, or empty string in case of error. The pointer and its contents
+ * may no longer be valid if udatpg_setDateTimeFormat is called, or
+ * udatpg_setDateTimeFormatForStyle for the same style is called, or the
+ * UDateTimePatternGenerator object is closed.
+ * @draft ICU 71
+ */
+U_CAPI const UChar* U_EXPORT2
+udatpg_getDateTimeFormatForStyle(const UDateTimePatternGenerator *udtpg,
+ UDateFormatStyle style, int32_t *pLength,
+ UErrorCode *pErrorCode);
+#endif /* U_HIDE_DRAFT_API */
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
/**
* The decimal value is used in formatting fractions of seconds. If the
* skeleton contains fractional seconds, then this is used with the
{
const char* message = "Field position test 1";
- const UChar* expectedString = u"27. September 2010, 15:00 – 2. März 2011, 18:30";
+ const UChar* expectedString = u"27. September 2010 um 15:00 – 2. März 2011 um 18:30";
udtitvfmt_formatToResult(fmt, Date201009270800, Date201103021030, fdi, &ec);
assertSuccess("Formatting", &ec);
static const UFieldPositionWithCategory expectedFieldPositions[] = {
// category, field, begin index, end index
- {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 0, 0, 25},
+ {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 0, 0, 27},
{UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 0, 2},
{UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 4, 13},
{UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 14, 18},
- {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 20, 22},
- {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 23, 25},
- {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 1, 28, 47},
- {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 28, 29},
- {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 31, 35},
- {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 36, 40},
- {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 42, 44},
- {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 45, 47}};
+ {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 22, 24},
+ {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 25, 27},
+ {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 1, 30, 51},
+ {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 30, 31},
+ {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 33, 37},
+ {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 38, 42},
+ {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 46, 48},
+ {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 49, 51}};
checkMixedFormattedValue(
message,
udtitvfmt_resultAsValue(fdi, &ec),
{
const char* message = "Field position test 1";
- const UChar* expectedString = u"27. September 2010, 15:00 – 2. März 2011, 18:30";
+ const UChar* expectedString = u"27. September 2010 um 15:00 – 2. März 2011 um 18:30";
udtitvfmt_formatCalendarToResult(fmt, ucal1, ucal2, fdi, &ec);
assertSuccess("Formatting", &ec);
static const UFieldPositionWithCategory expectedFieldPositions[] = {
// category, field, begin index, end index
- {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 0, 0, 25},
+ {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 0, 0, 27},
{UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 0, 2},
{UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 4, 13},
{UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 14, 18},
- {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 20, 22},
- {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 23, 25},
- {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 1, 28, 47},
- {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 28, 29},
- {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 31, 35},
- {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 36, 40},
- {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 42, 44},
- {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 45, 47}};
+ {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 22, 24},
+ {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 25, 27},
+ {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 1, 30, 51},
+ {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 30, 31},
+ {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 33, 37},
+ {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 38, 42},
+ {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 46, 48},
+ {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 49, 51}};
checkMixedFormattedValue(
message,
udtitvfmt_resultAsValue(fdi, &ec),
ucal_setMillis(ucal5, Date158210160000, &ec);
// 1 2 3 4
// 012345678901234567890123456789012345678901234567890
- const UChar* expectedString = u"4. Oktober 1582, 00:00 – 16. Oktober 1582, 00:00";
+ const UChar* expectedString = u"4. Oktober 1582 um 00:00 – 16. Oktober 1582 um 00:00";
udtitvfmt_formatCalendarToResult(fmt, ucal4, ucal5, fdi, &ec);
assertSuccess("Formatting", &ec);
static const UFieldPositionWithCategory expectedFieldPositions[] = {
// category, field, begin index, end index
- {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 0, 0, 22},
+ {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 0, 0, 24},
{UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 0, 1},
{UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 3, 10},
{UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 11, 15},
- {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 17, 19},
- {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 20, 22},
- {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 1, 25, 48},
- {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 25, 27},
- {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 29, 36},
- {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 37, 41},
- {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 43, 45},
- {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 46, 48}};
+ {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 19, 21},
+ {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 22, 24},
+ {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 1, 27, 52},
+ {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 27, 29},
+ {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 31, 38},
+ {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 39, 43},
+ {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 47, 49},
+ {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 50, 52}};
checkMixedFormattedValue(
message,
udtitvfmt_resultAsValue(fdi, &ec),
const char* message = "Field position test 4";
// 1 2 3 4
// 012345678901234567890123456789012345678901234567890
- const UChar* expectedString = u"14. Oktober 1582, 00:00 – 16. Oktober 1582, 00:00";
+ const UChar* expectedString = u"14. Oktober 1582 um 00:00 – 16. Oktober 1582 um 00:00";
udtitvfmt_formatCalendarToResult(fmt, ucal4, ucal5, fdi, &ec);
assertSuccess("Formatting", &ec);
static const UFieldPositionWithCategory expectedFieldPositions[] = {
// category, field, begin index, end index
- {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 0, 0, 23},
+ {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 0, 0, 25},
{UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 0, 2},
{UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 4, 11},
{UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 12, 16},
- {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 18, 20},
- {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 21, 23},
- {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 1, 26, 49},
- {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 26, 28},
- {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 30, 37},
- {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 38, 42},
- {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 44, 46},
- {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 47, 49}};
+ {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 20, 22},
+ {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 23, 25},
+ {UFIELD_CATEGORY_DATE_INTERVAL_SPAN, 1, 28, 53},
+ {UFIELD_CATEGORY_DATE, UDAT_DATE_FIELD, 28, 30},
+ {UFIELD_CATEGORY_DATE, UDAT_MONTH_FIELD, 32, 39},
+ {UFIELD_CATEGORY_DATE, UDAT_YEAR_FIELD, 40, 44},
+ {UFIELD_CATEGORY_DATE, UDAT_HOUR_OF_DAY0_FIELD, 48, 50},
+ {UFIELD_CATEGORY_DATE, UDAT_MINUTE_FIELD, 51, 53}};
checkMixedFormattedValue(
message,
udtitvfmt_resultAsValue(fdi, &ec),
static void TestGetDefaultHourCycle(void);
static void TestGetDefaultHourCycleOnEmptyInstance(void);
static void TestEras(void);
+static void TestDateTimePatterns(void);
void addDateTimePatternGeneratorTest(TestNode** root) {
TESTCASE(TestOpenClose);
TESTCASE(TestGetDefaultHourCycle);
TESTCASE(TestGetDefaultHourCycleOnEmptyInstance);
TESTCASE(TestEras);
+ TESTCASE(TestDateTimePatterns);
}
/*
}
}
+enum { kNumDateTimePatterns = 4 };
+
+typedef struct {
+ const char* localeID;
+ const UChar* expectPat[kNumDateTimePatterns];
+} DTPLocaleAndResults;
+
+static void doDTPatternTest(UDateTimePatternGenerator* udtpg,
+ const UChar** skeletons,
+ DTPLocaleAndResults* localeAndResultsPtr);
+
+static void TestDateTimePatterns(void) {
+ const UChar* skeletons[kNumDateTimePatterns] = {
+ u"yMMMMEEEEdjmm", // full date, short time
+ u"yMMMMdjmm", // long date, short time
+ u"yMMMdjmm", // medium date, short time
+ u"yMdjmm" // short date, short time
+ };
+ // The following tests some locales in which there are differences between the
+ // DateTimePatterns of various length styles.
+ DTPLocaleAndResults localeAndResults[] = {
+ { "en", { u"EEEE, MMMM d, y 'at' h:mm a", // long != medium
+ u"MMMM d, y 'at' h:mm a",
+ u"MMM d, y, h:mm a",
+ u"M/d/y, h:mm a" } },
+ { "fr", { u"EEEE d MMMM y 'à' HH:mm", // medium != short
+ u"d MMMM y 'à' HH:mm",
+ u"d MMM y, HH:mm",
+ u"dd/MM/y HH:mm" } },
+ { "ha", { u"EEEE d MMMM, y HH:mm", // full != long
+ u"d MMMM, y 'da' HH:mm",
+ u"d MMM, y, HH:mm",
+ u"y-MM-dd, HH:mm" } },
+ { NULL, { NULL, NULL, NULL, NULL } } // terminator
+ };
+
+ const UChar* enDTPatterns[kNumDateTimePatterns] = {
+ u"{1} 'at' {0}",
+ u"{1} 'at' {0}",
+ u"{1}, {0}",
+ u"{1}, {0}"
+ };
+ const UChar* modDTPatterns[kNumDateTimePatterns] = {
+ u"{1} _0_ {0}",
+ u"{1} _1_ {0}",
+ u"{1} _2_ {0}",
+ u"{1} _3_ {0}"
+ };
+ DTPLocaleAndResults enModResults = { "en", { u"EEEE, MMMM d, y _0_ h:mm a",
+ u"MMMM d, y _1_ h:mm a",
+ u"MMM d, y _2_ h:mm a",
+ u"M/d/y _3_ h:mm a" }
+ };
+
+ // Test various locales with standard data
+ UErrorCode status;
+ UDateTimePatternGenerator* udtpg;
+ DTPLocaleAndResults* localeAndResultsPtr = localeAndResults;
+ for (; localeAndResultsPtr->localeID != NULL; localeAndResultsPtr++) {
+ status = U_ZERO_ERROR;
+ udtpg = udatpg_open(localeAndResultsPtr->localeID, &status);
+ if (U_FAILURE(status)) {
+ log_data_err("FAIL: udatpg_open for locale %s: %s", localeAndResultsPtr->localeID, myErrorName(status));
+ } else {
+ doDTPatternTest(udtpg, skeletons, localeAndResultsPtr);
+ udatpg_close(udtpg);
+ }
+ }
+ // Test getting and modifying date-time combining patterns
+ status = U_ZERO_ERROR;
+ udtpg = udatpg_open("en", &status);
+ if (U_FAILURE(status)) {
+ log_data_err("FAIL: udatpg_open #2 for locale en: %s", myErrorName(status));
+ } else {
+ char bExpect[64];
+ char bGet[64];
+ const UChar* uGet;
+ int32_t uGetLen, uExpectLen;
+
+ // Test error: style out of range
+ status = U_ZERO_ERROR;
+ uGet = udatpg_getDateTimeFormatForStyle(udtpg, UDAT_NONE, &uGetLen, &status);
+ if (status != U_ILLEGAL_ARGUMENT_ERROR || uGetLen != 0 || uGet==NULL || *uGet!= 0) {
+ if (uGet==NULL) {
+ log_err("FAIL: udatpg_getDateTimeFormatForStyle with invalid style, expected U_ILLEGAL_ARGUMENT_ERROR "
+ "and ptr to empty string but got %s, len %d, ptr = NULL\n", myErrorName(status), uGetLen);
+ } else {
+ log_err("FAIL: udatpg_getDateTimeFormatForStyle with invalid style, expected U_ILLEGAL_ARGUMENT_ERROR "
+ "and ptr to empty string but got %s, len %d, *ptr = %04X\n", myErrorName(status), uGetLen, *uGet);
+ }
+ }
+
+ // Test normal getting and setting
+ for (int32_t patStyle = 0; patStyle < kNumDateTimePatterns; patStyle++) {
+ status = U_ZERO_ERROR;
+ uExpectLen = u_strlen(enDTPatterns[patStyle]);
+ uGet = udatpg_getDateTimeFormatForStyle(udtpg, patStyle, &uGetLen, &status);
+ if (U_FAILURE(status)) {
+ log_err("FAIL udatpg_getDateTimeFormatForStyle %d (en before mod), get %s\n", patStyle, myErrorName(status));
+ } else if (uGetLen != uExpectLen || u_strncmp(uGet, enDTPatterns[patStyle], uExpectLen) != 0) {
+ u_austrcpy(bExpect, enDTPatterns[patStyle]);
+ u_austrcpy(bGet, uGet);
+ log_err("ERROR udatpg_getDateTimeFormatForStyle %d (en before mod), expect %d:\"%s\", get %d:\"%s\"\n",
+ patStyle, uExpectLen, bExpect, uGetLen, bGet);
+ }
+ status = U_ZERO_ERROR;
+ udatpg_setDateTimeFormatForStyle(udtpg, patStyle, modDTPatterns[patStyle], -1, &status);
+ if (U_FAILURE(status)) {
+ log_err("FAIL udatpg_setDateTimeFormatForStyle %d (en), get %s\n", patStyle, myErrorName(status));
+ } else {
+ uExpectLen = u_strlen(modDTPatterns[patStyle]);
+ uGet = udatpg_getDateTimeFormatForStyle(udtpg, patStyle, &uGetLen, &status);
+ if (U_FAILURE(status)) {
+ log_err("FAIL udatpg_getDateTimeFormatForStyle %d (en after mod), get %s\n", patStyle, myErrorName(status));
+ } else if (uGetLen != uExpectLen || u_strncmp(uGet, modDTPatterns[patStyle], uExpectLen) != 0) {
+ u_austrcpy(bExpect, modDTPatterns[patStyle]);
+ u_austrcpy(bGet, uGet);
+ log_err("ERROR udatpg_getDateTimeFormatForStyle %d (en after mod), expect %d:\"%s\", get %d:\"%s\"\n",
+ patStyle, uExpectLen, bExpect, uGetLen, bGet);
+ }
+ }
+ }
+ // Test result of setting
+ doDTPatternTest(udtpg, skeletons, &enModResults);
+ // Test old get/set functions
+ uExpectLen = u_strlen(modDTPatterns[UDAT_MEDIUM]);
+ uGet = udatpg_getDateTimeFormat(udtpg, &uGetLen);
+ if (uGetLen != uExpectLen || u_strncmp(uGet, modDTPatterns[UDAT_MEDIUM], uExpectLen) != 0) {
+ u_austrcpy(bExpect, modDTPatterns[UDAT_MEDIUM]);
+ u_austrcpy(bGet, uGet);
+ log_err("ERROR udatpg_getDateTimeFormat (en after mod), expect %d:\"%s\", get %d:\"%s\"\n",
+ uExpectLen, bExpect, uGetLen, bGet);
+ }
+ udatpg_setDateTimeFormat(udtpg, modDTPatterns[UDAT_SHORT], -1); // set all dateTimePatterns to the short format
+ uExpectLen = u_strlen(modDTPatterns[UDAT_SHORT]);
+ u_austrcpy(bExpect, modDTPatterns[UDAT_SHORT]);
+ for (int32_t patStyle = 0; patStyle < kNumDateTimePatterns; patStyle++) {
+ status = U_ZERO_ERROR;
+ uGet = udatpg_getDateTimeFormatForStyle(udtpg, patStyle, &uGetLen, &status);
+ if (U_FAILURE(status)) {
+ log_err("FAIL udatpg_getDateTimeFormatForStyle %d (en after second mod), get %s\n", patStyle, myErrorName(status));
+ } else if (uGetLen != uExpectLen || u_strncmp(uGet, modDTPatterns[UDAT_SHORT], uExpectLen) != 0) {
+ u_austrcpy(bGet, uGet);
+ log_err("ERROR udatpg_getDateTimeFormatForStyle %d (en after second mod), expect %d:\"%s\", get %d:\"%s\"\n",
+ patStyle, uExpectLen, bExpect, uGetLen, bGet);
+ }
+ }
+
+ udatpg_close(udtpg);
+ }
+}
+
+static void doDTPatternTest(UDateTimePatternGenerator* udtpg,
+ const UChar** skeletons,
+ DTPLocaleAndResults* localeAndResultsPtr) {
+ for (int32_t patStyle = 0; patStyle < kNumDateTimePatterns; patStyle++) {
+ UChar uGet[64];
+ int32_t uGetLen, uExpectLen;
+ UErrorCode status = U_ZERO_ERROR;
+ uExpectLen = u_strlen(localeAndResultsPtr->expectPat[patStyle]);
+ uGetLen = udatpg_getBestPattern(udtpg, skeletons[patStyle], -1, uGet, 64, &status);
+ if (U_FAILURE(status)) {
+ log_err("FAIL udatpg_getBestPattern locale %s style %d: %s\n", localeAndResultsPtr->localeID, patStyle, myErrorName(status));
+ } else if (uGetLen != uExpectLen || u_strncmp(uGet, localeAndResultsPtr->expectPat[patStyle], uExpectLen) != 0) {
+ char bExpect[64];
+ char bGet[64];
+ u_austrcpy(bExpect, localeAndResultsPtr->expectPat[patStyle]);
+ u_austrcpy(bGet, uGet);
+ log_err("ERROR udatpg_getBestPattern locale %s style %d, expect %d:\"%s\", get %d:\"%s\"\n",
+ localeAndResultsPtr->localeID, patStyle, uExpectLen, bExpect, uGetLen, bGet);
+ }
+ }
+}
+
#endif
{UDAT_ABBR_UTC_TZ, "ZZZZ", "en", "ZZZZ"},
{UDAT_YEAR_NUM_MONTH_DAY UDAT_ABBR_UTC_TZ, "yMdZZZZ", "en", "M/d/y, ZZZZ"},
- {UDAT_MONTH_DAY UDAT_LOCATION_TZ, "MMMMdVVVV", "en", "MMMM d, VVVV"}
+ {UDAT_MONTH_DAY UDAT_LOCATION_TZ, "MMMMdVVVV", "en", "MMMM d 'at' VVVV"}
};
IcuTestErrorCode errorCode(*this, "TestPatterns()");
TESTCASE(10, testGetDefaultHourCycle_OnEmptyInstance);
TESTCASE(11, test_jConsistencyOddLocales);
TESTCASE(12, testBestPattern);
+ TESTCASE(13, testDateTimePatterns);
default: name = ""; break;
}
}
format->applyPattern(gen->getBestPattern(UnicodeString("MMMMdHmm"), status));
dateReturned.remove();
dateReturned = format->format(sampleDate, dateReturned, status);
- expectedResult=UnicodeString("14. von Oktober, 08:58", -1, US_INV);
+ expectedResult=UnicodeString("14. von Oktober um 08:58", -1, US_INV);
if ( dateReturned != expectedResult ) {
errln(UnicodeString("ERROR: Simple test addPattern failed!: d\'. von\' MMMM Got: ") + dateReturned + UnicodeString(" Expected: ") + expectedResult);
}
}
}
+void IntlTestDateTimePatternGeneratorAPI::testDateTimePatterns() {
+ UnicodeString skeletons[kNumDateTimePatterns] = {
+ UnicodeString("yMMMMEEEEdjmm"), // full date, short time
+ UnicodeString("yMMMMdjmm"), // long date, short time
+ UnicodeString("yMMMdjmm"), // medium date, short time
+ UnicodeString("yMdjmm") // short date, short time
+ };
+ // The following tests some locales in which there are differences between the
+ // DateTimePatterns of various length styles.
+ DTPLocaleAndResults localeAndResults[] = {
+ { "en", { UnicodeString(u"EEEE, MMMM d, y 'at' h:mm a"), // long != medium
+ UnicodeString(u"MMMM d, y 'at' h:mm a"),
+ UnicodeString(u"MMM d, y, h:mm a"),
+ UnicodeString(u"M/d/y, h:mm a") } },
+ { "fr", { UnicodeString(u"EEEE d MMMM y 'à' HH:mm"), // medium != short
+ UnicodeString(u"d MMMM y 'à' HH:mm"),
+ UnicodeString(u"d MMM y, HH:mm"),
+ UnicodeString(u"dd/MM/y HH:mm") } },
+ { "ha", { UnicodeString(u"EEEE d MMMM, y HH:mm"), // full != long
+ UnicodeString(u"d MMMM, y 'da' HH:mm"),
+ UnicodeString(u"d MMM, y, HH:mm"),
+ UnicodeString(u"y-MM-dd, HH:mm") } },
+ { nullptr, { UnicodeString(""), UnicodeString(""), // terminator
+ UnicodeString(""), UnicodeString("") } },
+ };
+
+ UnicodeString enDTPatterns[kNumDateTimePatterns] = {
+ UnicodeString(u"{1} 'at' {0}"),
+ UnicodeString(u"{1} 'at' {0}"),
+ UnicodeString(u"{1}, {0}"),
+ UnicodeString(u"{1}, {0}")
+ };
+ UnicodeString modDTPatterns[kNumDateTimePatterns] = {
+ UnicodeString(u"{1} _0_ {0}"),
+ UnicodeString(u"{1} _1_ {0}"),
+ UnicodeString(u"{1} _2_ {0}"),
+ UnicodeString(u"{1} _3_ {0}")
+ };
+ DTPLocaleAndResults enModResults = { "en", { UnicodeString(u"EEEE, MMMM d, y _0_ h:mm a"),
+ UnicodeString(u"MMMM d, y _1_ h:mm a"),
+ UnicodeString(u"MMM d, y _2_ h:mm a"),
+ UnicodeString(u"M/d/y _3_ h:mm a") }
+ };
+
+ // Test various locales with standard data
+ UErrorCode status;
+ LocalPointer<DateTimePatternGenerator> dtpg;
+ DTPLocaleAndResults* localeAndResultsPtr = localeAndResults;
+ for (; localeAndResultsPtr->localeID != nullptr; localeAndResultsPtr++) {
+ status = U_ZERO_ERROR;
+ Locale locale(localeAndResultsPtr->localeID);
+ dtpg.adoptInstead(DateTimePatternGenerator::createInstance(locale, status));
+ if (U_FAILURE(status)) {
+ dataerrln("FAIL: DateTimePatternGenerator::createInstance for locale %s: %s",
+ localeAndResultsPtr->localeID, u_errorName(status));
+ } else {
+ doDTPatternTest(dtpg.getAlias(), skeletons, localeAndResultsPtr);
+ }
+ }
+ // Test getting and modifying date-time combining patterns
+ status = U_ZERO_ERROR;
+ dtpg.adoptInstead(DateTimePatternGenerator::createInstance(Locale::getEnglish(), status));
+ if (U_FAILURE(status)) {
+ dataerrln("FAIL: DateTimePatternGenerator::createInstance #2 for locale en: %s", u_errorName(status));
+ } else {
+ char bExpect[64];
+ char bGet[64];
+ // Test style out of range
+ status = U_ZERO_ERROR;
+ const UnicodeString& dtFormat0 = dtpg->getDateTimeFormat(UDAT_NONE, status);
+ int32_t dtFormat0Len = dtFormat0.length();
+ if (status != U_ILLEGAL_ARGUMENT_ERROR || dtFormat0Len != 0) {
+ errln("ERROR: getDateTimeFormat with invalid style, expected U_ILLEGAL_ARGUMENT_ERROR and lero-length string, "
+ "got %s with length %d", u_errorName(status), dtFormat0Len);
+ }
+ // Test normal getting and setting
+ for (int32_t patStyle = 0; patStyle < kNumDateTimePatterns; patStyle++) {
+ status = U_ZERO_ERROR;
+ const UnicodeString& dtFormat1 = dtpg->getDateTimeFormat((UDateFormatStyle)patStyle, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getDateTimeFormat for en before mod, style %d, get %s", patStyle, u_errorName(status));
+ } else if (dtFormat1 != enDTPatterns[patStyle]) {
+ enDTPatterns[patStyle].extract(0, enDTPatterns[patStyle].length(), bExpect, 64);
+ dtFormat1.extract(0, dtFormat1.length(), bGet, 64);
+ errln("ERROR: getDateTimeFormat for en before mod, style %d, expect \"%s\", get \"%s\"",
+ patStyle, bExpect, bGet);
+ }
+ status = U_ZERO_ERROR;
+ dtpg->setDateTimeFormat((UDateFormatStyle)patStyle, modDTPatterns[patStyle], status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: setDateTimeFormat for en, style %d, get %s", patStyle, u_errorName(status));
+ } else {
+ const UnicodeString& dtFormat2 = dtpg->getDateTimeFormat((UDateFormatStyle)patStyle, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getDateTimeFormat for en after mod, style %d, get %s", patStyle, u_errorName(status));
+ } else if (dtFormat2 != modDTPatterns[patStyle]) {
+ modDTPatterns[patStyle].extract(0, modDTPatterns[patStyle].length(), bExpect, 64);
+ dtFormat2.extract(0, dtFormat2.length(), bGet, 64);
+ errln("ERROR: getDateTimeFormat for en after mod, style %d, expect \"%s\", get \"%s\"",
+ patStyle, bExpect, bGet);
+ }
+ }
+ }
+ // Test result of setting
+ doDTPatternTest(dtpg.getAlias(), skeletons, &enModResults);
+ // Test old get/set functions
+ const UnicodeString& dtFormat3 = dtpg->getDateTimeFormat();
+ if (dtFormat3 != modDTPatterns[UDAT_MEDIUM]) {
+ modDTPatterns[UDAT_MEDIUM].extract(0, modDTPatterns[UDAT_MEDIUM].length(), bExpect, 64);
+ dtFormat3.extract(0, dtFormat3.length(), bGet, 64);
+ errln("ERROR: old getDateTimeFormat for en after mod, expect \"%s\", get \"%s\"", bExpect, bGet);
+ }
+ dtpg->setDateTimeFormat(modDTPatterns[UDAT_SHORT]); // set all dateTimePatterns to the short format
+ modDTPatterns[UDAT_SHORT].extract(0, modDTPatterns[UDAT_SHORT].length(), bExpect, 64);
+ for (int32_t patStyle = 0; patStyle < kNumDateTimePatterns; patStyle++) {
+ status = U_ZERO_ERROR;
+ const UnicodeString& dtFormat4 = dtpg->getDateTimeFormat((UDateFormatStyle)patStyle, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getDateTimeFormat for en after second mod, style %d, get %s", patStyle, u_errorName(status));
+ } else if (dtFormat4 != modDTPatterns[UDAT_SHORT]) {
+ dtFormat4.extract(0, dtFormat4.length(), bGet, 64);
+ errln("ERROR: getDateTimeFormat for en after second mod, style %d, expect \"%s\", get \"%s\"",
+ patStyle, bExpect, bGet);
+ }
+ }
+ }
+}
+
+void IntlTestDateTimePatternGeneratorAPI::doDTPatternTest(DateTimePatternGenerator* dtpg, UnicodeString* skeletons, DTPLocaleAndResults* localeAndResultsPtr) {
+ for (int32_t patStyle = 0; patStyle < kNumDateTimePatterns; patStyle++) {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString getPat = dtpg->getBestPattern(skeletons[patStyle], UDATPG_MATCH_NO_OPTIONS, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: DateTimePatternGenerator::getBestPattern locale %s, style %d: %s",
+ localeAndResultsPtr->localeID, patStyle, u_errorName(status));
+ } else if (getPat != localeAndResultsPtr->expectPat[patStyle]) {
+ char bExpect[64];
+ char bGet[64];
+ localeAndResultsPtr->expectPat[patStyle].extract(0, localeAndResultsPtr->expectPat[patStyle].length(), bExpect, 64);
+ getPat.extract(0, getPat.length(), bGet, 64);
+ errln("ERROR: DateTimePatternGenerator::getBestPattern locale %s, style %d, expect \"%s\", get \"%s\"",
+ localeAndResultsPtr->localeID, patStyle, bExpect, bGet);
+ }
+ }
+}
+
#endif /* #if !UCONFIG_NO_FORMATTING */
#if !UCONFIG_NO_FORMATTING
+#include "unicode/dtptngen.h"
+#include "unicode/ustring.h"
#include "intltest.h"
/**
void testGetDefaultHourCycle_OnEmptyInstance();
void test_jConsistencyOddLocales();
void testBestPattern();
+ void testDateTimePatterns();
+
+ enum { kNumDateTimePatterns = 4 };
+ typedef struct {
+ const char* localeID;
+ const UnicodeString expectPat[kNumDateTimePatterns];
+ } DTPLocaleAndResults;
+ void doDTPatternTest(DateTimePatternGenerator* dtpg, UnicodeString* skeletons, DTPLocaleAndResults* localeAndResultsPtr);
};
#endif /* #if !UCONFIG_NO_FORMATTING */
UDate date = LocaleTest::date(2021-1900, UCAL_NOVEMBER, 23, 16, 42, 55);
doTheRealDateTimeSkeletonTesting(date, u"{0,date,::MMMMd}", "en", u"November 23", status);
- doTheRealDateTimeSkeletonTesting(date, u"{0,date,::yMMMMdjm}", "en", u"November 23, 2021, 4:42 PM", status);
+ doTheRealDateTimeSkeletonTesting(date, u"{0,date,::yMMMMdjm}", "en", u"November 23, 2021 at 4:42 PM", status);
doTheRealDateTimeSkeletonTesting(date, u"{0,date, :: yMMMMd }", "en", u"November 23, 2021", status);
doTheRealDateTimeSkeletonTesting(date, u"{0,date,::yMMMMd}", "fr", u"23 novembre 2021", status);
doTheRealDateTimeSkeletonTesting(date, u"Expiration: {0,date,::yMMM}!", "en", u"Expiration: Nov 2021!", status);
UDate date = LocaleTest::date(2021-1900, UCAL_NOVEMBER, 23, 16, 42, 55);
doTheRealDateTimeSkeletonTesting(date, u"{0,time,::MMMMd}", "en", u"November 23", status);
- doTheRealDateTimeSkeletonTesting(date, u"{0,time,::yMMMMdjm}", "en", u"November 23, 2021, 4:42 PM", status);
+ doTheRealDateTimeSkeletonTesting(date, u"{0,time,::yMMMMdjm}", "en", u"November 23, 2021 at 4:42 PM", status);
doTheRealDateTimeSkeletonTesting(date, u"{0,time, :: yMMMMd }", "en", u"November 23, 2021", status);
doTheRealDateTimeSkeletonTesting(date, u"{0,time,::yMMMMd}", "fr", u"23 novembre 2021", status);
doTheRealDateTimeSkeletonTesting(date, u"Expiration: {0,time,::yMMM}!", "en", u"Expiration: Nov 2021!", status);
}
private void setDateTimeFromCalendar(ULocale uLocale) {
- String dateTimeFormat = Calendar.getDateTimePattern(Calendar.getInstance(uLocale), uLocale, DateFormat.MEDIUM);
- setDateTimeFormat(dateTimeFormat);
+ Calendar cal = Calendar.getInstance(uLocale);
+ for (int style = DateFormat.FULL; style <= DateFormat.SHORT; style++) {
+ String dateTimeFormat = Calendar.getDateTimePattern(cal, uLocale, style);
+ setDateTimeFormat(style, dateTimeFormat);
+ }
}
private void setDecimalSymbols(ULocale uLocale) {
if (datePattern == null) return timePattern == null ? "" : timePattern;
if (timePattern == null) return datePattern;
+ // determine which dateTimeFormat to use
+ String canonicalSkeleton = current.toCanonicalString(); // month fields use M, weekday fields use E
+ int style = DateFormat.SHORT;
+ int monthFieldLen = 0;
+ int monthFieldOffset = canonicalSkeleton.indexOf('M');
+ if (monthFieldOffset >= 0) {
+ monthFieldLen = 1 + canonicalSkeleton.lastIndexOf('M') - monthFieldOffset;
+ }
+ if (monthFieldLen == 4) {
+ if (canonicalSkeleton.indexOf('E') >= 0) {
+ style = DateFormat.FULL;
+ } else {
+ style = DateFormat.LONG;
+ }
+ } else if (monthFieldLen == 3) {
+ style = DateFormat.MEDIUM;
+ }
+ // and now use it to compose date and time
return SimpleFormatterImpl.formatRawPattern(
- getDateTimeFormat(), 2, 2, timePattern, datePattern);
+ getDateTimeFormat(style), 2, 2, timePattern, datePattern);
}
/*
* for those two skeletons, so the result is put together with this pattern,
* resulting in "d-MMM h:mm".
*
+ * There are four DateTimeFormats in a DateTimePatternGenerator object,
+ * corresponding to date styles DateFormat.FULL..DateFormat.SHORT. This method sets
+ * all of them to the specified pattern. To set them individually, see
+ * setDateTimeFormat(int style, ...).
+ *
* @param dateTimeFormat message format pattern, where {1} will be replaced by the date
* pattern and {0} will be replaced by the time pattern.
* @stable ICU 3.6
*/
public void setDateTimeFormat(String dateTimeFormat) {
checkFrozen();
- this.dateTimeFormat = dateTimeFormat;
+ for (int style = DateFormat.FULL; style <= DateFormat.SHORT; style++) {
+ setDateTimeFormat(style, dateTimeFormat);
+ }
}
/**
* Getter corresponding to setDateTimeFormat.
*
+ * There are four DateTimeFormats in a DateTimePatternGenerator object,
+ * corresponding to date styles DateFormat.FULL..DateFormat.SHORT. This method gets
+ * the style for DateFormat.MEDIUM (the default). To get them individually, see
+ * getDateTimeFormat(int style).
+ *
* @return pattern
* @stable ICU 3.6
*/
public String getDateTimeFormat() {
- return dateTimeFormat;
+ return getDateTimeFormat(DateFormat.MEDIUM);
+ }
+
+ /**
+ * dateTimeFormats are message patterns used to compose combinations of date
+ * and time patterns. There are four length styles, corresponding to the
+ * inferred style of the date pattern:
+ * - DateFormat.FULL (for date pattern with weekday and long month), else
+ * - DateFormat.LONG (for a date pattern with long month), else
+ * - DateFormat.MEDIUM (for a date pattern with abbreviated month), else
+ * - DateFormat.SHORT (for any other date pattern).
+ * For details on dateTimeFormats, see
+ * https://www.unicode.org/reports/tr35/tr35-dates.html#dateTimeFormats.
+ * The default pattern in the root locale for all styles is "{1} {0}".
+ *
+ * @param style
+ * one of DateFormat.FULL..DateFormat.SHORT. An exception will
+ * be thrown if out of range.
+ * @param dateTimeFormat
+ * the new dateTimeFormat to set for the specified style
+ * @draft ICU 71
+ */
+ public void setDateTimeFormat(int style, String dateTimeFormat) {
+ if (style < DateFormat.FULL || style > DateFormat.SHORT) {
+ throw new IllegalArgumentException("Illegal style here: " + style);
+ }
+ checkFrozen();
+ this.dateTimeFormats[style] = dateTimeFormat;
+ }
+
+ /**
+ * Getter corresponding to setDateTimeFormat.
+ *
+ * @param style
+ * one of DateFormat.FULL..DateFormat.SHORT. An exception will
+ * be thrown if out of range.
+ * @return
+ * the current dateTimeFormat for the specified style.
+ * @draft ICU 71
+ */
+ public String getDateTimeFormat(int style) {
+ if (style < DateFormat.FULL || style > DateFormat.SHORT) {
+ throw new IllegalArgumentException("Illegal style here: " + style);
+ }
+ return dateTimeFormats[style];
}
/**
DateTimePatternGenerator result = (DateTimePatternGenerator) (super.clone());
result.skeleton2pattern = (TreeMap<DateTimeMatcher, PatternWithSkeletonFlag>) skeleton2pattern.clone();
result.basePattern_pattern = (TreeMap<String, PatternWithSkeletonFlag>) basePattern_pattern.clone();
+ result.dateTimeFormats = dateTimeFormats.clone();
result.appendItemFormats = appendItemFormats.clone();
result.fieldDisplayNames = fieldDisplayNames.clone();
result.current = new DateTimeMatcher();
private TreeMap<DateTimeMatcher, PatternWithSkeletonFlag> skeleton2pattern = new TreeMap<>(); // items are in priority order
private TreeMap<String, PatternWithSkeletonFlag> basePattern_pattern = new TreeMap<>(); // items are in priority order
private String decimal = "?";
- private String dateTimeFormat = "{1} {0}";
+ // For the following, need fallback patterns in case an empty instance
+ // of DateTimePatterngenerator is used for formatting.
+ private String[] dateTimeFormats = {
+ "{1} {0}",
+ "{1} {0}",
+ "{1} {0}",
+ "{1} {0}"
+ };
private String[] appendItemFormats = new String[TYPE_LIMIT];
private String[][] fieldDisplayNames = new String[TYPE_LIMIT][DisplayWidth.COUNT];
private char defaultHourFormatChar = 'H';
{}, // marker for starting combinations
{DateFormat.YEAR_NUM_MONTH_DAY + DateFormat.ABBR_UTC_TZ, "yMdZZZZ", "en", "M/d/y, ZZZZ"},
- {DateFormat.MONTH_DAY + DateFormat.LOCATION_TZ, "MMMMdVVVV", "en", "MMMM d, VVVV"},
+ {DateFormat.MONTH_DAY + DateFormat.LOCATION_TZ, "MMMMdVVVV", "en", "MMMM d 'at' VVVV"},
};
Date testDate = new Date(2012-1900, 6, 1, 14, 58, 59); // just for verbose log
gen.addPattern("d'. von' MMMM", true, returnInfo);
// the returnInfo is mostly useful for debugging problem cases
format.applyPattern(gen.getBestPattern("MMMMdHmm"));
- assertEquals("modified format: MMMdHmm", "14. von Oktober, 08:58", format.format(sampleDate));
+ assertEquals("modified format: MMMMdHmm", "14. von Oktober um 08:58", format.format(sampleDate));
// get a pattern and modify it
format = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, locale);
}
}
}
+
+ private final static int NUM_DATE_TIME_PATTERNS = 4;
+
+ private final class DTPLocaleAndResults {
+ public String localeID;
+ public String[] expectPat;
+ // Simple constructor
+ public DTPLocaleAndResults(String locID, String[] exPat) {
+ localeID = locID;
+ expectPat = exPat;
+ }
+ }
+
+ @Test
+ public void testDateTimePatterns() {
+ String[] skeletons = {
+ "yMMMMEEEEdjmm", // full date, short time
+ "yMMMMdjmm", // long date, short time
+ "yMMMdjmm", // medium date, short time
+ "yMdjmm", // short date, short time
+ };
+ // The following tests some locales in which there are differences between the
+ // DateTimePatterns of various length styles.
+ final DTPLocaleAndResults[] localeAndResults = {
+ new DTPLocaleAndResults( "en", new String[]{ // long != medium
+ "EEEE, MMMM d, y 'at' h:mm a",
+ "MMMM d, y 'at' h:mm a",
+ "MMM d, y, h:mm a",
+ "M/d/y, h:mm a" } ),
+ new DTPLocaleAndResults( "fr", new String[]{ // medium != short
+ "EEEE d MMMM y 'à' HH:mm",
+ "d MMMM y 'à' HH:mm",
+ "d MMM y, HH:mm",
+ "dd/MM/y HH:mm" } ),
+ new DTPLocaleAndResults( "ha", new String[]{ // full != long
+ "EEEE d MMMM, y HH:mm",
+ "d MMMM, y 'da' HH:mm",
+ "d MMM, y, HH:mm",
+ "y-MM-dd, HH:mm" } ),
+ };
+
+ String[] enDTPatterns = {
+ "{1} 'at' {0}",
+ "{1} 'at' {0}",
+ "{1}, {0}",
+ "{1}, {0}",
+ };
+ String[] modDTPatterns = {
+ "{1} _0_ {0}",
+ "{1} _1_ {0}",
+ "{1} _2_ {0}",
+ "{1} _3_ {0}",
+ };
+ final DTPLocaleAndResults enModResults =
+ new DTPLocaleAndResults( "en", new String[]{
+ "EEEE, MMMM d, y _0_ h:mm a",
+ "MMMM d, y _1_ h:mm a",
+ "MMM d, y _2_ h:mm a",
+ "M/d/y _3_ h:mm a" } );
+
+ // Test various locales with standard data
+ DateTimePatternGenerator dtpg;
+ for (DTPLocaleAndResults localeAndResultItem: localeAndResults) {
+ dtpg = DateTimePatternGenerator.getInstance(new Locale(localeAndResultItem.localeID));
+ doDTPatternTest(dtpg, skeletons, localeAndResultItem);
+ }
+ // Test getting and modifying date-time combining patterns
+ dtpg = DateTimePatternGenerator.getInstance(ULocale.ENGLISH);
+ // Test style out of range
+ String dtFormat0 = "";
+ boolean gotException = false;
+ try {
+ dtFormat0 = dtpg.getDateTimeFormat(DateFormat.NONE);
+ } catch(IllegalArgumentException e) {
+ gotException = true;
+ }
+ if (!gotException) {
+ errln("ERROR: getDateTimeFormat with invalid style, expected IllegalArgumentException but got format \""
+ + dtFormat0 + "\"");
+ }
+ // Test normal getting and setting
+ for (int patStyle = 0; patStyle < NUM_DATE_TIME_PATTERNS; patStyle++) {
+ String dtFormat1 = dtpg.getDateTimeFormat(patStyle);
+ if (!dtFormat1.equals(enDTPatterns[patStyle])) {
+ errln("ERROR: getDateTimeFormat for en before mod, style " + patStyle +
+ ", expect \"" + enDTPatterns[patStyle] + "\", get \"" + dtFormat1 + "\"");
+ }
+ dtpg.setDateTimeFormat(patStyle, modDTPatterns[patStyle]);
+ String dtFormat2 = dtpg.getDateTimeFormat(patStyle);
+ if (!dtFormat2.equals(modDTPatterns[patStyle])) {
+ errln("ERROR: getDateTimeFormat for en after mod, style " + patStyle +
+ ", expect \"" + modDTPatterns[patStyle] + "\", get \"" + dtFormat2 + "\"");
+ }
+ }
+ // Test result of setting
+ doDTPatternTest(dtpg, skeletons, enModResults);
+ // Test old get/set functions
+ String dtFormat3 = dtpg.getDateTimeFormat();
+ if (!dtFormat3.equals(modDTPatterns[DateFormat.MEDIUM])) {
+ errln("ERROR: old getDateTimeFormat for en before mod, expect \"" +
+ modDTPatterns[DateFormat.MEDIUM] + "\", get \"" + dtFormat3 + "\"");
+ }
+ dtpg.setDateTimeFormat(modDTPatterns[DateFormat.SHORT]); // set all dateTimePatterns to the short format
+ for (int patStyle = 0; patStyle < NUM_DATE_TIME_PATTERNS; patStyle++) {
+ String dtFormat4 = dtpg.getDateTimeFormat(patStyle);
+ if (!dtFormat4.equals(modDTPatterns[DateFormat.SHORT])) {
+ errln("ERROR: getDateTimeFormat for en after second mod, style " + patStyle +
+ ", expect \"" + modDTPatterns[DateFormat.SHORT] + "\", get \"" + dtFormat4 + "\"");
+ }
+ }
+ }
+
+ private void doDTPatternTest(DateTimePatternGenerator dtpg, String[] skeletons, DTPLocaleAndResults localeAndResultItem) {
+ for (int patStyle = 0; patStyle < NUM_DATE_TIME_PATTERNS; patStyle++) {
+ String getPat = dtpg.getBestPattern(skeletons[patStyle]);
+ if (!getPat.equals(localeAndResultItem.expectPat[patStyle])) {
+ errln("ERROR: getBestPattern locale " + localeAndResultItem.localeID + ", style " + patStyle +
+ ", expect \"" + localeAndResultItem.expectPat[patStyle] + "\", get \"" + getPat + "\"");
+ }
+ }
+ }
}
Date date = new GregorianCalendar(2021, Calendar.NOVEMBER, 23, 16, 42, 55).getTime();
doTheRealDateTimeSkeletonTesting(date, "{0,date,::MMMMd}", ULocale.ENGLISH, "November 23");
- doTheRealDateTimeSkeletonTesting(date, "{0,date,::yMMMMdjm}", ULocale.ENGLISH, "November 23, 2021, 4:42 PM");
+ doTheRealDateTimeSkeletonTesting(date, "{0,date,::yMMMMdjm}", ULocale.ENGLISH, "November 23, 2021 at 4:42 PM");
doTheRealDateTimeSkeletonTesting(date, "{0,date, :: yMMMMd }", ULocale.ENGLISH, "November 23, 2021");
doTheRealDateTimeSkeletonTesting(date, "{0,date,::yMMMMd}", ULocale.FRENCH, "23 novembre 2021");
doTheRealDateTimeSkeletonTesting(date, "Expiration: {0,date,::yMMM}!", ULocale.ENGLISH, "Expiration: Nov 2021!");
Date date = new GregorianCalendar(2021, Calendar.NOVEMBER, 23, 16, 42, 55).getTime();
doTheRealDateTimeSkeletonTesting(date, "{0,time,::MMMMd}", ULocale.ENGLISH, "November 23");
- doTheRealDateTimeSkeletonTesting(date, "{0,time,::yMMMMdjm}", ULocale.ENGLISH, "November 23, 2021, 4:42 PM");
+ doTheRealDateTimeSkeletonTesting(date, "{0,time,::yMMMMdjm}", ULocale.ENGLISH, "November 23, 2021 at 4:42 PM");
doTheRealDateTimeSkeletonTesting(date, "{0,time, :: yMMMMd }", ULocale.ENGLISH, "November 23, 2021");
doTheRealDateTimeSkeletonTesting(date, "{0,time,::yMMMMd}", ULocale.FRENCH, "23 novembre 2021");
doTheRealDateTimeSkeletonTesting(date, "Expiration: {0,time,::yMMM}!", ULocale.ENGLISH, "Expiration: Nov 2021!");