Add parsing support to BTimeFormat.

This commit is contained in:
Adrien Destugues 2014-10-09 13:35:23 +02:00
parent 640158e2e7
commit 26b0a53d12
4 changed files with 111 additions and 88 deletions

View File

@ -5,11 +5,16 @@
#ifndef _B_TIME_FORMAT_H_
#define _B_TIME_FORMAT_H_
#include <DateTimeFormat.h>
class BString;
namespace BPrivate {
class BTime;
}
class BTimeFormat : public BFormat {
public:
@ -20,18 +25,16 @@ public:
BTimeFormat(const BTimeFormat &other);
virtual ~BTimeFormat();
void SetTimeFormat(BTimeFormatStyle style,
const BString& format);
// formatting
ssize_t Format(char* string, size_t maxSize,
time_t time, BTimeFormatStyle style) const;
ssize_t Format(char* string, size_t maxSize,
time_t time, BString format) const;
status_t Format(BString& string, const time_t time,
const BTimeFormatStyle style,
const BTimeZone* timeZone = NULL) const;
status_t Format(BString& string, const time_t time,
const BString format,
const BTimeZone* timeZone) const;
status_t Format(BString& string,
int*& fieldPositions, int& fieldCount,
time_t time, BTimeFormatStyle style) const;
@ -40,10 +43,14 @@ public:
int& fieldCount, BTimeFormatStyle style
) const;
// TODO parsing
// parsing
status_t Parse(BString source, BTimeFormatStyle style,
BPrivate::BTime& output);
private:
icu::DateFormat* _CreateTimeFormatter(
const BString& format) const;
const BTimeFormatStyle style) const;
};

View File

