diff --git a/headers/os/locale/DateFormat.h b/headers/os/locale/DateFormat.h index 1789768360..879a7a25fa 100644 --- a/headers/os/locale/DateFormat.h +++ b/headers/os/locale/DateFormat.h @@ -71,11 +71,14 @@ public: status_t GetStartOfWeek(BWeekday* weekday) const; status_t GetMonthName(int month, BString& outName); - // TODO parsing + // parsing + + status_t Parse(BString source, BDateFormatStyle style, + BDate& output); private: icu::DateFormat* _CreateDateFormatter( - const BString& format) const; + const BDateFormatStyle style) const; }; diff --git a/src/kits/locale/DateFormat.cpp b/src/kits/locale/DateFormat.cpp index 2ca66c7da0..30f7d3013a 100644 --- a/src/kits/locale/DateFormat.cpp +++ b/src/kits/locale/DateFormat.cpp @@ -72,9 +72,7 @@ BDateFormat::Format(char* string, const size_t maxSize, const time_t time, if (!lock.IsLocked()) return B_ERROR; - BString format; - fConventions.GetDateFormat(style, format); - ObjectDeleter dateFormatter(_CreateDateFormatter(format)); + ObjectDeleter dateFormatter(_CreateDateFormatter(style)); if (dateFormatter.Get() == NULL) return B_NO_MEMORY; @@ -99,9 +97,7 @@ BDateFormat::Format(BString& string, const time_t time, if (!lock.IsLocked()) return B_ERROR; - BString format; - fConventions.GetDateFormat(style, format); - ObjectDeleter dateFormatter(_CreateDateFormatter(format)); + ObjectDeleter dateFormatter(_CreateDateFormatter(style)); if (dateFormatter.Get() == NULL) return B_NO_MEMORY; @@ -135,9 +131,7 @@ BDateFormat::Format(BString& string, const BDate& time, if (!lock.IsLocked()) return B_ERROR; - BString format; - fConventions.GetDateFormat(style, format); - ObjectDeleter dateFormatter(_CreateDateFormatter(format)); + ObjectDeleter dateFormatter(_CreateDateFormatter(style)); if (dateFormatter.Get() == NULL) return B_NO_MEMORY; @@ -179,9 +173,7 @@ BDateFormat::Format(BString& string, int*& fieldPositions, int& fieldCount, if (!lock.IsLocked()) return B_ERROR; - BString format; - fConventions.GetDateFormat(style, format); - ObjectDeleter dateFormatter(_CreateDateFormatter(format)); + ObjectDeleter dateFormatter(_CreateDateFormatter(style)); if (dateFormatter.Get() == NULL) return B_NO_MEMORY; @@ -226,9 +218,7 @@ BDateFormat::GetFields(BDateElement*& fields, int& fieldCount, if (!lock.IsLocked()) return B_ERROR; - BString format; - fConventions.GetDateFormat(style, format); - ObjectDeleter dateFormatter(_CreateDateFormatter(format)); + ObjectDeleter dateFormatter(_CreateDateFormatter(style)); if (dateFormatter.Get() == NULL) return B_NO_MEMORY; @@ -332,9 +322,7 @@ BDateFormat::GetMonthName(int month, BString& outName) if (!lock.IsLocked()) return B_ERROR; - BString pattern; - fConventions.GetDateFormat(B_LONG_DATE_FORMAT, pattern); - DateFormat* format = _CreateDateFormatter(pattern); + DateFormat* format = _CreateDateFormatter(B_LONG_DATE_FORMAT); SimpleDateFormat* simpleFormat = dynamic_cast(format); if (simpleFormat == NULL) { @@ -360,8 +348,36 @@ BDateFormat::GetMonthName(int month, BString& outName) } +status_t +BDateFormat::Parse(BString source, BDateFormatStyle style, BDate& output) +{ + // FIXME currently this parses a date in any timezone (or the local one if + // none is specified) to a BDate in UTC. This may not be a good idea, we + // may want to parse to a "local" date instead. But BDate should be made + // timezone aware so things like BDate::Difference can work for dates in + // different timezones. + BAutolock lock(fLock); + if (!lock.IsLocked()) + return B_ERROR; + + ObjectDeleter dateFormatter(_CreateDateFormatter(style)); + if (dateFormatter.Get() == NULL) + return B_NO_MEMORY; + + + ParsePosition p(0); + UDate date = dateFormatter->parse(UnicodeString::fromUTF8(source.String()), + p); + + output.SetDate(1970, 1, 1); + output.AddDays(date / U_MILLIS_PER_DAY + 0.5); + + return B_OK; +} + + DateFormat* -BDateFormat::_CreateDateFormatter(const BString& format) const +BDateFormat::_CreateDateFormatter(const BDateFormatStyle style) const { Locale* icuLocale = fConventions.UseStringsFromPreferredLanguage() @@ -376,6 +392,9 @@ BDateFormat::_CreateDateFormatter(const BString& format) const SimpleDateFormat* dateFormatterImpl = static_cast(dateFormatter); + BString format; + fConventions.GetDateFormat(style, format); + UnicodeString pattern(format.String()); dateFormatterImpl->applyPattern(pattern); diff --git a/src/tests/kits/locale/DateFormatTest.cpp b/src/tests/kits/locale/DateFormatTest.cpp index 9430c2e9ef..0eb96ff947 100644 --- a/src/tests/kits/locale/DateFormatTest.cpp +++ b/src/tests/kits/locale/DateFormatTest.cpp @@ -143,6 +143,48 @@ DateFormatTest::TestMonthNames() CPPUNIT_ASSERT_EQUAL(B_OK, result); } +std::ostream& operator<<(std::ostream& stream, const BDate& date) +{ + stream << date.Year(); + stream << '-'; + stream << date.Month(); + stream << '-'; + stream << date.Day(); + + return stream; +} + + +void +DateFormatTest::TestParseDate() +{ + BLanguage language("en"); + BFormattingConventions formatting("en_US"); + BDateFormat format(&language, &formatting); + BDate date; + status_t result; + + struct Test { + const char* input; + BDate output; + }; + + static const Test tests[] = { + {"01/01/1970", BDate(1970, 1, 1)}, + {"05/07/1988", BDate(1988, 5, 7)}, + {"07/31/2345", BDate(2345, 7, 31)}, + {NULL} + }; + + for (int i = 0; tests[i].input != NULL; i++) { + NextSubTest(); + result = format.Parse(tests[i].input, B_SHORT_DATE_FORMAT, date); + + CPPUNIT_ASSERT_EQUAL(tests[i].output, date); + CPPUNIT_ASSERT_EQUAL(B_OK, result); + } +} + /*static*/ void DateFormatTest::AddTests(BTestSuite& parent) @@ -157,6 +199,8 @@ DateFormatTest::AddTests(BTestSuite& parent) "DateFormatTest::TestFormatDate", &DateFormatTest::TestFormatDate)); suite.addTest(new CppUnit::TestCaller( "DateFormatTest::TestMonthNames", &DateFormatTest::TestMonthNames)); + suite.addTest(new CppUnit::TestCaller( + "DateFormatTest::TestParseDate", &DateFormatTest::TestParseDate)); parent.addTest("DateFormatTest", &suite); } diff --git a/src/tests/kits/locale/DateFormatTest.h b/src/tests/kits/locale/DateFormatTest.h index b0e52d4be8..f886e69bde 100644 --- a/src/tests/kits/locale/DateFormatTest.h +++ b/src/tests/kits/locale/DateFormatTest.h @@ -19,6 +19,7 @@ public: void TestFormat(); void TestFormatDate(); void TestMonthNames(); + void TestParseDate(); static void AddTests(BTestSuite& suite); };