Excel 如何检查单元格中的日期是实际日期还是字符串日期?

Excel 如何检查单元格中的日期是实际日期还是字符串日期?,excel,vba,date,locale,Excel,Vba,Date,Locale,在工作中,我们使用Office 365 Excel文件作为预订系统。每个站点都有多个选项卡,其中每个记录都有一个预订日期。存在日期格式问题-基本上默认区域设置为“mm/dd/yyyy”,但日期显示在“dd/mm/yyyy”中。当人们手动添加行(通常每天自动生成预订时段)并以错误格式键入日期而不是从相邻单元格复制日期值时,它会显示正确,但顶部栏中的单元格值不同,但在桌面应用程序中打开此文件时,它根本不会将其视为不同的值。只有在应用筛选器时,才可以根据日期和字符串日期值进行筛选。这会导致宏在创建报告

在工作中,我们使用Office 365 Excel文件作为预订系统。每个站点都有多个选项卡,其中每个记录都有一个预订日期。存在日期格式问题-基本上默认区域设置为
“mm/dd/yyyy”
,但日期显示在
“dd/mm/yyyy”
中。当人们手动添加行(通常每天自动生成预订时段)并以错误格式键入日期而不是从相邻单元格复制日期值时,它会显示正确,但顶部栏中的单元格值不同,但在
桌面应用程序中打开此文件时,它根本不会将其视为不同的值。只有在应用筛选器时,才可以根据日期和字符串日期值进行筛选。这会导致宏在创建报告或基于日期导入数据时无法拾取某些日期

我一直在考虑编写一个实用程序宏,根据当前日期的上下日期对所有日期进行清理,但是我不确定这是否是最好的方法。我不认为我可以改变所有用户的语言环境设置,因为我在文档中读到的内容只会改变单用户设置,我不确定这将如何影响整个系统的整体功能。有没有比解析这个庞大的文件或手动查找这个日期更容易的方法

这是一个真正的痛苦,因为这个文件是在我加入团队之前很久设计的,现在我正在努力使它不那么容易出错


感谢您提前提供任何线索

实际日期是数字。因此,您可以使用
IsNumeric

If IsNumeric(Range("A1").Value2) Then
    Debug.Print "date"
Else
    Debug.Print "string"
End If

请注意,您需要检查
.Value2
而不是
。Value

实际日期是数字。因此,您可以使用
IsNumeric

If IsNumeric(Range("A1").Value2) Then
    Debug.Print "date"
Else
    Debug.Print "string"
End If

请注意,您需要检查
.Value2
而不是
。Value

看起来您的问题源于人们输入的日期无效。 您可以尝试对单元格应用数据验证,以便在数据输入期间进行清理。 数据验证允许将单元格设置为日期,然后可以指定日期范围。因此,只允许该范围内的有效日期


看来您的问题源于人们输入的日期无效。 您可以尝试对单元格应用数据验证,以便在数据输入期间进行清理。 数据验证允许将单元格设置为日期,然后可以指定日期范围。因此,只允许该范围内的有效日期


佩赫的回答引导我找到了正确的解决方案。如果有人遇到类似问题,下面是完整的代码:

Sub SanitizeDates()
    ' ---
    ' Utility macro that goes over all live sheets and checks all rows
    ' for the string dates that have been input manually
    ' and converts it to an actual Date values.
    ' ---

    Debug.Print "--- Log Start"
    
    Dim Prompt As String
    Dim Errors As Integer
    Dim TotalErrors As Integer
    TotalErrors = 0
    Errors = 0

    Dim Tracker As Workbook
    Dim WS As Worksheet
    
    Dim CurrentDateValue As Variant
    Dim NewDate As Date
    Dim RowCount As Long
    Dim nRow As Long
    
    Set Tracker = ThisWorkbook
    
    Application.ScreenUpdating = False
    
    For Each WS In Tracker.Worksheets
        If WS.Visible And Not WS.Name = "Matrix" Then ' if worksheet is not visible and not a Matrix
            If InStr(1, WS.Name, "Template", vbTextCompare) = 0 Then ' if worksheet is not a template
            
                Errors = 0
                
                RowCount = WS.ListObjects(1).DataBodyRange.Rows.Count
                
                'loop over all rows in table
                For nRow = 1 To RowCount
                    With WS.ListObjects(1).DataBodyRange
                    
                        ' check if the cell is a black bar / divider
                        If Not .Cells(nRow, 3).Interior.Color = RGB(0, 0, 0) Then
                            If Not IsNumeric(.Cells(nRow, 3).Value2) Then
                                                                
                                On Error GoTo SkipInvalid
                                NewDate = DateValue(.Cells(nRow, 3).Value2)
                                .Cells(nRow, 3).Value2 = NewDate
                                Errors = Errors + 1
                                
                                'Error logging
                                'Call LogError(.Cells(nRow, 5), .Cells(nRow, 15), "Date Format - dev")
                            End If
                        End If
                    End With
SkipInvalid:
                Next nRow
                
                TotalErrors = TotalErrors + Errors
                
                If Errors Then
                    Prompt = Prompt & "Found " & Errors & " errors in " & WS.Name & vbCrLf
                    Debug.Print "Found " & Errors & " errors in " & WS.Name
                End If
                
            End If
        End If
    Next WS
    
    Application.ScreenUpdating = True
    
    Debug.Print "--- Log End"
    
    If TotalErrors Then
        MsgBox (Prompt & vbCrLf & vbCrLf & _
            "Total of " & TotalErrors & " errors found. All data sanitized successfully.")
    Else
        MsgBox ("No errors found")
    End If
