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