Converting Strings or Numbers to Real Dates

The world of data isn’t perfect, that’s for sure, and data can come to your application in many formats. Dates are particularly troublesome because there are so many ways to display and format them. If you routinely need to gather information from outside sources, you’ll appreciate the two functions in this section. The first, dhCNumDate (Listing 2.18), attempts to convert dates stored in numeric values into true Date format. The second function, dhCStrDate (Listing 2.19), performs the same sort of task, but with formatted strings as input.

Some computer systems, for example, store dates as integers such as 19971231 (representing #12/31/1997#) or 52259 (representing #5/22/1959#). The code in dhCNumDate can convert those values into real VBA date/time format, as long as you tell it the layout of the number coming in. For example, to perform the first conversion, you might use

dtmBirthday = dhCNumDate(19971231, "YYYYMMDD")

The function, knowing how the date number was laid out, could pull out the various pieces.

The dhCStrDate function does similar work, but with string values as its input. For example, if all the dates coming in from your mainframe computer were in the format “MMDDYYYY”, you could use

' strOldDate contains "05221959"
dtmNewDate = dhCStrDate(strOldDate, "MMDDYYYY")

to convert the string into a real date.

Listing 2.18: Convert Formatted Numbers to Real Dates

Function dhCNumdate(ByVal lngdate As Long, _
 ByVal strFormat As String) As Variant
    ' Convert numbers to dates, depending on the specified format
    ' and the incoming number. In this case, the number and the
    ' format must match, or the output will be useless.
    Dim intYear As Integer
    Dim intMonth As Integer
    Dim intDay As Integer
    Dim fOK As Boolean
    fOK = True
    Select Case strFormat
        Case "MMDDYY"
            intYear = lngdate Mod 100
            intMonth = lngdate \ 10000
            intDay = (lngdate \ 100) Mod 100
        Case "MMDDYYYY"
            intYear = lngdate Mod 10000
            intMonth = lngdate \ 1000000
            intDay = (lngdate \ 10000) Mod 100
        Case "DDMMYY"
            intYear = lngdate Mod 100
            intMonth = (lngdate \ 100) Mod 100
            intDay = lngdate \ 10000
        Case "DDMMYYYY"
            intYear = lngdate Mod 10000
            intMonth = (lngdate \ 10000) Mod 100
            intDay = lngdate \ 1000000
        Case "YYMMDD", "YYYYMMDD"
            intYear = lngdate \ 10000
            intMonth = (lngdate \ 100) Mod 100
            intDay = lngdate Mod 100
        Case Else
            fOK = False
    End Select
    If fOK Then
        dhCNumdate = DateSerial(intYear, intMonth, intDay)
    Else
        dhCNumdate = Null
    End If
End Function

You’ll find an interesting code technique in dhCNumDate. Given a number like 220459 (#4/22/59# in date format), retrieving the month portion requires some effort. The code accomplishes this by first using integer division (the \ operator), resulting in 2204. Then, to retrieve just the month portion, the code uses the Mod operator to find the remainder you get when you divide 2204 by 100. You’ll find the integer division and the Mod operator useful if you want to retrieve specific digits from a number, as we did in dhCNumDate.

Listing 2.19: Convert Formatted Strings to Real Dates

Function dhCStrdate(strDate As String, Optional _
 strFormat As String = "") As Date
    ' Given a string containing a date value, and a format
    ' string describing the information in the date string,
    ' convert the string into a real date value.
    Dim strYear As String
    Dim strMonth As String
    Dim strDay As String
    Dim fDone As Boolean

    Select Case strFormat
        Case "MMDDYY", "MMDDYYYY"
            strYear = Mid(strDate, 5)
            strMonth = Left(strDate, 2)
            strDay = Mid(strDate, 3, 2)
        Case "DDMMYY", "DDMMYYYY"
            strYear = Mid(strDate, 5)
            strMonth = Mid(strDate, 3, 2)
            strDay = Left(strDate, 2)
        Case "YYMMDD"
            strYear = Left(strDate, 2)
            strMonth = Mid(strDate, 3, 2)
            strDay = Right(strDate, 2)
        Case "YYYYMMDD"
            strYear = Left(strDate, 4)
            strMonth = Mid(strDate, 5, 2)
            strDay = Right(strDate, 2)
        Case "DD/MM/YY", "DD/MM/YYYY"
            strYear = Mid(strDate, 7)
            strMonth = Mid(strDate, 4, 2)
            strDay = Left(strDate, 2)
        Case "YY/MM/DD"
            strYear = Left(strDate, 2)
            strMonth = Mid(strDate, 4, 2)
            strDay = Right(strDate, 2)
        Case "YYYY/MM/DD"
            strYear = Left(strDate, 4)
            strMonth = Mid(strDate, 6, 2)
            strDay = Right(strDate, 2)
        Case Else
            ' If none of the other formats were matched,
            ' just count on Cdate to do the conversion. It may fail,
            ' but we can't help out here.
            dhCStrdate = CDate(strDate)
            fDone = True
    End Select
    If Not fDone Then
        dhCStrdate = DateSerial(Val(strYear), Val(strMonth), _
         Val(strDay))
    End If
End Function

There’s no doubt about it—the code in both these functions relies on brute force. Given the examples already in the functions, you should find it to easy add your own new formats, should the need arise. In each case, it’s just a matter of using the correct mathematical or string functions to perform the necessary conversions.

© 1997 by SYBEX Inc. All rights reserved.