2014-10-28 221 views
0

这是非常令人沮丧的,对我来说没有意义。格式化日期和地区设置Excel VBA

这是在Excel 2010中

我录的宏来格式化一些数据,包含日期(日/月/年)。我导入它,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文本,因为它是左对齐(H列和我确认它实际上是):

enter image description here

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

enter image description here

您可以看到Excel将它视为日期,因为它是右对齐的。如果我将它转换为“数字”,我会像预期的那样看到底层序列。所以人们会认为这很好。但它真的不是:

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

enter image description here

所以基本上是从DD/MM/YYYY(它应该是)以MM/DD/YYYY(这是错误的)改变的格式。如果我在该数据集上再次运行该宏,它将切换回DD/MM/YYYY。但最坏的事情是,如果我手动做同样的事情(例如,而不是运行宏,我手动去“数据”,“文本到列”,并选择相同的选项),然后它不会不会改变。如果日期被格式化为DD/MM/YYYY,则它保持这种方式,并且如果它被格式化为MM/DD/YYYY(由于这个愚蠢的怪癖),那么它也保持这种方式。我重复一遍就足够了(甚至重新录制了这个宏几次),以确定我做了完全相同的事情。

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

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

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

我知道我可以要么中介导入步骤(和格式存在的数据,在主文件代替),然后或者使已经应用在宏只新导入的数据调整代码....但后来我觉得它不可靠,因为我怎么知道Excel不会搞乱格式呢?

哦,因为宏是一个有点神秘看VBA:

我去的数据,文本列,选择“分隔符号”(没关系,因为我并不实际拆分成多列),然后将“Delimiters”作为默认值(无关紧要,实际上我没有将文本拆分为列),然后选择“日期”,然后在下拉菜单中选择“DYM”,以显示DD/MM/YYYY编辑:请罗恩罗森菲尔德的答案详见全文。对于completedness,这里是我将运行导入数据&格式它在导入代码,而不是将其导入,然后格式化:

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

我会尝试使用'DateSerial'函数,结合'For'循环,将原始数据中的特定字符手动分配给月/日/年(使用'Mid','Right','Left '找到每个部分的正确数字)。 – BobbitWormJoe 2014-10-28 04:19:52

+0

你真的只需要两件事:日期作为DateSerial和一个与当前语言环境设置无关的自定义数字格式。我相信你已经拥有了前者。后者是通过明确选择区域来实现的,例如,英语为[[-409美元]日/月/年]。方括号中的数字是要使用的十六进制LCID。 – IInspectable 2014-10-28 09:10:58

回答

2

从你写的,看来你是从文本或CSV文件中获取数据您在Excel中打开OPEN,然后尝试处理日期。一个共同的问题。

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

这种选择应该是数据丝带的获取外部数据选项卡上:

Import Text

我对您正在使用从源到Excel中获取数据的确切过程有点朦胧工作表,但整个过程肯定可以通过VBA实现自动化。并且不应该在已经导入的数据上运行宏。

+0

这就是我最终会做的,非常感谢你的想法。这就是说,从我的角度来看,它仍然没有真正解释为什么从VBA中记录并重新运行的宏与手动执行工作簿中的命令不会产生相同的结果。这应该是(我会认为)记录一个宏的目的,并将它合并到你的代码中。 我爱/讨厌VBA ... – 2014-10-28 18:22:43

+0

@Francky_V我很高兴我的解决方案有效。但是我无法重现您仅在文本格式的日期上使用手动TTC报告的问题。当我尝试它时,我有一些“真实日期”和其他“文本日期”,当手动或通过录制的宏运行时,TTC会改变它们。 – 2014-10-28 19:13:53

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文本,前导零包含在内。

除了格式化它们之外,它不会触及任何实际的日期(即单元的实际值是串行的地方)。

+0

如上所述,我的情况太慢了。另外,您不会明确设置可能导致问题的活动工作表,除非您假设它已经设置在我的代码中的其他位置。我不同意downvote,这是说,这不是一个坏的选择,只是次优的任何大量的数据(我重新投票给你)。 – 2014-10-28 18:32:26

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 
+0

第一个选项在我的情况下不太实际我有太多的数据。第二个选项可能运行得足够快,但我有2个日期列循环。我有数字列,导入允许我自动格式化(与您的选项,我可能必须格式化它们以及安全)。 但谢谢你的答案,对于小问题会很有趣。 – 2014-10-28 18:31:07

0

其实我们在工作中遇到了这个问题。 我们发现解决此问题的最佳方法是确保基础数据中的日期格式为“YYYY/MM/DD”,这样它就可以在美国或正常日期格式中被识别为相同日期,并且它实际上会正确地按照您的区域设置在Excel中输入正确的日期...