End Sub

佩赫的回答引导我找到了正确的解决方案。如果有人遇到类似问题,下面是完整的代码:

Sub SanitizeDates()
    ' ---
    ' Utility macro that goes over all live sheets and checks all rows
    ' for the string dates that have been input manually
    ' and converts it to an actual Date values.
    ' ---

    Debug.Print "--- Log Start"
    
    Dim Prompt As String
    Dim Errors As Integer
    Dim TotalErrors As Integer
    TotalErrors = 0
    Errors = 0

    Dim Tracker As Workbook
    Dim WS As Worksheet
    
    Dim CurrentDateValue As Variant
    Dim NewDate As Date
    Dim RowCount As Long
    Dim nRow As Long
    
    Set Tracker = ThisWorkbook
    
    Application.ScreenUpdating = False
    
    For Each WS In Tracker.Worksheets
        If WS.Visible And Not WS.Name = "Matrix" Then ' if worksheet is not visible and not a Matrix
            If InStr(1, WS.Name, "Template", vbTextCompare) = 0 Then ' if worksheet is not a template
            
                Errors = 0
                
                RowCount = WS.ListObjects(1).DataBodyRange.Rows.Count
                
                'loop over all rows in table
                For nRow = 1 To RowCount
                    With WS.ListObjects(1).DataBodyRange
                    
                        ' check if the cell is a black bar / divider
                        If Not .Cells(nRow, 3).Interior.Color = RGB(0, 0, 0) Then
                            If Not IsNumeric(.Cells(nRow, 3).Value2) Then
                                                                
                                On Error GoTo SkipInvalid
                                NewDate = DateValue(.Cells(nRow, 3).Value2)
                                .Cells(nRow, 3).Value2 = NewDate
                                Errors = Errors + 1
                                
                                'Error logging
                                'Call LogError(.Cells(nRow, 5), .Cells(nRow, 15), "Date Format - dev")
                            End If
                        End If
                    End With
SkipInvalid:
                Next nRow
                
                TotalErrors = TotalErrors + Errors
                
                If Errors Then
                    Prompt = Prompt & "Found " & Errors & " errors in " & WS.Name & vbCrLf
                    Debug.Print "Found " & Errors & " errors in " & WS.Name
                End If
                
            End If
        End If
    Next WS
    
    Application.ScreenUpdating = True
    
    Debug.Print "--- Log End"
    
    If TotalErrors Then
        MsgBox (Prompt & vbCrLf & vbCrLf & _
            "Total of " & TotalErrors & " errors found. All data sanitized successfully.")
    Else
        MsgBox ("No errors found")
    End If
End Sub


对于
VBA
有一个函数
IsDate()
试试看。@Harun24HR小心
IsDate
只告诉您字符串是否可以读取为日期。它不会告诉您单元格内容是否是真正的数字日期
IsDate
将返回
True
,即使单元格包含一个看起来像日期的字符串。@Pᴇ哦,糟糕!我不知道这个信息。不用担心;)出于您的兴趣:(参见此处的示例)。另一种可能是让他们从日历(日期选择器)中选择日期。对于
VBA
,有函数
IsDate()
试试看。@Harun24HR小心
IsDate
只会告诉您字符串是否可以读取为日期。它不会告诉您单元格内容是否是真正的数字日期
IsDate
将返回
True
,即使单元格包含一个看起来像日期的字符串。@Pᴇ哦,糟糕!我不知道这个信息。不用担心;)出于您的兴趣:(参见此处的示例)。另一种可能是让他们从日历(日期选择器)中选择日期。所有日期单元格上都设置了数据验证,但在某些情况下,这没有帮助,例如,必须手动添加其他行或从外部源复制/粘贴数据(如预订表单),在所有日期单元格上设置数据验证,但在某些情况下,这没有帮助,例如必须手动添加其他行或从外部源(如预订表单)复制/粘贴数据,这就像实用程序宏过程中的一个魅力!如果有人对解决方案感兴趣,我已经发布了代码。很好,这在实用程序宏过程中起到了很好的作用!如果有人对解决方案感兴趣,我已经发布了代码请注意,
DateValue
根据操作系统(Windows)中设置的日期格式从字符串中猜测日期。如果你有一个像
02/03/2021
这样的字符串,世界上没有一台计算机能说出它是
dd/mm/yyyyy
还是
mm/dd/yyyyy
,仅凭字符串本身是不可能说出的。因此,您的代码可能会猜测对或错,在最坏的情况下,您的数据中的日期是错误的。唯一可靠的字符串日期是格式
yyyy-mm-dd
(),因为这里不会有任何混淆。因此,如果您知道字符串的日期格式,最好不要让Excel猜测并拆分字符串,将其作为真实日期放在一起。例如,如果您确定所有字符串日期都是
dd/mm/yyyy
,则使用
Part=Split(YourStringDate,“/”
并创建一个实际日期
RealDate=DateSerial(第(2)部分、第(1)部分、第(0)部分))
。通过这种方式,您可以告诉Excel该做什么,而不是让它猜测。这很有意义!我将更正此定义请注意,
DateValue
根据操作系统(Windows)中设置的日期格式从字符串中猜测日期。如果你有一个像
02/03/2021
这样的字符串,世界上没有一台计算机能说出它是
dd/mm/yyyyy
还是
mm/dd/yyyyy
,仅凭字符串本身是不可能说出的。因此,您的代码可能猜测正确或错误