none
Is there a faster way to parse a date string using Regex RRS feed

  • Question

  • Currently I have a routine that converts a date string with the format of yyyMMdd to mm/dd/yy.   The current function works just fine, but when I ran an analyzer it pointed to the "DateTime.ParseExact" as the highest cpu usage statement.   This doesn't cause me too many issues except when I run a batch process that calls this function tens of thousands times.  So, I thought I would try and find a faster way.  I tried using Regex, but that is even a bit slower.

    So I have two questions...

    1. Is there a faster way to convert a date string from one format to another?

    2. Is there a faster way to use Regex to accomplish this?

    Current function.

    Public Function StringToShortDate(ByVal input As String) As String
            Dim culture As CultureInfo = New CultureInfo("en-us", True)
            Dim outDate As Date
            outDate = DateTime.ParseExact(input, "yyyyMMdd", culture)
            Return String.Format("{0}/{1}/{2}", outDate.Month, outDate.Day, outDate.Year)
    End Function

    Function using Regex

    Public Function StringToShortDate3(ByVal input As String) As String
        Dim pattern As String = "\d+"
        Dim rgx As New Regex(pattern)
        Return String.Format("{0}/{1}/{2}", rgx.Match(input, 4, 2), rgx.Match(input, 6, 2), rgx.Match(input, 0, 4))
    End Function


    • Edited by RNes Thursday, December 3, 2015 4:31 PM
    Thursday, December 3, 2015 4:30 PM

Answers

  • Thank you Viorel.

    I thought I would share my results.  Below you will see the results for 6 different functions in milliseconds to execute it 10000 times with a date of '20151202' 

    Then below that the code.  As you can see the worst by far is the "DateTime.ParseExact" function.  I am a little surprised that a simple substring and "string.concat" are much better.

    ParseExact method: 7673 
    Substring method: 2
    Regex.match method: 35
    Math method: 7
    Regex.Replace method: 13
    string.Concat method: 3

        Public Function StringToShortDate(ByVal input As String) As String
            If IsDateEmpty(input) Then
                Return Nothing
            Else
                Dim culture As CultureInfo = New CultureInfo("en-us", True)
                Dim outDate As Date
                outDate = DateTime.ParseExact(input, "yyyyMMdd", culture)
                Return String.Format("{0}/{1}/{2}", outDate.Month, outDate.Day, outDate.Year)
            End If
        End Function
        Public Function StringToShortDate2(ByVal input As String) As String
            If IsDateEmpty(input) Then
                Return Nothing
            Else
                Return String.Format("{0}/{1}/{2}", input.Substring(0, 4), input.Substring(4, 2), input.Substring(6, 2))
            End If
        End Function
    
        Public Function StringToShortDate3(ByVal input As String) As String
            If IsDateEmpty(input) Then
                Return Nothing
            Else
                Dim pattern As String = "\d+"
                Dim rgx As New Regex(pattern)
                Return String.Format("{0}/{1}/{2}", rgx.Match(input, 4, 2), rgx.Match(input, 6, 2), rgx.Match(input, 0, 4))
            End If
    
        End Function
    
        Public Function StringToShortDate4(ByVal input As String) As String
            If IsDateEmpty(input) Then
                Return Nothing
            Else
                Dim remainder As Int32
                Dim numInput As Int32 = CInt(input)
                Dim yy As Int32 = numInput / 10000
                Dim mm As Int32
                Math.DivRem(numInput, 10000, remainder)
                mm = remainder / 100
    
                Math.DivRem(numInput, 100, remainder)
                Dim dd As Int32 = remainder
                Return String.Format("{0}/{1}/{2}", mm, dd, yy)
            End If
    
        End Function
        Public Function StringToShortDate5(ByVal input As String) As String
            If IsDateEmpty(input) Then
                Return Nothing
            Else
                Return Regex.Replace(input, "(\d{4})(\d{2})(\d{2})", "$2/$3/$1")
            End If
        End Function
        Public Function StringToShortDate6(ByVal input As String) As String
            If IsDateEmpty(input) Then
                Return Nothing
            Else
                Dim b = String.Concat(input(4), input(5), "/"c, input(6), input(7), "/"c, input(0), input(1), input(2), input(3))
            End If
        End Function



    Friday, December 4, 2015 12:18 AM

