Excel VBA — Как можно сравнивать даты разных форматов

#excel #vba

Вопрос:

Я пытаюсь сравнить даты из двух разных листов, которые имеют разные форматы. Формат первого листа-ГГГГММДД, а второго-ДД/ММ/ГГГГ.

Предостережение заключается в том, что год второго листа неверен (он написан как 2020 и должен быть 2021). Строки также могут располагаться в разных порядках. Данные первого рабочего листа для даты вводятся в виде текста, а не даты.

Как бы мне ни хотелось, я не могу изменить данные на этих двух листах и вместо этого могу выводить только на третий лист (по сути, проверяя данные на наличие записей с той же датой, не считая неправильного года, и выводя что-то, если некоторые ключевые данные отличаются между ними).

Например, если на одном листе есть…

Дата Цена
20210101 500
20210102 1000
20210103 2000

…и у другого есть…

Дата Цена
01/01/2020 500
03/01/2020 3000
02/01/2020 750

…Я бы хотел вывести это на третий лист…

Дата Лист 1 Цена Лист 2 Цена
20210102 1000 750
20210103 2000 3000

У меня есть некоторый код VBA, который в принципе работал бы, но только в том случае, если бы форматы были идентичными.

 ' the columns to check in the first worksheet
Const ws1Date As Integer = 1          'first worksheet, Column A
Const ws1Price As Integer = 2         'first worksheet, Column B

' the columns to check in the second worksheet
Const ws2Date As Integer = 1         'second worksheet, Column A
Const ws2Price As Integer = 2        'second worksheet, Column B

' the columns to write to in the result worksheet
Const resultWsDate As Integer = 1          'result worksheet, Column A
Const resultWsPrice As Integer = 2         'result worksheet, Column B
Const resultWsClientPrice As Integer = 3   'result worksheet, Column C

Dim ws1DateArray As Variant, ws2DateArray As Variant
Dim ws1 As Worksheet, ws2 As Worksheet, resultWs As Worksheet

Set ws1 = Sheets(1) 'the first worksheet
Set ws1 = Sheets(2) 'the second worksheet
Set resultWs = Sheets(3) 'the outputted results

Sub compareFiles()

'-- Store ws1 dates in array --
compareRowMaxLength = ws1.Cells(Rows.Count, ws1Date).End(xlUp).Row
ws1DateArray = ws1.Range(Cells(1, ws1Date).Address, _
                       Cells(compareRowMaxLength, ws1Date).Address).Value
                       
'-- Store ws2 dates in array --
compareRowMaxLength = ws2.Cells(Rows.Count, ws2Date).End(xlUp).Row
ws2DateArray = ws2.Range(Cells(1, ws2Date).Address, _
                       Cells(compareRowMaxLength, ws2Date).Address).Value

'-- Store ws1 depth in array --
compareRowMaxLength = resultWs.Cells(Rows.Count, ws1Date).End(xlUp).Row
ws1DepthArray = resultWs.Range(Cells(1, ws1Date).Address, _
                       Cells(compareRowMaxLength, ws1Depth).Address).Value

'-- Interate through arrays --
For compareRow = 2 To UBound(ws2DateArray, 1)
    matchData = 0
    On Error Resume Next
    
    matchData = WorksheetFunction.Match(ws2DateArray(compareRow, 1), ws1DateArray, 0)
    On Error GoTo 0
    ' if the date of the current row is found in the second sheet
    If matchData <> 0 Then
        If ws2.Cells(compareRow, ws2Price).Value <> ws1.Cells(matchData, ws1Price).Value Then
            ' Copy the matching data to the results worksheet
            resultWs.Cells(resultRow, resultWsDate).Value = ws1.Cells(matchData, ws1Date).Value
            resultWs.Cells(resultRow, resultWsPrice).Value = ws1.Cells(matchData, ws1Price).Value
            resultWs.Cells(resultRow, resultWsClientPrice).Value = ws2.Cells(compareRow, ws2Price).Value
        End If
    End If
Next compareRow

