0
votes

So, I've got a DateTime value, and I need to render it out using the ar-SA culture (using the Gregorian Calendar).

The format I'd like to use is dd-MMM-yyyy HH:mm.

I'm using this currently to format it -

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

In en-GB, I'd see -

06-Jun-2017 16:49

In ar-SA, when I use the same method, I see -

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

Now, from what I can work out, I think it's the RTL string that's causing the problem, since it's always on the right-hand side.

How do I render out this date correctly in RTL?

3
What do you expect to see and why? (plus make sure to clarify where you plan to show the string like HTML, console, WinForm, WPF, debugger,...)Alexei Levenkov
Hmmm.. with ar-SA, the day should be 11 and the year 1438. By default it uses the UmAlQuaraCalendar, not the GregorianCalendar. Did you alter the culture in some way? Please show that here so we can reproduce the problem. (But yes, I see that the Arabic text is pushed to the right with MMM. Looking into that still.)Matt Johnson-Pint
How are you actually rendering the string? In a desktop UI app control of some type? In a web page? It probably has more to do with how a string with mixed rtl/ltr text is rendered then how the string is generated.Matt Johnson-Pint
Sorry, should have been clearer: I'm displaying this in HTML, but I want to add unit tests to make sure this works first. As for what I'm expecting to see: I don't know, and that doesn't help much. All I know is that the month probably shouldn't be at the end, and I suspect that's a RTL/LTR issue, rather than a date format issue.Jamie Burns
@MattJohnson I'm intentionally using Gregorian calendar, not UmAlQuara, so the year is correct at 2017. I'm changing it by overriding the DateTimeFormat.Calendar of the date object.Jamie Burns

3 Answers

1
votes

Right, after a bit of digging, I've managed to get a solution that works.

Even though my question was originally about ar-SA, it does apply to any right-to-left culture.

I ended up using unicode characters to explicitly state what parts of the string were left-to-right and right-to-left.

So, using the constants -

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

I can then build up a string of the date as follows -

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);

...where culture is a CultureInfo (with the DateTimeFormat.Calendar set to new GregorianCalendar()) and date is a DateTime.

So, for the date 06-Jun-2017, in en-GB I get -

06-Jun-2017

and in ar-SA I get -

2017-‏يونيو‎-06

Now that I've got that as a string, I can add the time on either side (to the left, if the culture is RTL and on the right if the culture is LTR).

It was useful seeing how Unicode deals with these characters, along with the other characters I could have used instead - http://www.unicode.org/reports/tr9/

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

And you can't parse this string with ar-SA culture because this culture uses ص as a AMDesignator since it uses UmAlQuraCalendar rather than a GregorianCalendar.

You can use InvariantCulture (which uses AM as a AMDesignator and uses GregorianCalendar) instead with DateTime.ParseExact method with specify it's format exactly.

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

Reference here. Someone had the same problem as you more or less and this seemed to have solved the error. Hope this helps.

To render it go have a look here and here. They seemed to have a similar issue with the rendering that may be able to resolve your issue.

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