1/*
2 * Copyright 2003, Axel D��rfler, axeld@pinc-software.de.
3 * Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de.
4 * Copyright 2012, John Scipione, jscipione@gmail.com
5 * All rights reserved. Distributed under the terms of the OpenBeOS License.
6 */
7
8
9#include <AutoDeleter.h>
10#include <Autolock.h>
11#include <CalendarView.h>
12#include <Catalog.h>
13#include <FormattingConventionsPrivate.h>
14#include <LanguagePrivate.h>
15#include <Locale.h>
16#include <LocaleRoster.h>
17#include <TimeZone.h>
18
19#include <ICUWrapper.h>
20
21#include <unicode/datefmt.h>
22#include <unicode/dcfmtsym.h>
23#include <unicode/decimfmt.h>
24#include <unicode/dtfmtsym.h>
25#include <unicode/numfmt.h>
26#include <unicode/smpdtfmt.h>
27#include <unicode/ustring.h>
28
29#include <vector>
30
31
32using BPrivate::ObjectDeleter;
33
34
35BLocale::BLocale(const BLanguage* language,
36	const BFormattingConventions* conventions)
37{
38	if (conventions != NULL)
39		fConventions = *conventions;
40	else
41		BLocale::Default()->GetFormattingConventions(&fConventions);
42
43	if (language != NULL)
44		fLanguage = *language;
45	else
46		BLocale::Default()->GetLanguage(&fLanguage);
47}
48
49
50BLocale::BLocale(const BLocale& other)
51	:
52	fConventions(other.fConventions),
53	fLanguage(other.fLanguage)
54{
55}
56
57
58/*static*/ const BLocale*
59BLocale::Default()
60{
61	return BLocaleRoster::Default()->GetDefaultLocale();
62}
63
64
65BLocale&
66BLocale::operator=(const BLocale& other)
67{
68	if (this == &other)
69		return *this;
70
71	BAutolock lock(fLock);
72	BAutolock otherLock(other.fLock);
73	if (!lock.IsLocked() || !otherLock.IsLocked())
74		return *this;
75
76	fConventions = other.fConventions;
77	fLanguage = other.fLanguage;
78
79	return *this;
80}
81
82
83BLocale::~BLocale()
84{
85}
86
87
88status_t
89BLocale::GetCollator(BCollator* collator) const
90{
91	if (!collator)
92		return B_BAD_VALUE;
93
94	BAutolock lock(fLock);
95	if (!lock.IsLocked())
96		return B_ERROR;
97
98	*collator = fCollator;
99
100	return B_OK;
101}
102
103
104status_t
105BLocale::GetLanguage(BLanguage* language) const
106{
107	if (!language)
108		return B_BAD_VALUE;
109
110	BAutolock lock(fLock);
111	if (!lock.IsLocked())
112		return B_ERROR;
113
114	*language = fLanguage;
115
116	return B_OK;
117}
118
119
120status_t
121BLocale::GetFormattingConventions(BFormattingConventions* conventions) const
122{
123	if (!conventions)
124		return B_BAD_VALUE;
125
126	BAutolock lock(fLock);
127	if (!lock.IsLocked())
128		return B_ERROR;
129
130	*conventions = fConventions;
131
132	return B_OK;
133}
134
135
136const char *
137BLocale::GetString(uint32 id) const
138{
139	// Note: this code assumes a certain order of the string bases
140
141	BAutolock lock(fLock);
142	if (!lock.IsLocked())
143		return "";
144
145	if (id >= B_OTHER_STRINGS_BASE) {
146		if (id == B_CODESET)
147			return "UTF-8";
148
149		return "";
150	}
151	return fLanguage.GetString(id);
152}
153
154
155void
156BLocale::SetFormattingConventions(const BFormattingConventions& conventions)
157{
158	BAutolock lock(fLock);
159	if (!lock.IsLocked())
160		return;
161
162	fConventions = conventions;
163}
164
165
166void
167BLocale::SetCollator(const BCollator& newCollator)
168{
169	BAutolock lock(fLock);
170	if (!lock.IsLocked())
171		return;
172
173	fCollator = newCollator;
174}
175
176
177void
178BLocale::SetLanguage(const BLanguage& newLanguage)
179{
180	BAutolock lock(fLock);
181	if (!lock.IsLocked())
182		return;
183
184	fLanguage = newLanguage;
185}
186
187
188// #pragma mark - Date
189
190
191ssize_t
192BLocale::FormatDate(char* string, size_t maxSize, time_t time,
193	BDateFormatStyle style) const
194{
195	BAutolock lock(fLock);
196	if (!lock.IsLocked())
197		return B_ERROR;
198
199	BString format;
200	fConventions.GetDateFormat(style, format);
201	ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format));
202	if (dateFormatter.Get() == NULL)
203		return B_NO_MEMORY;
204
205	UnicodeString icuString;
206	dateFormatter->format((UDate)time * 1000, icuString);
207
208	CheckedArrayByteSink stringConverter(string, maxSize);
209	icuString.toUTF8(stringConverter);
210
211	if (stringConverter.Overflowed())
212		return B_BAD_VALUE;
213
214	return stringConverter.NumberOfBytesWritten();
215}
216
217
218status_t
219BLocale::FormatDate(BString *string, time_t time, BDateFormatStyle style,
220	const BTimeZone* timeZone) const
221{
222	BAutolock lock(fLock);
223	if (!lock.IsLocked())
224		return B_ERROR;
225
226	BString format;
227	fConventions.GetDateFormat(style, format);
228	ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format));
229	if (dateFormatter.Get() == NULL)
230		return B_NO_MEMORY;
231
232	if (timeZone != NULL) {
233		ObjectDeleter<TimeZone> icuTimeZone(
234			TimeZone::createTimeZone(timeZone->ID().String()));
235		if (icuTimeZone.Get() == NULL)
236			return B_NO_MEMORY;
237		dateFormatter->setTimeZone(*icuTimeZone.Get());
238	}
239
240	UnicodeString icuString;
241	dateFormatter->format((UDate)time * 1000, icuString);
242
243	string->Truncate(0);
244	BStringByteSink stringConverter(string);
245	icuString.toUTF8(stringConverter);
246
247	return B_OK;
248}
249
250
251status_t
252BLocale::FormatDate(BString* string, int*& fieldPositions, int& fieldCount,
253	time_t time, BDateFormatStyle style) const
254{
255	BAutolock lock(fLock);
256	if (!lock.IsLocked())
257		return B_ERROR;
258
259	BString format;
260	fConventions.GetDateFormat(style, format);
261	ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format));
262	if (dateFormatter.Get() == NULL)
263		return B_NO_MEMORY;
264
265	fieldPositions = NULL;
266	UErrorCode error = U_ZERO_ERROR;
267	icu::FieldPositionIterator positionIterator;
268	UnicodeString icuString;
269	dateFormatter->format((UDate)time * 1000, icuString, &positionIterator,
270		error);
271
272	if (error != U_ZERO_ERROR)
273		return B_BAD_VALUE;
274
275	icu::FieldPosition field;
276	std::vector<int> fieldPosStorage;
277	fieldCount  = 0;
278	while (positionIterator.next(field)) {
279		fieldPosStorage.push_back(field.getBeginIndex());
280		fieldPosStorage.push_back(field.getEndIndex());
281		fieldCount += 2;
282	}
283
284	fieldPositions = (int*) malloc(fieldCount * sizeof(int));
285
286	for (int i = 0 ; i < fieldCount ; i++ )
287		fieldPositions[i] = fieldPosStorage[i];
288
289	string->Truncate(0);
290	BStringByteSink stringConverter(string);
291
292	icuString.toUTF8(stringConverter);
293
294	return B_OK;
295}
296
297
298status_t
299BLocale::GetDateFields(BDateElement*& fields, int& fieldCount,
300	BDateFormatStyle style) const
301{
302	BAutolock lock(fLock);
303	if (!lock.IsLocked())
304		return B_ERROR;
305
306	BString format;
307	fConventions.GetDateFormat(style, format);
308	ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format));
309	if (dateFormatter.Get() == NULL)
310		return B_NO_MEMORY;
311
312	fields = NULL;
313	UErrorCode error = U_ZERO_ERROR;
314	icu::FieldPositionIterator positionIterator;
315	UnicodeString icuString;
316	time_t now;
317	dateFormatter->format((UDate)time(&now) * 1000, icuString,
318		&positionIterator, error);
319
320	if (U_FAILURE(error))
321		return B_BAD_VALUE;
322
323	icu::FieldPosition field;
324	std::vector<int> fieldPosStorage;
325	fieldCount  = 0;
326	while (positionIterator.next(field)) {
327		fieldPosStorage.push_back(field.getField());
328		fieldCount ++;
329	}
330
331	fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement));
332
333	for (int i = 0 ; i < fieldCount ; i++ ) {
334		switch (fieldPosStorage[i]) {
335			case UDAT_YEAR_FIELD:
336				fields[i] = B_DATE_ELEMENT_YEAR;
337				break;
338			case UDAT_MONTH_FIELD:
339				fields[i] = B_DATE_ELEMENT_MONTH;
340				break;
341			case UDAT_DATE_FIELD:
342				fields[i] = B_DATE_ELEMENT_DAY;
343				break;
344			default:
345				fields[i] = B_DATE_ELEMENT_INVALID;
346				break;
347		}
348	}
349
350	return B_OK;
351}
352
353
354status_t
355BLocale::GetStartOfWeek(BWeekday* startOfWeek) const
356{
357	if (startOfWeek == NULL)
358		return B_BAD_VALUE;
359
360	BAutolock lock(fLock);
361	if (!lock.IsLocked())
362		return B_ERROR;
363
364	UErrorCode err = U_ZERO_ERROR;
365	ObjectDeleter<Calendar> calendar = Calendar::createInstance(
366		*BFormattingConventions::Private(&fConventions).ICULocale(), err);
367
368	if (U_FAILURE(err))
369		return B_ERROR;
370
371	UCalendarDaysOfWeek icuWeekStart = calendar->getFirstDayOfWeek(err);
372	if (U_FAILURE(err))
373		return B_ERROR;
374
375	switch (icuWeekStart) {
376		case UCAL_SUNDAY:
377			*startOfWeek = B_WEEKDAY_SUNDAY;
378			break;
379		case UCAL_MONDAY:
380			*startOfWeek = B_WEEKDAY_MONDAY;
381			break;
382		case UCAL_TUESDAY:
383			*startOfWeek = B_WEEKDAY_TUESDAY;
384			break;
385		case UCAL_WEDNESDAY:
386			*startOfWeek = B_WEEKDAY_WEDNESDAY;
387			break;
388		case UCAL_THURSDAY:
389			*startOfWeek = B_WEEKDAY_THURSDAY;
390			break;
391		case UCAL_FRIDAY:
392			*startOfWeek = B_WEEKDAY_FRIDAY;
393			break;
394		case UCAL_SATURDAY:
395			*startOfWeek = B_WEEKDAY_SATURDAY;
396			break;
397		default:
398			return B_ERROR;
399	}
400
401	return B_OK;
402}
403
404
405ssize_t
406BLocale::FormatDateTime(char* target, size_t maxSize, time_t time,
407	BDateFormatStyle dateStyle, BTimeFormatStyle timeStyle) const
408{
409	BAutolock lock(fLock);
410	if (!lock.IsLocked())
411		return B_ERROR;
412
413	BString format;
414	fConventions.GetDateFormat(dateStyle, format);
415	ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format));
416	if (dateFormatter.Get() == NULL)
417		return B_NO_MEMORY;
418
419	fConventions.GetTimeFormat(timeStyle, format);
420	ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
421	if (timeFormatter.Get() == NULL)
422		return B_NO_MEMORY;
423
424	UnicodeString icuString;
425	dateFormatter->format((UDate)time * 1000, icuString);
426
427	icuString.append(UnicodeString::fromUTF8(", "));
428
429	timeFormatter->format((UDate)time * 1000, icuString);
430
431	CheckedArrayByteSink stringConverter(target, maxSize);
432	icuString.toUTF8(stringConverter);
433
434	if (stringConverter.Overflowed())
435		return B_BAD_VALUE;
436
437	return stringConverter.NumberOfBytesWritten();
438}
439
440
441status_t
442BLocale::FormatDateTime(BString* target, time_t time,
443	BDateFormatStyle dateStyle, BTimeFormatStyle timeStyle,
444	const BTimeZone* timeZone) const
445{
446	BAutolock lock(fLock);
447	if (!lock.IsLocked())
448		return B_ERROR;
449
450	BString format;
451	fConventions.GetDateFormat(dateStyle, format);
452	ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format));
453	if (dateFormatter.Get() == NULL)
454		return B_NO_MEMORY;
455
456	fConventions.GetTimeFormat(timeStyle, format);
457	ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
458	if (timeFormatter.Get() == NULL)
459		return B_NO_MEMORY;
460
461	if (timeZone != NULL) {
462		ObjectDeleter<TimeZone> icuTimeZone(
463			TimeZone::createTimeZone(timeZone->ID().String()));
464		if (icuTimeZone.Get() == NULL)
465			return B_NO_MEMORY;
466		timeFormatter->setTimeZone(*icuTimeZone.Get());
467	}
468
469	UnicodeString icuString;
470	dateFormatter->format((UDate)time * 1000, icuString);
471	icuString.append(UnicodeString::fromUTF8(", "));
472	timeFormatter->format((UDate)time * 1000, icuString);
473
474	target->Truncate(0);
475	BStringByteSink stringConverter(target);
476	icuString.toUTF8(stringConverter);
477
478	return B_OK;
479}
480
481
482// #pragma mark - Time
483
484
485ssize_t
486BLocale::FormatTime(char* string, size_t maxSize, time_t time,
487	BTimeFormatStyle style) const
488{
489	BAutolock lock(fLock);
490	if (!lock.IsLocked())
491		return B_ERROR;
492
493	BString format;
494	fConventions.GetTimeFormat(style, format);
495	ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
496	if (timeFormatter.Get() == NULL)
497		return B_NO_MEMORY;
498
499	UnicodeString icuString;
500	timeFormatter->format((UDate)time * 1000, icuString);
501
502	CheckedArrayByteSink stringConverter(string, maxSize);
503	icuString.toUTF8(stringConverter);
504
505	if (stringConverter.Overflowed())
506		return B_BAD_VALUE;
507
508	return stringConverter.NumberOfBytesWritten();
509}
510
511
512ssize_t
513BLocale::FormatTime(char* string, size_t maxSize, time_t time,
514	BString format) const
515{
516	BAutolock lock(fLock);
517	if (!lock.IsLocked())
518		return B_ERROR;
519
520	if (format == NULL || format.CountChars() <= 0)
521		return B_BAD_VALUE;
522
523	ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
524	if (timeFormatter.Get() == NULL)
525		return B_NO_MEMORY;
526
527	UnicodeString icuString;
528	timeFormatter->format((UDate)time * 1000, icuString);
529
530	CheckedArrayByteSink stringConverter(string, maxSize);
531	icuString.toUTF8(stringConverter);
532
533	if (stringConverter.Overflowed())
534		return B_BAD_VALUE;
535
536	return stringConverter.NumberOfBytesWritten();
537}
538
539
540status_t
541BLocale::FormatTime(BString* string, time_t time, BTimeFormatStyle style,
542	const BTimeZone* timeZone) const
543{
544	BAutolock lock(fLock);
545	if (!lock.IsLocked())
546		return B_ERROR;
547
548	BString format;
549	fConventions.GetTimeFormat(style, format);
550	ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
551	if (timeFormatter.Get() == NULL)
552		return B_NO_MEMORY;
553
554	if (timeZone != NULL) {
555		ObjectDeleter<TimeZone> icuTimeZone(
556			TimeZone::createTimeZone(timeZone->ID().String()));
557		if (icuTimeZone.Get() == NULL)
558			return B_NO_MEMORY;
559		timeFormatter->setTimeZone(*icuTimeZone.Get());
560	}
561
562	UnicodeString icuString;
563	timeFormatter->format((UDate)time * 1000, icuString);
564
565	string->Truncate(0);
566	BStringByteSink stringConverter(string);
567	icuString.toUTF8(stringConverter);
568
569	return B_OK;
570}
571
572
573status_t
574BLocale::FormatTime(BString* string, time_t time, BString format,
575	const BTimeZone* timeZone) const
576{
577	BAutolock lock(fLock);
578	if (!lock.IsLocked())
579		return B_ERROR;
580
581	if (format == NULL || format.CountChars() <= 0)
582		return B_BAD_VALUE;
583
584	ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
585	if (timeFormatter.Get() == NULL)
586		return B_NO_MEMORY;
587
588	if (timeZone != NULL) {
589		ObjectDeleter<TimeZone> icuTimeZone(
590			TimeZone::createTimeZone(timeZone->ID().String()));
591		if (icuTimeZone.Get() == NULL)
592			return B_NO_MEMORY;
593		timeFormatter->setTimeZone(*icuTimeZone.Get());
594	}
595
596	UnicodeString icuString;
597	timeFormatter->format((UDate)time * 1000, icuString);
598
599	string->Truncate(0);
600	BStringByteSink stringConverter(string);
601	icuString.toUTF8(stringConverter);
602
603	return B_OK;
604}
605
606
607status_t
608BLocale::FormatTime(BString* string, int*& fieldPositions, int& fieldCount,
609	time_t time, BTimeFormatStyle style) const
610{
611	BAutolock lock(fLock);
612	if (!lock.IsLocked())
613		return B_ERROR;
614
615	BString format;
616	fConventions.GetTimeFormat(style, format);
617	ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
618	if (timeFormatter.Get() == NULL)
619		return B_NO_MEMORY;
620
621	fieldPositions = NULL;
622	UErrorCode error = U_ZERO_ERROR;
623	icu::FieldPositionIterator positionIterator;
624	UnicodeString icuString;
625	timeFormatter->format((UDate)time * 1000, icuString, &positionIterator,
626		error);
627
628	if (error != U_ZERO_ERROR)
629		return B_BAD_VALUE;
630
631	icu::FieldPosition field;
632	std::vector<int> fieldPosStorage;
633	fieldCount  = 0;
634	while (positionIterator.next(field)) {
635		fieldPosStorage.push_back(field.getBeginIndex());
636		fieldPosStorage.push_back(field.getEndIndex());
637		fieldCount += 2;
638	}
639
640	fieldPositions = (int*) malloc(fieldCount * sizeof(int));
641
642	for (int i = 0 ; i < fieldCount ; i++ )
643		fieldPositions[i] = fieldPosStorage[i];
644
645	string->Truncate(0);
646	BStringByteSink stringConverter(string);
647	icuString.toUTF8(stringConverter);
648
649	return B_OK;
650}
651
652
653status_t
654BLocale::GetTimeFields(BDateElement*& fields, int& fieldCount,
655	BTimeFormatStyle style) const
656{
657	BAutolock lock(fLock);
658	if (!lock.IsLocked())
659		return B_ERROR;
660
661	BString format;
662	fConventions.GetTimeFormat(style, format);
663	ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format));
664	if (timeFormatter.Get() == NULL)
665		return B_NO_MEMORY;
666
667	fields = NULL;
668	UErrorCode error = U_ZERO_ERROR;
669	icu::FieldPositionIterator positionIterator;
670	UnicodeString icuString;
671	time_t now;
672	timeFormatter->format((UDate)time(&now) * 1000, icuString,
673		&positionIterator, error);
674
675	if (error != U_ZERO_ERROR)
676		return B_BAD_VALUE;
677
678	icu::FieldPosition field;
679	std::vector<int> fieldPosStorage;
680	fieldCount  = 0;
681	while (positionIterator.next(field)) {
682		fieldPosStorage.push_back(field.getField());
683		fieldCount ++;
684	}
685
686	fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement));
687
688	for (int i = 0 ; i < fieldCount ; i++ ) {
689		switch (fieldPosStorage[i]) {
690			case UDAT_HOUR_OF_DAY1_FIELD:
691			case UDAT_HOUR_OF_DAY0_FIELD:
692			case UDAT_HOUR1_FIELD:
693			case UDAT_HOUR0_FIELD:
694				fields[i] = B_DATE_ELEMENT_HOUR;
695				break;
696			case UDAT_MINUTE_FIELD:
697				fields[i] = B_DATE_ELEMENT_MINUTE;
698				break;
699			case UDAT_SECOND_FIELD:
700				fields[i] = B_DATE_ELEMENT_SECOND;
701				break;
702			case UDAT_AM_PM_FIELD:
703				fields[i] = B_DATE_ELEMENT_AM_PM;
704				break;
705			default:
706				fields[i] = B_DATE_ELEMENT_INVALID;
707				break;
708		}
709	}
710
711	return B_OK;
712}
713
714
715// #pragma mark - Numbers
716
717
718ssize_t
719BLocale::FormatNumber(char* string, size_t maxSize, double value) const
720{
721	BString fullString;
722	status_t status = FormatNumber(&fullString, value);
723	if (status != B_OK)
724		return status;
725
726	return strlcpy(string, fullString.String(), maxSize);
727}
728
729
730status_t
731BLocale::FormatNumber(BString* string, double value) const
732{
733	BAutolock lock(fLock);
734	if (!lock.IsLocked())
735		return B_ERROR;
736
737	UErrorCode err = U_ZERO_ERROR;
738	ObjectDeleter<NumberFormat> numberFormatter(NumberFormat::createInstance(
739		*BFormattingConventions::Private(&fConventions).ICULocale(),
740		UNUM_DECIMAL, err));
741
742	if (numberFormatter.Get() == NULL)
743		return B_NO_MEMORY;
744	if (U_FAILURE(err))
745		return B_BAD_VALUE;
746
747	UnicodeString icuString;
748	numberFormatter->format(value, icuString);
749
750	string->Truncate(0);
751	BStringByteSink stringConverter(string);
752	icuString.toUTF8(stringConverter);
753
754	return B_OK;
755}
756
757
758ssize_t
759BLocale::FormatNumber(char* string, size_t maxSize, int32 value) const
760{
761	BString fullString;
762	status_t status = FormatNumber(&fullString, value);
763	if (status != B_OK)
764		return status;
765
766	return strlcpy(string, fullString.String(), maxSize);
767}
768
769
770status_t
771BLocale::FormatNumber(BString* string, int32 value) const
772{
773	BAutolock lock(fLock);
774	if (!lock.IsLocked())
775		return B_ERROR;
776
777	UErrorCode err = U_ZERO_ERROR;
778	ObjectDeleter<NumberFormat> numberFormatter(NumberFormat::createInstance(
779		*BFormattingConventions::Private(&fConventions).ICULocale(),
780		UNUM_DECIMAL, err));
781
782	if (numberFormatter.Get() == NULL)
783		return B_NO_MEMORY;
784	if (U_FAILURE(err))
785		return B_BAD_VALUE;
786
787	UnicodeString icuString;
788	numberFormatter->format((int32_t)value, icuString);
789
790	string->Truncate(0);
791	BStringByteSink stringConverter(string);
792	icuString.toUTF8(stringConverter);
793
794	return B_OK;
795}
796
797
798ssize_t
799BLocale::FormatMonetary(char* string, size_t maxSize, double value) const
800{
801	BString fullString;
802	status_t status = FormatMonetary(&fullString, value);
803	if (status != B_OK)
804		return status;
805
806	return strlcpy(string, fullString.String(), maxSize);
807}
808
809
810status_t
811BLocale::FormatMonetary(BString* string, double value) const
812{
813	if (string == NULL)
814		return B_BAD_VALUE;
815
816	BAutolock lock(fLock);
817	if (!lock.IsLocked())
818		return B_ERROR;
819
820	UErrorCode err = U_ZERO_ERROR;
821	ObjectDeleter<NumberFormat> numberFormatter(
822		NumberFormat::createCurrencyInstance(
823			*BFormattingConventions::Private(&fConventions).ICULocale(),
824			err));
825
826	if (numberFormatter.Get() == NULL)
827		return B_NO_MEMORY;
828	if (U_FAILURE(err))
829		return B_BAD_VALUE;
830
831	UnicodeString icuString;
832	numberFormatter->format(value, icuString);
833
834	string->Truncate(0);
835	BStringByteSink stringConverter(string);
836	icuString.toUTF8(stringConverter);
837
838	return B_OK;
839}
840
841
842DateFormat*
843BLocale::_CreateDateFormatter(const BString& format) const
844{
845	Locale* icuLocale
846		= fConventions.UseStringsFromPreferredLanguage()
847			? BLanguage::Private(&fLanguage).ICULocale()
848			: BFormattingConventions::Private(&fConventions).ICULocale();
849
850	DateFormat* dateFormatter
851		= DateFormat::createDateInstance(DateFormat::kShort, *icuLocale);
852	if (dateFormatter == NULL)
853		return NULL;
854
855	SimpleDateFormat* dateFormatterImpl
856		= static_cast<SimpleDateFormat*>(dateFormatter);
857
858	UnicodeString pattern(format.String());
859	dateFormatterImpl->applyPattern(pattern);
860
861	return dateFormatter;
862}
863
864
865DateFormat*
866BLocale::_CreateTimeFormatter(const BString& format) const
867{
868	Locale* icuLocale
869		= fConventions.UseStringsFromPreferredLanguage()
870			? BLanguage::Private(&fLanguage).ICULocale()
871			: BFormattingConventions::Private(&fConventions).ICULocale();
872
873	DateFormat* timeFormatter
874		= DateFormat::createTimeInstance(DateFormat::kShort, *icuLocale);
875	if (timeFormatter == NULL)
876		return NULL;
877
878	SimpleDateFormat* timeFormatterImpl
879		= static_cast<SimpleDateFormat*>(timeFormatter);
880
881	UnicodeString pattern(format.String());
882	timeFormatterImpl->applyPattern(pattern);
883
884	return timeFormatter;
885}
886