Изменение формата даты на гггг-ММ-ДД

у меня есть столбец даты, который содержит даты в смешанном формате. Например:

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