如何正确呈现 ar-SA 日期和时间字符串

How to correctly render a ar-SA date and time string

所以,我有一个 DateTime 值,我需要使用 ar-SA 区域性(使用公历)将其呈现出来。

我想使用的格式是 dd-MMM-yyyy HH:mm。

我目前正在使用它来格式化它 -

dateTimeValue.ToString("dd-MMM-yyyy HH:mm", culture)

在 en-GB 中,我会看到 -

06-Jun-2017 16:49

在ar-SA中,当我使用相同的方法时,我看到-

06-يونيو-2017 16:49

现在,据我所知,我认为是 RTL 字符串导致了问题,因为它总是在右侧。

如何在 RTL 中正确呈现此日期?

var dt = DateTime.Parse("31/1/2016 12:00 AM", CultureInfo.GetCultureInfo("ar-SA"));
// Throws FormatException

并且您无法使用 ar-SA 区域性解析此字符串,因为此区域性使用 ص 作为 AMDesignator,因为它使用 UmAlQuraCalendar 而不是 GregorianCalendar。

您可以使用 InvariantCulture(它使用 AM 作为 AMDesignator 并使用 GregorianCalendar)代替 DateTime.ParseExact 方法并准确指定它的格式。

string s = "31/1/2016 12:00 AM";
DateTime dt = DateTime.ParseExact(s, "dd/M/yyyy hh:mm tt",CultureInfo.InvariantCulture);

参考here。有人或多或少遇到了与您相同的问题,这似乎解决了错误。希望这有帮助。

渲染它去看看 and 。他们似乎对可能能够解决您的问题的渲染有类似的问题。

是的,经过一番挖掘,我设法找到了一个可行的解决方案。

即使我的问题最初是关于 ar-SA,它也适用于任何从右到左的文化。

我最终使用 unicode 字符来明确说明字符串的哪些部分是从左到右和从右到左的。

因此,使用常量 -

private const char LeftToRightCharacter = (char)0x200E;
private const char RightToLeftCharacter = (char)0x200F;

然后我可以构建一个日期字符串,如下所示 -

if (culture.TextInfo.IsRightToLeft)
{
    return
        LeftToRightCharacter +
        date.ToString("yyyy-", culture) +
        RightToLeftCharacter +
        date.ToString("MMM", culture) +
        LeftToRightCharacter +
        date.ToString("-dd", culture);
}
return date.ToString("dd-MMM-yyyy", culture);

...其中 culture 是 CultureInfo(DateTimeFormat.Calendar 设置为 new GregorianCalendar()),date 是 DateTime。

因此,对于日期 06-Jun-2017,在 en-GB 我得到 -

06-Jun-2017

在 ar-SA 中我得到 -

2017-‏يونيو‎-06

既然我已将其作为字符串,我可以在任一侧添加时间(如果区域性是 RTL,则在左侧,如果区域性是 LTR,则在右侧)。

了解 Unicode 如何处理这些字符以及我本可以使用的其他字符非常有用 - http://www.unicode.org/reports/tr9/

CultureInfo CurrentCulture = CultureInfo.GetCultureInfo("ar-AE");
string text = DateTime.Now.ToString("yyyy MMMM dd", CurrentCulture);

ar-SA 短日期模式是:

  • d[U+200F] /M [U+200F]/yyyy g for dotnet v6.0.1
  • MM/dd/yyyy for date-fns/locale/ar-SA v4.26

U+200F 是Right-To-Left标记字符。
如果打印出来,它显示为“d /M /yyyy g”。
不确定最后的“g”是什么,也许是时代(如果不是“G”?)
此外,date-fns.format() 函数不接受“g”并引发错误。

open System
open System.Globalization
open System.IO

let culture = CultureInfo.GetCultureInfo("ar-SA") 
let pattern = culture.DateTimeFormat.ShortDatePattern

let date1 = DateTime(2017, 6, 6).ToString(pattern)
let date2 = DateTime(2017, 6, 6).ToString(pattern, culture)
use writer = File.CreateText("C://temp//ar-SA date.txt")
writer.WriteLine $"Short date1: {date1}"
writer.WriteLine $"Short date2: {date2}"

结果,从记事本++复制粘贴:

Short date1: 6‏/6‏/2017 AD        <- bad rendering here in the post
Short date2: 11‏‏/9‏‏/1438 بعد الهجرة   <- bad rendering here in the post

在记事本++中,“6”和“11”出现在正确的位置:

所以,“错误”位置似乎真的是日期打印位置的问题(HTML,文本文件...)。
当您更改当前线程的文化时,它会正确使用回历,因此年份为 1438。

我在模式中添加了一个额外的 RLM 标记(一天之前):
" [U+200F]d[U+200F] /M[U+200F] /yyyy g"
它在 notepad++ 和 copy-pasted 中都是正确的:

Short date3: ‏11‏‏/9‏‏/1438 بعد الهجرة