diff --git a/icu4c/source/i18n/Makefile.in b/icu4c/source/i18n/Makefile.in index e9ec0ac2889..7d0e7459cc6 100644 --- a/icu4c/source/i18n/Makefile.in +++ b/icu4c/source/i18n/Makefile.in @@ -62,7 +62,7 @@ LIBS = $(LIBICUUC) $(DEFAULT_LIBS) OBJECTS = ucln_in.o \ fmtable.o format.o msgfmt.o umsg.o numfmt.o unum.o decimfmt.o dcfmtsym.o \ ucurr.o digitlst.o fmtable_cnv.o \ -choicfmt.o datefmt.o smpdtfmt.o dtfmtsym.o udat.o \ +choicfmt.o datefmt.o smpdtfmt.o reldtfmt.o dtfmtsym.o udat.o \ nfrs.o nfrule.o nfsubs.o rbnf.o ucsdet.o \ ucal.o calendar.o gregocal.o timezone.o simpletz.o olsontz.o \ astro.o buddhcal.o persncal.o islamcal.o japancal.o gregoimp.o hebrwcal.o \ diff --git a/icu4c/source/i18n/datefmt.cpp b/icu4c/source/i18n/datefmt.cpp index b07622c39e8..c5c0e671747 100644 --- a/icu4c/source/i18n/datefmt.cpp +++ b/icu4c/source/i18n/datefmt.cpp @@ -24,6 +24,7 @@ #include "unicode/ures.h" #include "unicode/datefmt.h" #include "unicode/smpdtfmt.h" +#include "reldtfmt.h" #include "cstring.h" #include "windtfmt.h" @@ -287,6 +288,13 @@ DateFormat::create(EStyle timeStyle, EStyle dateStyle, const Locale& locale) } #endif + // is it relative? + if(/*((timeStyle!=UDAT_NONE)&&(timeStyle & UDAT_RELATIVE)) || */((dateStyle!=(UDateFormatStyle)UDAT_NONE)&&((dateStyle-kDateOffset) & UDAT_RELATIVE))) { + RelativeDateFormat *r = new RelativeDateFormat((UDateFormatStyle)timeStyle, (UDateFormatStyle)(dateStyle-kDateOffset), locale, status); + if(U_SUCCESS(status)) return r; + delete r; + status = U_ZERO_ERROR; + } // Try to create a SimpleDateFormat of the desired style. SimpleDateFormat *f = new SimpleDateFormat(timeStyle, dateStyle, locale, status); diff --git a/icu4c/source/i18n/i18n.vcproj b/icu4c/source/i18n/i18n.vcproj index d1084ab8203..b9589caa6a8 100644 --- a/icu4c/source/i18n/i18n.vcproj +++ b/icu4c/source/i18n/i18n.vcproj @@ -1139,6 +1139,13 @@ /> + + + diff --git a/icu4c/source/i18n/unicode/datefmt.h b/icu4c/source/i18n/unicode/datefmt.h index ad2c55b2d27..4efc4dae600 100644 --- a/icu4c/source/i18n/unicode/datefmt.h +++ b/icu4c/source/i18n/unicode/datefmt.h @@ -160,6 +160,19 @@ public: // kShort + kDateOffset = 7 kDateTime = 8, + + + // relative dates + kRelative = (1 << 7), + + kFullRelative = (kFull | kRelative), + + kLongRelative = kLong | kRelative, + + kMediumRelative = kMedium | kRelative, + + kShortRelative = kShort | kRelative, + kDefault = kMedium, diff --git a/icu4c/source/i18n/unicode/udat.h b/icu4c/source/i18n/unicode/udat.h index 03376ed9167..b68afef4654 100644 --- a/icu4c/source/i18n/unicode/udat.h +++ b/icu4c/source/i18n/unicode/udat.h @@ -151,6 +151,19 @@ typedef enum UDateFormatStyle { UDAT_SHORT, /** Default style */ UDAT_DEFAULT = UDAT_MEDIUM, + + /** Bitfield for relative date */ + UDAT_RELATIVE = (1 << 7), + + UDAT_FULL_RELATIVE = UDAT_FULL | UDAT_RELATIVE, + + UDAT_LONG_RELATIVE = UDAT_LONG | UDAT_RELATIVE, + + UDAT_MEDIUM_RELATIVE = UDAT_MEDIUM | UDAT_RELATIVE, + + UDAT_SHORT_RELATIVE = UDAT_SHORT | UDAT_RELATIVE, + + /** No style */ UDAT_NONE = -1, /** for internal API use only */ diff --git a/icu4c/source/test/intltest/dtfmttst.cpp b/icu4c/source/test/intltest/dtfmttst.cpp index b386c7303d2..039d4752f40 100644 --- a/icu4c/source/test/intltest/dtfmttst.cpp +++ b/icu4c/source/test/intltest/dtfmttst.cpp @@ -19,6 +19,7 @@ #include "cmemory.h" #include "cstring.h" #include "caltest.h" // for fieldName +#include // for sprintf #ifdef U_WINDOWS #include "windttst.h" @@ -26,7 +27,7 @@ #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) -#define ASSERT_OK(status) if(U_FAILURE(status)) {errln(#status " = %s", u_errorName(status)); return; } +#define ASSERT_OK(status) if(U_FAILURE(status)) {errln(#status " = %s @ %s:%d", u_errorName(status), __FILE__, __LINE__); return; } //-------------------------------------------------------------------- // Time bomb - allows temporary behavior that expires at a given @@ -76,6 +77,11 @@ void DateFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &nam TESTCASE(31,TestStandAloneMonths); TESTCASE(32,TestQuarters); TESTCASE(33,TestZTimeZoneParsing); + TESTCASE(34,TestRelative); + /* + TESTCASE(35,TestRelativeError); + TESTCASE(36,TestRelativeOther); + */ default: name = ""; break; } } @@ -1966,6 +1972,119 @@ void DateFormatTest::TestHost(void) #endif } +// Relative Date Tests + +void DateFormatTest::TestRelative(int daysdelta, + const Locale& loc, + const char *expectChars) { + char banner[25]; + sprintf(banner, "%d", daysdelta); + UnicodeString bannerStr(banner, ""); + + UErrorCode status = U_ZERO_ERROR; + + FieldPosition pos(0); + UnicodeString test; + Locale en("en"); + DateFormat *fullrelative = DateFormat::createDateInstance(DateFormat::kFullRelative, loc); + DateFormat *full = DateFormat::createDateInstance(DateFormat::kFull , loc); + + DateFormat *en_full = DateFormat::createDateInstance(DateFormat::kFull, en); + DateFormat *en_fulltime = DateFormat::createDateTimeInstance(DateFormat::kFull,DateFormat::kFull,en); + UnicodeString result; + UnicodeString normalResult; + UnicodeString expect; + UnicodeString parseResult; + + Calendar *c = Calendar::createInstance(status); + + // Today = Today + c->setTime(Calendar::getNow(), status); + if(daysdelta != 0) { + c->add(Calendar::DATE,daysdelta,status); + } + ASSERT_OK(status); + + // calculate the expected string + if(expectChars != NULL) { + expect = expectChars; + } else { + full->format(*c, expect, pos); // expected = normal full + } + + fullrelative ->format(*c, result, pos); + en_full ->format(*c, normalResult, pos); + + if(result != expect) { + errln("FAIL: Relative Format ["+bannerStr+"] of "+normalResult+" failed, expected "+expect+" but got " + result); + } else { + logln("PASS: Relative Format ["+bannerStr+"] of "+normalResult+" got " + result); + } + + + //verify + UDate d = fullrelative->parse(result, status); + ASSERT_OK(status); + + UnicodeString parseFormat; // parse rel->format full + en_full->format(d, parseFormat, status); + + UnicodeString origFormat; + en_full->format(*c, origFormat, pos); + + if(parseFormat!=origFormat) { + errln("FAIL: Relative Parse ["+bannerStr+"] of "+result+" failed, expected "+parseFormat+" but got "+origFormat); + } else { + logln("PASS: Relative Parse ["+bannerStr+"] of "+result+" passed, got "+parseFormat); + } + + + delete full; + delete fullrelative; + delete en_fulltime; + delete en_full; + delete c; + +} + + +void DateFormatTest::TestRelative(void) +{ + Locale en("en"); + TestRelative( 0, en, "Today"); + TestRelative(-1, en, "Yesterday"); + TestRelative( 1, en, "Tomorrow"); + TestRelative( 2, en, NULL); + TestRelative( -2, en, NULL); + TestRelative( 3, en, NULL); + TestRelative( -3, en, NULL); + TestRelative( 300, en, NULL); + TestRelative( -300, en, NULL); +} + +/* +void DateFormatTest::TestRelativeError(void) +{ + UErrorCode status; + Locale en("en"); + + DateFormat *en_reltime_reldate = DateFormat::createDateTimeInstance(DateFormat::kFullRelative,DateFormat::kFullRelative,en); + if(en_reltime_reldate == NULL) { + logln("PASS: rel date/rel time failed"); + } else { + errln("FAIL: rel date/rel time created, should have failed."); + delete en_reltime_reldate; + } +} + +void DateFormatTest::TestRelativeOther(void) +{ + logln("Nothing in this test. When we get more data from CLDR, put in some tests of -2, +2, etc. "); +} +*/ + + + #endif /* #if !UCONFIG_NO_FORMATTING */ //eof diff --git a/icu4c/source/test/intltest/dtfmttst.h b/icu4c/source/test/intltest/dtfmttst.h index 15d7355d226..7e3df797688 100644 --- a/icu4c/source/test/intltest/dtfmttst.h +++ b/icu4c/source/test/intltest/dtfmttst.h @@ -180,6 +180,20 @@ public: void TestQuarters(void); void TestZTimeZoneParsing(void); + +public: + /*** + * Test Relative Dates + */ + void TestRelative(void); +/* void TestRelativeError(void); + void TestRelativeOther(void); +*/ + + private: + void TestRelative(int daysdelta, + const Locale& loc, + const char *expectChars); private: void expectParse(const char** data, int32_t data_length,