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