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,