对于VB6更好CDATE(A better CDate for VB6)

2019-06-24 11:23发布

我们有AA VB6应用程序(在COM组件),使用CDATE()取一个字符串,并将其转换为一个日期,用于存储在数据库中。

根据如果我们希望应用程序在DD / MM / YYMM / DD / YY例如说话,我们必须改变身份用户的区域设置为COM应用程序。 (现在,我们唯一的选择是一个肮脏的黑客 。)

我们有用于格式化所有输出日期的日期格式字符串,并且假定日期

如果这是.NET我们将使用DateTime.ParseExact和客场笑。 呼唤.NET编写这个唯一目的COM对象是一个选项。 是否有不同的或更好的选择,包括周围的Format命令一些黑魔法,或者根据标记化的格式字符串,等等日期长可重复使用的功能?

Answer 1:

这应该是接近,但它的硬编码作为分隔符“/”和Windows 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)”。



Answer 2:

你看,有没有简单的方法来这样说 - 你就完蛋了。 如果您通过网络接受自由输入,你不得不接受的现实,世界各地的人们格式不同的日期。 这就是为什么这么多的网站使用弹出日历,而这样,才能获得用户的输入。 没有歧义存在。 不管你怎么想,.NET的库程序无法捉摸你的用户的意图比任何其他库任何好转。

FWIW,麦克发布的代码是绝对VB6。 我不知道它什么样子VB.NET? 一旦你得到一个日期/时间到一个日期变量,可以显示你想要的东西与格式()。 这是比较容易的部分。

我强烈建议你要么A)找到一个方法来明确收集您的输入,或B)告知用户所期望的格式,并住在一起,他们输入了什么。 说了这么多,有没有可能我误解了这个问题,你真的不知道是什么格式的用户在提供数据? (因为如果是这样,我真的无法理解什么是在ClassicVB解释它的问题 - 抱歉)



Answer 3:

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)


Answer 4:

你提到的意见,你是从网上取输入其他的答案之一。

在这种情况下可以控制正被提交通过限制用户输入到<SELECT>下拉列表中的日期格式。 使本月框列表短期或长期的月份名称一月/二月一月/二月等等,然后构建一个日期字符串格式为“2009年1月1日”

然后,它不要紧,你的区域设置是什么,你会得到的日期预定用户。



Answer 5:

You can use the built-in Format function to do this for you.

Here is a simple test to confirm this:

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

It might seem like magic, but it isn't. It takes advantage of how the Format function works in conjunction with the current regional settings.

For example, suppose your Regional Settings are configured to use the "mm/dd/yyyy" format for dates.

Now, you get a date string from a user in "dd/mm/yyyy" format. If you Format this date string and tell Format to also use "dd/mm/yyy", it will swap the month and day parts of the date because your settings say dates are in "mm/dd/yyyy" format.

In other words, Format always assumes the date string from the user is formatted according to your current Regional Settings (in this case, "mm/dd/yyyy"), so when you tell it to format the date using "dd/mm/yyyy", it will force it to swap the month and day parts. If your Regional Settings use the same format as the user-provided date, this code will still work: Format will simply return the user date unchanged. Confused yet? ;)

The same thing will happen if your Regional Settings are set for "dd/mm/yyyy" and the user sends a date in "mm/dd/yyyy" format.

The catch is that you have to know ahead of time which format the user is sending dates in. They can't start mixing and matching date formats (and they shouldn't be anyway).


EDIT (by MarkJ) - just to prove that Mike's code can convert a string to Date. Mike, please roll back or change this edit if you want.

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


Answer 6:

我不知道一个简单的解决方案。 你可以拆分通过分隔符输入字符串转换成子串,然后用DateSerial到年,月,小时数字重新组合成一个本地VB6 日期变量。 事情是这样的下面。 如果你需要支持很多的语言环境,这有可能会复杂(参见Bob的答案 )。 你要知道,这样会使用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'


Answer 7:

去另一种方式:

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


Answer 8:

你应该有一个日期变量(不是格式化字符串)交谈,然后使用用户区域设置的格式显示格式化值或采取从用户输入的日期变量。



文章来源: A better CDate for VB6