在Excel中强制日期格式

时间:2017-05-03 10:28:53

标签: excel vba excel-vba formatting

我的列中包含正确格式的日期:

dd.MM.yyyy hh:mm:ss

我想首先改变"。"到" /"哪个工作正常,以下代码,但它会自动修改日期格式,并将日期识别为月份,如果它在12岁以下。

dd/MM/yyyy hh:mm:ss

'2) Replace "." by "/"
    'Range("C:C").NumberFormat = "@" ' I tried with AND without this line...no difference
    'Range("C:C").NumberFormat = "dd.mm.yyyy hh:mm:ss" ' if I add this then only "." starting from 13th of January are reaplced by "/"
    'Range("C:C").NumberFormat = "dd/mm/yyyy hh:mm:ss" ' no differences at all neither
    Columns("C:C").Select
    Selection.Replace What:=".", Replacement:="/", LookAt:=xlPart, _
        SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
        ReplaceFormat:=False

太烦人了...任何想法如何解决这个问题?

6 个答案:

答案 0 :(得分:2)

如果您不介意循环浏览数据,可以执行以下操作:

Sub Test()

Dim ws As Worksheet

Set ws = ThisWorkbook.Sheets("SheetName")

For Each Cell In ws.Range("C2:C" & ws.Cells(ws.Rows.Count, "C").End(xlUp).Row)
    Cell.Value = CDate(Replace(Cell.Value, ".", "/"))
Next Cell

End Sub

或者,如果您需要,可以使用辅助列并使用以下公式:

=TEXT(DATE(MID(C2,SEARCH(".",C2,SEARCH(".",C2,1)+1)+1,4),MID(C2,SEARCH(".",C2,1)+1,2),MID(C2,1,2))+TIMEVALUE(RIGHT(C2,8)),"dd/mm/yyyy hh:mm:ss")

答案 1 :(得分:2)

此代码在C2:C25中使用Sheet1,将其转换为内存数组,遍历该数组并将所有值转换为实际日期,然后转储转换后的代码D2:D25Sheet1的值会在D列中应用所需的NumberFormat,然后调整列的大小以适应。

output result

结果是日期被正确地视为日期,自定义格式:

Public Sub ConvertToDate()

    Dim target As Variant
    target = ToArray(Sheet1.Range("C2:C25")) 'todo: adjust to desired range

    Dim i As Long
    For i = LBound(target) To UBound(target)
        target(i) = ToDate(target(i))
    Next

    'here you'd probably dump the result in C2:
    Sheet1.Range("D:D").NumberFormat = "dd.MM.yyyy hh:mm:ss"
    Sheet1.Range("D2").Resize(UBound(target), 1).value = Application.WorksheetFunction.Transpose(target)
    Sheet1.Range("D:D").EntireColumn.AutoFit

End Sub

Private Function ToDate(ByVal value As String) As Date

    ' make sure our assumptions are correct before going any further:
    Debug.Assert value Like "##.##.#### ##:##:##"

    Dim datetimeParts As Variant
    datetimeParts = Strings.Split(value, " ")

    Dim dateParts As Variant
    dateParts = Strings.Split(datetimeParts(0), ".")

    Dim datePart As Date
    datePart = DateTime.DateSerial(dateParts(2), dateParts(1), dateParts(0))

    Dim result As Date
    result = CDate((CStr(datePart) & " " & datetimeParts(1)))

    ToDate = result

End Function

ToArray辅助函数就是这个函数(改编自this post):

Private Function ToArray(ByVal target As Range) As Variant
    Select Case True
        Case target.Rows.Count = 1
            'horizontal 1D range
            ToArray = Application.WorksheetFunction.Transpose(Application.WorksheetFunction.Transpose(target.value))
        Case target.Columns.Count = 1
            'vertical 1D range
            ToArray = Application.WorksheetFunction.Transpose(target.value)
        Case Else
            '2D array: let Excel to the conversion itself
            ToArray = target.value
    End Select
End Function

您应该能够轻松调整此代码以使用您的工作表和数据。

答案 2 :(得分:1)

这应该足以满足您的需求。我不在乎.Range("C:C")这里,但只要C列中只有这些数据,这就没问题了。使用。Range("C:C")的问题在于它总是会修改并加载整个列,从而降低性能。如果我有机会,编辑代码以使用更优雅的解决方案,我只是想先得到一个有效的答案,让你开始。

无论如何,这里是代码:

