2014-10-28 48 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中輸入正確的日期...