diff --git a/Jint/Native/Intl/IntlUtilities.cs b/Jint/Native/Intl/IntlUtilities.cs index 618186cc70..81218970e8 100644 --- a/Jint/Native/Intl/IntlUtilities.cs +++ b/Jint/Native/Intl/IntlUtilities.cs @@ -1638,7 +1638,8 @@ private static string RemoveUnicodeExtensions(string locale) // Use new CultureInfo() instead of GetCultureInfo() to get correct locale-specific // data. GetCultureInfo returns a cached read-only culture that may have different // NumberFormatInfo patterns (e.g., CurrencyNegativePattern). - return new CultureInfo(cultureTag); + // useUserOverride: false ensures consistent behavior regardless of Windows regional settings. + return new CultureInfo(cultureTag, false); } catch (CultureNotFoundException) { diff --git a/Jint/Native/Intl/JsDateTimeFormat.cs b/Jint/Native/Intl/JsDateTimeFormat.cs index 24481fbf97..4914b9f407 100644 --- a/Jint/Native/Intl/JsDateTimeFormat.cs +++ b/Jint/Native/Intl/JsDateTimeFormat.cs @@ -465,58 +465,48 @@ public LocaleDateFormatInfo(string dateOrder, string dateSeparator, bool hasText } /// - /// Determines the locale-specific date format order and separator. + /// Determines the locale-specific date format order and separator + /// by parsing the ShortDatePattern from DateTimeFormatInfo. /// private LocaleDateFormatInfo GetLocaleDateFormat() { - // Check if month is textual (long, short, narrow) vs numeric var hasTextualMonth = Month != null && Month is "long" or "short" or "narrow"; - // Get locale's short date pattern to determine order - var lang = Locale.Split('-')[0].ToLowerInvariant(); - var region = Locale.Contains('-') ? Locale.Split('-')[1].ToUpperInvariant() : ""; + // Derive date order and separator from the locale's ShortDatePattern (e.g., "dd-MM-yyyy", "M/d/yyyy") + var pattern = CultureInfo.DateTimeFormat.ShortDatePattern; + var dateOrder = ParseDateOrder(pattern); + var dateSeparator = hasTextualMonth ? " " : CultureInfo.DateTimeFormat.DateSeparator; - // Determine date component order based on locale - // MDY: en-US, en-CA (Canada uses MDY in English), fil (Philippines) - // DMY: Most of Europe, UK, Australia, most of world - // YMD: East Asia (China, Japan, Korea), Lithuania, Hungary - string dateOrder; - if (string.Equals(lang, "en", StringComparison.Ordinal) && - (string.Equals(region, "US", StringComparison.Ordinal) || - string.Equals(region, "", StringComparison.Ordinal))) - { - // en-US and plain "en" use MDY - dateOrder = "Mdy"; - } - else if (string.Equals(lang, "zh", StringComparison.Ordinal) || - string.Equals(lang, "ja", StringComparison.Ordinal) || - string.Equals(lang, "ko", StringComparison.Ordinal) || - string.Equals(lang, "hu", StringComparison.Ordinal) || - string.Equals(lang, "lt", StringComparison.Ordinal)) - { - // East Asian languages and Hungarian/Lithuanian use YMD - dateOrder = "yMd"; - } - else - { - // Most of the world uses DMY - dateOrder = "dMy"; - } + return new LocaleDateFormatInfo(dateOrder, dateSeparator, hasTextualMonth); + } - // Determine separator based on whether month is textual - string dateSeparator; - if (hasTextualMonth) - { - // Textual month uses space separators: "Jan 3, 2019" - dateSeparator = " "; - } - else + /// + /// Parses a .NET ShortDatePattern to extract the date component order (e.g., "dMy", "Mdy", "yMd"). + /// + private static string ParseDateOrder(string pattern) + { + var order = new StringBuilder(3); + foreach (var c in pattern) { - // Numeric format uses "/" for en-US, varies by locale - dateSeparator = "/"; + var component = char.ToLowerInvariant(c) switch + { + 'd' => 'd', + 'm' => 'M', + 'y' => 'y', + _ => '\0' + }; + + if (component != '\0' && (order.Length == 0 || order[order.Length - 1] != component)) + { + order.Append(component); + if (order.Length == 3) + { + break; + } + } } - return new LocaleDateFormatInfo(dateOrder, dateSeparator, hasTextualMonth); + return order.Length == 3 ? order.ToString() : "dMy"; // fallback to DMY } private void AddMonthPart(DateTime dateTime, List result, ref bool hasDate, string separator, bool hasTextualMonth, ChineseCalendarHelper.ChineseCalendarDate? lunisolarDate = null) @@ -1198,9 +1188,11 @@ private string BuildFormatString(List parts) } else { - // Numeric format: "1/3/2019" - // Use literal '/' by escaping with single quotes to avoid .NET's culture-specific date separator - result.Append("'/'"); + // Numeric format: use locale-specific date separator + var sep = CultureInfo.DateTimeFormat.DateSeparator; + result.Append('\''); + result.Append(sep); + result.Append('\''); } } }