4

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

例如,根据我们是否希望应用程序以dd/MM/yyMM/dd/yy通话,我们必须更改 COM 应用程序的身份用户的区域设置。(现在我们唯一的选择是讨厌的黑客攻击。)

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

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

4

8 回答 8

3

Look, there's no easy way to say this - you're screwed. If you accept freeform input from the web, you have to live with the reality that people around the world format dates differently. That's why so many websites use popup calendars, and such, to get user input. No ambiguity there. No matter what you think, .NET's library routines can't fathom your user's intentions any better than any other library.

Fwiw, the code Mike posted is absolutely VB6. I'm not sure what about it looks like VB.NET? Once you get a date/time into a Date variable, you can display it however you want with Format(). That's the easy part.

I'd strongly suggest you either A) find a way to gather your inputs unambiguously, or B) tell your users what format you expect and live with what they input. All that said, is it possible I misunderstood the question, and you really do know what format the user is providing the data in? (Because if so, I really am having trouble understanding what's the problem interpreting it in ClassicVB - sorry.)

于 2009-06-30T01:42:22.813 回答
3

这应该很接近,尽管它将分隔符硬编码为“/”并且 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)”。

于 2009-06-30T02:59:34.267 回答
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)
于 2012-09-28T15:02:07.613 回答
1

You mention in the comments to one of the other answers that you are taking input from the web.

In that case you can control the date format that is being submitted by restricting user input to <select> drop lists. Make the month box list the short or long month names Jan/January Feb/February etc and then construct a date string in the format "1 Jan 2009"

Then it doesn't matter what your locale settings are, you'll get the date the user intended.

于 2009-06-30T01:53:04.243 回答
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
于 2009-06-30T13:03:20.090 回答
1

我不知道一个简单的解决方案。您可以通过分隔符将输入字符串拆分为子字符串,然后使用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'
于 2009-06-29T20:14:22.993 回答
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"

问题是您必须提前知道用户发送日期的格式。他们不能开始混合和匹配日期格式(无论如何也不应该如此)。


编辑(由 MarkJ 编写)——只是为了证明 Mike 的代码可以将字符串转换为日期。迈克,如果您愿意,请回滚或更改此编辑。

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
于 2009-06-29T20:47:24.110 回答
0

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

于 2009-06-29T19:17:09.287 回答