2

What I want is to convert the text into an Hijri date.

I tried the following code, but the problem was not solved.

Dim iString As String = "١٤٤٢/٠٨/٠٨ ٢:٣٨ ص"
Dim myDate As DateTime = CDate(iString)
Dim myDatea As DateTime = DateTime.ParseExact(iString, "yyyy-MM-dd HH:mm tt", Nothing)
Dim myDateb As DateTime = DateTime.Parse(iString)
Dim dta As DateTime = DateTime.ParseExact(iString, "dd/MM/yyyy hh:mm:ss tt", CultureInfo.GetCultureInfo("ar-sa"))
Dim dtb As DateTime = DateTime.Parse(iString).ToString("dd-MM-yyyy HH:mm:ss tt")
Dim culture As CultureInfo = New CultureInfo("ar-sa")
Dim tempDate As DateTime = Convert.ToDateTime(iString, culture)

MsgBox(tempDate)
Jimi
  • 29,621
  • 8
  • 43
  • 61
fast2021
  • 115
  • 1
  • 9

2 Answers2

2

It looks to me like you need to convert the Arabic numerals to 0-9 to be able to parse that to a DateTime.

Then, when you have it as a DateTime, you can display it as a Hirji date by using the Hirji calendar:

Public Shared Function GetDateTimeFromArabicNumerals(s As String) As DateTime

    ' DateTime.Parse may not handle am/pm in Arabic, so check and make the adjustment later
    Dim pmOffset = If(s.IndexOf("م") >= 0, 12, 0)
    s = s.Replace("م", "").Replace("ص", "")

    Dim t = ""
    For Each c In s
        Dim a = AscW(c)
        If a >= 1632 AndAlso a <= 1641 Then
            t &= Char.GetNumericValue(c).ToString()
        Else
            t &= c
        End If
    Next

    Dim ci As CultureInfo = New CultureInfo("ar-SA")
    Dim hijri As Calendar = New HijriCalendar()
    ci.DateTimeFormat.Calendar = hijri

    Dim df = "yyyy/MM/dd h:mm"
    Dim dts = DateTimeStyles.AllowWhiteSpaces
    Dim dt = DateTime.ParseExact(t, df, ci, dts).AddHours(pmOffset)

    Return dt

End Function

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim s As String = "١٤٤٢/٠٨/٠٨ ٢:٣٨ ص"
    Dim dt = GetDateTimeFromArabicNumerals(s)

    Dim ci As CultureInfo = New CultureInfo("ar-SA")
    Dim hijri As Calendar = New HijriCalendar()
    ci.DateTimeFormat.Calendar = hijri

    MsgBox(dt.ToString(ci))

End Sub

Outputs:

Picture of date hopefully in Hirji format

You will need to check it as I have no knowledge of Arabic, so I might have used the wrong text for "p.m.", or indeed it could have given completely the wrong date.


Refs:

Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
2

Arabic numbers are not parsed correctly.
You can replace the numeric values with the other Arabic notation (1, 2, 3, ...) and also replace the ص/م designators, if any, with the AM/PM alternative form:

Dim nativeDate As String = "١٤٤٢/٠٨/٠٨ ٢:٣٨ ص"

Dim hijriDate = ParseHijriDate(nativeDate, False)
Dim gregorianDate = ParseHijriDate(nativeDate, True)

Which print, respectively:

8/8/1442 2:38:00 AM
3/21/2021 2:38:00 AM
Private Function ParseHijriDate(HijriDate As String, AsGregorianDate As Boolean) As Date
    Dim culture = CultureInfo.CreateSpecificCulture("ar-SA")
    Dim arSADigitsMap = GetCultureDigitsMap(culture)

    For Each map In arSADigitsMap
        HijriDate = HijriDate.Replace(map.Key, map.Value)
    Next

    If AsGregorianDate Then
        Return Date.Parse(HijriDate, culture)
    Else
        Return Date.Parse(HijriDate, CultureInfo.InvariantCulture)
    End If
End Function

Private Function GetCultureDigitsMap(culture As CultureInfo) As Dictionary(Of String, String)
    Dim digits = culture.NumberFormat.NativeDigits

    Dim digitsMap = New Dictionary(Of String, String)()
    For n As Integer = 0 To 9
        digitsMap.Add(digits(n), n.ToString())
    Next
    digitsMap.Add(culture.DateTimeFormat.AMDesignator, "AM")
    digitsMap.Add(culture.DateTimeFormat.PMDesignator, "PM")
    Return digitsMap
End Function

If you want to force that specific format (yyyy/MM/dd H:mm tt), add the Format to DateTime.ParseExact():

Return Date.ParseExact(HijriDate, "yyyy/MM/dd H:mm tt", CultureInfo.InvariantCulture)

Note:
In case the Dictionary used to map the digits fails to achieve the result, you can use a pre-built Dictionary that provides a static representation of the digits in the two forms:

Dim arSAEastWest = New Dictionary(Of String, String)() From {
    {"٠", "0"}, {"١", "1"}, {"٢", "2"}, {"٣", "3"}, {"٤", "4"},
    {"٥", "5"}, {"٦", "6"}, {"٧", "7"}, {"٨", "8"}, {"٩", "9"},
    {"ص", "AM"}, {"م", "PM"}
}
Jimi
  • 29,621
  • 8
  • 43
  • 61
  • ٤٤٢ <- Indians - Arabic -> 123 :) – dr.null Mar 27 '21 at 20:28
  • @dr.null *You can replace the numeric values with **the other** Arabic notation (1, 2, 3, ...)*. Unless you mean that in your System `("ar-SA").NumberFormat.NativeDigits` returns `[1, 2, 3, ...]`. – Jimi Mar 27 '21 at 20:39
  • That what the Math 101 books say. What the native digits property returns is a Windows setting. Yes you could do that. The defaults not always accurate. Especially when it comes from Microsoft. :) Good day smart one. – dr.null Mar 27 '21 at 20:56
  • 1
    @dr.null These numeric representations are defined in the [Unicode Common Locale Data Repository](http://cldr.unicode.org/). See the *sponsors* that rely on this code-base (not just MS). But, yes, these values can change, see the notes here: [Why might my local machine be incorrectly formatting international dates?](https://stackoverflow.com/a/53138834/7444103). If you take a look at the [Revision history](https://stackoverflow.com/posts/66834009/revisions), you'll see that, initially, I hard-coded the digits *conversion* in a static Dictionary. Maybe I'll add it back as a fall-back option. – Jimi Mar 27 '21 at 21:14