2018年11月7日水曜日

VisualBasic6(VB6)Format, IsDateの新元号対応

業務システムでは今でもVB6使っているのが残っています。きっとMSさんが対応してくれると思ってはいますが、心配なのでオーバーライド関数を作ってみました。
レジストリHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras
を反映するように作成してあります。

modFormatOverride.bas
Attribute VB_Name = "modFormatOverride"
Option Explicit

Private Const HKEY_LOCAL_MACHINE = &H80000002
Private varEnumEras As Variant

' 新元号対応IsDate関数
Public Function IsDate(expression As Variant) As Boolean

    If vba.IsDate(expression) Then
        IsDate = True
        Exit Function
    End If
    IsDate = vba.IsDate(ConvertAD(expression))

End Function

' 新元号対応Format関数
Public Function Format(expression As Variant, Optional fmtstr As Variant = "", Optional firstdayofweek As Variant = vbSunday, Optional firstweekofyear As Variant = vbUseSystem) As String

    Dim i As Integer, intYear As Integer
    Dim varDef As Variant, varExp As Variant, varTmpfmt As Variant
    
    If Not IsDate(expression) Then
        Format = vba.Format(expression, fmtstr, firstdayofweek, firstweekofyear)
        Exit Function
    End If

    varExp = ConvertAD(expression)

    varDef = Array("General Date", "Long Date", "Medium Date", "Short Date", "Long Time", "Medium Time", "Short Time")
    
    For i = 0 To UBound(varDef)
        If LCase(fmtstr) = LCase(varDef(i)) Then
            Format = vba.Format(varExp, fmtstr, firstdayofweek, firstweekofyear)
            Exit Function
        End If
    Next
    
    If InStr(LCase(fmtstr), "g") = 0 And InStr(LCase(fmtstr), "e") = 0 Then
        Format = vba.Format(varExp, fmtstr, firstdayofweek, firstweekofyear)
        Exit Function
    End If

    For i = 0 To UBound(varEnumEras)
        If CDate(varExp) < varEnumEras(i)(0) Then
            Exit For
        End If
    Next
    i = i - 1

    If i > 3 Then
        varTmpfmt = Replace(Replace(fmtstr, "g", "z"), "G", "z")
        varTmpfmt = Replace(Replace(varTmpfmt, "e", "x"), "E", "x")
        varTmpfmt = Replace(varTmpfmt, ".", "v")
        varTmpfmt = vba.Format(varExp, varTmpfmt, firstdayofweek, firstweekofyear)
        varTmpfmt = Replace(varTmpfmt, "v", ".")
        varTmpfmt = Replace(varTmpfmt, "zzz", varEnumEras(i)(1)(0))
        varTmpfmt = Replace(varTmpfmt, "zz", varEnumEras(i)(1)(1))
        varTmpfmt = Replace(varTmpfmt, "z", varEnumEras(i)(1)(3))
        intYear = Year(varExp) - Year(varEnumEras(i)(0)) + 1
        varTmpfmt = Replace(varTmpfmt, "xx", Right("0" & intYear, 2))
        Format = Replace(varTmpfmt, "x", intYear)
    Else
        Format = vba.Format(varExp, fmtstr, firstdayofweek, firstweekofyear)
    End If

End Function

' 新元号文字列を西暦文字列に変換
Private Function ConvertAD(expression As Variant) As Variant

    Dim i As Integer, j As Integer, k As Integer
    Dim objRegistry As Object
    Dim strKeyPath As String, strChar As String
    Dim varEras As Variant, varValue As Variant, varNum As Variant

    ConvertAD = expression
    
    If IsEmpty(varEnumEras) Then
        Set objRegistry = GetObject("winmgmts:\root\default:StdRegProv")
        strKeyPath = "SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras"
        objRegistry.EnumValues HKEY_LOCAL_MACHINE, strKeyPath, varEras
        ReDim varValue(UBound(varEras))
        ReDim varEnumEras(UBound(varEras))
        For i = 0 To UBound(varEras)
            objRegistry.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath, varEras(i), varValue(i)
            varEras(i) = CDate(Replace(varEras(i), " ", "/"))
            varValue(i) = Split(varValue(i), "_")
            varValue(i)(2) = LCase(varValue(i)(3))
            varValue(i)(3) = UCase(varValue(i)(3))
            varEnumEras(i) = Array(varEras(i), varValue(i))
        Next
        Set objRegistry = Nothing
    End If
    
    If Not vba.IsDate(expression) Then
        For i = 4 To UBound(varEnumEras)
            For j = 0 To UBound(varEnumEras(i)(1))
                If InStr(Trim(expression), varEnumEras(i)(1)(j)) = 1 Then
                    For k = InStr(expression, varEnumEras(i)(1)(j)) + Len(varEnumEras(i)(1)(j)) To Len(expression)
                        strChar = Mid(expression, k, 1)
                        If InStr("年/,-", strChar) > 0 Then
                            Exit For
                        Else
                            varNum = varNum & strChar
                        End If
                    Next
                    If IsNumeric(varNum) Then
                        ConvertAD = Replace(expression, varEnumEras(i)(1)(j) & varNum, Year(varEnumEras(i)(0)) + varNum - 1)
                        Exit Function
                    End If
                End If
            Next
        Next
    End If

End Function
まあ、CDate("新元号1年5月1日")みたいにCDateに直接新元号を入れられるとだめですけどね...

0 件のコメント:

コメントを投稿

postfix main.cf smtpd_sender_restrictions

最近、メールサーバでキューを確認すると、やたらと???@0000.comへのバウンスメールが溜まっている。 中身を確認すると、PICほにゃららというファイル名で難読化したJavaScriptが添付されているメールです。 何が目的なのか分かりませんが、ごみメール送ってきてバウン...