Sub FixDateFormatting()
    Dim ArrayDates() As Variant

    ' Load all the dates into an array for modification
    ArrayDates = ThisWorkbook.Sheets(1).Range("C:C").Value

    ' Edit the format of the destination to be text based. This will prevent Excel from assuming format
    ' Note: This must be done after the values are put into the array, otherwise you could load values in the
    ' wrong format.
    ThisWorkbook.Sheets(1).Range("C:C").NumberFormat = "@"

    Dim i As Long
    ' Loop through the array and properly format all of the data
    For i = LBound(ArrayDates, 1) To UBound(ArrayDates, 1)
        ArrayDates(i, 1) = Format(CStr(Replace(ArrayDates(i, 1), ".", "/")), "dd/mm/yyyy hh:mm:ss")
    Next

    ' Output the modified data
    ThisWorkbook.Sheets(1).Range("C:C").Value = ArrayDates
End Sub

ThisWorkbook.Sheets(1)替换为您正在修改的工作表的适当参考。如果目标工作表是运行代码的工作簿中的第一个工作表,则不必如此。

这应该比循环好得多。这种方法的唯一缺点是,为了从这些单元格中检索值并对它们执行操作(使用dd-mm-yyyy格式),您必须在另一个数组中检索和操作这些值。如果您尝试在这些值上使用excel公式,则无法获得预期结果。当您使用非标准日期格式时,这是不可避免的(至少据我所知)。

如果您有任何问题,请与我们联系。

小心,

布兰登

编辑:

这是一个稍微优雅的解决方案,应该会略微提升性能。我(希望)更容易设置正确的目标工作表。我还调整了范围,只包含必要的行数。见下文:

Sub FixDateFormatting()
    Dim TargetSheet As Worksheet
    ' Set the correct target sheet here:
    Set TargetSheet = ThisWorkbook.Sheets(1)

    Dim LastColRow As Long
    ' Store the absolute last row within a long variable for later use
    LastColRow = TargetSheet.Range("C1048576").End(xlUp).Row

    Dim TargetRange As Range
    ' Assumes your data starts in cell 2 (has a header row). Change the 2 as needed.
    Set TargetRange = TargetSheet.Range("C2:C" & LastColRow)

    Dim ArrayDates() As Variant

    ' Load all the dates into an array for modification
    ArrayDates = TargetRange.Value

    ' Edit the format of the destination to be text based. This will prevent Excel from assuming format
    ' Note: This must be done after the values are put into the array, otherwise you could load values in the
    ' wrong format.
    TargetRange.NumberFormat = "@"

    Dim i As Long
    ' Loop through the array and properly format all of the data
    For i = LBound(ArrayDates, 1) To UBound(ArrayDates, 1)
        ArrayDates(i, 1) = Format(CStr(Replace(ArrayDates(i, 1), ".", "/")), "dd/mm/yyyy hh:mm:ss")
    Next

    ' Output the modified data
    TargetRange.Value = ArrayDates
End Sub

编辑(再次):

这最后一个解决方案更优雅,并保留了" DATE"格式。然后,您可以根据需要编辑单元格。这使用UDF(用户定义的函数)。您只需键入要将日期固定为目标的函数即可。它将输出一个日期,然后您可以将其修改为所需的格式:

Public Function FixDateFormat(InputDate As String) As Date
    ' This will ensure that the string being input is appropriate for this function
    ' Modify the pattern as needed.

    If InputDate Like "##.##.#### ##:##:##" Then
        Dim DateTime As Variant
        DateTime = Split(InputDate, " ")

        Dim DateInfo As Variant
        DateInfo = Split(DateTime(0), ".")

        Dim HolderString As String
        HolderString = Format(DateInfo(1), "00") & "/" & Format(DateInfo(0), "00") & "/" & Format(DateInfo(2), "0000") & " " & DateTime(1)

        Debug.Print HolderString

        Dim OutputDate As Date
        OutputDate = CDate(HolderString)

        FixDateFormat = OutputDate
    Else
        ' Comment out this line to return a "#VALUE" error instead
        FixDateFormat = vbNullDate
        Exit Function
    End If
End Function

答案 3 :(得分:0)

无需手动修改区域设置,您必须使用循环。

LastRow = Cells(Rows.Count, "C").End(xlUp).Row
Set r = Range(Cells(1, "C"), Cells(LastRow, "C"))
t = r.Value
For i = 1 To UBound(t)
 t(i, 1) = Replace(t(i, 1), ".", "/")
Next
r.NumberFormat = ""
r.FormulaLocal = t

答案 4 :(得分:-1)

有多种方法可以解决这个问题,最明显的方法是调整NumberFormat属性。尝试录制一些具有各种格式的宏,以了解它如何适合您。在您的情况下,代码可能是这样的:

Sheet1.Columns("C:C").NumberFormat = "mm/dd/yyyy"

答案 5 :(得分:-1)

这样的事情

Sub Makro3()

Columns("C:C").Select

Selection.NumberFormat = "dd\/mm\/yyyy hh:mm:ss"
End Sub

添加了hh:mm:ss