End Sub
 

Я попытался переформатировать дату с листа 2, используя что-то подобное в цикле For…

     ReplacementYear = 2021
    
    FormatDay = Left(ws2DateArray(compareRow, 1), 2)
    FormatMonth = Mid(ws2DateArray(compareRow, 1), 4, 2)
    FormattedDate = CStr(ReplacementYear)   CStr(FormatMonth)   CStr(FormatDay)
 

…и меняется matchData = WorksheetFunction.Match(ws2DateArray(compareRow, 1), ws1DateArray, 0) на matchData = WorksheetFunction.Match(FormatDate, ws1DateArray, 0) , но, похоже, Матч не может работать таким образом.

Большое спасибо за любую помощь!

Комментарии:

1. Как хранятся эти даты? Excel хранит «реальные даты» в виде серийных номеров, начиная с 1-Jan-1900 . Если оба являются «реальными датами» и отличается только формат, сравните свойство .Value2 (оно должно быть двойным или длинным, а НЕ ЦЕЛЫМ ЧИСЛОМ ). Если разница заключается в типе данных, а не в формате, предлагаю вам преобразовать их в реальную дату, а затем провести сравнение.

2. Когда вы нажмете на ячейку, в которой есть 20210102 , проверьте строку формул. Что ты видишь?

3. @RonRosenfeld На первом листе даты хранятся в виде текста, а не в виде «реальной даты». Однако на втором листе она помечена как дата. Спасибо, я попробую и посмотрю, смогу ли я это сделать. Я вообще не могу изменить первый рабочий лист (на самом деле обе книги являются отдельными книгами, которые я могу только просматривать, а не редактировать, помещая в отчет по третьей книге), поэтому мне придется преобразовать его с помощью макроса. @Siddharthout Первый лист 20210102 (введен как текст), а второй 02/01/2020 (введен как Дата).

4. Вам придется преобразовать это в реальную дату, чтобы провести прямое сравнение. Используется DateSerial(Left(Range("A1").Value2, 4), Mid(Range("A1").Value2, 5, 2), Right(Range("A1").Value2, 2)) для преобразования 20210102 в дату для сравнения

5. Если вам интересно, все вышеперечисленное также можно сделать в Power Query. Это требует использования таблиц для ваших данных листов 1 и 2.

Ответ №1:

Это вполне может быть не лучшим решением, но на тот случай, если это поможет кому-нибудь в будущем, вот что я придумал.

Я не могу изменить данные на других листах, но я могу скопировать данные на новый лист, изменить его, а затем удалить позже.

 ' copy the worksheets and modify dates
ws1.Copy After:=Sheets(4)
ws2.Copy After:=Sheets(5)

Set modifyWs1 = Sheets(4)
Set modifyWs2 = Sheets(5)

' fix dates and apply consistent formatting to dates and depth
modifyWs1 .Activate

Dim ws1DateCol As Range

For Each ws1DateCol In Range(Range("A2"), Range("A2").End(xlDown))
    ws1DateCol.NumberFormat = "yyyymmdd" ' confirm date format
    ws1DateCol.Value = ws1DateCol.Text ' change cells to text so they can be Matched
    ws1DateCol.NumberFormat = "@"
Next

' fix dates and apply consistent formatting to dates and depth
modifyWs2.Activate

Dim ws2DateCol As Range

For Each ws2DateCol In Range(Range("A2"), Range("A2").End(xlDown))
    ws2DateCol.Value = DateAdd("yyyy", 1, ws2DateCol.Value) ' add 1 to the year, as 2020 should be 2021
    ws2DateCol.NumberFormat = "yyyymmdd" ' change date format
    ws2DateCol.Value = ws2DateCol.Text ' change cells to text so they can be Matched
    ws2DateCol.NumberFormat = "@"
Next
 

Данные из этих новых столбцов затем помещаются в ws1DateArray и ws2DateArray вместо и WorksheetFunction.Match(ws2DateArray(compareRow, 1), ws1DateArray, 0) работают по желанию.