Add API for parsing dates.

This commit is contained in:
Adrien Destugues
2014-10-07 17:40:18 +02:00
parent 090a0d7686
commit 97d07c8af2
4 changed files with 88 additions and 21 deletions
+5 -2
View File
@@ -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;
};
+38 -19
View File
@@ -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<DateFormat> dateFormatter(_CreateDateFormatter(format));
ObjectDeleter<DateFormat> 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<DateFormat> dateFormatter(_CreateDateFormatter(format));
ObjectDeleter<DateFormat> 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<DateFormat> dateFormatter(_CreateDateFormatter(format));
ObjectDeleter<DateFormat> 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<DateFormat> dateFormatter(_CreateDateFormatter(format));
ObjectDeleter<DateFormat> 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<DateFormat> dateFormatter(_CreateDateFormatter(format));
ObjectDeleter<DateFormat> 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<SimpleDateFormat*>(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<DateFormat> 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<SimpleDateFormat*>(dateFormatter);
BString format;
fConventions.GetDateFormat(style, format);
UnicodeString pattern(format.String());
dateFormatterImpl->applyPattern(pattern);
+44
View File
@@ -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>(
"DateFormatTest::TestMonthNames", &DateFormatTest::TestMonthNames));
suite.addTest(new CppUnit::TestCaller<DateFormatTest>(
"DateFormatTest::TestParseDate", &DateFormatTest::TestParseDate));
parent.addTest("DateFormatTest", &suite);
}
+1
View File
@@ -19,6 +19,7 @@ public:
void TestFormat();
void TestFormatDate();
void TestMonthNames();
void TestParseDate();
static void AddTests(BTestSuite& suite);
};