Add parsing support to BTimeFormat.
This commit is contained in:
@@ -5,11 +5,16 @@
|
|||||||
#ifndef _B_TIME_FORMAT_H_
|
#ifndef _B_TIME_FORMAT_H_
|
||||||
#define _B_TIME_FORMAT_H_
|
#define _B_TIME_FORMAT_H_
|
||||||
|
|
||||||
|
|
||||||
#include <DateTimeFormat.h>
|
#include <DateTimeFormat.h>
|
||||||
|
|
||||||
|
|
||||||
class BString;
|
class BString;
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
class BTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class BTimeFormat : public BFormat {
|
class BTimeFormat : public BFormat {
|
||||||
public:
|
public:
|
||||||
@@ -20,18 +25,16 @@ public:
|
|||||||
BTimeFormat(const BTimeFormat &other);
|
BTimeFormat(const BTimeFormat &other);
|
||||||
virtual ~BTimeFormat();
|
virtual ~BTimeFormat();
|
||||||
|
|
||||||
|
void SetTimeFormat(BTimeFormatStyle style,
|
||||||
|
const BString& format);
|
||||||
|
|
||||||
// formatting
|
// formatting
|
||||||
|
|
||||||
ssize_t Format(char* string, size_t maxSize,
|
ssize_t Format(char* string, size_t maxSize,
|
||||||
time_t time, BTimeFormatStyle style) const;
|
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,
|
status_t Format(BString& string, const time_t time,
|
||||||
const BTimeFormatStyle style,
|
const BTimeFormatStyle style,
|
||||||
const BTimeZone* timeZone = NULL) const;
|
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,
|
status_t Format(BString& string,
|
||||||
int*& fieldPositions, int& fieldCount,
|
int*& fieldPositions, int& fieldCount,
|
||||||
time_t time, BTimeFormatStyle style) const;
|
time_t time, BTimeFormatStyle style) const;
|
||||||
@@ -40,10 +43,14 @@ public:
|
|||||||
int& fieldCount, BTimeFormatStyle style
|
int& fieldCount, BTimeFormatStyle style
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
// TODO parsing
|
// parsing
|
||||||
|
|
||||||
|
status_t Parse(BString source, BTimeFormatStyle style,
|
||||||
|
BPrivate::BTime& output);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
icu::DateFormat* _CreateTimeFormatter(
|
icu::DateFormat* _CreateTimeFormatter(
|
||||||
const BString& format) const;
|
const BTimeFormatStyle style) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
#include <Autolock.h>
|
#include <Autolock.h>
|
||||||
|
#include <DateTime.h>
|
||||||
#include <FormattingConventionsPrivate.h>
|
#include <FormattingConventionsPrivate.h>
|
||||||
#include <LanguagePrivate.h>
|
#include <LanguagePrivate.h>
|
||||||
#include <TimeZone.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
|
// #pragma mark - Formatting
|
||||||
|
|
||||||
|
|
||||||
@@ -55,37 +64,7 @@ BTimeFormat::Format(char* string, size_t maxSize, time_t time,
|
|||||||
if (!lock.IsLocked())
|
if (!lock.IsLocked())
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
BString format;
|
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
|
||||||
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));
|
|
||||||
if (timeFormatter.Get() == NULL)
|
if (timeFormatter.Get() == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -110,43 +89,7 @@ BTimeFormat::Format(BString& string, const time_t time,
|
|||||||
if (!lock.IsLocked())
|
if (!lock.IsLocked())
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
BString format;
|
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
|
||||||
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));
|
|
||||||
if (timeFormatter.Get() == NULL)
|
if (timeFormatter.Get() == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -177,9 +120,7 @@ BTimeFormat::Format(BString& string, int*& fieldPositions, int& fieldCount,
|
|||||||
if (!lock.IsLocked())
|
if (!lock.IsLocked())
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
BString format;
|
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
|
||||||
fConventions.GetTimeFormat(style, format);
|
|
||||||
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
|
|
||||||
if (timeFormatter.Get() == NULL)
|
if (timeFormatter.Get() == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -223,9 +164,7 @@ BTimeFormat::GetTimeFields(BDateElement*& fields, int& fieldCount,
|
|||||||
if (!lock.IsLocked())
|
if (!lock.IsLocked())
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
BString format;
|
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
|
||||||
fConventions.GetTimeFormat(style, format);
|
|
||||||
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
|
|
||||||
if (timeFormatter.Get() == NULL)
|
if (timeFormatter.Get() == NULL)
|
||||||
return B_NO_MEMORY;
|
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*
|
DateFormat*
|
||||||
BTimeFormat::_CreateTimeFormatter(const BString& format) const
|
BTimeFormat::_CreateTimeFormatter(const BTimeFormatStyle style) const
|
||||||
{
|
{
|
||||||
Locale* icuLocale
|
Locale* icuLocale
|
||||||
= fConventions.UseStringsFromPreferredLanguage()
|
= fConventions.UseStringsFromPreferredLanguage()
|
||||||
@@ -293,6 +259,9 @@ BTimeFormat::_CreateTimeFormatter(const BString& format) const
|
|||||||
SimpleDateFormat* timeFormatterImpl
|
SimpleDateFormat* timeFormatterImpl
|
||||||
= static_cast<SimpleDateFormat*>(timeFormatter);
|
= static_cast<SimpleDateFormat*>(timeFormatter);
|
||||||
|
|
||||||
|
BString format;
|
||||||
|
fConventions.GetTimeFormat(style, format);
|
||||||
|
|
||||||
UnicodeString pattern(format.String());
|
UnicodeString pattern(format.String());
|
||||||
timeFormatterImpl->applyPattern(pattern);
|
timeFormatterImpl->applyPattern(pattern);
|
||||||
|
|
||||||
|
|||||||
@@ -162,15 +162,28 @@ DateFormatTest::TestMonthNames()
|
|||||||
CPPUNIT_ASSERT_EQUAL(B_OK, result);
|
CPPUNIT_ASSERT_EQUAL(B_OK, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& stream, const BDate& date)
|
std::ostream& operator<<(std::ostream& stream, const BDate& date)
|
||||||
{
|
{
|
||||||
stream << date.Year();
|
stream << date.Year();
|
||||||
stream << '-';
|
stream << '-';
|
||||||
stream << date.Month();
|
stream << date.Month();
|
||||||
stream << '-';
|
stream << '-';
|
||||||
stream << date.Day();
|
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
|
/*static*/ void
|
||||||
DateFormatTest::AddTests(BTestSuite& parent)
|
DateFormatTest::AddTests(BTestSuite& parent)
|
||||||
{
|
{
|
||||||
@@ -220,6 +264,8 @@ DateFormatTest::AddTests(BTestSuite& parent)
|
|||||||
"DateFormatTest::TestMonthNames", &DateFormatTest::TestMonthNames));
|
"DateFormatTest::TestMonthNames", &DateFormatTest::TestMonthNames));
|
||||||
suite.addTest(new CppUnit::TestCaller<DateFormatTest>(
|
suite.addTest(new CppUnit::TestCaller<DateFormatTest>(
|
||||||
"DateFormatTest::TestParseDate", &DateFormatTest::TestParseDate));
|
"DateFormatTest::TestParseDate", &DateFormatTest::TestParseDate));
|
||||||
|
suite.addTest(new CppUnit::TestCaller<DateFormatTest>(
|
||||||
|
"DateFormatTest::TestParseTime", &DateFormatTest::TestParseTime));
|
||||||
|
|
||||||
parent.addTest("DateFormatTest", &suite);
|
parent.addTest("DateFormatTest", &suite);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public:
|
|||||||
void TestFormatDate();
|
void TestFormatDate();
|
||||||
void TestMonthNames();
|
void TestMonthNames();
|
||||||
void TestParseDate();
|
void TestParseDate();
|
||||||
|
void TestParseTime();
|
||||||
|
|
||||||
static void AddTests(BTestSuite& suite);
|
static void AddTests(BTestSuite& suite);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user