繁体   English   中英

格式化日期和区域设置 Excel VBA

[英]Formatting Dates & regional setting Excel VBA

这非常令人沮丧,对我来说没有意义。

这是在 Excel 2010 中。

我录制了一个宏来格式化一些数据,包括日期(DD/MM/YYYY)。 我导入它,Excel 将其视为文本。 所以我使用我记录的“文本到日期”宏,存储到 VBA 子中。

这是录制的宏:

Sub DateFormatting()
    Sheets("Donnees").Select
    Columns("H:H").Select
    Selection.TextToColumns Destination:=Range("H1"), DataType:=xlDelimited, _
        TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
        Semicolon:=False, Comma:=False, Space:=False, Other:=False, OtherChar _
        :="/", FieldInfo:=Array(1, 4), TrailingMinusNumbers:=True
End Sub

当我导入我的数据时,起初我有这个。 您可以看到它被 Excel 视为 TEXT,因为它是左对齐的(H 列,我确认它确实是):

在此处输入图像描述

然后我运行宏,得到这个(H 列):

在此处输入图像描述

您可以看到 Excel 将其视为日期,因为它是右对齐的。 如果我将它转换为“数字”,我会看到底层序列,正如预期的那样。 所以有人会认为这很好。 但实际上并非如此:

如果我再次运行宏(我会,因为稍后会添加更多数据,所以我需要确保这些底部新导入的数据也将正确格式化),我得到这个:

在此处输入图像描述

所以基本上它将格式从 DD/MM/YYYY(它应该是)更改为 MM/DD/YYYY(这是错误的)。 如果我在该数据集上再次运行该宏,它会切换回 DD/MM/YYYY。

但最糟糕的是,如果我手动执行完全相同的操作(例如,我没有运行宏,而是手动将 go 设置为“数据”、“文本到列”和 select 完全相同的选项),那么它不会改变。 如果日期格式为 DD/MM/YYYY,它会保持这种状态,如果它的格式是 MM/DD/YYYY(因为这个愚蠢的怪癖),那么它也会保持这种状态。 我重复了很多次(甚至重新录制了几次宏)以确保我做完全相同的事情。

我知道这是因为区域设置,但该文件不会一直在我的计算机上使用,而且我无法确保最终用户将拥有任何特定的区域设置。 基本上,我需要这个文件独立于区域设置。

我的问题是:我怎样才能确保这些日期是:

  • 由 Excel 格式化并识别为日期
  • 独立于用户的本地区域设置?

我知道我可以进行中间导入步骤(并在那里格式化数据,而不是在主文件中),或者然后调整代码,以便只有新导入的数据才应用宏......但后来我觉得不是可靠,因为我怎么知道 Excel 不会弄乱格式?

哦,因为看 VBA 的宏有点神秘:

我 go 到数据,文本到列,选择“分隔”(没关系,因为我实际上并没有将其拆分为列),然后将“分隔符”作为默认值(再次无关紧要,我实际上并没有拆分文本到列中),然后是“日期”,然后在 DD/MM/YYYY 的下拉列表“DYM”中

编辑:有关详细信息,请参阅 Ron Rosenfield 的回答。 为了完整起见,我将运行以下代码来导入数据并在导入时对其进行格式化,而不是先导入然后格式化:

Sub importData()
Dim myFile As String
myFile = Sheet5.Cells(2, 5).Value 'My metadata sheet, containing name of file to import

Sheet1.Select  'Setting target sheet as active worksheet
    With ActiveSheet.QueryTables.Add(Connection:="TEXT;C:\ChadTest\" & myFile, _
    Destination:=Sheet1.Cells(Sheet5.Cells(2, 1).Value, 1))
        .Name = "ExternalData_1"
        .FieldNames = True
        .RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = True
        .RefreshOnFileOpen = False
        .RefreshStyle = xlOverwriteCells
        .SavePassword = False
        .SaveData = True
        .AdjustColumnWidth = True
        .RefreshPeriod = 0
        .TextFilePromptOnRefresh = False
        .TextFilePlatform = 1252
If Sheet1.Cells(1, 1).Value = "" Then
  .TextFileStartRow = 1
Else
  .TextFileStartRow = 2
