Skip to content

Commit

Permalink
Reimplement BDateTimeFormat using ICU support
Browse files Browse the repository at this point in the history
* Avoid hardcoding the format to "date, time"
* Allows using DateTimePatternGenerator to create custom formats from a
set of fields.
  • Loading branch information
pulkomandy committed Oct 7, 2014
1 parent 7fb9021 commit 4a3a474
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 87 deletions.
12 changes: 1 addition & 11 deletions headers/os/locale/DateFormat.h
Expand Up @@ -7,6 +7,7 @@


#include <DateTime.h>
#include <DateTimeFormat.h>
#include <Format.h>
#include <FormattingConventions.h>
#include <Language.h>
Expand All @@ -22,17 +23,6 @@ class BString;
class BTimeZone;


enum BDateElement {
B_DATE_ELEMENT_INVALID = B_BAD_DATA,
B_DATE_ELEMENT_YEAR = 0,
B_DATE_ELEMENT_MONTH,
B_DATE_ELEMENT_DAY,
B_DATE_ELEMENT_AM_PM,
B_DATE_ELEMENT_HOUR,
B_DATE_ELEMENT_MINUTE,
B_DATE_ELEMENT_SECOND
};

enum BWeekday {
B_WEEKDAY_MONDAY = 1,
B_WEEKDAY_TUESDAY,
Expand Down
31 changes: 25 additions & 6 deletions headers/os/locale/DateTimeFormat.h
Expand Up @@ -6,21 +6,42 @@
#define _B_DATE_TIME_FORMAT_H_


#include <DateFormat.h>
#include <Format.h>
#include <FormatParameters.h>
#include <TimeFormat.h>


class BString;
class BTimeZone;


enum BDateElement {
B_DATE_ELEMENT_INVALID = 0,
B_DATE_ELEMENT_YEAR = 1 << 0,
B_DATE_ELEMENT_MONTH = 1 << 1,
B_DATE_ELEMENT_WEEKDAY = 1 << 2,
B_DATE_ELEMENT_DAY = 1 << 3,
B_DATE_ELEMENT_AM_PM = 1 << 4,
B_DATE_ELEMENT_HOUR = 1 << 5,
B_DATE_ELEMENT_MINUTE = 1 << 6,
B_DATE_ELEMENT_SECOND = 1 << 7,
B_DATE_ELEMENT_TIMEZONE = 1 << 8
};



class BDateTimeFormat : public BFormat {
public:
BDateTimeFormat();
BDateTimeFormat(
const BLanguage* const language = NULL,
const BFormattingConventions* const format
= NULL);
BDateTimeFormat(const BDateTimeFormat &other);
virtual ~BDateTimeFormat();

void SetDateTimeFormat(BDateFormatStyle dateStyle,
BTimeFormatStyle timeStyle,
int32 elements);

// formatting

ssize_t Format(char* target, const size_t maxSize,
Expand All @@ -33,9 +54,7 @@ class BDateTimeFormat : public BFormat {
const BTimeZone* timeZone = NULL) const;

private:
icu::DateFormat* _CreateDateFormatter(
const BString& format) const;
icu::DateFormat* _CreateTimeFormatter(
icu::DateFormat* _CreateDateTimeFormatter(
const BString& format) const;
};

Expand Down
13 changes: 13 additions & 0 deletions headers/os/locale/FormattingConventions.h
Expand Up @@ -83,13 +83,20 @@ class BFormattingConventions : public BArchivable {
BString& outFormat) const;
status_t GetTimeFormat(BTimeFormatStyle style,
BString& outFormat) const;
status_t GetDateTimeFormat(BDateFormatStyle dateStyle,
BTimeFormatStyle timeStyle,
BString& outFormat) const;
status_t GetNumericFormat(BString& outFormat) const;
status_t GetMonetaryFormat(BString& outFormat) const;

void SetExplicitDateFormat(BDateFormatStyle style,
const BString& format);
void SetExplicitTimeFormat(BTimeFormatStyle style,
const BString& format);
void SetExplicitDateTimeFormat(
BDateFormatStyle dateStyle,
BTimeFormatStyle timeStyle,
const BString& format);
void SetExplicitNumericFormat(const BString& format);
void SetExplicitMonetaryFormat(
const BString& format);
Expand All @@ -112,12 +119,18 @@ class BFormattingConventions : public BArchivable {

mutable BString fCachedDateFormats[B_DATE_FORMAT_STYLE_COUNT];
mutable BString fCachedTimeFormats[B_TIME_FORMAT_STYLE_COUNT];
mutable BString fCachedDateTimeFormats
[B_DATE_FORMAT_STYLE_COUNT]
[B_TIME_FORMAT_STYLE_COUNT];
mutable BString fCachedNumericFormat;
mutable BString fCachedMonetaryFormat;
mutable int8 fCachedUse24HourClock;

BString fExplicitDateFormats[B_DATE_FORMAT_STYLE_COUNT];
BString fExplicitTimeFormats[B_TIME_FORMAT_STYLE_COUNT];
BString fExplicitDateTimeFormats
[B_DATE_FORMAT_STYLE_COUNT]
[B_TIME_FORMAT_STYLE_COUNT];
BString fExplicitNumericFormat;
BString fExplicitMonetaryFormat;
int8 fExplicitUse24HourClock;
Expand Down
2 changes: 1 addition & 1 deletion headers/os/locale/TimeFormat.h
Expand Up @@ -9,7 +9,7 @@


class BString;
class BTimeZone;


class BTimeFormat : public BFormat {
public:
Expand Down
104 changes: 55 additions & 49 deletions src/kits/locale/DateTimeFormat.cpp
Expand Up @@ -17,12 +17,18 @@
#include <ICUWrapper.h>

#include <unicode/datefmt.h>
#include <unicode/dtptngen.h>
#include <unicode/smpdtfmt.h>


BDateTimeFormat::BDateTimeFormat()
: BFormat()
BDateTimeFormat::BDateTimeFormat(const BLanguage* const language,
const BFormattingConventions* const conventions)
{
if (conventions != NULL)
fConventions = *conventions;

if (language != NULL)
fLanguage = *language;
}


Expand All @@ -37,6 +43,45 @@ BDateTimeFormat::~BDateTimeFormat()
}


void
BDateTimeFormat::SetDateTimeFormat(BDateFormatStyle dateStyle,
BTimeFormatStyle timeStyle, int32 elements) {
UErrorCode error = U_ZERO_ERROR;
DateTimePatternGenerator* generator
= DateTimePatternGenerator::createInstance(error);

BString skeleton;
if (elements & B_DATE_ELEMENT_YEAR)
skeleton << "yyyy";
if (elements & B_DATE_ELEMENT_MONTH)
skeleton << "MM";
if (elements & B_DATE_ELEMENT_WEEKDAY)
skeleton << "eee";
if (elements & B_DATE_ELEMENT_DAY)
skeleton << "dd";
if (elements & B_DATE_ELEMENT_AM_PM)
skeleton << "a";
if (elements & B_DATE_ELEMENT_HOUR)
skeleton << "jj";
if (elements & B_DATE_ELEMENT_MINUTE)
skeleton << "mm";
if (elements & B_DATE_ELEMENT_SECOND)
skeleton << "ss";
if (elements & B_DATE_ELEMENT_TIMEZONE)
skeleton << "V";

UnicodeString pattern = generator->getBestPattern(
UnicodeString::fromUTF8(skeleton.String()), error);

BString buffer;
BStringByteSink stringConverter(&buffer);
pattern.toUTF8(stringConverter);
fConventions.SetExplicitDateTimeFormat(dateStyle, timeStyle, buffer);

delete generator;
}


// #pragma mark - Formatting


Expand All @@ -49,23 +94,14 @@ BDateTimeFormat::Format(char* target, size_t maxSize, time_t time,
return B_ERROR;

BString format;
fConventions.GetDateFormat(dateStyle, format);
ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format));
fConventions.GetDateTimeFormat(dateStyle, timeStyle, format);
ObjectDeleter<DateFormat> dateFormatter(_CreateDateTimeFormatter(format));
if (dateFormatter.Get() == NULL)
return B_NO_MEMORY;

fConventions.GetTimeFormat(timeStyle, format);
ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
if (timeFormatter.Get() == NULL)
return B_NO_MEMORY;

UnicodeString icuString;
dateFormatter->format((UDate)time * 1000, icuString);

icuString.append(UnicodeString::fromUTF8(", "));

timeFormatter->format((UDate)time * 1000, icuString);

CheckedArrayByteSink stringConverter(target, maxSize);
icuString.toUTF8(stringConverter);

Expand All @@ -86,28 +122,21 @@ BDateTimeFormat::Format(BString& target, const time_t time,
return B_ERROR;

BString format;
fConventions.GetDateFormat(dateStyle, format);
ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format));
fConventions.GetDateTimeFormat(dateStyle, timeStyle, format);
ObjectDeleter<DateFormat> dateFormatter(_CreateDateTimeFormatter(format));
if (dateFormatter.Get() == NULL)
return B_NO_MEMORY;

fConventions.GetTimeFormat(timeStyle, 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());
dateFormatter->setTimeZone(*icuTimeZone.Get());
}

UnicodeString icuString;
dateFormatter->format((UDate)time * 1000, icuString);
icuString.append(UnicodeString::fromUTF8(", "));
timeFormatter->format((UDate)time * 1000, icuString);

target.Truncate(0);
BStringByteSink stringConverter(&target);
Expand All @@ -118,15 +147,15 @@ BDateTimeFormat::Format(BString& target, const time_t time,


DateFormat*
BDateTimeFormat::_CreateDateFormatter(const BString& format) const
BDateTimeFormat::_CreateDateTimeFormatter(const BString& format) const
{
Locale* icuLocale
= fConventions.UseStringsFromPreferredLanguage()
? BLanguage::Private(&fLanguage).ICULocale()
: BFormattingConventions::Private(&fConventions).ICULocale();

icu::DateFormat* dateFormatter
= icu::DateFormat::createDateInstance(DateFormat::kShort, *icuLocale);
icu::DateFormat* dateFormatter = icu::DateFormat::createDateTimeInstance(
DateFormat::kDefault, DateFormat::kDefault, *icuLocale);
if (dateFormatter == NULL)
return NULL;

Expand All @@ -138,26 +167,3 @@ BDateTimeFormat::_CreateDateFormatter(const BString& format) const

return dateFormatter;
}


DateFormat*
BDateTimeFormat::_CreateTimeFormatter(const BString& format) const
{
Locale* icuLocale
= fConventions.UseStringsFromPreferredLanguage()
? BLanguage::Private(&fLanguage).ICULocale()
: BFormattingConventions::Private(&fConventions).ICULocale();

icu::DateFormat* timeFormatter
= icu::DateFormat::createTimeInstance(DateFormat::kShort, *icuLocale);
if (timeFormatter == NULL)
return NULL;

SimpleDateFormat* timeFormatterImpl
= static_cast<SimpleDateFormat*>(timeFormatter);

UnicodeString pattern(format.String());
timeFormatterImpl->applyPattern(pattern);

return timeFormatter;
}

0 comments on commit 4a3a474

Please sign in to comment.