При сохранении печатной формы из 1с в Excel ячейки с датами сохраняются как общий формат. И это никак не изменить настройками макета печатной формы.
Сначала решил сделать задачу с помощью Excel установленного на сервере 1с, но через некоторое время Excel на сервере начал зависать, потому решил отказаться от такой реализации.
Процедура СделатьФорматЯчеекДатаВЕкселе2(ПутьКФайлу) Экспорт
Попытка
Excel = Новый COMОбъект("Excel.Application");
Excel.Visible = Ложь;
Excel.DisplayAlerts = Ложь;
КнигаExcel = Excel.WorkBooks.Open(ПутьКФайлу);
НомерЛиста = 1;
КнигаExcel.Sheets(НомерЛиста).Range(КнигаExcel.Sheets(НомерЛиста).Cells(2,2),КнигаExcel.Sheets(НомерЛиста).Cells(2,3)).NumberFormat = "ДД.ММ.ГГГГ";
КнигаExcel.Sheets(НомерЛиста).Cells(2, 6).NumberFormat = "ДД.ММ.ГГГГ";
КнигаExcel.Sheets(НомерЛиста).Cells(2, 10).NumberFormat = "ДД.ММ.ГГГГ";
КнигаExcel.Save();
КнигаExcel.Close();
Excel.DisplayAlerts = Истина;
Excel.Quit();
Excel = Неопределено;
Исключение
Ошибка = ОписаниеОшибки();
g = 1;
КонецПопытки;
КонецПроцедуры
Решил пойти другим путем.
Файл xlsx - это набор xml-файлов в zip-архиве.
1. Для начала нужно распаковать файл в папку на диске.
ПутьВыгрузки = КаталогВременныхФайлов()+"excel\"+Строка(Новый УникальныйИдентификатор);
Зип = Новый ЧтениеZipФайла;
Зип.Открыть(ПутьКФайлу);
Зип.ИзвлечьВсе(ПутьВыгрузки, РежимВосстановленияПутейФайловZIP.Восстанавливать);
2. Открываем xml и читаем с помощью ПостроительDOM.
ОбъектXML = Новый ЧтениеXML;
ОбъектXML.ОткрытьФайл(ПолныйПуть);
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ОбъектXML);
ОбъектXML.Закрыть();
3. Добавляем новый элемент с описанием формата дата в styles.xml. Также у элемента "cellXfs" в атрибуте "count" нужно увеличить счетчик на 1.
Элементы1 = ДокументDOM.ПолучитьЭлементыПоИмени("cellXfs");
НужныйЭлемент = Элементы1[0];
ИндексXfs = НужныйЭлемент.Атрибуты.ПолучитьИменованныйЭлемент("count").ЗначениеУзла;
НужныйЭлемент.Атрибуты.ПолучитьИменованныйЭлемент("count").ЗначениеУзла=XMLСтрока(Число(ИндексXfs)+1);
Элемент = ДокументDOM.СоздатьЭлемент("xf");
Элемент.УстановитьАтрибут("numFmtId", "14");
Для Каждого Атр Из НужныйЭлемент.ПоследнийДочерний.Атрибуты Цикл
Если Атр.Имя = "borderId" Тогда
Элемент.УстановитьАтрибут("borderId", Атр.Значение);
ИначеЕсли Атр.Имя = "fillId" Тогда
Элемент.УстановитьАтрибут("fillId", Атр.Значение);
ИначеЕсли Атр.Имя = "fontId" Тогда
Элемент.УстановитьАтрибут("fontId", Атр.Значение);
ИначеЕсли Атр.Имя = "applyNumberFormat" Тогда
Элемент.УстановитьАтрибут("applyNumberFormat", Атр.Значение);
ИначеЕсли Атр.Имя = "xfId" Тогда
Элемент.УстановитьАтрибут("xfId", Атр.Значение);
ИначеЕсли Атр.Имя = "applyBorder" Тогда
Элемент.УстановитьАтрибут("applyBorder", Атр.Значение);
КонецЕсли;
КонецЦикла;
НужныйЭлемент.ДобавитьДочерний(Элемент);
Формат определяется по атрибуту numFmtId элемента xf
1 0
2 0.00
3 #,##0
4 #,##0.00
5 $#,##0_);($#,##0)
6 $#,##0_);[Red]($#,##0)
7 $#,##0.00_);($#,##0.00)
8 $#,##0.00_);[Red]($#,##0.00)
9 0%
10 0.00%
11 0.00E+00
12 # ?/?
13 # ??/??
14 m/d/yyyy
15 d-mmm-yy
16 d-mmm
17 mmm-yy
18 h:mm AM/PM
19 h:mm:ss AM/PM
20 h:mm
21 h:mm:ss
22 m/d/yyyy h:mm
37 #,##0_);(#,##0)
38 #,##0_);[Red](#,##0)
39 #,##0.00_);(#,##0.00)
40 #,##0.00_);[Red](#,##0.00)
45 mm:ss
46 [h]:mm:ss
47 mm:ss.0
48 ##0.0E+0
49 @
4. Значение всех текстовых ячеек хранится в файле sharedStrings.xml. Прочитаем все эти значения в переменную элементы_si потом будем получать из этой переменной значения по индексу, который хранится в значении ячейки в файле sheet1.xml.
ОбъектXML2 = Новый ЧтениеXML;
ОбъектXML2.ОткрытьФайл(СтрЗаменить(ПолныйПуть,"worksheets\sheet1","sharedStrings"));
ПостроительDOM2 = Новый ПостроительDOM;
ДокументDOM2 = ПостроительDOM2.Прочитать(ОбъектXML2);
ОбъектXML2.Закрыть();
Элементы_si = ДокументDOM2.ПолучитьЭлементыПоИмени("si");
5. Добавляю ячейки в которых нужно поменять формат в "Соответствие". Ключом в соответствии является номер строки, а значением массив со столбцами.
Находим нужные ячейки на "листе1" в файле sheet1.xml и меняем атрибут "s" на индекс значения формата из файла styles.xml
МассивЯчеек = Новый Массив();
МассивЯчеек.Добавить("B2");
МассивЯчеек.Добавить("C2");
МассивЯчеек.Добавить("F2");
МассивЯчеек.Добавить("J2");
МассивЯчеек2 = Новый Массив();
МассивЯчеек2.Добавить("B3");
МассивЯчеек2.Добавить("C3");
Параметры1 = Новый Соответствие;
Параметры1.Вставить("2", МассивЯчеек);
Параметры1.Вставить("3", МассивЯчеек2);
Элементы1 = ДокументDOM.ПолучитьЭлементыПоИмени("row");
Для Каждого Эл1 Из Элементы1 Цикл
МассивЯчеек = Параметры1.Получить(Эл1.Атрибуты.ПолучитьИменованныйЭлемент("r").ЗначениеУзла);
Если МассивЯчеек <> Неопределено Тогда
Для Каждого Эл2 Из Эл1.ДочерниеУзлы Цикл
Если МассивЯчеек.Найти(Эл2.Атрибуты.ПолучитьИменованныйЭлемент("r").ЗначениеУзла) <> Неопределено Тогда
Эл2.ПервыйДочерний.ТекстовоеСодержимое = XMLСтрока(ПоучитьЧислоЕксель(Дата(Элементы_si[Число(Эл2.ПервыйДочерний.ТекстовоеСодержимое)].ТекстовоеСодержимое+ " 00:00:00")));
Эл2.Атрибуты.УдалитьИменованныйЭлемент("t");
Эл2.Атрибуты.ПолучитьИменованныйЭлемент("s").ЗначениеУзла=ИндексXfs;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЦикла;
6. Переносим значение из файла sharedStrings.xml в значение ячейки непосредственно в файл sheet1.xml.
Но в файле sharedStrings.xml хранится текстовое значение ДД.ММ.ГГГГ, его нужно преобразовать к числу в котором хранится дата в Excel.
Удаляем атрибут "t", который обозначает что нужно искать значение в файле sharedStrings.xml по индексу, который хранился в значении ячейки.
До изменений
после
Эл2.ПервыйДочерний.ТекстовоеСодержимое = XMLСтрока(ПоучитьЧислоЕксель(Дата(Элементы_si[Число(Эл2.ПервыйДочерний.ТекстовоеСодержимое)].ТекстовоеСодержимое+ " 00:00:00")));
Эл2.Атрибуты.УдалитьИменованныйЭлемент("t");
Функция ПоучитьЧислоЕксель(Дата2)
Возврат ((Дата2-'19000101000000')/86400) + 2;
КонецФункции
7. Записываем изменения в файлах и запаковываем все обратно в zip.
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПолныйПуть);
ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокументDOM, ЗаписьXML);
ЗаписьXML.Закрыть();
ЗаписьZIP = Новый ЗаписьZipФайла();
ЗаписьZIP.Открыть(ПутьКФайлу);
ЗаписьZIP.Добавить(ПутьВыгрузки+"\*", РежимСохраненияПутейZIP.СохранятьОтносительныеПути, РежимОбработкиПодкаталоговZIP.ОбрабатыватьРекурсивно);
ЗаписьZIP.Записать();
Процедуры одинаково работают, как на клиенте так и на сервере
Тестировал:
1С:Комплексная автоматизация 2 (2.4.9.98)
Платформа 1С:Предприятие 8.3 (8.3.16.1148)