【问题标题】:VBA Date Format For Variable变量的 VBA 日期格式
【发布时间】:2019-03-11 21:25:24
【问题描述】:

我需要将电子表格列中的内容从文本转换为日期。

单元格格式为文本,并指示输入者输入日期为“ddmmyyyy”。

发生了意外,我发现了一些无法解析为日期的内容,包括“未知”之类的条目。

所以我使用了一个声明为日期的变量,并编写了一个错误处理程序来处理无法解析的内容。

现在我无法锻炼。

如果日期是 2000 年 3 月 3 日,并且有人将其输入为“03332000”,则不会解析,因为“33”不能是一个月或一天;它被我想要的错误处理程序捕获。

但如果输入为“03132000”,我想不出办法阻止 VBA 将其转换为有效日期为“13/03/2000”。

声明日期变量的格式不会阻止 VBA 解析日期。

我可以编写一些东西来测试字符串的日期和月份部分的数字范围,但那是额外的代码行,我希望只通过错误处理程序来完成。

【问题讨论】:

  • 请展示您现有的代码 - 调整它比让我们尝试准确地猜测您做了什么要容易得多。您可以尝试使用 DateSerial() 并使用 Left()/Mid()/Right() 解析条目的特定部分
  • 蒂姆谢谢。我会稍微修改一下帖子。
  • 蒂姆,当我重写代码时(我现在在家)@Gary 的学生已经确认我必须测试日期的组件的有效性。
  • 我并不是建议您不需要测试有效性,只是您可以防止 Excel 在需要时交换日期和月份。

标签: excel vba date format


【解决方案1】:

我会采取一些不同的方法,让 Excel 来完成这项工作。

Public Function ValidateDate(ByVal strDate As String) As Boolean
    Dim intDay As Integer, intMonth As Integer, intYear As Integer, dtDate As Date

    ValidateDate = True

    On Error GoTo IsInValid

    If Len(strDate) <> 8 Then GoTo IsInValid
    If Not IsNumeric(strDate) Then GoTo IsInValid

    intDay = Left(strDate, 2)
    intMonth = Mid(strDate, 3, 2)
    intYear = Right(strDate, 4)

    dtDate = DateSerial(intYear, intMonth, intDay)

    If DatePart("d", dtDate) <> intDay Then GoTo IsInValid
    If DatePart("m", dtDate) <> intMonth Then GoTo IsInValid
    If DatePart("yyyy", dtDate) <> intYear Then GoTo IsInValid

    Exit Function

IsInValid:
    ValidateDate = False

End Function

...这将确保与闰年等相关的任何内容仍能正常工作,并将确保所有条目都得到正确验证。

【讨论】:

  • 呃-Goto。如果您首先设置 ValidateDate = False ,然后设置 ValidateDate = (DatePart(...) = intDay) And [...] ,则可以避免 Goto 。如果Len(...) = 8 And IsNumeric(...),您只能到达此行。总而言之,您可以将其减少到大约 6-8 行。
  • @AJD 也许我不想。这是非常故意的。如果想要确切地确定条目未通过测试的原因,则将其拆分成这样可以更好地进行调试。为了便于阅读,它还将其拆分。这并不总是与减少代码行数有关。
  • 我评论的要点是Goto 是代码臭的标志。通过重新考虑条件(特别是如果您以defaultOutcome =TRUEdefaultOutcome - FALSE 开头),您可以在不使用Goto 的情况下获得更好的结果。是的,您仍然可以将每个条件拆分为单独的行以进行调试(例如Test1 = Conditional : Test2 = Conditional2 [...] finalTest = Test1 And test2 And [... etc]`) 所以它并不总是关于保存行。
  • @AJD 这是你的意见。我可以看到我想要检查的确切条件,并且从逻辑的角度来看,它突出了我想要跳出的点。感谢您的建议,但我非常感谢。
  • 不是意见 - 良好的编码习惯。不过,如果你不想接受这个建议,那我也很好,谢谢。
【解决方案2】:

如果你放置:

03332000

在单元格 A1 中并运行:

Sub CheckDate()
    Dim s As String, d As Date
    s = Range("A1").Text
    d = DateSerial(CInt(Right(s, 4)), CInt(Mid(s, 3, 2)), CInt(Left(s, 2)))
    MsgBox s & vbCrLf & d
End Sub

你会得到:

因此,即使有效月份只能在 [1-12] 范围内,Excel 仍试图通过将 33 解释为未来日期的预测来“帮助”您。例如,如果月份输入为 13,Excel 会将其视为下一年的12 月

您不能为此依赖错误处理。您需要以下检查:

Sub CheckDate2()
    Dim s As String, d As Date
    Dim dd As Integer, mm As Integer, yr As Integer

    s = Range("A1").Text

    yr = CInt(Right(s, 4))
    mm = CInt(Mid(s, 3, 2))
    dd = CInt(Left(s, 2))

    If yr = 0 Or yr < 1900 Then
        MsgBox "year is bad"
        Exit Sub
    End If

    If dd = o Or dd > 31 Then
        MsgBox "day is bad"
        Exit Sub
    End If

    If mm = 0 Or mm > 12 Then
        MsgBox "month is bad"
        Exit Sub
    End If

    d = DateSerial(yr, mm, dd)
    MsgBox s & vbCrLf & d
End Sub

您还可以进行其他检查,例如查看字段的长度等。

【讨论】:

  • 加里的学生 谢谢,我只需要检查各个部分。谢谢大家看这个。
  • @River42 每当您允许人类输入数据时,您都必须执行某种类型的验证。 (我对人类没有任何反对意见;其中许多都非常准确)
猜你喜欢
  • 1970-01-01
  • 2017-12-18
  • 1970-01-01
  • 2022-01-03
  • 2016-10-27
  • 2013-11-17
  • 2015-08-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多