vb.netdatetimetimedatetimeformatinfo

AM/PM designatior special case for noon and midnight


VB2012: I am reading data from a legacy system. One of the fields is a time and I am reading that into a DateTime variable. I use the "hhmmt" format to parse out the date with DateTime.ParseExact. The only issue I have is that the legacy system displays A for AM and P for PM with a special case for N for noon. Well .NET doesn't like the N designator so I detect it and change it to P. Works great.

003 0300 AAABBB  845A 1200N
005 1400 CCCDDD 1055A  240P
007 7000 EEEFFF  306P  531P

Now I do some processing and print out the data to a file. I want to print out the times in the format that they are printed in the legacy system. My first thought was to use a custom DateTimeFormatInfo

Dim info As New DateTimeFormatInfo
info.PMDesignator = "N"

and feed that to my string formatter as the IFormatProvider

trip.ArriveTime.ToString("hmmt", info)

But I realize that setting the DateTimeFormatInfo is static and will not be of any use when the time is 12:00P or noon. Is there any way to create a format that will account for this unique scenario and use the N suffix when it is noon but keep the standard A for AM and P for PM for other times?

Update with possible solution:

Imports System.Text.RegularExpressions
Imports System.Globalization

Module mdlExtensions
    Private rgxTimePeriod As New Regex("t+")
    <System.Runtime.CompilerServices.Extension()> _
    Public Function LegacyFormat(dt As DateTime, fmt As String, Optional provider As IFormatProvider = Nothing) As String
        Dim formatted As String
        If dt.TimeOfDay = New TimeSpan(12, 0, 0) Then
            fmt = rgxTimePeriod.Replace(fmt, "N")
        End If
        If provider Is Nothing Then
            formatted = dt.ToString(fmt)
        Else
            formatted = dt.ToString(fmt, provider)
        End If

        Return formatted
    End Function

    <System.Runtime.CompilerServices.Extension()> _
    Public Function ToLegacy(dt As DateTime, fmt As String, Optional provider As IFormatProvider = Nothing) As String
        'setup the master DateTimeFormatInfo
        Dim ci As CultureInfo = CType(provider, CultureInfo)
        Dim mstrDtfi As DateTimeFormatInfo
        If provider Is Nothing Then
            'designate a new DateTimeFormatInfo class if Nothing was passed in
            mstrDtfi = New DateTimeFormatInfo
        Else
            'get a reference to the DateTimeFormatInfo class of the FormatProvider that was passed in
            mstrDtfi = ci.DateTimeFormat
        End If

        'check to see if the time is noon and set a new PMDesignator if it is
        If dt.TimeOfDay = New TimeSpan(12, 0, 0) Then
            mstrDtfi.PMDesignator = "NN"
        End If

        'check to see if the time is midnight and set a new AMDesignator if it is
        If dt.TimeOfDay = New TimeSpan(0, 0, 0) Then
            mstrDtfi.AMDesignator = "MM"
        End If

        'now format the date string with the proper provider 
        Dim formattedDate As String
        If provider Is Nothing Then
            formattedDate = dt.ToString(fmt, mstrDtfi)
        Else
            formattedDate = dt.ToString(fmt, ci)
        End If

        Return formattedDate
    End Function

End Module

Solution

  • I was aiming for something of a generic solution where the format could change like ddmm hhmmt or hmtt and the overload would take care of the various formats except for the special case of the "t" specifier.

    A simple Function can still handle this. Here is an example as an extension method.

    Module Extensions
        Private rgxTimePeriod As New Regex("t+")
        <System.Runtime.CompilerServices.Extension()> _
        Public Function LegacyFmt(dt As DateTime, fmt As String, Optional provider As IFormatProvider = Nothing) As String
            Dim formatted As String
            If dt.TimeOfDay = New TimeSpan(12, 0, 0) Then
                fmt = rgxTimePeriod.Replace(fmt, "N")
            End If
            If provider Is Nothing Then
                formatted = dt.ToString(fmt)
            Else
                formatted = dt.ToString(fmt, provider)
            End If
            Return formatted
        End Function
    End Module
    
    ?#12:00#.LegacyFmt("hmmt", Globalization.CultureInfo.InvariantCulture)
    "1200N"
    ?now.LegacyFmt("ddmm")
    "2551"
    ?#2:01#.LegacyFmt("hmmt")
    ?#12:00#.LegacyFmt("hmtt")
    "120N"
    "201A"
    ?#2:01#.LegacyFmt("hmtt")
    "21AM"