From 819e146254554ee7fb38472d7024bff262df888f Mon Sep 17 00:00:00 2001 From: Meri Khamoyan Date: Fri, 4 Aug 2023 11:23:42 +0200 Subject: [PATCH 1/7] Implement calendar info for hybrid mode --- .../features/globalization-hybrid-mode.md | 31 ++++ .../src/Interop/Interop.Calendar.iOS.cs | 15 ++ .../DateTimeFormatInfoMonthDayPattern.cs | 13 ++ .../System.Globalization.IOS.Tests.csproj | 30 ++++ .../System.Private.CoreLib.Shared.projitems | 4 + .../System/Globalization/CalendarData.Unix.cs | 12 +- .../System/Globalization/CalendarData.iOS.cs | 111 +++++++++++++ src/mono/mono/mini/CMakeLists.txt | 3 +- .../CMakeLists.txt | 2 +- .../System.Globalization.Native/entrypoints.c | 1 + .../pal_calendarData.h | 8 + .../pal_calendarData.m | 153 ++++++++++++++++++ 12 files changed, 379 insertions(+), 4 deletions(-) create mode 100644 src/libraries/Common/src/Interop/Interop.Calendar.iOS.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.iOS.cs create mode 100644 src/native/libs/System.Globalization.Native/pal_calendarData.m diff --git a/docs/design/features/globalization-hybrid-mode.md b/docs/design/features/globalization-hybrid-mode.md index 7f7b3bba2c03b7..d0cc31600f8fa8 100644 --- a/docs/design/features/globalization-hybrid-mode.md +++ b/docs/design/features/globalization-hybrid-mode.md @@ -423,3 +423,34 @@ Below function are used from apple native functions: - [uppercaseStringWithLocale](https://developer.apple.com/documentation/foundation/nsstring/1413316-uppercasestringwithlocale?language=objc) - [lowercaseStringWithLocale](https://developer.apple.com/documentation/foundation/nsstring/1417298-lowercasestringwithlocale?language=objc) +## Calandars + +Affected public APIs: +- DateTimeFormatInfo.AbbreviatedDayNames +- DateTimeFormatInfo.GetAbbreviatedDayName() +- DateTimeFormatInfo.AbbreviatedMonthGenitiveNames +- DateTimeFormatInfo.AbbreviatedMonthNames +- DateTimeFormatInfo.GetAbbreviatedMonthName() +- DateTimeFormatInfo.AMDesignator +- DateTimeFormatInfo.CalendarWeekRule +- DateTimeFormatInfo.DayNames +- DateTimeFormatInfo.GetDayName +- DateTimeFormatInfo.GetEraName() +- DateTimeFormatInfo.FirstDayOfWeek +- DateTimeFormatInfo.FullDateTimePattern +- DateTimeFormatInfo.LongDatePattern +- DateTimeFormatInfo.LongTimePattern +- DateTimeFormatInfo.MonthDayPattern +- DateTimeFormatInfo.MonthGenitiveNames +- DateTimeFormatInfo.MonthNames +- DateTimeFormatInfo.GetMonthName() +- DateTimeFormatInfo.NativeCalendarName +- DateTimeFormatInfo.PMDesignator +- DateTimeFormatInfo.ShortDatePattern +- DateTimeFormatInfo.ShortestDayNames +- DateTimeFormatInfo.GetShortestDayName() +- DateTimeFormatInfo.ShortTimePattern +- DateTimeFormatInfo.YearMonthPattern + +Apple Native API does not have an equivalent for abbreviated era name and will return empty string +- DateTimeFormatInfo.GetAbbreviatedEraName() diff --git a/src/libraries/Common/src/Interop/Interop.Calendar.iOS.cs b/src/libraries/Common/src/Interop/Interop.Calendar.iOS.cs new file mode 100644 index 00000000000000..c8cef7e4d60137 --- /dev/null +++ b/src/libraries/Common/src/Interop/Interop.Calendar.iOS.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Globalization; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Globalization + { + [LibraryImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetCalendarInfoNative", StringMarshalling = StringMarshalling.Utf8)] + internal static unsafe partial string GetCalendarInfoNative(string localeName, CalendarId calendarId, CalendarDataType calendarDataType); + } +} diff --git a/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoMonthDayPattern.cs b/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoMonthDayPattern.cs index 3ca5b313cbf5c2..1429a19cb25048 100644 --- a/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoMonthDayPattern.cs +++ b/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoMonthDayPattern.cs @@ -35,6 +35,19 @@ public void MonthDayPattern_Set_GetReturnsExpected(string value) Assert.Equal(value, format.MonthDayPattern); } + public static IEnumerable MonthDayPattern_Get_TestData() + { + yield return new object[] { new CultureInfo("ar-SA").DateTimeFormat, "d MMMM" }; + yield return new object[] { new CultureInfo("am-ET").DateTimeFormat, "MMMM d" }; + } + + [Theory] + [MemberData(nameof(MonthDayPattern_Get_TestData))] + public void MonthDayPattern_Get_GetReturnsExpected(DateTimeFormatInfo format, string expected) + { + Assert.Equal(expected, format.MonthDayPattern); + } + [Fact] public void MonthDayPattern_SetNull_ThrowsArgumentNullException() { diff --git a/src/libraries/System.Globalization/tests/Hybrid/System.Globalization.IOS.Tests.csproj b/src/libraries/System.Globalization/tests/Hybrid/System.Globalization.IOS.Tests.csproj index f21ff6dafff2b8..eac50b0d2f3e0f 100644 --- a/src/libraries/System.Globalization/tests/Hybrid/System.Globalization.IOS.Tests.csproj +++ b/src/libraries/System.Globalization/tests/Hybrid/System.Globalization.IOS.Tests.csproj @@ -18,9 +18,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 82eb84609a6f09..9feb7fd5f44dea 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -319,6 +319,7 @@ + @@ -1287,6 +1288,9 @@ Common\Interop\Interop.Calendar.cs + + Common\Interop\Interop.Calendar.iOS.cs + Common\Interop\Interop.Casing.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Unix.cs index ff4b34b2a35d27..59785ded51a1e3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Unix.cs @@ -7,8 +7,16 @@ namespace System.Globalization { internal sealed partial class CalendarData { - private bool LoadCalendarDataFromSystemCore(string localeName, CalendarId calendarId) => - IcuLoadCalendarDataFromSystem(localeName, calendarId); + private bool LoadCalendarDataFromSystemCore(string localeName, CalendarId calendarId) + { +#if TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS + return GlobalizationMode.Hybrid ? + LoadCalendarDataFromNative(localeName, calendarId) : + IcuLoadCalendarDataFromSystem(localeName, calendarId); +#else + return IcuLoadCalendarDataFromSystem(localeName, calendarId); +#endif + } #pragma warning disable IDE0060 internal static int GetCalendarsCore(string localeName, bool useUserOverride, CalendarId[] calendars) => diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.iOS.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.iOS.cs new file mode 100644 index 00000000000000..b12637b707b42a --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.iOS.cs @@ -0,0 +1,111 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace System.Globalization +{ + internal sealed partial class CalendarData + { + private bool LoadCalendarDataFromNative(string localeName, CalendarId calendarId) + { + Debug.Assert(!GlobalizationMode.UseNls); + + this.sNativeName = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.NativeName); + this.sMonthDay = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.MonthDay); + this.saShortDates = new string [] { GetCalendarInfoNative(localeName, calendarId, CalendarDataType.ShortDates) }; + this.saLongDates = new string [] { GetCalendarInfoNative(localeName, calendarId, CalendarDataType.LongDates) }; + this.saYearMonths = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.YearMonths).Split("||"); + this.saDayNames = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.DayNames).Split("||"); + this.saAbbrevDayNames = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.AbbrevDayNames).Split("||"); + this.saSuperShortDayNames = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.SuperShortDayNames).Split("||"); + + string? leapHebrewMonthName = null; + this.saMonthNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.MonthNames).Split("||"), calendarId, ref leapHebrewMonthName); + if (leapHebrewMonthName != null) + { + Debug.Assert(this.saMonthNames != null); + + // In Hebrew calendar, get the leap month name Adar II and override the non-leap month 7 + Debug.Assert(calendarId == CalendarId.HEBREW && saMonthNames.Length == 13); + saLeapYearMonthNames = (string[]) saMonthNames.Clone(); + saLeapYearMonthNames[6] = leapHebrewMonthName; + + // The returned data has 6th month name as 'Adar I' and 7th month name as 'Adar' + // We need to adjust that in the list used with non-leap year to have 6th month as 'Adar' and 7th month as 'Adar II' + // note that when formatting non-leap year dates, 7th month shouldn't get used at all. + saMonthNames[5] = saMonthNames[6]; + saMonthNames[6] = leapHebrewMonthName; + + } + this.saAbbrevMonthNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.AbbrevMonthNames).Split("||"), calendarId, ref leapHebrewMonthName); + this.saMonthGenitiveNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.MonthGenitiveNames).Split("||"), calendarId, ref leapHebrewMonthName); + this.saAbbrevMonthGenitiveNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.AbbrevMonthGenitiveNames).Split("||"), calendarId, ref leapHebrewMonthName); + + this.saEraNames = NormalizeEraNames(calendarId, GetCalendarInfoNative(localeName, calendarId, CalendarDataType.EraNames).Split("||")); + this.saAbbrevEraNames = Array.Empty();//NormalizeEraNames(calendarId, GetCalendarInfoNative(localeName, calendarId, CalendarDataType.AbbrevEraNames).Split("||")); + + return this.sNativeName != null && this.saShortDates != null && this.saLongDates != null && this.saYearMonths != null && + this.saDayNames != null && this.saAbbrevDayNames != null && this.saSuperShortDayNames != null && this.saMonthNames != null && + this.saAbbrevMonthNames != null && this.saMonthGenitiveNames != null && this.saAbbrevMonthGenitiveNames != null && + this.saEraNames != null && this.saAbbrevEraNames != null; + } + + private static string[] NormalizeEraNames(CalendarId calendarId, string[]? eraNames) + { + // .NET expects that only the Japanese calendars have more than 1 era. + // So for other calendars, only return the latest era. + if (calendarId != CalendarId.JAPAN && calendarId != CalendarId.JAPANESELUNISOLAR && eraNames?.Length > 0) + { + string[] latestEraName = new string[] { eraNames![eraNames.Length - 1] }; + eraNames = latestEraName; + } + + return eraNames ?? Array.Empty(); + } + + private static string[] NormalizeMonthArray(string[] months, CalendarId calendarId, ref string? leapHebrewMonthName) + { + if (months.Length == 13) + return months; + + string[] normalizedMonths = new string[13]; + // the month-name arrays are expected to have 13 elements. If only returns 12, add an + // extra empty string to fill the array. + if (months.Length == 12) + { + normalizedMonths[12] = ""; + months.CopyTo(normalizedMonths, 0); + return normalizedMonths; + } + + if (months.Length > 13) + { + Debug.Assert(calendarId == CalendarId.HEBREW && months.Length == 14); + + if (calendarId == CalendarId.HEBREW) + { + leapHebrewMonthName = months[13]; + } + for (int i = 0; i < 13; i++) + { + normalizedMonths[i] = months[i]; + } + return normalizedMonths; + } + + return normalizedMonths; + } + + private static unsafe string GetCalendarInfoNative(string localeName, CalendarId calendarId, CalendarDataType calendarDataType) + { + Debug.Assert(localeName != null); + + return Interop.Globalization.GetCalendarInfoNative(localeName, calendarId, calendarDataType); + } + } +} diff --git a/src/mono/mono/mini/CMakeLists.txt b/src/mono/mono/mini/CMakeLists.txt index adb4922b9b36cf..47a6abcb7c71e3 100644 --- a/src/mono/mono/mini/CMakeLists.txt +++ b/src/mono/mono/mini/CMakeLists.txt @@ -72,7 +72,8 @@ if(HAVE_SYS_ICU) ${icu_shim_sources_base} pal_locale.m pal_collation.m - pal_casing.m) + pal_casing.m + pal_calendarData.m) endif() addprefix(icu_shim_sources "${ICU_SHIM_PATH}" "${icu_shim_sources_base}") diff --git a/src/native/libs/System.Globalization.Native/CMakeLists.txt b/src/native/libs/System.Globalization.Native/CMakeLists.txt index 1c9a25f5d5d6f6..7b4ad155554adf 100644 --- a/src/native/libs/System.Globalization.Native/CMakeLists.txt +++ b/src/native/libs/System.Globalization.Native/CMakeLists.txt @@ -93,7 +93,7 @@ else() endif() if (CLR_CMAKE_TARGET_APPLE) - set(NATIVEGLOBALIZATION_SOURCES ${NATIVEGLOBALIZATION_SOURCES} pal_locale.m pal_collation.m pal_casing.m) + set(NATIVEGLOBALIZATION_SOURCES ${NATIVEGLOBALIZATION_SOURCES} pal_locale.m pal_collation.m pal_casing.m pal_calendarData.m) endif() # time zone names are filtered out of icu data for the browser and associated functionality is disabled diff --git a/src/native/libs/System.Globalization.Native/entrypoints.c b/src/native/libs/System.Globalization.Native/entrypoints.c index 1ba348b910b5ff..cffad72a023721 100644 --- a/src/native/libs/System.Globalization.Native/entrypoints.c +++ b/src/native/libs/System.Globalization.Native/entrypoints.c @@ -63,6 +63,7 @@ static const Entry s_globalizationNative[] = DllImportEntry(GlobalizationNative_ChangeCaseNative) DllImportEntry(GlobalizationNative_CompareStringNative) DllImportEntry(GlobalizationNative_EndsWithNative) + DllImportEntry(GlobalizationNative_GetCalendarInfoNative) DllImportEntry(GlobalizationNative_GetLocaleInfoIntNative) DllImportEntry(GlobalizationNative_GetLocaleInfoPrimaryGroupingSizeNative) DllImportEntry(GlobalizationNative_GetLocaleInfoSecondaryGroupingSizeNative) diff --git a/src/native/libs/System.Globalization.Native/pal_calendarData.h b/src/native/libs/System.Globalization.Native/pal_calendarData.h index c6465791f7294e..1a23376641a463 100644 --- a/src/native/libs/System.Globalization.Native/pal_calendarData.h +++ b/src/native/libs/System.Globalization.Native/pal_calendarData.h @@ -91,3 +91,11 @@ PALEXPORT int32_t GlobalizationNative_GetJapaneseEraStartDate(int32_t era, int32_t* startYear, int32_t* startMonth, int32_t* startDay); + +#ifdef __APPLE__ +PALEXPORT const char* GlobalizationNative_GetCalendarInfoNative(const char* localeName, + CalendarId calendarId, + CalendarDataType dataType); +#endif + + diff --git a/src/native/libs/System.Globalization.Native/pal_calendarData.m b/src/native/libs/System.Globalization.Native/pal_calendarData.m new file mode 100644 index 00000000000000..0901cf5e3add19 --- /dev/null +++ b/src/native/libs/System.Globalization.Native/pal_calendarData.m @@ -0,0 +1,153 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include +#include +#include +#include +#include "pal_locale_internal.h" +#include "pal_errors_internal.h" +#include "pal_calendarData.h" +#import + +#if defined(TARGET_MACCATALYST) || defined(TARGET_IOS) || defined(TARGET_TVOS) + +/* +Function: +GetCalendarIdentifier + +Gets the associated NSCalendarIdentifier for the CalendarId. +*/ +static NSString* GetCalendarIdentifier(CalendarId calendarId) +{ + NSString *calendarIdentifier = NSCalendarIdentifierGregorian; + switch (calendarId) + { + case JAPAN: + calendarIdentifier = NSCalendarIdentifierJapanese; + break; + case THAI: + calendarIdentifier = NSCalendarIdentifierBuddhist; + break; + case HEBREW: + calendarIdentifier = NSCalendarIdentifierHebrew; + break; + case PERSIAN: + calendarIdentifier = NSCalendarIdentifierPersian; + break; + case HIJRI: + calendarIdentifier = NSCalendarIdentifierIslamic; + break; + case UMALQURA: + calendarIdentifier = NSCalendarIdentifierIslamicUmmAlQura; + break; + case TAIWAN: + calendarIdentifier = NSCalendarIdentifierRepublicOfChina; + break; + default: + calendarIdentifier = NSCalendarIdentifierGregorian; + break; + } + return calendarIdentifier; +} + +/* +Function: +GlobalizationNative_GetCalendarInfoNative + +Gets a single string of calendar information for a given locale, calendar, and calendar data type. +with the requested value. +*/ +const char* GlobalizationNative_GetCalendarInfoNative(const char* localeName, CalendarId calendarId, CalendarDataType dataType) +{ + NSString *locName = [NSString stringWithFormat:@"%s", localeName]; + NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; + const char* resultString = NULL; + + NSString *calendarIdentifier = GetCalendarIdentifier(calendarId); + NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:calendarIdentifier]; + NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; + dateFormat.locale = currentLocale; + dateFormat.calendar = calendar; + + switch (dataType) + { + case CalendarData_NativeName: + return calendar ? strdup([[calendar calendarIdentifier] UTF8String]) : NULL; + case CalendarData_MonthDay: + { + NSString *formatString = [NSDateFormatter dateFormatFromTemplate:@"MMMMd" options:0 locale:currentLocale]; + return formatString ? strdup([formatString UTF8String]) : NULL; + } + case CalendarData_ShortDates: + { + [dateFormat setDateStyle:NSDateFormatterShortStyle]; // also NSDateFormatterMediumStyle ? and 'y', 'M', 'd' + NSString *shortFormatString = [dateFormat dateFormat]; + return shortFormatString ? strdup([shortFormatString UTF8String]) : NULL; + } + case CalendarData_LongDates: + { + [dateFormat setDateStyle:NSDateFormatterLongStyle]; // also NSDateFormatterFullStyle ? + NSString *longFormatString = [dateFormat dateFormat]; + return longFormatString ? strdup([longFormatString UTF8String]) : NULL; + } + case CalendarData_YearMonths: + { + NSString *formatString = [NSDateFormatter dateFormatFromTemplate:@"MMMM yyyy" options:0 locale:currentLocale]; + return formatString ? strdup([formatString UTF8String]) : NULL; + } + case CalendarData_DayNames: + { + NSArray *standaloneWeekdaySymbols = [dateFormat standaloneWeekdaySymbols]; + NSString *arrayToString = [[standaloneWeekdaySymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; + return arrayToString ? strdup([arrayToString UTF8String]) : NULL; + } + case CalendarData_AbbrevDayNames: + { + NSArray *shortStandaloneWeekdaySymbols = [dateFormat shortStandaloneWeekdaySymbols]; + NSString *arrayToString = [[shortStandaloneWeekdaySymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; + return arrayToString ? strdup([arrayToString UTF8String]) : NULL; + } + case CalendarData_MonthNames: + { + NSArray *standaloneMonthSymbols = [dateFormat standaloneMonthSymbols]; + NSString *arrayToString = [[standaloneMonthSymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; + return arrayToString ? strdup([arrayToString UTF8String]) : NULL; + } + case CalendarData_AbbrevMonthNames: + { + NSArray *shortStandaloneMonthSymbols = [dateFormat shortStandaloneMonthSymbols]; + NSString *arrayToString = [[shortStandaloneMonthSymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; + return arrayToString ? strdup([arrayToString UTF8String]) : NULL; + } + case CalendarData_SuperShortDayNames: + { + NSArray *veryShortStandaloneWeekdaySymbols = [dateFormat veryShortStandaloneWeekdaySymbols]; + NSString *arrayToString = [[veryShortStandaloneWeekdaySymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; + return arrayToString ? strdup([arrayToString UTF8String]) : NULL; + } + case CalendarData_MonthGenitiveNames: + { + NSArray *monthSymbols = [dateFormat monthSymbols]; + NSString *arrayToString = [[monthSymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; + return arrayToString ? strdup([arrayToString UTF8String]) : NULL; + } + case CalendarData_AbbrevMonthGenitiveNames: + { + NSArray *shortMonthSymbols = [dateFormat shortMonthSymbols]; + NSString *arrayToString = [[shortMonthSymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; + return arrayToString ? strdup([arrayToString UTF8String]) : NULL; + } + case CalendarData_EraNames: + case CalendarData_AbbrevEraNames: + { + NSArray *eraSymbols = [dateFormat eraSymbols]; + NSString *arrayToString = [[eraSymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; + return arrayToString ? strdup([arrayToString UTF8String]) : NULL; + } + default: + assert(false); + return resultString; + } +} +#endif From 58806cb0a32705d6a76cc93739303d77e1341194 Mon Sep 17 00:00:00 2001 From: Meri Khamoyan Date: Fri, 4 Aug 2023 14:15:25 +0200 Subject: [PATCH 2/7] Add calendar tests for hybrid mode iOS --- ...m.Globalization.Calendars.IOS.Tests.csproj | 109 ++++++++++++++++++ .../System/Globalization/CalendarTestBase.cs | 2 +- .../DateTimeFormatInfoMonthDayPattern.cs | 13 --- .../CMakeLists.txt | 2 +- .../pal_calendarData.m | 6 +- 5 files changed, 112 insertions(+), 20 deletions(-) create mode 100644 src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.IOS.Tests.csproj diff --git a/src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.IOS.Tests.csproj b/src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.IOS.Tests.csproj new file mode 100644 index 00000000000000..9ee7faa302f9e8 --- /dev/null +++ b/src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.IOS.Tests.csproj @@ -0,0 +1,109 @@ + + + $(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-maccatalyst + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/libraries/System.Globalization.Calendars/tests/System/Globalization/CalendarTestBase.cs b/src/libraries/System.Globalization.Calendars/tests/System/Globalization/CalendarTestBase.cs index 62e1b360069875..f40e246576e915 100644 --- a/src/libraries/System.Globalization.Calendars/tests/System/Globalization/CalendarTestBase.cs +++ b/src/libraries/System.Globalization.Calendars/tests/System/Globalization/CalendarTestBase.cs @@ -430,7 +430,7 @@ public void GetEra_Invalid_ThrowsArgumentOutOfRangeException() Assert.All(DateTime_TestData(calendar), dt => { // JapaneseCalendar throws on ICU, but not on NLS - if ((calendar is JapaneseCalendar && PlatformDetection.IsNlsGlobalization) || calendar is HebrewCalendar || calendar is TaiwanLunisolarCalendar || calendar is JapaneseLunisolarCalendar) + if ((calendar is JapaneseCalendar && (PlatformDetection.IsNlsGlobalization || PlatformDetection.IsHybridGlobalizationOnOSX)) || calendar is HebrewCalendar || calendar is TaiwanLunisolarCalendar || calendar is JapaneseLunisolarCalendar) { calendar.GetEra(dt); } diff --git a/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoMonthDayPattern.cs b/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoMonthDayPattern.cs index 1429a19cb25048..3ca5b313cbf5c2 100644 --- a/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoMonthDayPattern.cs +++ b/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoMonthDayPattern.cs @@ -35,19 +35,6 @@ public void MonthDayPattern_Set_GetReturnsExpected(string value) Assert.Equal(value, format.MonthDayPattern); } - public static IEnumerable MonthDayPattern_Get_TestData() - { - yield return new object[] { new CultureInfo("ar-SA").DateTimeFormat, "d MMMM" }; - yield return new object[] { new CultureInfo("am-ET").DateTimeFormat, "MMMM d" }; - } - - [Theory] - [MemberData(nameof(MonthDayPattern_Get_TestData))] - public void MonthDayPattern_Get_GetReturnsExpected(DateTimeFormatInfo format, string expected) - { - Assert.Equal(expected, format.MonthDayPattern); - } - [Fact] public void MonthDayPattern_SetNull_ThrowsArgumentNullException() { diff --git a/src/native/libs/System.Globalization.Native/CMakeLists.txt b/src/native/libs/System.Globalization.Native/CMakeLists.txt index ed6e548e9e81cd..cf06b6c80482a4 100644 --- a/src/native/libs/System.Globalization.Native/CMakeLists.txt +++ b/src/native/libs/System.Globalization.Native/CMakeLists.txt @@ -94,7 +94,7 @@ endif() if (CLR_CMAKE_TARGET_APPLE) set(NATIVEGLOBALIZATION_SOURCES ${NATIVEGLOBALIZATION_SOURCES} pal_locale.m pal_collation.m pal_casing.m pal_calendarData.m) - set_source_files_properties(pal_locale.m pal_collation.m pal_casing.m PROPERTIES COMPILE_FLAGS ${CLR_CMAKE_COMMON_OBJC_FLAGS}) + set_source_files_properties(pal_locale.m pal_collation.m pal_casing.m pal_calendarData.m PROPERTIES COMPILE_FLAGS ${CLR_CMAKE_COMMON_OBJC_FLAGS}) endif() # time zone names are filtered out of icu data for the browser and associated functionality is disabled diff --git a/src/native/libs/System.Globalization.Native/pal_calendarData.m b/src/native/libs/System.Globalization.Native/pal_calendarData.m index 0901cf5e3add19..1dad83a3d5eb6a 100644 --- a/src/native/libs/System.Globalization.Native/pal_calendarData.m +++ b/src/native/libs/System.Globalization.Native/pal_calendarData.m @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. #include -#include -#include -#include -#include "pal_locale_internal.h" -#include "pal_errors_internal.h" +#include "pal_icushim_internal.h" #include "pal_calendarData.h" #import From 9c7eca0ce46fe07dbdde230f6fca23a11c0cdd52 Mon Sep 17 00:00:00 2001 From: Meri Khamoyan Date: Fri, 4 Aug 2023 15:07:33 +0200 Subject: [PATCH 3/7] Minor fix --- .../Hybrid/System.Globalization.Calendars.IOS.Tests.csproj | 1 - .../libs/System.Globalization.Native/pal_calendarData.m | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.IOS.Tests.csproj b/src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.IOS.Tests.csproj index 9ee7faa302f9e8..4130b1f9a00b98 100644 --- a/src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.IOS.Tests.csproj +++ b/src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.IOS.Tests.csproj @@ -3,7 +3,6 @@ $(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-maccatalyst true true - diff --git a/src/native/libs/System.Globalization.Native/pal_calendarData.m b/src/native/libs/System.Globalization.Native/pal_calendarData.m index 1dad83a3d5eb6a..62fcaf62711445 100644 --- a/src/native/libs/System.Globalization.Native/pal_calendarData.m +++ b/src/native/libs/System.Globalization.Native/pal_calendarData.m @@ -58,10 +58,10 @@ { NSString *locName = [NSString stringWithFormat:@"%s", localeName]; NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; - const char* resultString = NULL; NSString *calendarIdentifier = GetCalendarIdentifier(calendarId); NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:calendarIdentifier]; + NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; dateFormat.locale = currentLocale; dateFormat.calendar = calendar; @@ -143,7 +143,7 @@ } default: assert(false); - return resultString; + return NULL; } } #endif From 93d18454823045970adc29f844a544798ba60018 Mon Sep 17 00:00:00 2001 From: Meri Khamoyan Date: Fri, 4 Aug 2023 17:08:04 +0200 Subject: [PATCH 4/7] update shortDates and longDates --- .../System/Globalization/CalendarData.iOS.cs | 4 ++-- .../pal_calendarData.m | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.iOS.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.iOS.cs index b12637b707b42a..67fee5a1638809 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.iOS.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.iOS.cs @@ -17,8 +17,8 @@ private bool LoadCalendarDataFromNative(string localeName, CalendarId calendarId this.sNativeName = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.NativeName); this.sMonthDay = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.MonthDay); - this.saShortDates = new string [] { GetCalendarInfoNative(localeName, calendarId, CalendarDataType.ShortDates) }; - this.saLongDates = new string [] { GetCalendarInfoNative(localeName, calendarId, CalendarDataType.LongDates) }; + this.saShortDates = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.ShortDates).Split("||"); + this.saLongDates = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.LongDates).Split("||"); this.saYearMonths = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.YearMonths).Split("||"); this.saDayNames = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.DayNames).Split("||"); this.saAbbrevDayNames = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.AbbrevDayNames).Split("||"); diff --git a/src/native/libs/System.Globalization.Native/pal_calendarData.m b/src/native/libs/System.Globalization.Native/pal_calendarData.m index 62fcaf62711445..0353b7c6a23fe1 100644 --- a/src/native/libs/System.Globalization.Native/pal_calendarData.m +++ b/src/native/libs/System.Globalization.Native/pal_calendarData.m @@ -77,15 +77,24 @@ } case CalendarData_ShortDates: { - [dateFormat setDateStyle:NSDateFormatterShortStyle]; // also NSDateFormatterMediumStyle ? and 'y', 'M', 'd' + [dateFormat setDateStyle:NSDateFormatterShortStyle]; NSString *shortFormatString = [dateFormat dateFormat]; - return shortFormatString ? strdup([shortFormatString UTF8String]) : NULL; + [dateFormat setDateStyle:NSDateFormatterMediumStyle]; + NSString *mediumFormatString = [dateFormat dateFormat]; + NSString *yearMonthDayFormat = [NSDateFormatter dateFormatFromTemplate:@"yMd" options:0 locale:currentLocale]; + NSArray *shortDates = @[shortFormatString, mediumFormatString, yearMonthDayFormat]; + NSString *shortDatesString = [[shortDates valueForKey:@"description"] componentsJoinedByString:@"||"]; + return shortDatesString ? strdup([shortDatesString UTF8String]) : NULL; } case CalendarData_LongDates: { - [dateFormat setDateStyle:NSDateFormatterLongStyle]; // also NSDateFormatterFullStyle ? + [dateFormat setDateStyle:NSDateFormatterLongStyle]; NSString *longFormatString = [dateFormat dateFormat]; - return longFormatString ? strdup([longFormatString UTF8String]) : NULL; + [dateFormat setDateStyle:NSDateFormatterFullStyle]; + NSString *fullFormatString = [dateFormat dateFormat]; + NSArray *longDates = @[longFormatString, fullFormatString]; + NSString *longDatesString = [[longDates valueForKey:@"description"] componentsJoinedByString:@"||"]; + return longDatesString ? strdup([longDatesString UTF8String]) : NULL; } case CalendarData_YearMonths: { From e7f33f7798fe8b0fa7801cff609f3ea9b3904669 Mon Sep 17 00:00:00 2001 From: Meri Khamoyan <96171496+mkhamoyan@users.noreply.github.com> Date: Mon, 7 Aug 2023 20:46:12 +0400 Subject: [PATCH 5/7] Update src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.IOS.Tests.csproj MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alexander Köplinger --- .../Hybrid/System.Globalization.Calendars.IOS.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.IOS.Tests.csproj b/src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.IOS.Tests.csproj index 4130b1f9a00b98..614c0d2a47f65a 100644 --- a/src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.IOS.Tests.csproj +++ b/src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.IOS.Tests.csproj @@ -1,6 +1,6 @@ - $(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-maccatalyst + $(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-maccatalyst true true From 81dc1805d6f2b25e6172240d135ac95a500598e8 Mon Sep 17 00:00:00 2001 From: Meri Khamoyan <96171496+mkhamoyan@users.noreply.github.com> Date: Mon, 7 Aug 2023 20:46:22 +0400 Subject: [PATCH 6/7] Update docs/design/features/globalization-hybrid-mode.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alexander Köplinger --- docs/design/features/globalization-hybrid-mode.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/design/features/globalization-hybrid-mode.md b/docs/design/features/globalization-hybrid-mode.md index d0cc31600f8fa8..9430f0dd8e1caf 100644 --- a/docs/design/features/globalization-hybrid-mode.md +++ b/docs/design/features/globalization-hybrid-mode.md @@ -434,7 +434,7 @@ Affected public APIs: - DateTimeFormatInfo.AMDesignator - DateTimeFormatInfo.CalendarWeekRule - DateTimeFormatInfo.DayNames -- DateTimeFormatInfo.GetDayName +- DateTimeFormatInfo.GetDayName() - DateTimeFormatInfo.GetEraName() - DateTimeFormatInfo.FirstDayOfWeek - DateTimeFormatInfo.FullDateTimePattern From d4b015e911f6de4344dcf4b61629442cebf35d6e Mon Sep 17 00:00:00 2001 From: Meri Khamoyan Date: Tue, 8 Aug 2023 14:05:03 +0200 Subject: [PATCH 7/7] Updates requested by review --- .../src/Interop/Interop.Calendar.iOS.cs | 2 +- .../System/Globalization/CalendarData.iOS.cs | 47 +++++---- .../pal_calendarData.h | 2 - .../pal_calendarData.m | 97 ++++++++----------- 4 files changed, 61 insertions(+), 87 deletions(-) diff --git a/src/libraries/Common/src/Interop/Interop.Calendar.iOS.cs b/src/libraries/Common/src/Interop/Interop.Calendar.iOS.cs index c8cef7e4d60137..11a6246a1d700b 100644 --- a/src/libraries/Common/src/Interop/Interop.Calendar.iOS.cs +++ b/src/libraries/Common/src/Interop/Interop.Calendar.iOS.cs @@ -10,6 +10,6 @@ internal static partial class Interop internal static partial class Globalization { [LibraryImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetCalendarInfoNative", StringMarshalling = StringMarshalling.Utf8)] - internal static unsafe partial string GetCalendarInfoNative(string localeName, CalendarId calendarId, CalendarDataType calendarDataType); + internal static partial string GetCalendarInfoNative(string localeName, CalendarId calendarId, CalendarDataType calendarDataType); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.iOS.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.iOS.cs index 67fee5a1638809..46bfb3d481ca2d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.iOS.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.iOS.cs @@ -15,20 +15,20 @@ private bool LoadCalendarDataFromNative(string localeName, CalendarId calendarId { Debug.Assert(!GlobalizationMode.UseNls); - this.sNativeName = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.NativeName); - this.sMonthDay = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.MonthDay); - this.saShortDates = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.ShortDates).Split("||"); - this.saLongDates = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.LongDates).Split("||"); - this.saYearMonths = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.YearMonths).Split("||"); - this.saDayNames = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.DayNames).Split("||"); - this.saAbbrevDayNames = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.AbbrevDayNames).Split("||"); - this.saSuperShortDayNames = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.SuperShortDayNames).Split("||"); + sNativeName = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.NativeName); + sMonthDay = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.MonthDay); + saShortDates = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.ShortDates).Split("||"); + saLongDates = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.LongDates).Split("||"); + saYearMonths = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.YearMonths).Split("||"); + saDayNames = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.DayNames).Split("||"); + saAbbrevDayNames = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.AbbrevDayNames).Split("||"); + saSuperShortDayNames = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.SuperShortDayNames).Split("||"); string? leapHebrewMonthName = null; - this.saMonthNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.MonthNames).Split("||"), calendarId, ref leapHebrewMonthName); + saMonthNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.MonthNames).Split("||"), calendarId, ref leapHebrewMonthName); if (leapHebrewMonthName != null) { - Debug.Assert(this.saMonthNames != null); + Debug.Assert(saMonthNames != null); // In Hebrew calendar, get the leap month name Adar II and override the non-leap month 7 Debug.Assert(calendarId == CalendarId.HEBREW && saMonthNames.Length == 13); @@ -42,17 +42,17 @@ private bool LoadCalendarDataFromNative(string localeName, CalendarId calendarId saMonthNames[6] = leapHebrewMonthName; } - this.saAbbrevMonthNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.AbbrevMonthNames).Split("||"), calendarId, ref leapHebrewMonthName); - this.saMonthGenitiveNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.MonthGenitiveNames).Split("||"), calendarId, ref leapHebrewMonthName); - this.saAbbrevMonthGenitiveNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.AbbrevMonthGenitiveNames).Split("||"), calendarId, ref leapHebrewMonthName); + saAbbrevMonthNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.AbbrevMonthNames).Split("||"), calendarId, ref leapHebrewMonthName); + saMonthGenitiveNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.MonthGenitiveNames).Split("||"), calendarId, ref leapHebrewMonthName); + saAbbrevMonthGenitiveNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.AbbrevMonthGenitiveNames).Split("||"), calendarId, ref leapHebrewMonthName); - this.saEraNames = NormalizeEraNames(calendarId, GetCalendarInfoNative(localeName, calendarId, CalendarDataType.EraNames).Split("||")); - this.saAbbrevEraNames = Array.Empty();//NormalizeEraNames(calendarId, GetCalendarInfoNative(localeName, calendarId, CalendarDataType.AbbrevEraNames).Split("||")); + saEraNames = NormalizeEraNames(calendarId, GetCalendarInfoNative(localeName, calendarId, CalendarDataType.EraNames).Split("||")); + saAbbrevEraNames = Array.Empty(); - return this.sNativeName != null && this.saShortDates != null && this.saLongDates != null && this.saYearMonths != null && - this.saDayNames != null && this.saAbbrevDayNames != null && this.saSuperShortDayNames != null && this.saMonthNames != null && - this.saAbbrevMonthNames != null && this.saMonthGenitiveNames != null && this.saAbbrevMonthGenitiveNames != null && - this.saEraNames != null && this.saAbbrevEraNames != null; + return sNativeName != null && saShortDates != null && saLongDates != null && saYearMonths != null && + saDayNames != null && saAbbrevDayNames != null && saSuperShortDayNames != null && saMonthNames != null && + saAbbrevMonthNames != null && saMonthGenitiveNames != null && saAbbrevMonthGenitiveNames != null && + saEraNames != null && saAbbrevEraNames != null; } private static string[] NormalizeEraNames(CalendarId calendarId, string[]? eraNames) @@ -60,10 +60,7 @@ private static string[] NormalizeEraNames(CalendarId calendarId, string[]? eraNa // .NET expects that only the Japanese calendars have more than 1 era. // So for other calendars, only return the latest era. if (calendarId != CalendarId.JAPAN && calendarId != CalendarId.JAPANESELUNISOLAR && eraNames?.Length > 0) - { - string[] latestEraName = new string[] { eraNames![eraNames.Length - 1] }; - eraNames = latestEraName; - } + return new string[] { eraNames![eraNames.Length - 1] }; return eraNames ?? Array.Empty(); } @@ -98,10 +95,10 @@ private static string[] NormalizeMonthArray(string[] months, CalendarId calendar return normalizedMonths; } - return normalizedMonths; + throw new Exception("CalendarData.GetCalendarInfoNative() returned an unexpected number of month names."); } - private static unsafe string GetCalendarInfoNative(string localeName, CalendarId calendarId, CalendarDataType calendarDataType) + private static string GetCalendarInfoNative(string localeName, CalendarId calendarId, CalendarDataType calendarDataType) { Debug.Assert(localeName != null); diff --git a/src/native/libs/System.Globalization.Native/pal_calendarData.h b/src/native/libs/System.Globalization.Native/pal_calendarData.h index c95d62d9eb0323..50458ac471a609 100644 --- a/src/native/libs/System.Globalization.Native/pal_calendarData.h +++ b/src/native/libs/System.Globalization.Native/pal_calendarData.h @@ -97,5 +97,3 @@ PALEXPORT const char* GlobalizationNative_GetCalendarInfoNative(const char* loca CalendarId calendarId, CalendarDataType dataType); #endif - - diff --git a/src/native/libs/System.Globalization.Native/pal_calendarData.m b/src/native/libs/System.Globalization.Native/pal_calendarData.m index 0353b7c6a23fe1..307590dfc7a9be 100644 --- a/src/native/libs/System.Globalization.Native/pal_calendarData.m +++ b/src/native/libs/System.Globalization.Native/pal_calendarData.m @@ -41,7 +41,6 @@ calendarIdentifier = NSCalendarIdentifierRepublicOfChina; break; default: - calendarIdentifier = NSCalendarIdentifierGregorian; break; } return calendarIdentifier; @@ -59,22 +58,30 @@ NSString *locName = [NSString stringWithFormat:@"%s", localeName]; NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; + if (dataType == CalendarData_MonthDay) + { + NSString *formatString = [NSDateFormatter dateFormatFromTemplate:@"MMMMd" options:0 locale:currentLocale]; + return formatString ? strdup([formatString UTF8String]) : NULL; + } + else if (dataType == CalendarData_YearMonths) + { + NSString *formatString = [NSDateFormatter dateFormatFromTemplate:@"MMMM yyyy" options:0 locale:currentLocale]; + return formatString ? strdup([formatString UTF8String]) : NULL; + } + NSString *calendarIdentifier = GetCalendarIdentifier(calendarId); NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:calendarIdentifier]; + if (dataType == CalendarData_NativeName) + return calendar ? strdup([[calendar calendarIdentifier] UTF8String]) : NULL; + NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; dateFormat.locale = currentLocale; dateFormat.calendar = calendar; + NSArray *result; switch (dataType) { - case CalendarData_NativeName: - return calendar ? strdup([[calendar calendarIdentifier] UTF8String]) : NULL; - case CalendarData_MonthDay: - { - NSString *formatString = [NSDateFormatter dateFormatFromTemplate:@"MMMMd" options:0 locale:currentLocale]; - return formatString ? strdup([formatString UTF8String]) : NULL; - } case CalendarData_ShortDates: { [dateFormat setDateStyle:NSDateFormatterShortStyle]; @@ -82,9 +89,8 @@ [dateFormat setDateStyle:NSDateFormatterMediumStyle]; NSString *mediumFormatString = [dateFormat dateFormat]; NSString *yearMonthDayFormat = [NSDateFormatter dateFormatFromTemplate:@"yMd" options:0 locale:currentLocale]; - NSArray *shortDates = @[shortFormatString, mediumFormatString, yearMonthDayFormat]; - NSString *shortDatesString = [[shortDates valueForKey:@"description"] componentsJoinedByString:@"||"]; - return shortDatesString ? strdup([shortDatesString UTF8String]) : NULL; + result = @[shortFormatString, mediumFormatString, yearMonthDayFormat]; + break; } case CalendarData_LongDates: { @@ -92,67 +98,40 @@ NSString *longFormatString = [dateFormat dateFormat]; [dateFormat setDateStyle:NSDateFormatterFullStyle]; NSString *fullFormatString = [dateFormat dateFormat]; - NSArray *longDates = @[longFormatString, fullFormatString]; - NSString *longDatesString = [[longDates valueForKey:@"description"] componentsJoinedByString:@"||"]; - return longDatesString ? strdup([longDatesString UTF8String]) : NULL; - } - case CalendarData_YearMonths: - { - NSString *formatString = [NSDateFormatter dateFormatFromTemplate:@"MMMM yyyy" options:0 locale:currentLocale]; - return formatString ? strdup([formatString UTF8String]) : NULL; + result = @[longFormatString, fullFormatString]; + break; } case CalendarData_DayNames: - { - NSArray *standaloneWeekdaySymbols = [dateFormat standaloneWeekdaySymbols]; - NSString *arrayToString = [[standaloneWeekdaySymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; - return arrayToString ? strdup([arrayToString UTF8String]) : NULL; - } + result = [dateFormat standaloneWeekdaySymbols]; + break; case CalendarData_AbbrevDayNames: - { - NSArray *shortStandaloneWeekdaySymbols = [dateFormat shortStandaloneWeekdaySymbols]; - NSString *arrayToString = [[shortStandaloneWeekdaySymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; - return arrayToString ? strdup([arrayToString UTF8String]) : NULL; - } + result = [dateFormat shortStandaloneWeekdaySymbols]; + break; case CalendarData_MonthNames: - { - NSArray *standaloneMonthSymbols = [dateFormat standaloneMonthSymbols]; - NSString *arrayToString = [[standaloneMonthSymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; - return arrayToString ? strdup([arrayToString UTF8String]) : NULL; - } + result = [dateFormat standaloneMonthSymbols]; + break; case CalendarData_AbbrevMonthNames: - { - NSArray *shortStandaloneMonthSymbols = [dateFormat shortStandaloneMonthSymbols]; - NSString *arrayToString = [[shortStandaloneMonthSymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; - return arrayToString ? strdup([arrayToString UTF8String]) : NULL; - } + result = [dateFormat shortStandaloneMonthSymbols]; + break; case CalendarData_SuperShortDayNames: - { - NSArray *veryShortStandaloneWeekdaySymbols = [dateFormat veryShortStandaloneWeekdaySymbols]; - NSString *arrayToString = [[veryShortStandaloneWeekdaySymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; - return arrayToString ? strdup([arrayToString UTF8String]) : NULL; - } + result = [dateFormat veryShortStandaloneWeekdaySymbols]; + break; case CalendarData_MonthGenitiveNames: - { - NSArray *monthSymbols = [dateFormat monthSymbols]; - NSString *arrayToString = [[monthSymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; - return arrayToString ? strdup([arrayToString UTF8String]) : NULL; - } + result = [dateFormat monthSymbols]; + break; case CalendarData_AbbrevMonthGenitiveNames: - { - NSArray *shortMonthSymbols = [dateFormat shortMonthSymbols]; - NSString *arrayToString = [[shortMonthSymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; - return arrayToString ? strdup([arrayToString UTF8String]) : NULL; - } + result = [dateFormat shortMonthSymbols]; + break; case CalendarData_EraNames: case CalendarData_AbbrevEraNames: - { - NSArray *eraSymbols = [dateFormat eraSymbols]; - NSString *arrayToString = [[eraSymbols valueForKey:@"description"] componentsJoinedByString:@"||"]; - return arrayToString ? strdup([arrayToString UTF8String]) : NULL; - } + result = [dateFormat eraSymbols]; + break; default: assert(false); return NULL; } + + NSString *arrayToString = [[result valueForKey:@"description"] componentsJoinedByString:@"||"]; + return arrayToString ? strdup([arrayToString UTF8String]) : NULL; } #endif