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

时间:2014-10-28 02:44:30

标签: excel vba date regional-settings

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

这是在Excel 2010中。

我录制了一个宏来格式化一些数据,包含日期(DD / MM / YYYY)。我导入它,Excel将其视为文本。所以我使用我记录的“text to date”宏,存储到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列和我确认它实际上是):

enter image description here

然后我运行宏,并得到它(列H):

enter image description here

您可以看到Excel将其视为日期,因为它是右对齐的。如果我将其转换为“数字”,我会看到底层序列,如预期的那样。所以人们会认为没关系。但事实并非如此:

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

enter image description here

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

但最糟糕的是,如果我手动完成同样的事情(例如,不是运行宏,而是手动转到“数据”,“文本到列”并选择完全相同的选项),然后它不会改变。如果日期格式为DD / MM / YYYY,则保持这种状态,如果格式化为MM / DD / YYYY(因为这个愚蠢的怪癖),那么它也会保持这种状态。我重复一遍(甚至重新录制了几次宏),我确实做了同样的事情。

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

我的问题是:我如何确保这些日期是:

  • 格式化&被Excel确认为日期
  • 独立于用户的本地区域设置?

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

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

我转到Data,Text to Column,选择“Delimited”(无关紧要,因为我实际上并没有将它拆分为列),然后将“Delimiters”作为默认值(再无关紧要我实际上并不重要)将文本拆分为列),然后是“日期”,并在下拉列表“DYM”中为DD / MM / YYYY

编辑:有关详细信息,请参阅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

4 个答案:

答案 0 :(得分:2)

根据您所写的内容,您似乎从Excel中 OPEN 的TEXT或CSV文件中获取数据,然后尝试处理日期。一个常见的问题。

相反,您可以做的是 IMPORT 该文件。如果执行此操作,文本导入向导(与文本到列向导相同)将在数据写入工作表之前打开,并使您有机会指定要导入的日期的格式。

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

Import Text

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

答案 1 :(得分:0)

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

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格式导入为文本,包含前导零。

它不会触及任何实际日期(即单元格的实际值是连续的),除非格式化它们。

答案 2 :(得分:0)

在这里,我假设您的日期将始终以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

答案 3 :(得分:0)

实际上我们在工作中遇到了很多这个问题。 我们发现解决这个问题的最佳方法是确保基础数据中的日期格式为" YYYY / MM / DD",这样它被认为是同一个日期在美国或日期格式中,它实际上会正确地按照您的区域设置在Excel中输入正确的日期...