1/*
2 * Copyright 2010-2014, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Oliver Tappe <zooey@hirschkaefer.de>
7 */
8
9#include <unicode/uversion.h>
10#include <DateTimeFormat.h>
11
12#include <AutoDeleter.h>
13#include <Autolock.h>
14#include <FormattingConventionsPrivate.h>
15#include <LanguagePrivate.h>
16#include <TimeZone.h>
17
18#include <ICUWrapper.h>
19
20#include <unicode/datefmt.h>
21#include <unicode/dtptngen.h>
22#include <unicode/smpdtfmt.h>
23
24
25U_NAMESPACE_USE
26
27
28BDateTimeFormat::BDateTimeFormat(const BLocale* locale)
29	: BFormat(locale)
30{
31}
32
33
34BDateTimeFormat::BDateTimeFormat(const BLanguage& language,
35	const BFormattingConventions& conventions)
36	: BFormat(language, conventions)
37{
38}
39
40
41BDateTimeFormat::BDateTimeFormat(const BDateTimeFormat &other)
42	: BFormat(other)
43{
44}
45
46
47BDateTimeFormat::~BDateTimeFormat()
48{
49}
50
51
52void
53BDateTimeFormat::SetDateTimeFormat(BDateFormatStyle dateStyle,
54	BTimeFormatStyle timeStyle, int32 elements) {
55	UErrorCode error = U_ZERO_ERROR;
56	DateTimePatternGenerator* generator
57		= DateTimePatternGenerator::createInstance(
58			*BLanguage::Private(&fLanguage).ICULocale(), error);
59
60	BString skeleton;
61	if (elements & B_DATE_ELEMENT_YEAR)
62		skeleton << "yyyy";
63	if (elements & B_DATE_ELEMENT_MONTH)
64		skeleton << "MM";
65	if (elements & B_DATE_ELEMENT_WEEKDAY)
66		skeleton << "eee";
67	if (elements & B_DATE_ELEMENT_DAY)
68		skeleton << "dd";
69	if (elements & B_DATE_ELEMENT_AM_PM)
70		skeleton << "a";
71	if (elements & B_DATE_ELEMENT_HOUR) {
72		if (fConventions.Use24HourClock())
73			skeleton << "k";
74		else
75			skeleton << "K";
76	}
77	if (elements & B_DATE_ELEMENT_MINUTE)
78		skeleton << "mm";
79	if (elements & B_DATE_ELEMENT_SECOND)
80		skeleton << "ss";
81	if (elements & B_DATE_ELEMENT_TIMEZONE)
82		skeleton << "z";
83
84	UnicodeString pattern = generator->getBestPattern(
85		UnicodeString::fromUTF8(skeleton.String()), error);
86
87	BString buffer;
88	BStringByteSink stringConverter(&buffer);
89	pattern.toUTF8(stringConverter);
90
91	fConventions.SetExplicitDateTimeFormat(dateStyle, timeStyle, buffer);
92
93	delete generator;
94}
95
96
97// #pragma mark - Formatting
98
99
100ssize_t
101BDateTimeFormat::Format(char* target, size_t maxSize, time_t time,
102	BDateFormatStyle dateStyle, BTimeFormatStyle timeStyle) const
103{
104	BString format;
105	fConventions.GetDateTimeFormat(dateStyle, timeStyle, format);
106	ObjectDeleter<DateFormat> dateFormatter(_CreateDateTimeFormatter(format));
107	if (!dateFormatter.IsSet())
108		return B_NO_MEMORY;
109
110	UnicodeString icuString;
111	dateFormatter->format((UDate)time * 1000, icuString);
112
113	CheckedArrayByteSink stringConverter(target, maxSize);
114	icuString.toUTF8(stringConverter);
115
116	if (stringConverter.Overflowed())
117		return B_BAD_VALUE;
118
119	return stringConverter.NumberOfBytesWritten();
120}
121
122
123status_t
124BDateTimeFormat::Format(BString& target, const time_t time,
125	BDateFormatStyle dateStyle, BTimeFormatStyle timeStyle,
126	const BTimeZone* timeZone) const
127{
128	BString format;
129	fConventions.GetDateTimeFormat(dateStyle, timeStyle, format);
130	ObjectDeleter<DateFormat> dateFormatter(_CreateDateTimeFormatter(format));
131	if (!dateFormatter.IsSet())
132		return B_NO_MEMORY;
133
134	if (timeZone != NULL) {
135		ObjectDeleter<TimeZone> icuTimeZone(
136			TimeZone::createTimeZone(timeZone->ID().String()));
137		if (!icuTimeZone.IsSet())
138			return B_NO_MEMORY;
139		dateFormatter->setTimeZone(*icuTimeZone.Get());
140	}
141
142	UnicodeString icuString;
143	dateFormatter->format((UDate)time * 1000, icuString);
144
145	target.Truncate(0);
146	BStringByteSink stringConverter(&target);
147	icuString.toUTF8(stringConverter);
148
149	return B_OK;
150}
151
152
153DateFormat*
154BDateTimeFormat::_CreateDateTimeFormatter(const BString& format) const
155{
156	Locale* icuLocale
157		= fConventions.UseStringsFromPreferredLanguage()
158			? BLanguage::Private(&fLanguage).ICULocale()
159			: BFormattingConventions::Private(&fConventions).ICULocale();
160
161	icu::DateFormat* dateFormatter = icu::DateFormat::createDateTimeInstance(
162		DateFormat::kDefault, DateFormat::kDefault, *icuLocale);
163	if (dateFormatter == NULL)
164		return NULL;
165
166	SimpleDateFormat* dateFormatterImpl
167		= static_cast<SimpleDateFormat*>(dateFormatter);
168
169	UnicodeString pattern(format.String());
170	dateFormatterImpl->applyPattern(pattern);
171
172	return dateFormatter;
173}
174