6

I am trying to convert persianDate to standarddate .

public DateTime ConvertPersianToEnglish(string persianDate)
{
    string[] formats = { "yyyy/MM/dd", "yyyy/M/d", "yyyy/MM/d", "yyyy/M/dd" };
    DateTime d1 = DateTime.ParseExact(persianDate, formats,
                                      CultureInfo.CurrentCulture, DateTimeStyles.None);
    PersianCalendar persian_date = new PersianCalendar();
    DateTime dt = persian_date.ToDateTime(d1.Year, d1.Month, d1.Day, 0, 0, 0, 0, 0);
    return dt;
}

The Persiandate has formats like this: 1392/10/12(Year/month/day)

In my application i am trying to convert Year/month/31 to standard time but i got this error :

{System.FormatException: String was not recognized as a valid DateTime.
   at System.DateTimeParse.ParseExactMultiple(String s, String[] formats, DateTimeFormatInfo dtfi, DateTimeStyles style)

The exactly value that i get the error is 1393/04/31

Ehsan Akbar
  • 6,977
  • 19
  • 96
  • 180

3 Answers3

6

Sergey's solution of explicitly using a culture which uses the Persian calendar should work, but another option is to use my Noda Time library:

using System;
using System.Globalization;
using NodaTime;
using NodaTime.Text;

public class Test
{
    public static void Main()        
    {
        // Providing the sample date to the pattern tells it which
        // calendar to use.

        // Noda Time 2.0 uses a property instead of a method.
        // var calendar = CalendarSystem.Persian;           // 2.0+
        var calendar = CalendarSystem.GetPersianCalendar(); // 1.x

        LocalDate sampleDate = new LocalDate(1392, 10, 12, calendar);
        var pattern = LocalDatePattern.Create(
            "yyyy/M/d", CultureInfo.InvariantCulture, sampleDate);
        string text = "1393/04/31";
        ParseResult<LocalDate> parseResult = pattern.Parse(text);
        if (parseResult.Success)
        {
            LocalDate date = parseResult.Value;
            // Use the date
        }
    }    
}

Unlike DateTime, the LocalDate result here knows that it's just a date (so won't offer time aspects) and also knows which calendar system it's in (so you don't need to keep calling methods like calendar.GetYear(date) to get specific parts).

Note that a parse pattern of yyyy/M/d will be able to parse values with leading zeroes, so you don't need multiple patterns. If you know the format always will have two digits for the month and day, however, I'd explicitly use yyyy/MM/dd instead.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
2

Explanation

There are couple of problems here:

  1. DateTime d1 = DateTime.ParseExact(persianDate, formats,
                                      CultureInfo.CurrentCulture, DateTimeStyles.None);
    

    CultureInfo.CurrentCulture is machine dependent. But the function name is ConvertPersianToEnglish which means that provider argument of ParseExact should be set to Persian date format provider.

  2. For some reason, Iranian CultureInfo instances has GregorianCalendar as a default calendars. Moreover, it doesn't have PersianCalendar in OptionalCalendars. Which is weird because System.Globalization namespace includes PersianCalendar class.

Solutions

There are couple options that you can use here.

Solution 1

In this article Babak Mahmoudi provides a helper class that can fix CultureInfo instance to accept PersianCalendar. Methods inside this class are not very gentle (in terms of implementation). But it contains FixPersianDateTimeFormat method which is quite innocent. Using it, your code would look like this:

public static DateTime ConvertPersianToEnglish(string persianDate)
{
    string[] formats = { "yyyy/MM/dd", "yyyy/M/d", "yyyy/MM/d", "yyyy/M/dd" };
    DateTimeFormatInfo persianDateTimeFormatInfo = new CultureInfo("fa-Ir").DateTimeFormat;
    PersianCultureHelper.FixPersianDateTimeFormat(persianDateTimeFormatInfo, true);
    return DateTime.ParseExact(persianDate, formats, persianDateTimeFormatInfo, DateTimeStyles.None);
}

Solution 2

You can parse string yourself and then use PersianCalendar.ToDateTime. See comecme's answer here: How to convert Persian Calendar date string to DateTime?

Community
  • 1
  • 1
Sergey Krusch
  • 1,928
  • 16
  • 17
1

Here's a simple way to convert Persian date to DateTime:

    public DateTime GetGregorianDate(string persianDate)
    {
        PersianCalendar persian_date = new PersianCalendar();
        var dateParts = GetDateParts(persianDate);
        DateTime dt = persian_date.ToDateTime(dateParts[0], dateParts[1], dateParts[2], 0, 0, 0, 0, 0);
        return dt;
    }

    public int[] GetDateParts(string persianDate)
    {
        return persianDate.Split('/').Select(datePart => int.Parse(datePart)).ToArray();
    }
brz
  • 5,926
  • 1
  • 18
  • 18