"String was not recognized as a valid DateTime.” error occurs for some exact dates

I have a problem converting Gregorian calendar dates to Persian(Hijri calendar) using default system "en-GB" culture in my ASP.NET MVC Application. I used the globalization tag in my web.config so the default culture would be "en-GB":

    <system.web>
        ...
        <globalization uiCulture="en-GB" culture="en-GB" />
        ...
    </system.web>

The conversion will happen for any date except for these exact dates that I listed them below and will throw "String was not recognized as a valid DateTime.” error.

The exact dates that will throw exception are:

  1. 22/07/(any year)
  2. 22/09/(any year)
  3. 19/05/(any year)
  4. 20/05/(any year)
  5. 21/05/(any year)

A part of my sample code:

using System.Globalization;
    ...
    ...
    public static PersianCalendar PC = new PersianCalendar();
    ...

    //I'm using this method for conversion
    public static DateTime GregorianToPersian(DateTime date)
    {
                ...

                string stringDate = string.Format("{0}/{1}/{2} {3}:{4}:{5}"
                    , PC.GetDayOfMonth(date), PC.GetMonth(date), PC.GetYear(date)
                    , PC.GetHour(date), PC.GetMinute(date), PC.GetSecond(date));
                return DateTime.Parse(stringDate); //error!
    }

Hope you guys can help me out with. Thanks.

Jon Skeet
people
quotationmark

Leaving the parsing error aside, this isn't going to achieve what you want to achieve. A DateTime value is always in the Gregorian calendar - trying to parse 31/04/1396 as a DateTime is never going to work because it's not a valid date in the Gregorian calendar.

I would advise using my Noda Time library for this instead, where appropriate types "know" which calendar system they're part of, and you can explicitly convert between them. For example:

// The Gregorian calendar is used implicitly
LocalDate gregorian = new LocalDate(2017, 7, 22);
LocalDate persian = gregorian.WithCalendar(CalendarSystem.PersianArithmetic);
Console.WriteLine($"{persian:yyyy-MM-dd}");

Output:

1396-04-31

You can then do sensible arithmetic with persian such as adding a month etc, which would give the wrong answer if you tried doing it with DateTime naively. (You could use Calendar.AddMonths etc, but you'd need to remember to do so everywhere.)

people

See more on this question at Stackoverflow