All replies

  • If you cannot avoid such conversions, then consider this approach too:

        Dim a = "20151203"

        Dim b = String.Concat(a(4), a(5), "/"c, a(6), a(7), "/"c, a(0), a(1), a(2), a(3))

    or this alternative solution based on Regular Expressions:

        Dim a = "20151203"

        Dim b = Regex.Replace(a, "(\d{4})(\d{2})(\d{2})", "$2/$3/$1")

    Seems similar to https://social.msdn.microsoft.com/Forums/vstudio/en-US/61c48431-e1ac-463e-9cf7-da1c96a594aa

    Thursday, December 3, 2015 8:17 PM
  • Thank you Viorel.

    I thought I would share my results.  Below you will see the results for 6 different functions in milliseconds to execute it 10000 times with a date of '20151202' 

    Then below that the code.  As you can see the worst by far is the "DateTime.ParseExact" function.  I am a little surprised that a simple substring and "string.concat" are much better.

    ParseExact method: 7673 
    Substring method: 2
    Regex.match method: 35
    Math method: 7
    Regex.Replace method: 13
    string.Concat method: 3

        Public Function StringToShortDate(ByVal input As String) As String
            If IsDateEmpty(input) Then
                Return Nothing
            Else
                Dim culture As CultureInfo = New CultureInfo("en-us", True)
                Dim outDate As Date
                outDate = DateTime.ParseExact(input, "yyyyMMdd", culture)
                Return String.Format("{0}/{1}/{2}", outDate.Month, outDate.Day, outDate.Year)
            End If
        End Function
        Public Function StringToShortDate2(ByVal input As String) As String
            If IsDateEmpty(input) Then
                Return Nothing
            Else
                Return String.Format("{0}/{1}/{2}", input.Substring(0, 4), input.Substring(4, 2), input.Substring(6, 2))
            End If
        End Function
    
        Public Function StringToShortDate3(ByVal input As String) As String
            If IsDateEmpty(input) Then
                Return Nothing
            Else
                Dim pattern As String = "\d+"
                Dim rgx As New Regex(pattern)
                Return String.Format("{0}/{1}/{2}", rgx.Match(input, 4, 2), rgx.Match(input, 6, 2), rgx.Match(input, 0, 4))
            End If
    
        End Function
    
        Public Function StringToShortDate4(ByVal input As String) As String
            If IsDateEmpty(input) Then
                Return Nothing
            Else
                Dim remainder As Int32
                Dim numInput As Int32 = CInt(input)
                Dim yy As Int32 = numInput / 10000
                Dim mm As Int32
                Math.DivRem(numInput, 10000, remainder)
                mm = remainder / 100
    
                Math.DivRem(numInput, 100, remainder)
                Dim dd As Int32 = remainder
                Return String.Format("{0}/{1}/{2}", mm, dd, yy)
            End If
    
        End Function
        Public Function StringToShortDate5(ByVal input As String) As String
            If IsDateEmpty(input) Then
                Return Nothing
            Else
                Return Regex.Replace(input, "(\d{4})(\d{2})(\d{2})", "$2/$3/$1")
            End If
        End Function
        Public Function StringToShortDate6(ByVal input As String) As String
            If IsDateEmpty(input) Then
                Return Nothing
            Else
                Dim b = String.Concat(input(4), input(5), "/"c, input(6), input(7), "/"c, input(0), input(1), input(2), input(3))
            End If
        End Function



    Friday, December 4, 2015 12:18 AM
  • If you are interested in more variants, try these ones:

    Public Function StringToShortDate2a(ByVal input As String) As String
        If IsDateEmpty(input) Then
            Return Nothing
        Else
            Return input.Substring(0, 4) & "/" & input.Substring(4, 2) & "/" & input.Substring(6, 2)
        End If
    End Function
    
    Public Function StringToShortDate6a(ByVal  input As String) As String
        If IsDateEmpty(input) Then
            Return Nothing
        Else
            Return New String({input(4), input(5), "/"c, input(6), input(7), "/"c, input(0), input(1), input(2), input(3)})
        End If
    End Function
    
    Public Function StringToShortDate7(ByVal input As String) As String
        If IsDateEmpty(input) Then
            Return Nothing
        Else
            Return New StringBuilder(input, 0, 4, 10).Append("/").Append(input, 4, 2).Append("/").Append(input, 6, 2).ToString()
        End If
    End Function
    
    

    • Edited by Viorel_MVP Friday, December 4, 2015 6:56 AM
    Friday, December 4, 2015 6:52 AM
  • If you are using a non-culture-dependent format (as you return it from your function), why are you using ParseExact?

    Use Parse instead and the DateTimeObject.ToString("YourFromatString").

    The Exact method runs slow, cause it needs to enforce Curlture-Dependent formats, and check the string respectivly. You don't want it to check for specific Culture formats, you want to enforce your own format, so i suggest: use a compiled regex to check the format, parse with parse (not exact) and use ToString for your format.

    The different methods you created are not the same as the one using exact, as they do not check if the string is actually in the culture format that you explicitly give in the exact function.
    • Edited by MDeero Friday, December 4, 2015 7:47 AM
    Friday, December 4, 2015 7:39 AM