【问题标题】:Unexpected Date Results - Excel VBA - Day Month Year get mixed up意外的日期结果 - Excel VBA - 日月年混淆
【发布时间】:2020-11-06 18:54:45
【问题描述】:

我有两个日期范围,我试图将它们转换为两个字符串 OldestDateNewestDate。但是,今天我遇到了一个问题,其中一个日期格式为dd/mm/yyyy,另一个日期格式为mm/dd/yyyy

这是我放置在两个单独工作表上的示例数据:注意,我复制了“日期”格式单元格旁边的单元格内容以供视觉参考,但在我的实际数据中,只有“日期”列。

这是我用来转换成字符串的代码和调试输出:

Public Sub Get_Date()
 
DateHeader = "A"

Set rng = Application.ActiveSheet.Range(DateHeader & "1:" & DateHeader & Cells(Rows.Count, 1).End(xlUp).Offset(1).Row)

OldestDate = Format(WorksheetFunction.min(rng), "dd/mm/yyyy")
Debug.Print OldestDate

NewestDate = Format(WorksheetFunction.Max(rng), "dd/mm/yyyy")
Debug.Print NewestDate

'20200908
'Sept 8, 2020

aDate = Split(OldestDate, "/")
If UBound(aDate) = 2 Then
 sDay = aDate(0)
 If Len(sDay) = 1 Then
  sDay = "0" & sDay
 End If
 sMonth = aDate(1)
 If Len(sMonth) = 1 Then
  sMonth = "0" & sMonth
 End If
 sYear = aDate(2)
End If
OldestDateStr = sYear & sMonth & sDay
Debug.Print OldestDateStr

aDate = Split(NewestDate, "/")
If UBound(aDate) = 2 Then
 sDay = aDate(0)
 If Len(sDay) = 1 Then
  sDay = "0" & sDay
 End If
 sMonth = aDate(1)
 If Len(sMonth) = 1 Then
  sMonth = "0" & sMonth
 End If
 sYear = aDate(2)
End If
NewestDateStr = sYear & sMonth & sDay
Debug.Print NewestDateStr

End Sub

控制台/调试:

7/10/2020 ' This is Correct
8/10/2020 ' This is Correct
20201007  ' This is Correct
20201008  ' This is Correct
8/17/2020 ' Incorrect
8/18/2020 ' Incorrect
20201708  ' Incorrect
20201808  ' Incorrect

【问题讨论】:

  • 可能数据来源于一个CSV文件,该文件是OPEN的,并且文件中的日期格式与您Windows中的短日期格式不同区域设置。如果是这种情况,似乎格式正确的那个将被错误地解析。数据的来源很重要,因为它将决定相关的修复。
  • 两者都来自我从中抓取数据的同一个内部 web 应用程序,但我怀疑您可能是正确的。我发现了一个“解决方法”,因为我不愿意进一步调试。谢谢@RonRosenfeld

标签: excel vba date


【解决方案1】:

我采用了一种解决方法,而不是调试,只是刮掉了月份/年份,然后在第一天硬编码 1,并使用函数 EoMonth 得到最后一天。这被用来创建一个基于日期查询的 URL,查询将花费一点时间并且有额外的数据,但是这对我来说没问题,我宁愿有 100% 的可靠性。

这是新代码,阅读起来也不那么复杂:)

Public Sub Get_Date()
 
DateHeader = "A"

Set rng = Application.ActiveSheet.Range(DateHeader & "1:" & DateHeader & Cells(Rows.Count, 1).End(xlUp).Offset(1).Row)

Dim OldestDate As Date, NewestDate As Date

OldestDate = Format(WorksheetFunction.min(rng), "mm/yyyy")
Debug.Print OldestDate
NewestDate = Format(WorksheetFunction.Max(rng), "mm/yyyy")
Debug.Print NewestDate

'20200908
'Sept 8, 2020

'OldestDate
aDate = Split(OldestDate, "/")
sYear = aDate(2)
sMonth = aDate(0)
If Len(sMonth) = 1 Then
 sMonth = "0" & sMonth
End If
sDay = "01"
OldestDateStr = sYear & sMonth & sDay
Debug.Print OldestDateStr

'NewestDate
aDate = Split(NewestDate, "/")
sYear = aDate(2)
sMonth = aDate(0)
If Len(sMonth) = 1 Then
 sMonth = "0" & sMonth