End If
        .TextFileParseType = xlDelimited
        .TextFileTextQualifier = xlTextQualifierDoubleQuote
        .TextFileConsecutiveDelimiter = False
        .TextFileTabDelimiter = True
        .TextFileSemicolonDelimiter = False
        .TextFileCommaDelimiter = True
        .TextFileSpaceDelimiter = False
        .TextFileColumnDataTypes = Array(1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 1)
        .TextFileTrailingMinusNumbers = True
        .Refresh BackgroundQuery:=False
    End With
    Sheet1.Select
    Application.WindowState = xlMinimized
    Application.WindowState = xlNormal
End Sub

从您写的内容看来,您似乎是从在Excel中打开的TEXT或CSV文件中获取数据,然后尝试处理日期。 常见问题。

相反,您可以做的是导入文件。 如果这样做,文本导入向导(与文本到列向导相同)将在数据写入工作表之前打开,并为您提供指定导入日期格式的机会。

该选项应该在数据功能区的“获取外部数据”选项卡上:

导入文字

对于从源头将数据获取到Excel工作表的确切过程,我有些困惑,但是整个过程肯定可以使用VBA自动化。 并且不需要在已导入的数据上运行宏。

这就是我在上面的评论中提到的内容:

Sub DateFormatting()

    On Error Resume Next

    Application.ScreenUpdating = False

    Dim wbCurrent As Workbook
    Dim wsCurrent As Worksheet
    Dim nLastRow, i, nDay, nMonth, nYear As Integer
    Dim lNewDate As Long

    Set wbCurrent = ActiveWorkbook
    Set wsCurrent = wbCurrent.ActiveSheet
    nLastRow = wsCurrent.Cells.Find("*", LookIn:=xlValues, SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row

    For i = nLastRow To 2 Step -1
        If InStr(1, wsCurrent.Cells(i, 8), "/", vbBinaryCompare) > 0 Then
            nYear = Right(wsCurrent.Cells(i, 8), 4)
            nMonth = Mid(wsCurrent.Cells(i, 8), InStr(1, wsCurrent.Cells(i, 8), "/", vbBinaryCompare) + 1, 2)
            nDay = Left(wsCurrent.Cells(i, 8), 2)
            lNewDate = CLng(DateSerial(nYear, nMonth, nDay))
            wsCurrent.Cells(i, 8).Value = lNewDate
        End If
    Next i

    wsCurrent.Range("H:H").NumberFormat = "dd/mm/yyyy"

    Application.ScreenUpdating = True

End Sub

此代码假定原始原始数据将始终以dd / mm / yyyy格式作为文本导入,包括前导零。

除了格式化日期外,它不会触及任何实际日期(即单元格的实际值是一个序列号)。

在这里,我假设您的日期将始终以dd/mm/yyyy格式书写。

如果我只有一个单元格要检查,则可以这样做:

Dim s() As String
With Range("A1")
    If .NumberFormat = "@" Then
        'It's formatted as text.
        .NumberFormat = "dd/mm/yyyy"
        s = Split(.Value, "/")
        .Value = DateSerial(CInt(s(2)), CInt(s(1)), CInt(s(0)))
    Else
        'It isn't formatted as text. Do nothing.
    End If
End With

但是,如果要检查的单元格很多,这将无法很好地扩展。 通过细胞循环很慢。 这样遍历数组要快得多,如下所示:

Dim r As Range
Dim v As Variant
Dim i As Long
Dim s() As String
Set r = Range("H:H").Resize(GetLastNonblankRowNumber(Range("H:H"))) 'or wherever 
v = r.Value ' read all values into an array (could be strings, could be real dates)
For i = 1 To UBound(v, 1)
    If VarType(v(i, 1)) = vbString Then
        s = Split(v(i, 1), "/")
        v(i, 1) = DateSerial(CInt(s(2)), CInt(s(1)), CInt(s(0)))
    End If
Next i
With r
    .NumberFormat = "dd/mm/yyyy"
    .Value = v 'write dates back to sheet
End With

我在这里利用:

Function GetLastNonblankRowNumber(r As Range) As Long
    GetLastNonblankRowNumber = r.Find("*", r.Cells(1, 1), xlFormulas, xlPart, _
       xlByRows, xlPrevious).Row
End Function

实际上,我们在工作中遇到了很多问题。 我们发现解决此问题的最佳方法是确保基本数据中的日期采用“ YYYY / MM / DD”格式,这样就可以将其识别为美国或普通日期格式中的同一日期,并且实际上会正确遵循您的区域设置以在Excel中放置正确的日期...

如果您正在打开文本文件(例如 csv),则使用 vba 强制使用本地日期格式打开它 Workbooks.Open Filename:=strPath & strFile, Local:=True

避免所有变通方法

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM