2014-10-28 3 views
0

Это супер разочаровывает, и для меня это не имеет смысла.Форматирование Даты и региональные настройки Excel VBA

Это в Excel 2010.

Я записал макрос для форматирования некоторых данных, содержащий дату (ДД/ММ/ГГГГ). Я импортирую его, 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, поскольку он выровнен по левому краю (колонка H, и я подтверждаю, что на самом деле):

enter image description here

Затем я запустить макрос, и получить это (колонка H):

enter image description here

Вы можете увидеть Excel рассматривает его как дата, так как она выравнивается по правому краю. Если я преобразую его в «число», я вижу основной сериал, как и ожидалось. Поэтому можно подумать, что все в порядке. Но это действительно не так:

Если я запустил макрос AGAIN (и я бы хотел, потому что позже будет добавлено к нему больше данных, поэтому мне нужно убедиться, что недавно импортированные данные в нижней части будут правильно отформатированы как хорошо), я получаю это:

enter image description here

Так в основном он изменил формат от DD/MM/YYYY (который он должен быть) в MM/DD/YYYY (что неправильно). Если я снова запустил этот макрос в этом наборе данных, он переключится на DD/MM/YYYY.

Но НАСТОЯТЕЛЬНО, что если я ПРОЧИТАЮ ТОЛЬКО то же самое (например, вместо того, чтобы запускать макрос, я вручную перехожу в «Данные», «Текст в столбцы» и выбираю ТОЧНЫЕ одинаковые параметры), тогда он не делает Не меняйте. Если дата отформатирована как DD/MM/YYYY, она остается такой, и если она отформатирована как MM/DD/YYYY (из-за этой глупой причуды), то она остается и в этом случае. Я повторяю это достаточно (и даже повторно записал макрос пару раз), чтобы быть уверенным, что я делаю то же самое.

Я знаю, что это связано с региональными настройками, но файл не всегда будет использоваться на моем компьютере, и я не могу гарантировать, что у конечного пользователя будут какие-либо региональные настройки. Мне нужен этот файл, чтобы быть независимым от региона, в основном.

Мой вопрос: Как я могу убедиться, что эти даты:

  • отформатированный & признан сегодняшний день Excel
  • Independant локальных региональных настроек пользователей?

Я знаю, что могу либо перейти к промежуточному этапу импорта (и форматировать данные там, а не в основном файле), либо затем настроить код так, чтобы только новые импортированные данные применяли макрос .... Но тогда я чувствую, что это ненадежно, потому что, как я знаю, Excel не испортит формат?

О, потому что макросъемки немного загадочно глядя на VBA:

Я иду к данным, текст к колонке, выберите «разделителями» (не имеет значения, потому что я на самом деле не разделить его на столбцы), то «Разделители» по умолчанию (не имеет значения, опять-таки я фактически не разбиваю текст на столбцы), затем «Дата» и в раскрывающемся списке «DYM» для DD/MM/YYYY

EDIT: Please см. ответ Рона Розенфилда для получения полной информации. Для 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

+0

Вам действительно нужны только две вещи: дата как DateSerial и формат пользовательского номера, который не соответствует текущим настройкам локали. Я считаю, что у вас уже есть первая. Последнее достигается путем явного выбора локали, например. '[$ -409] dd/mm/yyyy' для английского. Число в квадратных скобках - это шестнадцатеричный LCID для использования. – IInspectable

ответ

2

Из того, что вы пишете, это, кажется, вы получаете данные из текстового или CSV файла который вы OPEN в Excel, а затем попробуйте обработать дату. Обычная проблема.

Вместо этого, что вы можете сделать, это IMPORT файл. Если вы это сделаете, мастер импорта текста (такой же, как и мастер «текст-столбцы») откроется до того, как данные будут записаны на рабочий лист и предоставит вам возможность указать формат импортируемых дат.

Этот вариант должен быть на вкладке Получить Внешние данные на ленте данных:

Import Text

Я немного туманно о точном процессе, который вы используете, чтобы получить данные из источника в Excel рабочий лист, но весь процесс может быть автоматизирован с помощью VBA. И не должно быть необходимости запускать макрос уже импортированных данных.

+0

Вот что я в итоге сделаю, большое спасибо за эту идею. Это, как говорится, по-прежнему не объясняет, с моей точки зрения, почему макрос, который вы записали и повторно запускаете из VBA, не дает того же результата, что и ручное выполнение команд в книге. Предполагается, что это (я думаю) сама цель записи макроса и включения его в ваш код. Я люблю/ненавижу VBA ... –

+0

@Francky_V Я рад, что мое решение работает. Но я не могу воспроизвести проблему, о которой вы сообщаете в руководстве TTC, только работая с датами форматирования текста. Когда я пытаюсь это сделать, и у меня есть некоторые «реальные даты» и другие «текстовые даты», TTC изменяет как при запуске вручную, так и через ваш записанный макрос. –

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 

Этот код предполагает, что первоначальные исходные данные всегда будут импортированы в виде текста в формате дд/мм/гггг, ведущие нули включены.

Он не будет касаться каких-либо реальных дат (то есть, когда фактическое значение ячейки является последовательным), кроме как для их форматирования.

+0

Как объяснялось выше, слишком медленно в моем случае. Кроме того, вы не устанавливаете активный рабочий лист явно, что может вызвать проблемы, если вы не предполагаете, что он уже установлен где-то еще в моем коде. Я не согласен с downvote, это говорит о том, что это не вариант BAD, просто малооптимальный для любого большого объема данных (я снова вас поддержал). –

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

Первый вариант не практичен в моем случае У меня слишком много данных. Второй вариант, вероятно, будет работать достаточно быстро, хотя у меня есть два столбца даты для циклического перехода. У меня есть столбцы чисел, которые импорт позволяет мне также автоматически форматировать (с вами вариант, который, возможно, придется отформатировать, чтобы быть в безопасности). Но спасибо за ответ, для небольших проблем было бы интересно. –

0

На самом деле у нас была эта проблема довольно много на работе. мы выяснили, что лучший способ обойти эту проблему - убедиться, что даты в базовых данных в формате «ГГГГ/ММ/ДД», таким образом, она признана той же датой в любом американском или нормальном формате даты и он действительно правильно выполнит ваши региональные настройки, чтобы установить правильную дату в Excel ...

Смежные вопросы