一个更好的CD6 for VB6

时间:2009-06-29 19:07:29

标签: datetime vb6 casting regional

我们有一个VB6应用程序(在COM组件中),它使用CDate()获取字符串并将其强制转换为Date,以存储在数据库中。

例如,根据我们是否希望应用程序在 dd / MM / yy MM / dd / yy 中进行通话,我们必须更改区域设置COM应用程序的标识用户。 (现在我们唯一的选择是a nasty hack。)

我们有一个日期格式字符串,用于格式化所有输出日期,并假设日期

如果这是.NET,我们会使用DateTime.ParseExact并且不要笑。出于此唯一目的,调用以.NET编写的COM对象是一种选择。是否有一个不同的或更好的选项,包括Format命令周围的一些黑魔法,或一个长的可重用函数,根据格式字符串等标记日期?

8 个答案:

答案 0 :(得分:3)

看,没有简单的方法可以这么说 - 你被搞砸了。如果您接受来自网络的自由形式输入,您必须忍受世界各地的人格式不同的现实。这就是这么多网站使用弹出日历等原因来获取用户输入的原因。那里没有歧义。无论你怎么想,.NET的库例程都无法比任何其他库更好地理解用户的意图。

Fwiw,Mike发布的代码绝对是VB6。我不确定它看起来像VB.NET?获得Date变量的日期/时间后,您可以使用Format()显示它。这很容易。

我强烈建议你A)找到一种明确收集输入的方法,或者B)告诉用户你期望的格式和他们输入的内容。所有这一切,我是否有可能误解了这个问题,你真的知道用户提供数据的格式是什么? (因为如果是这样,我真的很难理解在ClassicVB中解释它的问题 - 对不起。)

答案 1 :(得分:3)

这应该很接近,虽然它将分隔符硬编码为“/”,窗口YY年份为50:

Private Function ParseDate(ByVal DateString As String, _
                           ByVal DatePattern As String) As Date
    'DateString:  i/j/k formatting.
    'DatePattern: i/j/k formatting, each to be:
    '               M or MM for month position.
    '               D or DD for day position.
    '               YY or YYYY for year position, if YY
    '                 then century windowed at 50.
    Dim strStringParts() As String
    Dim strPatternParts() As String
    Dim intPart As Integer, intScore As Integer
    Dim intMonth As Integer, intDay As Integer, intYear As Integer
    Const DELIM As String = "/"
    Const YYWINDOW As Integer = 50

    strStringParts = Split(DateString, DELIM)
    strPatternParts = Split(UCase$(DatePattern), DELIM)
    For intPart = 0 To UBound(strStringParts)
        If intPart > UBound(strPatternParts) Then
            Err.Raise 5, "ParseDate"
        End If
        Select Case strPatternParts(intPart)
            Case "M", "MM"
                intMonth = CInt(strStringParts(intPart))
                intScore = intScore Or &H1
            Case "D", "DD"
                intDay = CInt(strStringParts(intPart))
                intScore = intScore Or &H2
            Case "YY"
                intYear = CInt(strStringParts(intPart))
                If 0 > intYear Or intYear > 99 Then
                    Err.Raise 5, "ParseDate"
                End If
                intYear = intYear + IIf(intYear < YYWINDOW, 2000, 1900)
                intScore = intScore Or &H4
            Case "YYYY"
                intYear = CInt(strStringParts(intPart))
                If 100 > intYear Or intYear > 9999 Then
                    Err.Raise 5, "ParseDate"
                End If
                intScore = intScore Or &H4
            Case Else
                Err.Raise 5, "ParseDate"
        End Select
    Next
    If intScore = &H7 Then
        ParseDate = DateSerial(intYear, intMonth, intDay)
    Else
        Err.Raise 5, "ParseDate"
    End If
End Function

验证可能不完美,但它应该是接近的。它会在错误的输入上抛出“无效的过程调用或参数(错误5)”。

答案 2 :(得分:2)

DateAdd以正确的格式接受各种输入和输出。

ThisLine =  "Tuesday, September 04, 2012 2:02 PM"

i = InStr(ThisLine, ",")  ' get rid of the leading day

If i > 0 Then
     TempResult = Trim(Right$(ThisLine, Len(ThisLine) - i))
end if

TempResult = DateAdd("s", 0, TempResult)

答案 3 :(得分:1)

