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