@ -10,6 +10,7 @@
#include <AutoDeleter.h>
#include <Autolock.h>
#include <DateTime.h>
#include <FormattingConventionsPrivate.h>
#include <LanguagePrivate.h>
#include <TimeZone.h>
@ -44,6 +45,14 @@ BTimeFormat::~BTimeFormat()
}
void
BTimeFormat::SetTimeFormat(BTimeFormatStyle style,
const BString& format)
{
fConventions.SetExplicitTimeFormat(style, format);
}
// #pragma mark - Formatting
@ -55,37 +64,7 @@ BTimeFormat::Format(char* string, size_t maxSize, time_t time,
if (!lock.IsLocked())
return B_ERROR;
BString format;
fConventions.GetTimeFormat(style, format);
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
if (timeFormatter.Get() == NULL)
return B_NO_MEMORY;
UnicodeString icuString;
timeFormatter->format((UDate)time * 1000, icuString);
CheckedArrayByteSink stringConverter(string, maxSize);
icuString.toUTF8(stringConverter);
if (stringConverter.Overflowed())
return B_BAD_VALUE;
return stringConverter.NumberOfBytesWritten();
}
ssize_t
BTimeFormat::Format(char* string, size_t maxSize, time_t time,
BString format) const
{
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
if (format == NULL || format.CountChars() <= 0)
return B_BAD_VALUE;
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
if (timeFormatter.Get() == NULL)
return B_NO_MEMORY;
@ -110,43 +89,7 @@ BTimeFormat::Format(BString& string, const time_t time,
if (!lock.IsLocked())
return B_ERROR;
BString format;
fConventions.GetTimeFormat(style, format);
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
if (timeFormatter.Get() == NULL)
return B_NO_MEMORY;
if (timeZone != NULL) {
ObjectDeleter<TimeZone> icuTimeZone(
TimeZone::createTimeZone(timeZone->ID().String()));
if (icuTimeZone.Get() == NULL)
return B_NO_MEMORY;
timeFormatter->setTimeZone(*icuTimeZone.Get());
}
UnicodeString icuString;
timeFormatter->format((UDate)time * 1000, icuString);
string.Truncate(0);
BStringByteSink stringConverter(&string);
icuString.toUTF8(stringConverter);
return B_OK;
}
status_t
BTimeFormat::Format(BString& string, const time_t time,
const BString format, const BTimeZone* timeZone) const
{
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
if (format == NULL || format.CountChars() <= 0)
return B_BAD_VALUE;
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
if (timeFormatter.Get() == NULL)
return B_NO_MEMORY;
@ -177,9 +120,7 @@ BTimeFormat::Format(BString& string, int*& fieldPositions, int& fieldCount,
if (!lock.IsLocked())
return B_ERROR;
BString format;
fConventions.GetTimeFormat(style, format);
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
if (timeFormatter.Get() == NULL)
return B_NO_MEMORY;
@ -223,9 +164,7 @@ BTimeFormat::GetTimeFields(BDateElement*& fields, int& fieldCount,
if (!lock.IsLocked())
return B_ERROR;
BString format;
fConventions.GetTimeFormat(style, format);
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
if (timeFormatter.Get() == NULL)
return B_NO_MEMORY;
@ -277,8 +216,35 @@ BTimeFormat::GetTimeFields(BDateElement*& fields, int& fieldCount,
}
status_t
BTimeFormat::Parse(BString source, BTimeFormatStyle style, BTime& output)
{
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
if (timeFormatter.Get() == NULL)
return B_NO_MEMORY;
// If no timezone is specified in the time string, assume GMT
timeFormatter->setTimeZone(*icu::TimeZone::getGMT());
ParsePosition p(0);
UDate date = timeFormatter->parse(UnicodeString::fromUTF8(source.String()),
p);
printf("T %f\n", date);
output.SetTime(0, 0, 0);
output.AddMilliseconds(date);
return B_OK;
}
DateFormat*
BTimeFormat::_CreateTimeFormatter(const BString& format) const
BTimeFormat::_CreateTimeFormatter(const BTimeFormatStyle style) const
{
Locale* icuLocale
= fConventions.UseStringsFromPreferredLanguage()
@ -293,6 +259,9 @@ BTimeFormat::_CreateTimeFormatter(const BString& format) const
SimpleDateFormat* timeFormatterImpl
= static_cast<SimpleDateFormat*>(timeFormatter);
BString format;
fConventions.GetTimeFormat(style, format);
UnicodeString pattern(format.String());
timeFormatterImpl->applyPattern(pattern);

View File

@ -162,15 +162,28 @@ 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();
stream << date.Year();
stream << '-';
stream << date.Month();
stream << '-';
stream << date.Day();
return stream;
return stream;
}
std::ostream& operator<<(std::ostream& stream, const BTime& date)
{
stream << date.Hour();
stream << ':';
stream << date.Minute();
stream << ':';
stream << date.Second();
return stream;
}
@ -205,6 +218,37 @@ DateFormatTest::TestParseDate()
}
void
DateFormatTest::TestParseTime()
{
BLanguage language("fr");
BFormattingConventions formatting("fr_FR");
BTimeFormat format(&language, &formatting);
BTime date;
status_t result;
struct Test {
const char* input;
BTime output;
};
static const Test tests[] = {
{"03:25", BTime(3, 25, 0)},
{"16:18", BTime(16, 18, 0)},
{"23:59", BTime(23, 59, 0)},
{NULL}
};
for (int i = 0; tests[i].input != NULL; i++) {
NextSubTest();
result = format.Parse(tests[i].input, B_SHORT_TIME_FORMAT, date);
CPPUNIT_ASSERT_EQUAL(tests[i].output, date);
CPPUNIT_ASSERT_EQUAL(B_OK, result);
}
}
/*static*/ void
DateFormatTest::AddTests(BTestSuite& parent)
{
@ -220,6 +264,8 @@ DateFormatTest::AddTests(BTestSuite& parent)
"DateFormatTest::TestMonthNames", &DateFormatTest::TestMonthNames));
suite.addTest(new CppUnit::TestCaller<DateFormatTest>(
"DateFormatTest::TestParseDate", &DateFormatTest::TestParseDate));
suite.addTest(new CppUnit::TestCaller<DateFormatTest>(
"DateFormatTest::TestParseTime", &DateFormatTest::TestParseTime));
parent.addTest("DateFormatTest", &suite);
}

View File

@ -20,6 +20,7 @@ public:
void TestFormatDate();
void TestMonthNames();
void TestParseDate();
void TestParseTime();
static void AddTests(BTestSuite& suite);
};