简体   繁体   English

意外日期结果 - Excel VBA - 日月年混淆

[英]Unexpected Date Results - Excel VBA - Day Month Year get mixed up

I have two date ranges that I am trying to turn into two strings OldestDate and NewestDate .我有两个日期范围,我试图将它们转换为两个字符串OldestDateNewestDate But, today I came across and issue where one date was formatted dd/mm/yyyy and the other mm/dd/yyyy但是,今天我遇到了问题,其中一个日期的格式为dd/mm/yyyy ,而另一个日期的格式为mm/dd/yyyy

Here is example data that I placed on two separate worksheets: Note, I copied the cells contents next to the "date" formatted cell for visual reference, but in my actual data, there is only the "date" column.这是我放在两个单独工作表上的示例数据: 注意,我复制了“日期”格式单元格旁边的单元格内容以供视觉参考,但在我的实际数据中,只有“日期”列。

在此处输入图片说明

and

在此处输入图片说明

Here is the code I use to transform into string and the debug output:这是我用来转换为字符串和调试输出的代码:

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

Console/Debug:控制台/调试:

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

I took a workaround approach vs debugging to much and just scraped the month/year and then hard coded 1 for first day and used the function EoMonth to get the last day.我采取了一种解决方法与调试相比,只是刮掉了月/年,然后在第一天硬编码 1 并使用函数EoMonth来获得最后一天。 This was being used to create a URL to query based on dates, the query will take a tiny bit longer and have extra data, but thats OK w/ me, I'd rather have reliability 100%.这被用来创建一个 URL 以根据日期进行查询,查询将花费更长的时间并有额外的数据,但是对我来说没关系,我宁愿拥有 100% 的可靠性。

here is the new code, which is also less complicated to read :)这是新代码,阅读起来也不那么复杂:)

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

Debug: (Note I changed one date to Nov just for testing)调试:(注意我将一个日期更改为 Nov 只是为了测试)

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

Format will do this in one go: Format 将一次性完成此操作:

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

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

If your cell values are text dates formatted as the "reversed" US format mm/dd/yyyy , and you are not in a US environment, you can use this function to convert these to true date values:如果您的单元格值是格式化为“反向”美国格式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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM