internal static int GetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars) { // NOTE: there are no 'user overrides' on Linux int count = Interop.GlobalizationInterop.GetCalendars(localeName, calendars, calendars.Length); // ensure there is at least 1 calendar returned if (count == 0 && calendars.Length > 0) { calendars[0] = CalendarId.GREGORIAN; count = 1; } return count; }
private bool LoadCalendarDataFromSystem(String localeName, CalendarId calendarId) { bool result = true; result &= GetCalendarInfo(localeName, calendarId, CalendarDataType.NativeName, out this.sNativeName); result &= GetCalendarInfo(localeName, calendarId, CalendarDataType.MonthDay, out this.sMonthDay); this.sMonthDay = NormalizeDatePattern(this.sMonthDay); result &= EnumDatePatterns(localeName, calendarId, CalendarDataType.ShortDates, out this.saShortDates); result &= EnumDatePatterns(localeName, calendarId, CalendarDataType.LongDates, out this.saLongDates); result &= EnumDatePatterns(localeName, calendarId, CalendarDataType.YearMonths, out this.saYearMonths); result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.DayNames, out this.saDayNames); result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.AbbrevDayNames, out this.saAbbrevDayNames); result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.SuperShortDayNames, out this.saSuperShortDayNames); result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthNames, out this.saMonthNames); result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthNames, out this.saAbbrevMonthNames); result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthGenitiveNames, out this.saMonthGenitiveNames); result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthGenitiveNames, out this.saAbbrevMonthGenitiveNames); result &= EnumEraNames(localeName, calendarId, CalendarDataType.EraNames, out this.saEraNames); result &= EnumEraNames(localeName, calendarId, CalendarDataType.AbbrevEraNames, out this.saAbbrevEraNames); return result; }
private static unsafe bool CallEnumCalendarInfo(string localeName, CalendarId calendar, uint calType, uint lcType, out string[] data) { EnumData context = new EnumData(); context.userOverride = null; context.strings = new LowLevelList<string>(); // First call GetLocaleInfo if necessary if (((lcType != 0) && ((lcType & CAL_NOUSEROVERRIDE) == 0)) && // Get user locale, see if it matches localeName. // Note that they should match exactly, including letter case GetUserDefaultLocaleName() == localeName) { // They want user overrides, see if the user calendar matches the input calendar CalendarId userCalendar = (CalendarId)Interop.mincore.GetLocaleInfoExInt(localeName, LOCALE_ICALENDARTYPE); // If the calendars were the same, see if the locales were the same if (userCalendar == calendar) { // They matched, get the user override since locale & calendar match string res = Interop.mincore.GetLocaleInfoEx(localeName, lcType); // if it succeeded remember the override for the later callers if (res != "") { // Remember this was the override (so we can look for duplicates later in the enum function) context.userOverride = res; // Add to the result strings. context.strings.Add(res); } } } GCHandle contextHandle = GCHandle.Alloc(context); try { Interop.mincore_private.EnumCalendarInfoExExCallback callback = new Interop.mincore_private.EnumCalendarInfoExExCallback(EnumCalendarInfoCallback); Interop.mincore_private.LParamCallbackContext ctx = new Interop.mincore_private.LParamCallbackContext(); ctx.lParam = (IntPtr)contextHandle; // Now call the enumeration API. Work is done by our callback function Interop.mincore_private.EnumCalendarInfoExEx(callback, localeName, (uint)calendar, null, calType, ctx); } finally { contextHandle.Free(); } // Now we have a list of data, fail if we didn't find anything. if (context.strings.Count == 0) { data = null; return false; } string[] output = context.strings.ToArray(); if (calType == CAL_SABBREVERASTRING || calType == CAL_SERASTRING) { // Eras are enumerated backwards. (oldest era name first, but // Japanese calendar has newest era first in array, and is only // calendar with multiple eras) Array.Reverse(output, 0, output.Length); } data = output; return true; }
private static String CalendarIdToCultureName(CalendarId calendarId) { switch (calendarId) { case CalendarId.GREGORIAN_US: return "fa-IR"; // "fa-IR" Iran case CalendarId.JAPAN: return "ja-JP"; // "ja-JP" Japan case CalendarId.TAIWAN: return "zh-TW"; // zh-TW Taiwan case CalendarId.KOREA: return "ko-KR"; // "ko-KR" Korea case CalendarId.HIJRI: case CalendarId.GREGORIAN_ARABIC: case CalendarId.UMALQURA: return "ar-SA"; // "ar-SA" Saudi Arabia case CalendarId.THAI: return "th-TH"; // "th-TH" Thailand case CalendarId.HEBREW: return "he-IL"; // "he-IL" Israel case CalendarId.GREGORIAN_ME_FRENCH: return "ar-DZ"; // "ar-DZ" Algeria case CalendarId.GREGORIAN_XLIT_ENGLISH: case CalendarId.GREGORIAN_XLIT_FRENCH: return "ar-IQ"; // "ar-IQ"; Iraq default: // Default to gregorian en-US break; } return "en-US"; }
private static bool CallGetCalendarInfoEx(string localeName, CalendarId calendar, uint calType, out int data) { return (Interop.mincore.GetCalendarInfoEx(localeName, (uint)calendar, IntPtr.Zero, calType | CAL_RETURN_NUMBER, IntPtr.Zero, 0, out data) != 0); }
// Get native two digit year max internal static int GetTwoDigitYearMax(CalendarId calendarId) { int twoDigitYearMax = -1; if (!CallGetCalendarInfoEx(null, calendarId, (uint)CAL_ITWODIGITYEARMAX, out twoDigitYearMax)) { twoDigitYearMax = -1; } return twoDigitYearMax; }
private bool LoadCalendarDataFromSystem(String localeName, CalendarId calendarId) { bool ret = true; uint useOverrides = this.bUseUserOverrides ? 0 : CAL_NOUSEROVERRIDE; // // Windows doesn't support some calendars right now, so remap those. // switch (calendarId) { case CalendarId.JAPANESELUNISOLAR: // Data looks like Japanese calendarId = CalendarId.JAPAN; break; case CalendarId.JULIAN: // Data looks like gregorian US case CalendarId.CHINESELUNISOLAR: // Algorithmic, so actual data is irrelevent case CalendarId.SAKA: // reserved to match Office but not implemented in our code, so data is irrelevent case CalendarId.LUNAR_ETO_CHN: // reserved to match Office but not implemented in our code, so data is irrelevent case CalendarId.LUNAR_ETO_KOR: // reserved to match Office but not implemented in our code, so data is irrelevent case CalendarId.LUNAR_ETO_ROKUYOU: // reserved to match Office but not implemented in our code, so data is irrelevent case CalendarId.KOREANLUNISOLAR: // Algorithmic, so actual data is irrelevent case CalendarId.TAIWANLUNISOLAR: // Algorithmic, so actual data is irrelevent calendarId = CalendarId.GREGORIAN_US; break; } // // Special handling for some special calendar due to OS limitation. // This includes calendar like Taiwan calendar, UmAlQura calendar, etc. // CheckSpecialCalendar(ref calendarId, ref localeName); // Numbers ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_ITWODIGITYEARMAX | useOverrides, out this.iTwoDigitYearMax); // Strings ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_SCALNAME, out this.sNativeName); ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_SMONTHDAY | useOverrides, out this.sMonthDay); // String Arrays // Formats ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SSHORTDATE, LOCALE_SSHORTDATE | useOverrides, out this.saShortDates); ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SLONGDATE, LOCALE_SLONGDATE | useOverrides, out this.saLongDates); // Get the YearMonth pattern. ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SYEARMONTH, LOCALE_SYEARMONTH, out this.saYearMonths); // Day & Month Names // These are all single calType entries, 1 per day, so we have to make 7 or 13 calls to collect all the names // Day // Note that we're off-by-one since managed starts on sunday and windows starts on monday ret &= GetCalendarDayInfo(localeName, calendarId, CAL_SDAYNAME7, out this.saDayNames); ret &= GetCalendarDayInfo(localeName, calendarId, CAL_SABBREVDAYNAME7, out this.saAbbrevDayNames); // Month names ret &= GetCalendarMonthInfo(localeName, calendarId, CAL_SMONTHNAME1, out this.saMonthNames); ret &= GetCalendarMonthInfo(localeName, calendarId, CAL_SABBREVMONTHNAME1, out this.saAbbrevMonthNames); // // The following LCTYPE are not supported in some platforms. If the call fails, // don't return a failure. // GetCalendarDayInfo(localeName, calendarId, CAL_SSHORTESTDAYNAME7, out this.saSuperShortDayNames); // Gregorian may have genitive month names if (calendarId == CalendarId.GREGORIAN) { GetCalendarMonthInfo(localeName, calendarId, CAL_SMONTHNAME1 | CAL_RETURN_GENITIVE_NAMES, out this.saMonthGenitiveNames); GetCalendarMonthInfo(localeName, calendarId, CAL_SABBREVMONTHNAME1 | CAL_RETURN_GENITIVE_NAMES, out this.saAbbrevMonthGenitiveNames); } // Calendar Parts Names // This doesn't get always get localized names for gregorian (not available in windows < 7) // so: eg: coreclr on win < 7 won't get these CallEnumCalendarInfo(localeName, calendarId, CAL_SERASTRING, 0, out this.saEraNames); CallEnumCalendarInfo(localeName, calendarId, CAL_SABBREVERASTRING, 0, out this.saAbbrevEraNames); // // Calendar Era Info // Note that calendar era data (offsets, etc) is hard coded for each calendar since this // data is implementation specific and not dynamic (except perhaps Japanese) // // Clean up the escaping of the formats this.saShortDates = CultureData.ReescapeWin32Strings(this.saShortDates); this.saLongDates = CultureData.ReescapeWin32Strings(this.saLongDates); this.saYearMonths = CultureData.ReescapeWin32Strings(this.saYearMonths); this.sMonthDay = CultureData.ReescapeWin32String(this.sMonthDay); return ret; }
private void InitializeEraNames(string localeName, CalendarId calendarId) { // Note that the saEraNames only include "A.D." We don't have localized names for other calendars available from windows switch (calendarId) { // For Localized Gregorian we really expect the data from the OS. case CalendarId.GREGORIAN: // Fallback for CoreCLR < Win7 or culture.dll missing if (this.saEraNames == null || this.saEraNames.Length == 0 || string.IsNullOrEmpty(this.saEraNames[0])) { this.saEraNames = new string[] { "A.D." }; } break; // The rest of the calendars have constant data, so we'll just use that case CalendarId.GREGORIAN_US: case CalendarId.JULIAN: this.saEraNames = new string[] { "A.D." }; break; case CalendarId.HEBREW: this.saEraNames = new string[] { "C.E." }; break; case CalendarId.HIJRI: case CalendarId.UMALQURA: if (localeName == "dv-MV") { // Special case for Divehi this.saEraNames = new string[] { "\x0780\x07a8\x0796\x07b0\x0783\x07a9" }; } else { this.saEraNames = new string[] { "\x0628\x0639\x062F \x0627\x0644\x0647\x062C\x0631\x0629" }; } break; case CalendarId.GREGORIAN_ARABIC: case CalendarId.GREGORIAN_XLIT_ENGLISH: case CalendarId.GREGORIAN_XLIT_FRENCH: // These are all the same: this.saEraNames = new string[] { "\x0645" }; break; case CalendarId.GREGORIAN_ME_FRENCH: this.saEraNames = new string[] { "ap. J.-C." }; break; case CalendarId.TAIWAN: if (SystemSupportsTaiwaneseCalendar()) { this.saEraNames = new string[] { "\x4e2d\x83ef\x6c11\x570b" }; } else { this.saEraNames = new string[] { string.Empty }; } break; case CalendarId.KOREA: this.saEraNames = new string[] { "\xb2e8\xae30" }; break; case CalendarId.THAI: this.saEraNames = new string[] { "\x0e1e\x002e\x0e28\x002e" }; break; case CalendarId.JAPAN: case CalendarId.JAPANESELUNISOLAR: this.saEraNames = JapaneseCalendar.EraNames(); break; case CalendarId.PERSIAN: if (this.saEraNames == null || this.saEraNames.Length == 0 || string.IsNullOrEmpty(this.saEraNames[0])) { this.saEraNames = new string[] { "\x0647\x002e\x0634" }; } break; default: // Most calendars are just "A.D." this.saEraNames = Invariant.saEraNames; break; } }
/*=================================GetCalendarInstance========================== **Action: Map a Win32 CALID to an instance of supported calendar. **Returns: An instance of calendar. **Arguments: calType The Win32 CALID **Exceptions: ** Shouldn't throw exception since the calType value is from our data table or from Win32 registry. ** If we are in trouble (like getting a weird value from Win32 registry), just return the GregorianCalendar. ============================================================================*/ internal static Calendar GetCalendarInstance(CalendarId calType) { if (calType == CalendarId.GREGORIAN) { return (new GregorianCalendar()); } return GetCalendarInstanceRare(calType); }
private bool LoadCalendarDataFromSystem(String localeName, CalendarId calendarId) { Debug.Assert(!GlobalizationMode.Invariant); bool ret = true; uint useOverrides = this.bUseUserOverrides ? 0 : CAL_NOUSEROVERRIDE; // // Windows doesn't support some calendars right now, so remap those. // switch (calendarId) { case CalendarId.JAPANESELUNISOLAR: // Data looks like Japanese calendarId = CalendarId.JAPAN; break; case CalendarId.JULIAN: // Data looks like gregorian US case CalendarId.CHINESELUNISOLAR: // Algorithmic, so actual data is irrelevent case CalendarId.SAKA: // reserved to match Office but not implemented in our code, so data is irrelevent case CalendarId.LUNAR_ETO_CHN: // reserved to match Office but not implemented in our code, so data is irrelevent case CalendarId.LUNAR_ETO_KOR: // reserved to match Office but not implemented in our code, so data is irrelevent case CalendarId.LUNAR_ETO_ROKUYOU: // reserved to match Office but not implemented in our code, so data is irrelevent case CalendarId.KOREANLUNISOLAR: // Algorithmic, so actual data is irrelevent case CalendarId.TAIWANLUNISOLAR: // Algorithmic, so actual data is irrelevent calendarId = CalendarId.GREGORIAN_US; break; } // // Special handling for some special calendar due to OS limitation. // This includes calendar like Taiwan calendar, UmAlQura calendar, etc. // CheckSpecialCalendar(ref calendarId, ref localeName); // Numbers ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_ITWODIGITYEARMAX | useOverrides, out this.iTwoDigitYearMax); // Strings ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_SCALNAME, out this.sNativeName); ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_SMONTHDAY | useOverrides, out this.sMonthDay); // String Arrays // Formats ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SSHORTDATE, LOCALE_SSHORTDATE | useOverrides, out this.saShortDates); ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SLONGDATE, LOCALE_SLONGDATE | useOverrides, out this.saLongDates); // Get the YearMonth pattern. ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SYEARMONTH, LOCALE_SYEARMONTH, out this.saYearMonths); // Day & Month Names // These are all single calType entries, 1 per day, so we have to make 7 or 13 calls to collect all the names // Day // Note that we're off-by-one since managed starts on sunday and windows starts on monday ret &= GetCalendarDayInfo(localeName, calendarId, CAL_SDAYNAME7, out this.saDayNames); ret &= GetCalendarDayInfo(localeName, calendarId, CAL_SABBREVDAYNAME7, out this.saAbbrevDayNames); // Month names ret &= GetCalendarMonthInfo(localeName, calendarId, CAL_SMONTHNAME1, out this.saMonthNames); ret &= GetCalendarMonthInfo(localeName, calendarId, CAL_SABBREVMONTHNAME1, out this.saAbbrevMonthNames); // // The following LCTYPE are not supported in some platforms. If the call fails, // don't return a failure. // GetCalendarDayInfo(localeName, calendarId, CAL_SSHORTESTDAYNAME7, out this.saSuperShortDayNames); // Gregorian may have genitive month names if (calendarId == CalendarId.GREGORIAN) { GetCalendarMonthInfo(localeName, calendarId, CAL_SMONTHNAME1 | CAL_RETURN_GENITIVE_NAMES, out this.saMonthGenitiveNames); GetCalendarMonthInfo(localeName, calendarId, CAL_SABBREVMONTHNAME1 | CAL_RETURN_GENITIVE_NAMES, out this.saAbbrevMonthGenitiveNames); } // Calendar Parts Names // This doesn't get always get localized names for gregorian (not available in windows < 7) // so: eg: coreclr on win < 7 won't get these CallEnumCalendarInfo(localeName, calendarId, CAL_SERASTRING, 0, out this.saEraNames); CallEnumCalendarInfo(localeName, calendarId, CAL_SABBREVERASTRING, 0, out this.saAbbrevEraNames); // // Calendar Era Info // Note that calendar era data (offsets, etc) is hard coded for each calendar since this // data is implementation specific and not dynamic (except perhaps Japanese) // // Clean up the escaping of the formats this.saShortDates = CultureData.ReescapeWin32Strings(this.saShortDates); this.saLongDates = CultureData.ReescapeWin32Strings(this.saLongDates); this.saYearMonths = CultureData.ReescapeWin32Strings(this.saYearMonths); this.sMonthDay = CultureData.ReescapeWin32String(this.sMonthDay); return(ret); }
internal static extern bool EnumCalendarInfo(EnumCalendarInfoCallback callback, string localeName, CalendarId calendarId, CalendarDataType calendarDataType, IntPtr context);
private static unsafe bool CallEnumCalendarInfo(string localeName, CalendarId calendar, uint calType, uint lcType, out string[] data) { EnumData context = new EnumData(); context.userOverride = null; context.strings = new LowLevelList <string>(); // First call GetLocaleInfo if necessary if (((lcType != 0) && ((lcType & CAL_NOUSEROVERRIDE) == 0)) && // Get user locale, see if it matches localeName. // Note that they should match exactly, including letter case GetUserDefaultLocaleName() == localeName) { // They want user overrides, see if the user calendar matches the input calendar CalendarId userCalendar = (CalendarId)Interop.mincore.GetLocaleInfoExInt(localeName, LOCALE_ICALENDARTYPE); // If the calendars were the same, see if the locales were the same if (userCalendar == calendar) { // They matched, get the user override since locale & calendar match string res = Interop.mincore.GetLocaleInfoEx(localeName, lcType); // if it succeeded remember the override for the later callers if (res != "") { // Remember this was the override (so we can look for duplicates later in the enum function) context.userOverride = res; // Add to the result strings. context.strings.Add(res); } } } GCHandle contextHandle = GCHandle.Alloc(context); try { // Now call the enumeration API. Work is done by our callback function IntPtr callback = AddrofIntrinsics.AddrOf <Func <IntPtr, uint, IntPtr, IntPtr, Interop.BOOL> >(EnumCalendarInfoCallback); Interop.mincore.EnumCalendarInfoExEx(callback, localeName, (uint)calendar, null, calType, (IntPtr)contextHandle); } finally { contextHandle.Free(); } // Now we have a list of data, fail if we didn't find anything. if (context.strings.Count == 0) { data = null; return(false); } string[] output = context.strings.ToArray(); if (calType == CAL_SABBREVERASTRING || calType == CAL_SERASTRING) { // Eras are enumerated backwards. (oldest era name first, but // Japanese calendar has newest era first in array, and is only // calendar with multiple eras) Array.Reverse(output, 0, output.Length); } data = output; return(true); }
internal static int GetTwoDigitYearMax(CalendarId calendarId) { // There is no user override for this value on Linux or in ICU. // So just return -1 to use the hard-coded defaults. return(-1); }
private static bool CallGetCalendarInfoEx(string localeName, CalendarId calendar, uint calType, out int data) { return(Interop.mincore.GetCalendarInfoEx(localeName, (uint)calendar, IntPtr.Zero, calType | CAL_RETURN_NUMBER, IntPtr.Zero, 0, out data) != 0); }
private static unsafe bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, ref EnumCalendarsData callbackContext) { return(Interop.Globalization.EnumCalendarInfo(EnumCalendarInfoCallback, localeName, calendarId, dataType, (IntPtr)Unsafe.AsPointer(ref callbackContext))); }
private void InitializeAbbreviatedEraNames(string localeName, CalendarId calendarId) { // Note that the saAbbrevEraNames only include "AD" We don't have localized names for other calendars available from windows switch (calendarId) { // For Localized Gregorian we really expect the data from the OS. case CalendarId.GREGORIAN: // Fallback for CoreCLR < Win7 or culture.dll missing if (this.saAbbrevEraNames == null || this.saAbbrevEraNames.Length == 0 || string.IsNullOrEmpty(this.saAbbrevEraNames[0])) { this.saAbbrevEraNames = new string[] { "AD" }; } break; // The rest of the calendars have constant data, so we'll just use that case CalendarId.GREGORIAN_US: case CalendarId.JULIAN: this.saAbbrevEraNames = new string[] { "AD" }; break; case CalendarId.JAPAN: case CalendarId.JAPANESELUNISOLAR: this.saAbbrevEraNames = JapaneseCalendar.AbbrevEraNames(); break; case CalendarId.HIJRI: case CalendarId.UMALQURA: if (localeName == "dv-MV") { // Special case for Divehi this.saAbbrevEraNames = new string[] { "\x0780\x002e" }; } else { this.saAbbrevEraNames = new string[] { "\x0647\x0640" }; } break; case CalendarId.TAIWAN: // Get era name and abbreviate it this.saAbbrevEraNames = new string[1]; if (this.saEraNames[0].Length == 4) { this.saAbbrevEraNames[0] = this.saEraNames[0].Substring(2, 2); } else { this.saAbbrevEraNames[0] = this.saEraNames[0]; } break; case CalendarId.PERSIAN: if (this.saAbbrevEraNames == null || this.saAbbrevEraNames.Length == 0 || string.IsNullOrEmpty(this.saAbbrevEraNames[0])) { this.saAbbrevEraNames = this.saEraNames; } break; default: // Most calendars just use the full name this.saAbbrevEraNames = this.saEraNames; break; } }
//////////////////////////////////////////////////////////////////////// // // Get the native month names // // Parameters: // OUT pOutputStrings The output string[] value. // //////////////////////////////////////////////////////////////////////// private static bool GetCalendarMonthInfo(string localeName, CalendarId calendar, uint calType, out string[] outputStrings) { // // We'll need a new array of 13 items // string[] results = new string[13]; // Get each one of them for (int i = 0; i < 13; i++, calType++) { if (!CallGetCalendarInfoEx(localeName, calendar, calType, out results[i])) results[i] = ""; } outputStrings = results; return true; }
internal String[] AbbreviatedEnglishEraNames(CalendarId calendarId) { Contract.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0"); return this.GetCalendar(calendarId).saAbbrevEnglishEraNames; }
private void InitializeEraNames(string localeName, CalendarId calendarId) { // Note that the saEraNames only include "A.D." We don't have localized names for other calendars available from windows switch (calendarId) { // For Localized Gregorian we really expect the data from the OS. case CalendarId.GREGORIAN: // Fallback for CoreCLR < Win7 or culture.dll missing if (this.saEraNames == null || this.saEraNames.Length == 0 || String.IsNullOrEmpty(this.saEraNames[0])) { this.saEraNames = new String[] { "A.D." }; } break; // The rest of the calendars have constant data, so we'll just use that case CalendarId.GREGORIAN_US: case CalendarId.JULIAN: this.saEraNames = new String[] { "A.D." }; break; case CalendarId.HEBREW: this.saEraNames = new String[] { "C.E." }; break; case CalendarId.HIJRI: case CalendarId.UMALQURA: if (localeName == "dv-MV") { // Special case for Divehi this.saEraNames = new String[] { "\x0780\x07a8\x0796\x07b0\x0783\x07a9" }; } else { this.saEraNames = new String[] { "\x0628\x0639\x062F \x0627\x0644\x0647\x062C\x0631\x0629" }; } break; case CalendarId.GREGORIAN_ARABIC: case CalendarId.GREGORIAN_XLIT_ENGLISH: case CalendarId.GREGORIAN_XLIT_FRENCH: // These are all the same: this.saEraNames = new String[] { "\x0645" }; break; case CalendarId.GREGORIAN_ME_FRENCH: this.saEraNames = new String[] { "ap. J.-C." }; break; case CalendarId.TAIWAN: if (SystemSupportsTaiwaneseCalendar()) { this.saEraNames = new String[] { "\x4e2d\x83ef\x6c11\x570b" }; } else { this.saEraNames = new String[] { String.Empty }; } break; case CalendarId.KOREA: this.saEraNames = new String[] { "\xb2e8\xae30" }; break; case CalendarId.THAI: this.saEraNames = new String[] { "\x0e1e\x002e\x0e28\x002e" }; break; case CalendarId.JAPAN: case CalendarId.JAPANESELUNISOLAR: this.saEraNames = JapaneseCalendar.EraNames(); break; case CalendarId.PERSIAN: if (this.saEraNames == null || this.saEraNames.Length == 0 || String.IsNullOrEmpty(this.saEraNames[0])) { this.saEraNames = new String[] { "\x0647\x002e\x0634" }; } break; default: // Most calendars are just "A.D." this.saEraNames = Invariant.saEraNames; break; } }
// // Get a bunch of data for a calendar // internal CalendarData(string localeName, CalendarId calendarId, bool bUseUserOverrides) { this.bUseUserOverrides = bUseUserOverrides; Debug.Assert(!GlobalizationMode.Invariant); if (!LoadCalendarDataFromSystem(localeName, calendarId)) { // LoadCalendarDataFromSystem sometimes can fail on Linux if the installed ICU package is missing some resources. // The ICU package can miss some resources in some cases like if someone compile and build the ICU package manually or ICU has a regression. // Something failed, try invariant for missing parts // This is really not good, but we don't want the callers to crash. if (this.sNativeName == null) { this.sNativeName = string.Empty; // Calendar Name for the locale. } // Formats if (this.saShortDates == null) { this.saShortDates = Invariant.saShortDates; // Short Data format, default first } if (this.saYearMonths == null) { this.saYearMonths = Invariant.saYearMonths; // Year/Month Data format, default first } if (this.saLongDates == null) { this.saLongDates = Invariant.saLongDates; // Long Data format, default first } if (this.sMonthDay == null) { this.sMonthDay = Invariant.sMonthDay; // Month/Day format } // Calendar Parts Names if (this.saEraNames == null) { this.saEraNames = Invariant.saEraNames; // Names of Eras } if (this.saAbbrevEraNames == null) { this.saAbbrevEraNames = Invariant.saAbbrevEraNames; // Abbreviated Era Names } if (this.saAbbrevEnglishEraNames == null) { this.saAbbrevEnglishEraNames = Invariant.saAbbrevEnglishEraNames; // Abbreviated Era Names in English } if (this.saDayNames == null) { this.saDayNames = Invariant.saDayNames; // Day Names, null to use locale data, starts on Sunday } if (this.saAbbrevDayNames == null) { this.saAbbrevDayNames = Invariant.saAbbrevDayNames; // Abbrev Day Names, null to use locale data, starts on Sunday } if (this.saSuperShortDayNames == null) { this.saSuperShortDayNames = Invariant.saSuperShortDayNames; // Super short Day of week names } if (this.saMonthNames == null) { this.saMonthNames = Invariant.saMonthNames; // Month Names (13) } if (this.saAbbrevMonthNames == null) { this.saAbbrevMonthNames = Invariant.saAbbrevMonthNames; // Abbrev Month Names (13) } // Genitive and Leap names can follow the fallback below } if (calendarId == CalendarId.TAIWAN) { if (SystemSupportsTaiwaneseCalendar()) { // We got the month/day names from the OS (same as gregorian), but the native name is wrong this.sNativeName = "\x4e2d\x83ef\x6c11\x570b\x66c6"; } else { this.sNativeName = string.Empty; } } // Check for null genitive names (in case unmanaged side skips it for non-gregorian calendars, etc) if (this.saMonthGenitiveNames == null || this.saMonthGenitiveNames.Length == 0 || string.IsNullOrEmpty(this.saMonthGenitiveNames[0])) { this.saMonthGenitiveNames = this.saMonthNames; // Genitive month names (same as month names for invariant) } if (this.saAbbrevMonthGenitiveNames == null || this.saAbbrevMonthGenitiveNames.Length == 0 || string.IsNullOrEmpty(this.saAbbrevMonthGenitiveNames[0])) { this.saAbbrevMonthGenitiveNames = this.saAbbrevMonthNames; // Abbreviated genitive month names (same as abbrev month names for invariant) } if (this.saLeapYearMonthNames == null || this.saLeapYearMonthNames.Length == 0 || string.IsNullOrEmpty(this.saLeapYearMonthNames[0])) { this.saLeapYearMonthNames = this.saMonthNames; } InitializeEraNames(localeName, calendarId); InitializeAbbreviatedEraNames(localeName, calendarId); // Abbreviated English Era Names are only used for the Japanese calendar. if (calendarId == CalendarId.JAPAN) { this.saAbbrevEnglishEraNames = JapaneseCalendar.EnglishEraNames(); } else { // For all others just use the an empty string (doesn't matter we'll never ask for it for other calendars) this.saAbbrevEnglishEraNames = new string[] { "" }; } // Japanese is the only thing with > 1 era. Its current era # is how many ever // eras are in the array. (And the others all have 1 string in the array) this.iCurrentEra = this.saEraNames.Length; }
internal CalendarData GetCalendar(CalendarId calendarId) { Contract.Assert(calendarId > 0 && calendarId <= CalendarId.LAST_CALENDAR, "[CultureData.GetCalendar] Expect calendarId to be in a valid range"); // arrays are 0 based, calendarIds are 1 based int calendarIndex = (int)calendarId - 1; // Have to have calendars if (_calendars == null) { _calendars = new CalendarData[CalendarData.MAX_CALENDARS]; } // we need the following local variable to avoid returning null // when another thread creates a new array of CalendarData (above) // right after we insert the newly created CalendarData (below) CalendarData calendarData = _calendars[calendarIndex]; // Make sure that calendar has data if (calendarData == null) { Contract.Assert(_sWindowsName != null, "[CultureData.GetCalendar] Expected this.sWindowsName to be populated by already"); calendarData = new CalendarData(_sWindowsName, calendarId, this.UseUserOverride); _calendars[calendarIndex] = calendarData; } return calendarData; }
// (user can override) date year/month format. internal String[] YearMonths(CalendarId calendarId) { return GetCalendar(calendarId).saYearMonths; }
// Date separator (derived from short date format) internal String DateSeparator(CalendarId calendarId) { return GetDateSeparator(ShortDates(calendarId)[0]); }
// day names internal string[] DayNames(CalendarId calendarId) { return GetCalendar(calendarId).saDayNames; }
//This function exists as a shortcut to prevent us from loading all of the non-gregorian //calendars unless they're required. internal static Calendar GetCalendarInstanceRare(CalendarId calType) { Contract.Assert(calType != CalendarId.GREGORIAN, "calType!=CalendarId.GREGORIAN"); switch (calType) { case CalendarId.GREGORIAN_US: // Gregorian (U.S.) calendar case CalendarId.GREGORIAN_ME_FRENCH: // Gregorian Middle East French calendar case CalendarId.GREGORIAN_ARABIC: // Gregorian Arabic calendar case CalendarId.GREGORIAN_XLIT_ENGLISH: // Gregorian Transliterated English calendar case CalendarId.GREGORIAN_XLIT_FRENCH: // Gregorian Transliterated French calendar return (new GregorianCalendar((GregorianCalendarTypes)calType)); case CalendarId.TAIWAN: // Taiwan Era calendar return (new TaiwanCalendar()); case CalendarId.JAPAN: // Japanese Emperor Era calendar return (new JapaneseCalendar()); case CalendarId.KOREA: // Korean Tangun Era calendar return (new KoreanCalendar()); case CalendarId.THAI: // Thai calendar return (new ThaiBuddhistCalendar()); case CalendarId.HIJRI: // Hijri (Arabic Lunar) calendar return (new HijriCalendar()); case CalendarId.HEBREW: // Hebrew (Lunar) calendar return (new HebrewCalendar()); case CalendarId.UMALQURA: return (new UmAlQuraCalendar()); case CalendarId.PERSIAN: return (new PersianCalendar()); } return (new GregorianCalendar()); }
// abbreviated day names internal string[] AbbreviatedDayNames(CalendarId calendarId) { // Get abbreviated day names for this calendar from the OS if necessary return GetCalendar(calendarId).saAbbrevDayNames; }
internal static CalendarData GetCalendarData(CalendarId calendarId) { // // Get a calendar. // Unfortunately we depend on the locale in the OS, so we need a locale // no matter what. So just get the appropriate calendar from the // appropriate locale here // // Get a culture name // TODO: Note that this doesn't handle the new calendars (lunisolar, etc) String culture = CalendarIdToCultureName(calendarId); // Return our calendar return CultureInfo.GetCultureInfo(culture).m_cultureData.GetCalendar(calendarId); }
// The super short day names internal string[] SuperShortDayNames(CalendarId calendarId) { return GetCalendar(calendarId).saSuperShortDayNames; }
// Call native side to figure out which calendars are allowed internal static int GetCalendars(String localeName, bool useUserOverride, CalendarId[] calendars) { EnumCalendarsData data = new EnumCalendarsData(); data.userOverride = 0; data.calendars = new LowLevelList<int>(); // First call GetLocaleInfo if necessary if (useUserOverride) { // They want user overrides, see if the user calendar matches the input calendar int userCalendar = Interop.mincore.GetLocaleInfoExInt(localeName, LOCALE_ICALENDARTYPE); // If we got a default, then use it as the first calendar if (userCalendar != 0) { data.userOverride = userCalendar; data.calendars.Add(userCalendar); } } GCHandle contextHandle = GCHandle.Alloc(data); try { Interop.mincore_private.EnumCalendarInfoExExCallback callback = new Interop.mincore_private.EnumCalendarInfoExExCallback(EnumCalendarsCallback); Interop.mincore_private.LParamCallbackContext context = new Interop.mincore_private.LParamCallbackContext(); context.lParam = (IntPtr)contextHandle; // Now call the enumeration API. Work is done by our callback function Interop.mincore_private.EnumCalendarInfoExEx(callback, localeName, ENUM_ALL_CALENDARS, null, CAL_ICALINTVALUE, context); } finally { contextHandle.Free(); } // Copy to the output array for (int i = 0; i < Math.Min(calendars.Length, data.calendars.Count); i++) calendars[i] = (CalendarId)data.calendars[i]; // Now we have a list of data, return the count return data.calendars.Count; }
// month names internal string[] MonthNames(CalendarId calendarId) { return GetCalendar(calendarId).saMonthNames; }
//////////////////////////////////////////////////////////////////////// // // For calendars like Gregorain US/Taiwan/UmAlQura, they are not available // in all OS or all localized versions of OS. // If OS does not support these calendars, we will fallback by using the // appropriate fallback calendar and locale combination to retrieve data from OS. // // Parameters: // __deref_inout pCalendarInt: // Pointer to the calendar ID. This will be updated to new fallback calendar ID if needed. // __in_out pLocaleNameStackBuffer // Pointer to the StackSString object which holds the locale name to be checked. // This will be updated to new fallback locale name if needed. // //////////////////////////////////////////////////////////////////////// private static void CheckSpecialCalendar(ref CalendarId calendar, ref string localeName) { string data; // Gregorian-US isn't always available in the OS, however it is the same for all locales switch (calendar) { case CalendarId.GREGORIAN_US: // See if this works if (!CallGetCalendarInfoEx(localeName, calendar, CAL_SCALNAME, out data)) { // Failed, set it to a locale (fa-IR) that's alway has Gregorian US available in the OS localeName = "fa-IR"; } // See if that works if (!CallGetCalendarInfoEx(localeName, calendar, CAL_SCALNAME, out data)) { // Failed again, just use en-US with the gregorian calendar localeName = "en-US"; calendar = CalendarId.GREGORIAN; } break; case CalendarId.TAIWAN: // Taiwan calendar data is not always in all language version of OS due to Geopolical reasons. // It is only available in zh-TW localized versions of Windows. // Let's check if OS supports it. If not, fallback to Greogrian localized for Taiwan calendar. if (!SystemSupportsTaiwaneseCalendar()) { calendar = CalendarId.GREGORIAN; } break; } }
// Genitive month names internal string[] GenitiveMonthNames(CalendarId calendarId) { return GetCalendar(calendarId).saMonthGenitiveNames; }
private static unsafe bool CallGetCalendarInfoEx(string localeName, CalendarId calendar, uint calType, out string data) { const int BUFFER_LENGTH = 80; // The maximum size for values returned from GetCalendarInfoEx is 80 characters. char* buffer = stackalloc char[BUFFER_LENGTH]; int ret = Interop.mincore.GetCalendarInfoEx(localeName, (uint)calendar, IntPtr.Zero, calType, (IntPtr)buffer, BUFFER_LENGTH, IntPtr.Zero); if (ret > 0) { if (buffer[ret - 1] == '\0') { ret--; // don't include the null termination in the string } data = new string(buffer, 0, ret); return true; } data = ""; return false; }
// Genitive month names internal string[] AbbreviatedGenitiveMonthNames(CalendarId calendarId) { return GetCalendar(calendarId).saAbbrevMonthGenitiveNames; }
//////////////////////////////////////////////////////////////////////// // // Get the native day names // // NOTE: There's a disparity between .Net & windows day orders, the input day should // start with Sunday // // Parameters: // OUT pOutputStrings The output string[] value. // //////////////////////////////////////////////////////////////////////// private static bool GetCalendarDayInfo(string localeName, CalendarId calendar, uint calType, out string[] outputStrings) { bool result = true; // // We'll need a new array of 7 items // string[] results = new string[7]; // Get each one of them for (int i = 0; i < 7; i++, calType++) { result &= CallGetCalendarInfoEx(localeName, calendar, calType, out results[i]); // On the first iteration we need to go from CAL_SDAYNAME7 to CAL_SDAYNAME1, so subtract 7 before the ++ happens // This is because the framework starts on sunday and windows starts on monday when counting days if (i == 0) calType -= 7; } outputStrings = results; return result; }
// Leap year month names // Note: This only applies to Hebrew, and it basically adds a "1" to the 6th month name // the non-leap names skip the 7th name in the normal month name array internal string[] LeapYearMonthNames(CalendarId calendarId) { return GetCalendar(calendarId).saLeapYearMonthNames; }
// // Get a bunch of data for a calendar // internal CalendarData(String localeName, CalendarId calendarId, bool bUseUserOverrides) { this.bUseUserOverrides = bUseUserOverrides; if (!LoadCalendarDataFromSystem(localeName, calendarId)) { Contract.Assert(false, "[CalendarData] LoadCalendarDataFromSystem call isn't expected to fail for calendar " + calendarId + " locale " + localeName); // Something failed, try invariant for missing parts // This is really not good, but we don't want the callers to crash. if (this.sNativeName == null) this.sNativeName = String.Empty; // Calendar Name for the locale. // Formats if (this.saShortDates == null) this.saShortDates = Invariant.saShortDates; // Short Data format, default first if (this.saYearMonths == null) this.saYearMonths = Invariant.saYearMonths; // Year/Month Data format, default first if (this.saLongDates == null) this.saLongDates = Invariant.saLongDates; // Long Data format, default first if (this.sMonthDay == null) this.sMonthDay = Invariant.sMonthDay; // Month/Day format // Calendar Parts Names if (this.saEraNames == null) this.saEraNames = Invariant.saEraNames; // Names of Eras if (this.saAbbrevEraNames == null) this.saAbbrevEraNames = Invariant.saAbbrevEraNames; // Abbreviated Era Names if (this.saAbbrevEnglishEraNames == null) this.saAbbrevEnglishEraNames = Invariant.saAbbrevEnglishEraNames; // Abbreviated Era Names in English if (this.saDayNames == null) this.saDayNames = Invariant.saDayNames; // Day Names, null to use locale data, starts on Sunday if (this.saAbbrevDayNames == null) this.saAbbrevDayNames = Invariant.saAbbrevDayNames; // Abbrev Day Names, null to use locale data, starts on Sunday if (this.saSuperShortDayNames == null) this.saSuperShortDayNames = Invariant.saSuperShortDayNames; // Super short Day of week names if (this.saMonthNames == null) this.saMonthNames = Invariant.saMonthNames; // Month Names (13) if (this.saAbbrevMonthNames == null) this.saAbbrevMonthNames = Invariant.saAbbrevMonthNames; // Abbrev Month Names (13) // Genitive and Leap names can follow the fallback below } if (calendarId == CalendarId.TAIWAN) { if (SystemSupportsTaiwaneseCalendar()) { // We got the month/day names from the OS (same as gregorian), but the native name is wrong this.sNativeName = "\x4e2d\x83ef\x6c11\x570b\x66c6"; } else { this.sNativeName = String.Empty; } } // Check for null genitive names (in case unmanaged side skips it for non-gregorian calendars, etc) if (this.saMonthGenitiveNames == null || String.IsNullOrEmpty(this.saMonthGenitiveNames[0])) this.saMonthGenitiveNames = this.saMonthNames; // Genitive month names (same as month names for invariant) if (this.saAbbrevMonthGenitiveNames == null || String.IsNullOrEmpty(this.saAbbrevMonthGenitiveNames[0])) this.saAbbrevMonthGenitiveNames = this.saAbbrevMonthNames; // Abbreviated genitive month names (same as abbrev month names for invariant) if (this.saLeapYearMonthNames == null || String.IsNullOrEmpty(this.saLeapYearMonthNames[0])) this.saLeapYearMonthNames = this.saMonthNames; InitializeEraNames(localeName, calendarId); InitializeAbbreviatedEraNames(localeName, calendarId); // Abbreviated English Era Names are only used for the Japanese calendar. if (calendarId == CalendarId.JAPAN) { this.saAbbrevEnglishEraNames = JapaneseCalendar.EnglishEraNames(); } else { // For all others just use the an empty string (doesn't matter we'll never ask for it for other calendars) this.saAbbrevEnglishEraNames = new String[] { "" }; } // Japanese is the only thing with > 1 era. Its current era # is how many ever // eras are in the array. (And the others all have 1 string in the array) this.iCurrentEra = this.saEraNames.Length; }
// month/day format (single string, no override) internal String MonthDay(CalendarId calendarId) { return GetCalendar(calendarId).sMonthDay; }
private void InitializeAbbreviatedEraNames(string localeName, CalendarId calendarId) { // Note that the saAbbrevEraNames only include "AD" We don't have localized names for other calendars available from windows switch (calendarId) { // For Localized Gregorian we really expect the data from the OS. case CalendarId.GREGORIAN: // Fallback for CoreCLR < Win7 or culture.dll missing if (this.saAbbrevEraNames == null || this.saAbbrevEraNames.Length == 0 || String.IsNullOrEmpty(this.saAbbrevEraNames[0])) { this.saAbbrevEraNames = new String[] { "AD" }; } break; // The rest of the calendars have constant data, so we'll just use that case CalendarId.GREGORIAN_US: case CalendarId.JULIAN: this.saAbbrevEraNames = new String[] { "AD" }; break; case CalendarId.JAPAN: case CalendarId.JAPANESELUNISOLAR: this.saAbbrevEraNames = JapaneseCalendar.AbbrevEraNames(); break; case CalendarId.HIJRI: case CalendarId.UMALQURA: if (localeName == "dv-MV") { // Special case for Divehi this.saAbbrevEraNames = new String[] { "\x0780\x002e" }; } else { this.saAbbrevEraNames = new String[] { "\x0647\x0640" }; } break; case CalendarId.TAIWAN: // Get era name and abbreviate it this.saAbbrevEraNames = new String[1]; if (this.saEraNames[0].Length == 4) { this.saAbbrevEraNames[0] = this.saEraNames[0].Substring(2, 2); } else { this.saAbbrevEraNames[0] = this.saEraNames[0]; } break; case CalendarId.PERSIAN: if (this.saAbbrevEraNames == null || this.saAbbrevEraNames.Length == 0 || String.IsNullOrEmpty(this.saAbbrevEraNames[0])) { this.saAbbrevEraNames = this.saEraNames; } break; default: // Most calendars just use the full name this.saAbbrevEraNames = this.saEraNames; break; } }
internal static extern unsafe ResultCode GetCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType calendarDataType, char *result, int resultCapacity);