Изменение формата даты на гггг-ММ-ДД
у меня есть столбец даты, который содержит даты в смешанном формате. Например:
A
21.03.1990
03/21/1990
Итак, в основном есть два разных формата в одном столбце:dd.mm.yyyy
и mm/dd/yyyy
. Я пытаюсь написать сценарий VBA, чтобы изменить формат всех дат в столбце yyyy-mm-dd
. Вот что я получил до сих пор:
Sub changeFormat()
Dim rLastCell As Range
Dim cell As Range, i As Long
Dim LValue As String
i = 1
With ActiveWorkbook.Worksheets("Sheet1")
Set rLastCell = .Range("A65536").End(xlUp)
On Error Resume Next
For Each cell In .Range("A1:A" & rLastCell.Row)
LValue = Format(cell.Value, "yyyy-mm-dd")
.Range("B" & i).Value = LValue
i = i + 1
Next cell
On Error GoTo 0
End With
End Sub
Я знаю, что это не элегантный кусок кода, но я новичок в VBA так пожалуйста, прости меня.
Проблема с этим кодом заключается в том, что он просто переписывает неизмененный столбец в столбец B, Когда я изменяю аргумент в функции формата из yyyy-mm-dd
to dd/mm/yyyy
он работает, но только для дат в формате mm/dd/yyyy
, и листья dd.mm.yyyy
нетронутым. Я был бы признателен за любой совет.
6 ответов
ОБНОВЛЕНО: НОВЫЙ ОТВЕТ
вот решение, которое сделает эту работу! Подпрограмма sub включает функцию, которая выполняет замену (сама функция действительно полезна!). Запустите sub, и все вхождения в столбце A будут исправлены.
Sub FixDates()
Dim cell As range
Dim lastRow As Long
lastRow = range("A" & Rows.count).End(xlUp).Row
For Each cell In range("A1:A" & lastRow)
If InStr(cell.Value, ".") <> 0 Then
cell.Value = RegexReplace(cell.Value, _
"(\d{2})\.(\d{2})\.(\d{4})", "--")
End If
If InStr(cell.Value, "/") <> 0 Then
cell.Value = RegexReplace(cell.Value, _
"(\d{2})/(\d{2})/(\d{4})", "--")
End If
cell.NumberFormat = "yyyy-mm-d;@"
Next
End Sub
поместите эту функцию в тот же модуль:
Function RegexReplace(ByVal text As String, _
ByVal replace_what As String, _
ByVal replace_with As String) As String
Dim RE As Object
Set RE = CreateObject("vbscript.regexp")
RE.pattern = replace_what
RE.Global = True
RegexReplace = RE.Replace(text, replace_with)
End Function
как это работает: у меня есть отличная функция RegexReplace, которая позволяет выполнять замену с помощью регулярных выражений. Суб около циклы через ваш столбец A и заменяет регулярное выражение для тех 2 случаев, которые вы упомянули. Причина я использую функция instr() во-первых, это determain, если он нуждается в замене, и какие. Вы можете технически пропустить это, но делать замену на ячейки, которые не нуждаются в этом, действительно дорого. В конце я форматирую ячейку в ваш пользовательский формат даты независимо от того, что внутри для безопасной меры.
в случае, если вы не знакомы с Regex (для ref: http://www.regular-expressions.info/), выражение, которое я использую:
- каждый элемент в () являются группы захвата - ака, вещи, которые вы хотите возиться с
- \d означает число [0-9].
- {2} означает 2 из, а {4} означает 4 из. Я был откровенен здесь для безопасности.
- The \ перед . в первом случае необходимо заменить "."имеет особое значение.
- в VBA regex вы обратитесь к группам с помощью $ + нет. группы. Вот как я переворачиваю порядок из 3 пунктов.
посмотрите, делает ли это то, что вы хотите. Возможно, вам придется немного адаптировать его для вашего собственного приложения.
надеюсь, что это помогает!
Sub convertDates()
Dim rRng As Range
Dim rCell As Range
Dim sDest As String
Dim sYear, sMonth, sDay, aDate
'Range where the dates are stored, excluding header
Set rRng = Sheet1.Range("A2:A11")
'Column name of destination
sDest = "B"
'You could also use the following, and just select the range.
'Set rRng = Application.selection
For Each rCell In rRng.Cells
sYear = 99999
If InStr(rCell.Value, ".") > 0 Then
aDate = Split(rCell.Value, ".")
If UBound(aDate) = 2 Then
sDay = aDate(0)
sMonth = aDate(1)
sYear = aDate(2)
End If
ElseIf InStr(rCell.Value, "/") > 0 Then
aDate = Split(rCell.Value, "/")
If UBound(aDate) = 2 Then
sDay = aDate(1)
sMonth = aDate(0)
sYear = aDate(2)
End If
End If
With rCell.Range(sDest & "1")
If sYear <> 99999 Then
On Error Resume Next
.Value = "'" & Format(CDate(sMonth & "/" & sDay & "/" & sYear), "YYYY-MM-DD")
'If it can't convert the date, just put the original value in the dest
'cell. You can tailor this to your own preference.
If Err.Number <> 0 Then .Value = rCell.Value
On Error GoTo 0
Else
.Value = rCell.Value
End If
End With
Next
End Sub
вам действительно не нужен VBA для этого. Эта формула листа с одной строкой сделает трюк:
=IF(ISERROR(FIND(".",A1)),IF(ISERROR(FIND("/",A1)),"invalid format",
DATE(RIGHT(A1,4),LEFT(A1,2),MID(A1,4,2))),
DATE(RIGHT(A1,4),MID(A1,4,2),LEFT(A1,2)))
это предполагает, что день и месяц всегда задаются как двузначные числа (например, всегда 03 и никогда не только 3), а год имеет четыре цифры (т. е. "ограничен" годами 1000-9999). Но если это не так для вас, то формула может быть легко скорректирована в соответствии с вашей целью.
@Jean-François Corbett имеет решение формулы, которое работает, но которое может быть сокращено более чем наполовину, предшествуя сообщению об ошибке (на основании того, что #VALUE!
является информативным), а другой, если, обе даты, применяя IFERROR, а не ISERROR, и заменяют один левый, средний, правый набор:
=IFERROR(1*(MID(A1,4,3)&LEFT(A1,3)&RIGHT(A1,4)),1*SUBSTITUTE(A1,".","/"))
это применяет интерпретацию, упомянутую @Issun в комментарии к OP, и предполагает, что вывод будет в ячейки, отформатированные yyyy-mm-dd
.
может быть написанным с помощью подпрограммы, например:
Sub Macro1()
Range("B1:B10").Formula = "=IFERROR(1*(MID(A1,4,3)&LEFT(A1,3)&RIGHT(A1,4)),1*SUBSTITUTE(A1,""."",""/""))"
End Sub
вот простое решение этого:
Sub ChangeFormat1()
Dim ws as Worksheet
Set ws = Thisworkbook.Sheets("Sheet1")
LR = ws.cells(rows.count,1).End(Xlup).Row
with ws
For I = 1 to LR
.cells(I,2).value = .cells(I,1).value
Next
End with
ws.range("B1:B" & LR).numberformat = "yyyy-mm-dd"
End Sub