return s;
}
+int32_t
+PatternProps::skipWhiteSpace(const UnicodeString& s, int32_t start) {
+ int32_t i = start;
+ int32_t length = s.length();
+ while(i<length && isWhiteSpace(s.charAt(i))) {
+ ++i;
+ }
+ return i;
+}
+
const UChar *
PatternProps::trimWhiteSpace(const UChar *s, int32_t &length) {
if(length<=0 || (!isWhiteSpace(s[0]) && !isWhiteSpace(s[length-1]))) {
#ifndef __PATTERNPROPS_H__
#define __PATTERNPROPS_H__
+#include "unicode/unistr.h"
#include "unicode/utypes.h"
U_NAMESPACE_BEGIN
*/
static const UChar *skipWhiteSpace(const UChar *s, int32_t length);
+ /**
+ * Skips over Pattern_White_Space starting at index start in s.
+ * @return The smallest index at or after start with a non-white space character.
+ */
+ static int32_t skipWhiteSpace(const UnicodeString &s, int32_t start);
+
/**
* @return s except with leading and trailing Pattern_White_Space removed and length adjusted.
*/
}
}
-
Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeString& style,
Formattable::Type& formattableType, UParseError& parseError,
UErrorCode& ec) {
Format* fmt = NULL;
int32_t typeID, styleID;
DateFormat::EStyle date_style;
+ int32_t firstNonSpace;
switch (typeID = findKeyword(type, TYPE_IDS)) {
case 0: // number
fmt = createIntegerFormat(fLocale, ec);
break;
default: // pattern or skeleton
- int32_t i = 0;
- for (; PatternProps::isWhiteSpace(style.charAt(i)); i++);
- if (style.compare(i, 2, u"::", 0, 2) == 0) {
+ firstNonSpace = PatternProps::skipWhiteSpace(style, 0);
+ if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) {
// Skeleton
- UnicodeString skeleton = style.tempSubString(i + 2);
+ UnicodeString skeleton = style.tempSubString(firstNonSpace + 2);
fmt = number::NumberFormatter::forSkeleton(skeleton, ec).locale(fLocale).toFormat(ec);
} else {
// Pattern
case 1: // date
case 2: // time
formattableType = Formattable::kDate;
- styleID = findKeyword(style, DATE_STYLE_IDS);
- date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
-
- if (typeID == 1) {
- fmt = DateFormat::createDateInstance(date_style, fLocale);
+ firstNonSpace = PatternProps::skipWhiteSpace(style, 0);
+ if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) {
+ // Skeleton
+ UnicodeString skeleton = style.tempSubString(firstNonSpace + 2);
+ fmt = DateFormat::createInstanceForSkeleton(skeleton, fLocale, ec);
} else {
- fmt = DateFormat::createTimeInstance(date_style, fLocale);
- }
+ // Pattern
+ styleID = findKeyword(style, DATE_STYLE_IDS);
+ date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
- if (styleID < 0 && fmt != NULL) {
- SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt);
- if (sdtfmt != NULL) {
- sdtfmt->applyPattern(style);
+ if (typeID == 1) {
+ fmt = DateFormat::createDateInstance(date_style, fLocale);
+ } else {
+ fmt = DateFormat::createTimeInstance(date_style, fLocale);
+ }
+
+ if (styleID < 0 && fmt != NULL) {
+ SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt);
+ if (sdtfmt != NULL) {
+ sdtfmt->applyPattern(style);
+ }
}
}
break;
* <td><i>argStyleText</i>
* <td><code>new SimpleDateFormat(argStyleText, getLocale(), status)</code>
* <tr>
+ * <td><i>argSkeletonText</i>
+ * <td><code>DateFormat::createInstanceForSkeleton(argSkeletonText, getLocale(), status)</code>
+ * <tr>
* <td rowspan=6><code>time</code>
* <td><i>(none)</i>
* <td><code>DateFormat.createTimeInstance(kDefault, getLocale(), status)</code>
void cacheExplicitFormats(UErrorCode& status);
+ int32_t skipLeadingSpaces(UnicodeString& style);
+
Format* createAppropriateFormat(UnicodeString& type,
UnicodeString& style,
Formattable::Type& formattableType,
#include "tmsgfmt.h"
#include "cmemory.h"
+#include "loctest.h"
#include "unicode/format.h"
#include "unicode/decimfmt.h"
TESTCASE_AUTO(TestDecimals);
TESTCASE_AUTO(TestArgIsPrefixOfAnother);
TESTCASE_AUTO(TestMessageFormatNumberSkeleton);
+ TESTCASE_AUTO(TestMessageFormatDateSkeleton);
+ TESTCASE_AUTO(TestMessageFormatTimeSkeleton);
TESTCASE_AUTO_END;
}
result = msg.format(
*fmt,
result,
- //FieldPosition(0),
+ //FieldPosition(FieldPosition::DONT_CARE),
fp,
err);
result = msg.format(
ft_arr,
result,
- //FieldPosition(0),
+ //FieldPosition(FieldPosition::DONT_CARE),
fp,
err);
status.setScope(cas.messagePattern);
MessageFormat msgf(cas.messagePattern, cas.localeName, status);
UnicodeString sb;
- FieldPosition fpos(0);
+ FieldPosition fpos(FieldPosition::DONT_CARE);
Formattable argsArray[] = {{cas.arg}};
Formattable args(argsArray, 1);
msgf.format(args, sb, status);
}
}
+void TestMessageFormat::doTheRealDateTimeSkeletonTesting(UDate testDate,
+ const char16_t* messagePattern, const char* localeName, const char16_t* expected,
+ IcuTestErrorCode& status) {
+
+ status.setScope(messagePattern);
+ MessageFormat msgf(messagePattern, localeName, status);
+ UnicodeString sb;
+ FieldPosition fpos(FieldPosition::DONT_CARE);
+ Formattable argsArray[] = { Formattable(testDate, Formattable::kIsDate) };
+ Formattable args(argsArray, 1);
+ msgf.format(args, sb, status);
+
+ assertEquals(messagePattern, expected, sb);
+}
+
+void TestMessageFormat::TestMessageFormatDateSkeleton() {
+ IcuTestErrorCode status(*this, "TestMessageFormatDateSkeleton");
+
+ 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, :: 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);
+ // pattern literal
+ doTheRealDateTimeSkeletonTesting(date, u"{0,date,'::'yMMMMd}", "en", u"::2021November23", status);
+}
+
+void TestMessageFormat::TestMessageFormatTimeSkeleton() {
+ IcuTestErrorCode status(*this, "TestMessageFormatTimeSkeleton");
+
+ 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, :: 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);
+ // pattern literal
+ doTheRealDateTimeSkeletonTesting(date, u"{0,time,'::'yMMMMd}", "en", u"::2021November23", status);
+}
+
#endif /* #if !UCONFIG_NO_FORMATTING */
void TestDecimals();
void TestArgIsPrefixOfAnother();
void TestMessageFormatNumberSkeleton();
+ void TestMessageFormatDateSkeleton();
+ void TestMessageFormatTimeSkeleton();
private:
UnicodeString GetPatternAndSkipSyntax(const MessagePattern& pattern);
+ void doTheRealDateTimeSkeletonTesting(UDate testDate,
+ const char16_t* messagePattern, const char* localeName, const char16_t* expected,
+ IcuTestErrorCode& status);
};
#endif /* #if !UCONFIG_NO_FORMATTING */
* <td><i>argStyleText</i>
* <td><code>new SimpleDateFormat(argStyleText, getLocale())</code>
* <tr>
+ * <td><i>argSkeletonText</i>
+ * <td><code>DateFormat.getInstanceForSkeleton(argSkeletonText, getLocale())</code>
+ * <tr>
* <td rowspan=6><code>time</code>
* <td><i>(none)</i>
* <td><code>DateFormat.getTimeInstance(DateFormat.DEFAULT, getLocale())</code>
DATE_MODIFIER_LONG = 3,
DATE_MODIFIER_FULL = 4;
+ Format dateTimeFormatForPatternOrSkeleton(String style) {
+ // Ignore leading whitespace when looking for "::", the skeleton signal sequence
+ int i = PatternProps.skipWhiteSpace(style, 0);
+ if (style.regionMatches(i, "::", 0, 2)) { // Skeleton
+ return DateFormat.getInstanceForSkeleton(style.substring(i + 2), ulocale);
+ } else { // Pattern
+ return new SimpleDateFormat(style, ulocale);
+ }
+ }
+
// Creates an appropriate Format object for the type and style passed.
// Both arguments cannot be null.
private Format createAppropriateFormat(String type, String style) {
break;
default: // pattern or skeleton
// Ignore leading whitespace when looking for "::", the skeleton signal sequence
- int i = 0;
- for (; PatternProps.isWhiteSpace(style.charAt(i)); i++);
+ int i = PatternProps.skipWhiteSpace(style, 0);
if (style.regionMatches(i, "::", 0, 2)) {
// Skeleton
newFormat = NumberFormatter.forSkeleton(style.substring(i + 2)).locale(ulocale).toFormat();
case DATE_MODIFIER_FULL:
newFormat = DateFormat.getDateInstance(DateFormat.FULL, ulocale);
break;
- default:
- newFormat = new SimpleDateFormat(style, ulocale);
+ default: // pattern or skeleton
+ newFormat = dateTimeFormatForPatternOrSkeleton(style);
break;
}
break;
case DATE_MODIFIER_FULL:
newFormat = DateFormat.getTimeInstance(DateFormat.FULL, ulocale);
break;
- default:
- newFormat = new SimpleDateFormat(style, ulocale);
+ default: // pattern or skeleton
+ newFormat = dateTimeFormatForPatternOrSkeleton(style);
break;
}
break;
import com.ibm.icu.text.NumberFormat;
import com.ibm.icu.text.SimpleDateFormat;
import com.ibm.icu.text.UFormat;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.GregorianCalendar;
import com.ibm.icu.util.TimeZone;
import com.ibm.icu.util.ULocale;
errln("Number format creation failed for " + locale[i].getDisplayName());
continue;
}
- FieldPosition pos = new FieldPosition(0);
+ FieldPosition pos = new FieldPosition(FieldPosition_DONT_CARE);
buffer.setLength(0);
form.format(myNumber, buffer, pos);
parsePos.setIndex(0);
//it_out << "Pat out: " << form.toPattern(buffer));
StringBuffer result = new StringBuffer();
- FieldPosition fieldpos = new FieldPosition(0);
+ FieldPosition fieldpos = new FieldPosition(FieldPosition_DONT_CARE);
form.format(testArgs, result, fieldpos);
assertEquals("format", testResultStrings[i], result.toString());
return;
}
Object testArgs1[] = { "abc", "def" };
- FieldPosition fieldpos = new FieldPosition(0);
+ FieldPosition fieldpos = new FieldPosition(FieldPosition_DONT_CARE);
assertEquals("format",
"There are abc files on def",
form.format(testArgs1, buffer2, fieldpos).toString());
MessageFormat msg = new MessageFormat(formatStr, Locale.ENGLISH);
result.setLength(0);
- FieldPosition pos = new FieldPosition(0);
+ FieldPosition pos = new FieldPosition(FieldPosition_DONT_CARE);
result = msg.format(
arguments,
result,
String compareStr = "On Aug 8, 1997, it began.";
MessageFormat msg = new MessageFormat(formatStr);
- FieldPosition fp = new FieldPosition(0);
+ FieldPosition fp = new FieldPosition(FieldPosition_DONT_CARE);
try {
msg.format(new Date(871068000000L),
MessageFormat msg = new MessageFormat(formatStr, ULocale.US);
result.setLength(0);
- FieldPosition pos = new FieldPosition(0);
+ FieldPosition pos = new FieldPosition(FieldPosition_DONT_CARE);
result = msg.format(
arguments,
result,
msg.setFormatsByArgumentIndex(fmts);
result.setLength(0);
- pos = new FieldPosition(0);
+ pos = new FieldPosition(FieldPosition_DONT_CARE);
result = msg.format(
arguments,
result,
Format newFmt = NumberFormat.getCurrencyInstance(ULocale.GERMAN);
msg.setFormatByArgumentIndex(0, newFmt);
result.setLength(0);
- pos = new FieldPosition(0);
+ pos = new FieldPosition(FieldPosition_DONT_CARE);
result = msg.format(
arguments,
result,
String compareStr = "On Aug 8, 1997, it began.";
MessageFormat msg = new MessageFormat(formatStr);
- FieldPosition fp = new FieldPosition(0);
+ FieldPosition fp = new FieldPosition(FieldPosition_DONT_CARE);
try {
msg.format(arguments.get("startDate"), result, fp);
gotException = false;
try {
Object args[] = {new Long(42)};
- msg.format(args, new StringBuffer(), new FieldPosition(0));
+ msg.format(args, new StringBuffer(), new FieldPosition(FieldPosition_DONT_CARE));
} catch (IllegalArgumentException e) {
gotException = true;
}
gotException = false;
try {
Object args[] = {new Long(42)};
- msg.format((Object) args, new StringBuffer(), new FieldPosition(0));
+ msg.format((Object) args, new StringBuffer(), new FieldPosition(FieldPosition_DONT_CARE));
} catch (IllegalArgumentException e) {
gotException = true;
}
map.put("_oOo_", new Integer(3));
StringBuffer result = new StringBuffer();
assertEquals("trim-named-arg format() failed", "x 3 y",
- m.format(map, result, new FieldPosition(0)).toString());
+ m.format(map, result, new FieldPosition(FieldPosition_DONT_CARE)).toString());
}
@Test
MessageFormat msgf = new MessageFormat(messagePattern, locale);
StringBuffer sb = new StringBuffer();
- FieldPosition fpos = new FieldPosition(0);
+ FieldPosition fpos = new FieldPosition(FieldPosition_DONT_CARE);
msgf.format(new Object[] { arg }, sb, fpos);
assertEquals(messagePattern, expected, sb.toString());
}
}
+
+ private static void doTheRealDateTimeSkeletonTesting(Date date, String messagePattern, ULocale locale, String expected) {
+
+ MessageFormat msgf = new MessageFormat(messagePattern, locale);
+ StringBuffer sb = new StringBuffer();
+ FieldPosition fpos = new FieldPosition(FieldPosition_DONT_CARE);
+ msgf.format(new Object[] { date }, sb, fpos);
+
+ assertEquals(messagePattern, expected, sb.toString());
+ }
+
+ @Test
+ public void TestMessageFormatDateSkeleton() {
+ 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, :: 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!");
+ doTheRealDateTimeSkeletonTesting(date, "{0,date,'::'yMMMMd}", ULocale.ENGLISH, "::2021November23"); // pattern literal
+ }
+
+ @Test
+ public void TestMessageFormatTimeSkeleton() {
+ 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, :: 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!");
+ doTheRealDateTimeSkeletonTesting(date, "{0,time,'::'yMMMMd}", ULocale.ENGLISH, "::2021November23"); // pattern literal
+ }
}