summaryrefslogtreecommitdiff
path: root/src/corefx
diff options
context:
space:
mode:
authorSteve Harter <sharter@microsoft.com>2015-09-18 14:01:16 -0500
committerMatt Ellis <matell@microsoft.com>2015-09-22 11:50:40 -0700
commit7561e211e364255805314e27064ff62782a05b5e (patch)
tree00d454c29b4e3019e136b4f9b848ffa784982fb9 /src/corefx
parentcf5669690fbd4fe08ecf264783380667ceb25c27 (diff)
downloadcoreclr-7561e211e364255805314e27064ff62782a05b5e.tar.gz
coreclr-7561e211e364255805314e27064ff62782a05b5e.tar.bz2
coreclr-7561e211e364255805314e27064ff62782a05b5e.zip
complete core implementation of CultureData for Unix
Diffstat (limited to 'src/corefx')
-rw-r--r--src/corefx/System.Globalization.Native/locale.cpp49
-rw-r--r--src/corefx/System.Globalization.Native/locale.hpp8
-rw-r--r--src/corefx/System.Globalization.Native/localeNumberData.cpp248
-rw-r--r--src/corefx/System.Globalization.Native/localeStringData.cpp110
4 files changed, 335 insertions, 80 deletions
diff --git a/src/corefx/System.Globalization.Native/locale.cpp b/src/corefx/System.Globalization.Native/locale.cpp
index d0675047a2..e02c32d680 100644
--- a/src/corefx/System.Globalization.Native/locale.cpp
+++ b/src/corefx/System.Globalization.Native/locale.cpp
@@ -14,7 +14,21 @@
#include "unicode/localpointer.h"
#include "unicode/ulocdata.h"
-inline int32_t UErrorCodeToBool(UErrorCode code) { return U_SUCCESS(code) ? 1 : 0; }
+int32_t UErrorCodeToBool(UErrorCode status)
+{
+ if (U_SUCCESS(status))
+ {
+ return 1;
+ }
+
+ // assert errors that should never occur
+ assert(status != U_BUFFER_OVERFLOW_ERROR);
+ assert(status != U_INTERNAL_PROGRAM_ERROR);
+
+ // add possible SetLastError support here
+
+ return 0;
+}
Locale GetLocale(const UChar* localeName, bool canonize)
{
@@ -50,6 +64,22 @@ UErrorCode u_charsToUChars_safe(const char *str, UChar* value, int32_t valueLeng
return U_ZERO_ERROR;
}
+void FixupLocaleName(UChar* value, int32_t valueLength)
+{
+ for (int i = 0; i < valueLength; i++)
+ {
+ if (value[i] == (UChar)'\0')
+ {
+ break;
+ }
+ else if (value[i] == (UChar)'_')
+ {
+ value[i] = (UChar)'-';
+ }
+ }
+}
+
+
extern "C" int32_t GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength)
{
Locale locale = GetLocale(localeName, true);
@@ -60,26 +90,13 @@ extern "C" int32_t GetLocaleName(const UChar* localeName, UChar* value, int32_t
return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR);
}
- if (strlen(locale.getISO3Language()) == 0)
- {
- // unknown language; language is required (script and country optional)
- return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR);
- }
+ // other validation done on managed side
UErrorCode status = u_charsToUChars_safe(locale.getName(), value, valueLength);
if (U_SUCCESS(status))
{
- // replace underscores with hyphens to interop with existing .NET code
- for (UChar* ch = value; *ch != (UChar)'\0'; ch++)
- {
- if (*ch == (UChar)'_')
- {
- *ch = (UChar)'-';
- }
- }
+ FixupLocaleName(value, valueLength);
}
- assert(status != U_BUFFER_OVERFLOW_ERROR);
-
return UErrorCodeToBool(status);
}
diff --git a/src/corefx/System.Globalization.Native/locale.hpp b/src/corefx/System.Globalization.Native/locale.hpp
index 73d331df14..894ea90936 100644
--- a/src/corefx/System.Globalization.Native/locale.hpp
+++ b/src/corefx/System.Globalization.Native/locale.hpp
@@ -38,3 +38,11 @@ u_charsToUChars_safe
Copies the given null terminated char* to UChar with error checking. Replacement for ICU u_charsToUChars
*/
UErrorCode u_charsToUChars_safe(const char *str, UChar* value, int32_t valueLength);
+
+/*
+Function:
+FixupLocaleName
+
+Replace underscores with hyphens to interop with existing .NET code
+*/
+void FixupLocaleName(UChar* value, int32_t valueLength);
diff --git a/src/corefx/System.Globalization.Native/localeNumberData.cpp b/src/corefx/System.Globalization.Native/localeNumberData.cpp
index 8ba1f066a5..7ab62ca96f 100644
--- a/src/corefx/System.Globalization.Native/localeNumberData.cpp
+++ b/src/corefx/System.Globalization.Native/localeNumberData.cpp
@@ -8,20 +8,22 @@
#include "locale.hpp"
+#include "unicode/calendar.h"
#include "unicode/decimfmt.h"
+#include "unicode/localpointer.h"
#include "unicode/numfmt.h"
#include "unicode/ulocdata.h"
// invariant character definitions used by ICU
-#define chCurrencySign ((UChar)0x00A4) // international currency
-#define chSpace ((UChar)0x0020) // space
-#define chSpace2 ((UChar)0x00A0) // space
-#define chPatternDigit ((UChar)0x0023) // '#'
-#define chPatternSeparator ((UChar)0x003B) // ';'
-#define chPatternMinus ((UChar)0x002D) // '-'
-#define chPercent ((UChar)0x0025) // '%'
-#define chOpenParen ((UChar)0x0028) // '('
-#define chCloseParen ((UChar)0x0029) // ')'
+#define UCHAR_CURRENCY ((UChar)0x00A4) // international currency
+#define UCHAR_SPACE ((UChar)0x0020) // space
+#define UCHAR_NBSPACE ((UChar)0x00A0) // space
+#define UCHAR_DIGIT ((UChar)0x0023) // '#'
+#define UCHAR_SEMICOLON ((UChar)0x003B) // ';'
+#define UCHAR_MINUS ((UChar)0x002D) // '-'
+#define UCHAR_PERCENT ((UChar)0x0025) // '%'
+#define UCHAR_OPENPAREN ((UChar)0x0028) // '('
+#define UCHAR_CLOSEPAREN ((UChar)0x0029) // ')'
#define ARRAY_LENGTH(array) (sizeof(array)/sizeof(array[0]))
@@ -36,7 +38,7 @@ enum LocaleNumberData : int32_t
MonetaryFractionalDigitsCount = 0x00000019,
PositiveMonetaryNumberFormat = 0x0000001B,
NegativeMonetaryNumberFormat = 0x0000001C,
- CalendarType = 0x00001009,
+ FirstDayofWeek = 0x0000100C,
FirstWeekOfYear = 0x0000100D,
ReadingLayout = 0x00000070,
NegativePercentFormat = 0x00000074,
@@ -45,22 +47,30 @@ enum LocaleNumberData : int32_t
Monetary = 0x00000018
};
+// Enum that corresponds to managed enum System.Globalization.CalendarWeekRule
+enum CalendarWeekRule : int32_t
+{
+ FirstDay = 0,
+ FirstFullWeek = 1,
+ FirstFourDayWeek = 2
+};
+
/*
Function:
-NormalizePattern
+NormalizeNumericPattern
Returns a numeric string pattern in a format that we can match against the appropriate managed pattern.
*/
-void NormalizePattern(const UnicodeString *srcPattern, UnicodeString *destPattern, bool isNegative)
+void NormalizeNumericPattern(const UnicodeString *srcPattern, UnicodeString *destPattern, bool isNegative)
{
- // A srcPattern example: "#,##0.00 C;(#,##0.00 C)" but where C is the international currency symbol (chCurrencySign)
+ // A srcPattern example: "#,##0.00 C;(#,##0.00 C)" but where C is the international currency symbol (UCHAR_CURRENCY)
// The positive pattern comes first, then an optional negative pattern separated by a semicolon
// A destPattern example: "(C n)" where C represents the currency symbol, and n is the number
destPattern->remove();
int iStart = 0;
int iEnd = srcPattern->length() - 1;
- int32_t iNegativePatternStart = srcPattern->indexOf(chPatternSeparator);
+ int32_t iNegativePatternStart = srcPattern->indexOf(UCHAR_SEMICOLON);
if (iNegativePatternStart >= 0)
{
if (isNegative)
@@ -80,10 +90,10 @@ void NormalizePattern(const UnicodeString *srcPattern, UnicodeString *destPatter
for (int i = iStart; i <= iEnd; i++)
{
- UChar ch = srcPattern->char32At(i);
+ UChar ch = srcPattern->charAt(i);
switch (ch)
{
- case chPatternDigit:
+ case UCHAR_DIGIT:
if (!digitAdded)
{
digitAdded = true;
@@ -91,7 +101,7 @@ void NormalizePattern(const UnicodeString *srcPattern, UnicodeString *destPatter
}
break;
- case chCurrencySign:
+ case UCHAR_CURRENCY:
if (!currencyAdded)
{
currencyAdded = true;
@@ -99,12 +109,12 @@ void NormalizePattern(const UnicodeString *srcPattern, UnicodeString *destPatter
}
break;
- case chSpace:
- case chSpace2:
+ case UCHAR_SPACE:
+ case UCHAR_NBSPACE:
if (!spaceAdded)
{
spaceAdded = true;
- destPattern->append(chSpace);
+ destPattern->append(UCHAR_SPACE);
}
else
{
@@ -112,34 +122,34 @@ void NormalizePattern(const UnicodeString *srcPattern, UnicodeString *destPatter
}
break;
- case chPatternMinus:
- case chOpenParen:
- case chCloseParen:
+ case UCHAR_MINUS:
+ case UCHAR_OPENPAREN:
+ case UCHAR_CLOSEPAREN:
minusAdded = true;
destPattern->append(ch);
break;
- case chPercent:
+ case UCHAR_PERCENT:
destPattern->append(ch);
break;
}
}
- // if there is no negative subpattern, the convention is to prefix the minus sign
+ // if there is no negative subpattern, the ICU convention is to prefix the minus sign
if (isNegative && !minusAdded)
{
- destPattern->insert(0, chPatternMinus);
+ destPattern->insert(0, UCHAR_MINUS);
}
}
/*
Function:
-GetPattern
+GetNumericPattern
Determines the pattern from the decimalFormat and returns the matching pattern's index from patterns[].
Returns index -1 if no pattern is found.
*/
-int GetPattern(DecimalFormat *decimalFormat, const char* patterns[], int patternsCount, bool isNegative)
+int GetNumericPattern(DecimalFormat *decimalFormat, const char* patterns[], int patternsCount, bool isNegative)
{
const int INVALID_FORMAT = -1;
const int MAX_DOTNET_NUMERIC_PATTERN_LENGTH = 6; // example: "(C n)" plus terminator
@@ -149,7 +159,7 @@ int GetPattern(DecimalFormat *decimalFormat, const char* patterns[], int pattern
decimalFormat->toPattern(icuPattern);
UnicodeString normalizedPattern;
- NormalizePattern(&icuPattern, &normalizedPattern, isNegative);
+ NormalizeNumericPattern(&icuPattern, &normalizedPattern, isNegative);
assert(normalizedPattern.length() > 0);
assert(normalizedPattern.length() < MAX_DOTNET_NUMERIC_PATTERN_LENGTH);
@@ -186,14 +196,22 @@ int GetCurrencyNegativePattern(const Locale &locale)
UErrorCode status = U_ZERO_ERROR;
LocalPointer<NumberFormat> format(NumberFormat::createInstance(locale, UNUM_CURRENCY, status));
- if (U_FAILURE(status))
+ assert(U_SUCCESS(status));
+ if (U_SUCCESS(status))
{
- assert(false);
- return DEFAULT_VALUE;
+ DecimalFormat* decimalFormat = dynamic_cast<DecimalFormat*>(format.getAlias());
+ assert(decimalFormat != NULL);
+ if (decimalFormat != NULL)
+ {
+ int value = GetNumericPattern(decimalFormat, Patterns, ARRAY_LENGTH(Patterns), true);
+ if (value >= 0)
+ {
+ return value;
+ }
+ }
}
- int value = GetPattern(static_cast<DecimalFormat*>(format.getAlias()), Patterns, ARRAY_LENGTH(Patterns), true);
- return (value >= 0) ? value : DEFAULT_VALUE;
+ return DEFAULT_VALUE;
}
/*
@@ -210,14 +228,22 @@ int GetCurrencyPositivePattern(const Locale &locale)
UErrorCode status = U_ZERO_ERROR;
LocalPointer<NumberFormat> format(NumberFormat::createInstance(locale, UNUM_CURRENCY, status));
- if (U_FAILURE(status))
+ assert(U_SUCCESS(status));
+ if (U_SUCCESS(status))
{
- assert(false);
- return DEFAULT_VALUE;
+ DecimalFormat* decimalFormat = dynamic_cast<DecimalFormat*>(format.getAlias());
+ assert(decimalFormat != NULL);
+ if (decimalFormat != NULL)
+ {
+ int value = GetNumericPattern(decimalFormat, Patterns, ARRAY_LENGTH(Patterns), false);
+ if (value >= 0)
+ {
+ return value;
+ }
+ }
}
- int value = GetPattern(static_cast<DecimalFormat*>(format.getAlias()), Patterns, ARRAY_LENGTH(Patterns), false);
- return (value >= 0) ? value : DEFAULT_VALUE;
+ return DEFAULT_VALUE;
}
/*
@@ -234,14 +260,22 @@ int GetNumberNegativePattern(const Locale &locale)
UErrorCode status = U_ZERO_ERROR;
LocalPointer<NumberFormat> format(NumberFormat::createInstance(locale, UNUM_DECIMAL, status));
- if (U_FAILURE(status))
+ assert(U_SUCCESS(status));
+ if (U_SUCCESS(status))
{
- assert(false);
- return DEFAULT_VALUE;
+ DecimalFormat* decimalFormat = dynamic_cast<DecimalFormat*>(format.getAlias());
+ assert(decimalFormat != NULL);
+ if (decimalFormat != NULL)
+ {
+ int value = GetNumericPattern(decimalFormat, Patterns, ARRAY_LENGTH(Patterns), true);
+ if (value >= 0)
+ {
+ return value;
+ }
+ }
}
- int value = GetPattern(static_cast<DecimalFormat*>(format.getAlias()), Patterns, ARRAY_LENGTH(Patterns), true);
- return (value >= 0) ? value : DEFAULT_VALUE;
+ return DEFAULT_VALUE;
}
/*
@@ -258,14 +292,22 @@ int GetPercentNegativePattern(const Locale &locale)
UErrorCode status = U_ZERO_ERROR;
LocalPointer<NumberFormat> format(NumberFormat::createInstance(locale, UNUM_PERCENT, status));
- if (U_FAILURE(status))
+ assert(U_SUCCESS(status));
+ if (U_SUCCESS(status))
{
- assert(false);
- return DEFAULT_VALUE;
+ DecimalFormat* decimalFormat = dynamic_cast<DecimalFormat*>(format.getAlias());
+ assert(decimalFormat != NULL);
+ if (decimalFormat != NULL)
+ {
+ int value = GetNumericPattern(decimalFormat, Patterns, ARRAY_LENGTH(Patterns), true);
+ if (value >= 0)
+ {
+ return value;
+ }
+ }
}
- int value = GetPattern(static_cast<DecimalFormat*>(format.getAlias()), Patterns, ARRAY_LENGTH(Patterns), true);
- return (value >= 0) ? value : DEFAULT_VALUE;
+ return DEFAULT_VALUE;
}
/*
@@ -282,14 +324,22 @@ int GetPercentPositivePattern(const Locale &locale)
UErrorCode status = U_ZERO_ERROR;
LocalPointer<NumberFormat> format(NumberFormat::createInstance(locale, UNUM_PERCENT, status));
- if (U_FAILURE(status))
+ assert(U_SUCCESS(status));
+ if (U_SUCCESS(status))
{
- assert(false);
- return DEFAULT_VALUE;
+ DecimalFormat* decimalFormat = dynamic_cast<DecimalFormat*>(format.getAlias());
+ assert(decimalFormat != NULL);
+ if (decimalFormat != NULL)
+ {
+ int value = GetNumericPattern(decimalFormat, Patterns, ARRAY_LENGTH(Patterns), false);
+ if (value >= 0)
+ {
+ return value;
+ }
+ }
}
- int value = GetPattern(static_cast<DecimalFormat*>(format.getAlias()), Patterns, ARRAY_LENGTH(Patterns), false);
- return (value >= 0) ? value : DEFAULT_VALUE;
+ return DEFAULT_VALUE;
}
/*
@@ -366,15 +416,55 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo
case NegativeMonetaryNumberFormat:
*value = GetCurrencyNegativePattern(locale);
break;
- case CalendarType:
- *value = 1; //TODO: implement
- break;
case FirstWeekOfYear:
- *value = 0; //TODO: implement
+ {
+ // corresponds to DateTimeFormat.CalendarWeekRule
+ LocalPointer<Calendar> calendar(Calendar::createInstance(locale, status));
+ if (U_SUCCESS(status))
+ {
+ // values correspond to LOCALE_IFIRSTWEEKOFYEAR
+ int minDaysInWeek = calendar->getMinimalDaysInFirstWeek();
+ if (minDaysInWeek == 1)
+ {
+ *value = CalendarWeekRule::FirstDay;
+ }
+ else if (minDaysInWeek == 7)
+ {
+ *value = CalendarWeekRule::FirstFullWeek;
+ }
+ else if (minDaysInWeek >= 4)
+ {
+ *value = CalendarWeekRule::FirstFourDayWeek;
+ }
+ else
+ {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ }
break;
+ }
case ReadingLayout:
- *value = 0; //todo: implement
+ {
+ // coresponds to values 0 and 1 in LOCALE_IREADINGLAYOUT (values 2 and 3 not used in coreclr)
+ // 0 - Left to right (such as en-US)
+ // 1 - Right to left (such as arabic locales)
+ ULayoutType orientation = uloc_getCharacterOrientation(locale.getName(), &status);
+ // alternative implementation in ICU 54+ is Locale.isRightToLeft() which also supports script tags in locale
+ if (U_SUCCESS(status))
+ {
+ *value = (orientation == ULOC_LAYOUT_RTL) ? 1 : 0;
+ }
break;
+ }
+ case FirstDayofWeek:
+ {
+ LocalPointer<Calendar> pcalendar(Calendar::createInstance(locale, status));
+ if (U_SUCCESS(status))
+ {
+ *value = pcalendar->getFirstDayOfWeek(status) - 1; // .NET is 0-based and ICU is 1-based
+ }
+ break;
+ }
case NegativePercentFormat:
*value = GetPercentNegativePattern(locale);
break;
@@ -387,7 +477,45 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo
break;
}
- assert(status != U_BUFFER_OVERFLOW_ERROR);
+ return UErrorCodeToBool(status);
+}
+
+/*
+PAL Function:
+GetLocaleInfoGroupingSizes
+
+Obtains grouping sizes for decimal and currency
+Returns 1 for success, 0 otherwise
+*/
+extern "C" int32_t GetLocaleInfoGroupingSizes(const UChar* localeName, LocaleNumberData localeGroupingData, int32_t* primaryGroupSize, int32_t* secondaryGroupSize)
+{
+ Locale locale = GetLocale(localeName);
+ if (locale.isBogus())
+ {
+ return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR);
+ }
+
+ UNumberFormatStyle style;
+ switch (localeGroupingData)
+ {
+ case Digit:
+ style = UNUM_DECIMAL;
+ break;
+ case Monetary:
+ style = UNUM_CURRENCY;
+ break;
+ default:
+ return UErrorCodeToBool(U_UNSUPPORTED_ERROR);
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ UNumberFormat* numformat = unum_open(style, NULL, 0, locale.getName(), NULL, &status);
+ if (U_SUCCESS(status))
+ {
+ *primaryGroupSize = unum_getAttribute(numformat, UNUM_GROUPING_SIZE);
+ *secondaryGroupSize = unum_getAttribute(numformat, UNUM_SECONDARY_GROUPING_SIZE);
+ unum_close(numformat);
+ }
return UErrorCodeToBool(status);
}
diff --git a/src/corefx/System.Globalization.Native/localeStringData.cpp b/src/corefx/System.Globalization.Native/localeStringData.cpp
index 6c88211532..fc5250da1b 100644
--- a/src/corefx/System.Globalization.Native/localeStringData.cpp
+++ b/src/corefx/System.Globalization.Native/localeStringData.cpp
@@ -8,10 +8,14 @@
#include "locale.hpp"
-#include "unicode/dcfmtsym.h" //decimal
-#include "unicode/dtfmtsym.h" //date
+#include "unicode/dcfmtsym.h" //decimal symbols
+#include "unicode/dtfmtsym.h" //date symbols
+#include "unicode/smpdtfmt.h" //date format
#include "unicode/localpointer.h"
+// invariant character definitions used by ICU
+#define UCHAR_SPACE ((UChar)0x0020) // space
+#define UCHAR_NBSPACE ((UChar)0x00A0) // space
// Enum that corresponds to managed enum CultureData.LocaleStringData.
// The numeric values of the enum members match their Win32 counterparts.
@@ -41,6 +45,7 @@ enum LocaleStringData : int32_t
Iso3166CountryName = 0x0000005A,
NaNSymbol = 0x00000069,
PositiveInfinitySymbol = 0x0000006a,
+ ParentName = 0x0000006d,
PercentSymbol = 0x00000076,
PerMilleSymbol = 0x00000077
};
@@ -224,6 +229,22 @@ extern "C" int32_t GetLocaleInfoString(const UChar* localeName, LocaleStringData
case PositiveInfinitySymbol:
status = GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kInfinitySymbol, value, valueLength);
break;
+ case ParentName:
+ {
+ // ICU supports lang[-script][-region][-variant] so up to 4 parents including invariant locale
+ char localeNameTemp[ULOC_FULLNAME_CAPACITY];
+
+ uloc_getParent(locale.getName(), localeNameTemp, ULOC_FULLNAME_CAPACITY, &status);
+ if (U_SUCCESS(status))
+ {
+ status = u_charsToUChars_safe(localeNameTemp, value, valueLength);
+ if (U_SUCCESS(status))
+ {
+ FixupLocaleName(value, valueLength);
+ }
+ }
+ break;
+ }
case PercentSymbol:
status = GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kPercentSymbol, value, valueLength);
break;
@@ -232,11 +253,92 @@ extern "C" int32_t GetLocaleInfoString(const UChar* localeName, LocaleStringData
break;
default:
status = U_UNSUPPORTED_ERROR;
- assert(false);
break;
};
- assert(status != U_BUFFER_OVERFLOW_ERROR);
+ return UErrorCodeToBool(status);
+}
+
+/*
+Function:
+NormalizeTimePattern
+
+Convert an ICU non-localized time pattern to .NET format
+*/
+void NormalizeTimePattern(const UnicodeString *srcPattern, UnicodeString *destPattern)
+{
+ // An srcPattern example: "h:mm:ss a"
+ // A destPattern example: "h:mm:ss tt"
+ destPattern->remove();
+
+ bool amPmAdded = false;
+ for (int i = 0; i <= srcPattern->length() - 1; i++)
+ {
+ UChar ch = srcPattern->charAt(i);
+ switch (ch)
+ {
+ case ':':
+ case '.':
+ case 'H':
+ case 'h':
+ case 'm':
+ case 's':
+ destPattern->append(ch);
+ break;
+
+ case UCHAR_SPACE:
+ case UCHAR_NBSPACE:
+ destPattern->append(UCHAR_SPACE);
+ break;
+
+ case 'a': // AM/PM
+ if (!amPmAdded)
+ {
+ amPmAdded = true;
+ destPattern->append("tt");
+ }
+ break;
+ }
+ }
+}
+
+/*
+PAL Function:
+GetLocaleTimeFormat
+
+Obtains time format information.
+Returns 1 for success, 0 otherwise
+*/
+extern "C" int32_t GetLocaleTimeFormat(const UChar* localeName, int shortFormat, UChar* value, int32_t valueLength)
+{
+ Locale locale = GetLocale(localeName);
+ if (locale.isBogus())
+ {
+ return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR);
+ }
+
+ DateFormat::EStyle style = (shortFormat != 0) ? DateFormat::kShort : DateFormat::kMedium;
+ LocalPointer<DateFormat> dateFormat(DateFormat::createTimeInstance(style, locale));
+ if (dateFormat == NULL || !dateFormat.isValid())
+ {
+ return UErrorCodeToBool(U_MEMORY_ALLOCATION_ERROR);
+ }
+
+ // cast to SimpleDateFormat so we can call toPattern()
+ SimpleDateFormat* sdf = dynamic_cast<SimpleDateFormat*>(dateFormat.getAlias());
+ if (sdf == NULL)
+ {
+ return UErrorCodeToBool(U_INTERNAL_PROGRAM_ERROR);
+ }
+
+ UnicodeString icuPattern;
+ sdf->toPattern(icuPattern);
+
+ UnicodeString dotnetPattern;
+ NormalizeTimePattern(&icuPattern, &dotnetPattern);
+
+ UErrorCode status = U_ZERO_ERROR;
+ dotnetPattern.extract(value, valueLength, status);
return UErrorCodeToBool(status);
}