这非常令人沮丧,对我来说没有意义。
这是在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列和我确认它实际上是):
然后我运行宏,并得到它(列H):
您可以看到Excel将其视为日期,因为它是右对齐的。如果我将其转换为“数字”,我会看到底层序列,如预期的那样。所以人们会认为没关系。但事实并非如此:
如果我运行宏AGAIN(我会,因为稍后会添加更多数据,所以我需要确保这些数据底部的新导入数据也会正确格式化),我得到了这个:
所以基本上它将格式从DD / MM / YYYY(它是SUPPOSED)改为MM / DD / YYYY(这是错误的)。如果我再次在该数据集上运行该宏,它将切换回DD / MM / YYYY。
但最糟糕的是,如果我手动完成同样的事情(例如,不是运行宏,而是手动转到“数据”,“文本到列”并选择完全相同的选项),然后它不会改变。如果日期格式为DD / MM / YYYY,则保持这种状态,如果格式化为MM / DD / YYYY(因为这个愚蠢的怪癖),那么它也会保持这种状态。我重复一遍(甚至重新录制了几次宏),我确实做了同样的事情。
我知道这是因为区域设置,但该文件并不总是在我的计算机上使用,我无法确保最终用户具有任何特定的区域设置。我需要这个文件独立于区域设置,基本上。
我的问题是:我如何确保这些日期是:
我知道我可以进行中间导入步骤(并在那里格式化数据,而不是在主文件中),或者然后调整代码,以便只有新导入的数据才能应用宏....但是我觉得它不可靠,因为我怎么知道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
答案 0 :(得分:2)
根据您所写的内容,您似乎从Excel中 OPEN 的TEXT或CSV文件中获取数据,然后尝试处理日期。一个常见的问题。
相反,您可以做的是 IMPORT 该文件。如果执行此操作,文本导入向导(与文本到列向导相同)将在数据写入工作表之前打开,并使您有机会指定要导入的日期的格式。
该选项应位于数据功能区的“获取外部数据”选项卡上:
我对使用从源到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中输入正确的日期...