我不知道一个简单的解决方案。您可以通过分隔符将输入字符串Split转换为子字符串,然后使用DateSerial将年,月和小时数重新组合为本机VB6 Date变量。这样的事情如下。如果您需要支持很多语言环境,这可能会变得复杂(请参阅Bob's answer)。请注意,使用DateTime.ParseExact。

sInput = "1/3/71"
Dim splt() As String
splt = Split(sInput, "/")
dte = DateSerial(splt(2) + 1900, splt(1), splt(0))  ' dd/mm/yy'

答案 4 :(得分:1)

您可以使用内置的Format功能为您执行此操作。

这是一个简单的测试来证实这一点:

Public Sub TestDateParsing()

   'On my computer, the date format is U.S. (mm/dd/yyyy)'
   'This test creates a date string in dd/mm/yyyy format to'
   'simulate user input in a different format'

    Const TEST_DATE As Date = #6/1/2009#

    Dim inputDate As String
    inputDate = Format(TEST_DATE, "dd/mm/yyyy")
    'inputDate is "1/6/2009" (June 1 in dd/mm/yyyy format)'

    Debug.Print Format(inputDate, "dd/mm/yyyy")
    'It`s magic! The above line will print 6/1/2009'
    'which is the correct format for my Regional Settings'

End Sub

看起来似乎很神奇,但事实并非如此。它利用了Format函数与当前区域设置一起工作的方式。

例如,假设您的区域设置配置为使用"mm/dd/yyyy"格式作为日期。

现在,您以"dd/mm/yyyy"格式从用户处获取日期字符串。如果您Format这个日期字符串并告诉Format也使用"dd/mm/yyy",它会交换日期的月份和日期部分,因为您的设置说明日期为"mm/dd/yyyy"格式。

换句话说,Format始终假定用户的日期字符串是根据您当前的区域设置(在本例中为"mm/dd/yyyy")格式化的,因此当您告诉它使用日期格式化日期时"dd/mm/yyyy",它会强制它交换月份和日期部分。如果您的区域设置使用与用户提供的日期相同的格式,则此代码仍然有效:Format将仅返回用户日期不变。困惑了吗? ;)

如果您的区域设置设置为"dd/mm/yyyy"并且用户以"mm/dd/yyyy"格式发送日期,则会发生同样的事情。

问题在于你必须提前知道用户发送日期的格式。他们无法开始混合和匹配日期格式(并且它们不应该是。)


编辑( by MarkJ ) - 只是为了证明Mike的代码可以将字符串转换为Date。迈克,如果你愿意,请回滚或更改此编辑。

Public Sub Test()
  Dim dte As Date
  For dte = #1/1/2009# To #12/31/2009#
    Call TestDateParsing(dte)
  Next dte
End Sub

Public Sub TestDateParsing(ByVal dteIn As Date)

  'On my computer, the date format is U.S. (mm/dd/yyyy)'
  'This test creates a date string in dd/mm/yyyy format to'
  'simulate user input in a different format'

  Dim sExpected As String
  sExpected = Day(dteIn) & " / " & Month(dteIn) & " / " & Year(dteIn)
  Dim inputDate As String
  Dim dte As Date
  inputDate = Format(dteIn, "dd/mm/yyyy")
  dte = Format(inputDate, "dd/mm/yyyy")

  Debug.Assert sExpected = Day(dte) & " / " & Month(dte) & " / " & Year(dte)
  Debug.Print sExpected

End Sub

答案 5 :(得分:1)

您在评论中提到了您从网络上获取的其他答案之一。

在这种情况下,您可以通过将用户输入限制为&lt; select&gt;来控制正在提交的日期格式删除列表。使月份框列出短月或长月名称Jan / January Feb / February等,然后以“2009年1月1日”格式构建日期字符串

然后,您的区域设置无关紧要,您将获得用户想要的日期。

答案 6 :(得分:1)

另一种方法:

Public Enum abDateType
    abMDY
    abDMY
End Enum

Public Function MakeDate(ByVal dateString As String, ByVal dateType As abDateType, Optional delimiter As String = "/") As Date
    Dim strVals() As String
    Dim dtRtnVal As Date
    strVals = Split(dateString, delimiter)
    Select Case dateType
    Case abMDY
        dtRtnVal = DateSerial(strVals(2), strVals(0), strVals(1))
    Case abDMY
        dtRtnVal = DateSerial(strVals(2), strVals(1), strVals(0))
    Case Else
        Err.Raise vbObjectError, , "Unexpected date format."
    End Select
    MakeDate = dtRtnVal
End Function

答案 7 :(得分:0)

您应该使用日期变量(不是格式化的字符串),然后使用用户区域设置在表单中显示格式化的值,或者将用户的输入转换为日期变量。