Search code examples
c#datetimearabicculturehijri

Querying with Arabic (Hijri) DateTime


I essentially have a query that looks like this:

.Where(x=>x.Date < DateTimeOffset.UtcNow)

Now, this has worked as intended so far, but since also adding Arabic into my application, apparently their calendar system uses something called a Hijri calendar?

Anyway, date such as 24/09/2013 looks like 18/05/34 (invented values).

So, the query would end up using the 18/05/1834 date, and thus return no values.

tl;dr I want to be able to query with the non-cultured datetime. I've tried to google how to use CultureInvariant, but all the solutions showed a .ToString() whereas I need a datetime returned


Solution

  • DateTime and DateTimeOffset don't have any culture. You only use culture info when parsing a string or outputting a string. Internally, they always store their data using the Gregorian calendar. So if you are comparing DateTime or DateTimeOffset values, then it doesn't matter what calendar system is used for display - the comparison will always be done with their Gregorian equivalents.

    You had said in your question:

    So, the query would end up using the 18/05/1834 date, and thus return no values.

    If you are doing things normally, that won't be true. You won't have Hijri formatted dates in your database. Those will all be Gregorian still and the comparison should work as expected. If for some reason you actually have the Hijri values in your data, then somewhere you are passing your values by string, which is getting affected by culture. You shouldn't do that.

    Take a look at the sample code in this MSDN entry. It shows clearly that you need to use a calendar object to get numerical equivalents for each part, but there is no way to get back a single non-string value that represents the entire date in a non-Gregorian calendar system.

    For example:

    DateTime utc = DateTime.UtcNow;
    Calendar cal = new HijriCalendar();
    int y = cal.GetYear(utc);
    int m = cal.GetMonth(utc);
    int d = cal.GetDayOfMonth(utc);
    

    Or, as a string:

    DateTime utc = DateTime.UtcNow;
    var ci = CultureInfo.CreateSpecificCulture("ar-SA");
    string s = utc.ToString(ci);
    

    If you want a better way to represent Hijri calendar dates in your code, you might consider using Noda Time instead of the built-in types. It has much better support for alternative calendars. For example:

    Instant now = SystemClock.Instance.Now;
    CalendarSystem cal = CalendarSystem.GetIslamicCalendar(IslamicLeapYearPattern.Base15, IslamicEpoch.Civil);
    ZonedDateTime zdt = now.InZone(DateTimeZone.Utc, cal);
    LocalDateTime ldt = zdt.LocalDateTime;
    

    UPDATE

    It appears the question was with specific regard to querying in RavenDB, and was discussed here. The problem was tracked down to a culture related bug in RavenDB, and fixed in release 2.5.2715.