End If
sDay = Day(Application.WorksheetFunction.EoMonth(NewestDate , 0))
NewestDateStr = sYear & sMonth & sDay
Debug.Print NewestDateStr

End Sub

调试:(注意我将一个日期更改为 11 月只是为了测试)

10/1/2020 
11/1/2020 
20201001
20201130
8/1/2020 
8/1/2020 
20200801
20200830

【讨论】:

    【解决方案2】:

    格式将一次性完成:

    OldestDateStr = Format(WorksheetFunction.min(rng), "yyyymmdd")
    Debug.Print OldestDateStr
    
    NewestDateStr = Format(WorksheetFunction.Max(rng), "yyyymmdd")
    Debug.Print NewestDateStr
    

    如果您的单元格值是 text 格式为“反转”美国格式 mm/dd/yyyy 的日期,并且您不在美国环境中,则可以使用此函数将这些转换为真实的日期值:

    ' Converts a US formatted date/time string to a date value.
    '
    ' Examples:
    '   7/6/2016 7:00 PM    -> 2016-07-06 19:00:00
    '   7/6 7:00 PM         -> 2018-07-06 19:00:00  ' Current year is 2018.
    '   7/6/46 7:00 PM      -> 1946-07-06 19:00:00
    '   8/9-1982 9:33       -> 1982-08-09 09:33:00
    '   2/29 14:21:56       -> 2039-02-01 14:21:56  ' Month/year.
    '   2/39 14:21:56       -> 1939-02-01 14:21:56  ' Month/year.
    '   7/6/46 7            -> 1946-07-06 00:00:00  ' Cannot read time.
    '   7:32                -> 1899-12-30 07:32:00  ' Time value only.
    '   7:32 PM             -> 1899-12-30 19:32:00  ' Time value only.
    '   7.32 PM             -> 1899-12-30 19:32:00  ' Time value only.
    '   14:21:56            -> 1899-12-30 14:21:56  ' Time value only.
    '
    ' 2018-03-31. Gustav Brock. Cactus Data ApS, CPH.
    '
    Public Function CDateUs( _
        ByVal Expression As String) _
        As Date
        
        Const PartSeparator As String = " "
        Const DateSeparator As String = "/"
        Const DashSeparator As String = "-"
        Const MaxPartCount  As Integer = 2
    
        Dim Parts           As Variant
        Dim DateParts       As Variant
        
        Dim DatePart        As Date
        Dim TimePart        As Date
        Dim Result          As Date
        
        ' Split expression into maximum two parts.
        Parts = Split(Expression, PartSeparator, MaxPartCount)
        
        
        If IsDate(Parts(0)) Then
            ' A date or time part is found.
            ' Replace dashes with slashes.
            Parts(0) = Replace(Parts(0), DashSeparator, DateSeparator)
            If InStr(1, Parts(0), DateSeparator) > 1 Then
                ' A date part is found.
                DateParts = Split(Parts(0), DateSeparator)
                If UBound(DateParts) = 2 Then
                    ' The date includes year.
                    DatePart = DateSerial(DateParts(2), DateParts(0), DateParts(1))
                Else
                    If IsDate(CStr(Year(Date)) & DateSeparator & Join(DateParts, DateSeparator)) Then
                        ' Use current year.
                        DatePart = DateSerial(Year(Date), DateParts(0), DateParts(1))
                    Else
                        ' Expression contains month/year.
                        DatePart = CDate(Join(DateParts, DateSeparator))
                    End If
                End If
                If UBound(Parts) = 1 Then
                    If IsDate(Parts(1)) Then
                        ' A time part is found.
                        TimePart = CDate(Parts(1))
                    End If
                End If
            Else
                ' A time part it must be.
                ' Concatenate an AM/PM part if present.
                TimePart = CDate(Join(Parts, PartSeparator))
            End If
        End If
        
        Result = DatePart + TimePart
            
        CDateUs = Result
    
    End Function
    

    【讨论】:

    • 不幸的是,使用该方法是我第一次得到意外结果的方式,我不得不删除日块,但我看到你没有使用分隔符,我也许可以缩短我的代码有了这个
    • 我猜你有美国风格的 text 日期。请查看扩展答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-02
    • 2014-04-27
    • 2018-09-02
    • 2014-11-05
    • 2018-04-25
    • 1970-01-01
    • 2019-06-25
    相关资源
    最近更新 更多