При работе с внешними данными, особенно при импорте информации из файлов Excel в систему 1С, разработчики часто сталкиваются с нестандартным поведением при попытке загрузить временные значения. Одной из наиболее распространенных проблем является ситуация, когда время, ожидаемое в формате "ЧЧ:ММ" (например, "9:00"), при считывании из ячейки Excel с помощью COM-объекта внезапно преобразуется в десятичное число (например, 0,375). Эта особенность Excel может поставить в тупик, но, как мы выясним, имеет вполне логичное объяснение и несколько эффективных решений.
Мы подробно рассмотрим, почему Excel так хранит и передает время, и предоставим несколько методов для его корректной загрузки в поля 1С с типом "Дата" и составом "Время".
Прежде чем углубляться в решения, давайте выясним причину такого поведения. Excel хранит даты и время как числовое значение. Полная дата представляет собой количество дней, прошедших с определенной базовой даты (обычно 1 января 1900 года). Время же хранится как доля суток. То есть, если 9:00 утра — это 9 часов из 24, то в десятичном представлении это будет 9/24 = 0,375. Если бы это было 12:00, то это было бы 12/24 = 0,5, и так далее. Это объясняет, почему вы получаете 0,375 вместо "9:00", когда пытаетесь прочитать значение ячейки Excel напрямую через свойство Value.
Итак, когда вы используете конструкцию типа Строка(Лист.Cells(сч, 3).Value), вы фактически запрашиваете числовое значение ячейки и затем пытаетесь преобразовать его в строку, что приводит к получению строкового представления этого числа ("0,375"). Наша задача — либо получить время в его строковом виде сразу, либо правильно преобразовать числовое представление.
Наиболее простой и часто рекомендуемый способ решить эту проблему — это считывать значение ячейки Excel не как число (.Value), а как текст (.Text). Если ячейка в Excel отформатирована как время (например, "ЧЧ:ММ"), то при чтении ее свойства Text вы получите строковое представление времени точно так, как оно отображается в Excel.
.Text для прямого чтения отформатированного значения ячейки.Дата(), указав минимальные значения для года, месяца и дня (например, 1, 1, 1), так как для полей с типом "Время" в 1С важна только временная часть.Давайте посмотрим на пример кода, который демонстрирует этот подход:
// Предположим, что "Лист" - это COM-объект листа Excel
// и "сч" - это текущий номер строки.
// В данном примере мы считываем значение из 3-й колонки.
// 1. Получаем строковое представление времени из ячейки Excel
ЗначениеЯчейкиСтрока = Лист.Cells(сч, 3).Text; // Например, получаем "9:00" или "09:00"
// 2. Проверяем, что строка не пустая, чтобы избежать ошибок
Если ЗначениеЯчейкиСтрока <> "" Тогда
// 3. Разделяем строку по символу двоеточия для получения часов и минут
МассивЧастейВремени = СтрРазделить(ЗначениеЯчейкиСтрока, ":");
// 4. Проверяем, что получили две части (часы и минуты)
Если МассивЧастейВремени.Количество() = 2 Тогда
// 5. Преобразуем строковые части в числа
Часы = Число(МассивЧастейВремени[0]);
Минуты = Число(МассивЧастейВремени[1]);
// 6. Создаем значение типа "Дата" в 1С, указывая только время
// Год, месяц и день устанавливаем на минимальные значения, так как нам нужна только временная часть.
ВремяДля1С = Дата(1, 1, 1, Часы, Минуты, 0); // Результат: Дата, например, 01.01.0001 9:00:00
// Теперь переменная ВремяДля1С содержит корректное значение времени,
// которое можно присвоить полю в таблице 1С.
Сообщить("Успешно загружено время: " + ВремяДля1С);
Иначе
// Обработка ситуации, если формат строки некорректен (например, "9" или "9:00:00")
Сообщить("Ошибка: Некорректный формат времени в ячейке '" + ЗначениеЯчейкиСтрока + "'. Ожидался 'Ч:ММ' или 'ЧЧ:ММ'.");
КонецЕсли;
Иначе
Сообщить("Предупреждение: Ячейка со временем пуста.");
КонецЕсли;
Этот метод является предпочтительным, поскольку он полагается на то, как Excel отображает данные, что часто соответствует нашим ожиданиям.
В некоторых случаях, возможно, вы уже получили числовое значение из Excel (например, через .Value), или по какой-то причине ячейка не отформатирована как время, и .Text возвращает то же число. В такой ситуации нам потребуется выполнить математические преобразования, чтобы получить часы, минуты и секунды из доли суток.
Мы выяснили, что Excel хранит время как долю дня. В одном дне ровно 24 часа, или 86400 секунд (24 * 60 * 60). Следовательно, чтобы получить общее количество секунд, прошедших от начала суток, нам нужно умножить числовое значение из Excel на 86400.
.Value.Дата() с минимальными значениями даты.Рассмотрим пример кода для этого метода:
// Предположим, что "Лист" - это COM-объект листа Excel
// и "сч" - это текущий номер строки.
// В данном примере мы считываем значение из 3-й колонки.
// 1. Получаем числовое значение времени из ячейки Excel
ЗначениеЯчейкиЧисло = Лист.Cells(сч, 3).Value; // Например, получаем 0.375
// 2. Проверяем, что полученное значение является числом
Если ТипЗнч(ЗначениеЯчейкиЧисло) = Тип("Число") Тогда
// 3. Вычисляем общее количество секунд от начала суток
// Умножаем долю суток на общее количество секунд в сутках (24 * 60 * 60 = 86400)
ОбщееКоличествоСекунд = Цел(ЗначениеЯчейкиЧисло * 86400); // 0.375 * 86400 = 32400 секунд
// 4. Выделяем часы: общее количество секунд / количество секунд в часе (3600)
Часы = Цел(ОбщееКоличествоСекунд / 3600); // 32400 / 3600 = 9
// 5. Выделяем минуты: остаток от деления на 3600, затем делим на количество секунд в минуте (60)
Минуты = Цел((ОбщееКоличествоСекунд % 3600) / 60); // (32400 % 3600 = 0) / 60 = 0
// 6. Выделяем секунды: остаток от деления на 60
Секунды = ОбщееКоличествоСекунд % 60; // 0 % 60 = 0
// 7. Создаем значение типа "Дата" в 1С, указывая вычисленные часы, минуты и секунды
ВремяДля1С = Дата(1, 1, 1, Часы, Минуты, Секунды); // Результат: Дата, например, 01.01.0001 9:00:00
Сообщить("Успешно загружено время: " + ВремяДля1С);
Иначе
Сообщить("Ошибка: Значение в ячейке не является числом или пустым.");
КонецЕсли;
Этот метод более гибок, поскольку он работает независимо от форматирования ячейки в Excel, но требует более тщательных вычислений.
Хотя прямое взаимодействие с COM-объектами Excel через Лист.Cells(...) является рабочим решением, в разработке на платформе 1С зачастую более надежным и производительным подходом является использование встроенного объекта "Табличный документ" 1С (ТабличныйДокумент). Этот метод особенно актуален в клиент-серверном режиме, где прямой доступ к COM-объектам на сервере может быть ограничен или вообще невозможен.
Объект ТабличныйДокумент в 1С предоставляет удобные функции для чтения данных из файлов Excel с помощью метода Прочитать(). При чтении через "Табличный документ" система 1С часто уже сама пытается интерпретировать и форматировать значения ячеек. Это означает, что если ячейка в Excel содержит время и отформатирована соответствующим образом, то при чтении ее значения через ТабличныйДокумент.Область(Строка, Колонка).Значение или ТабличныйДокумент.Область(Строка, Колонка).Текст, вы с высокой вероятностью получите уже корректное строковое или даже датовое представление времени.
ТабличныйДокумент.Прочитать(), указывая путь к файлу Excel..Значение или .Текст, мы применяем один из вышеописанных методов (либо парсим строку, либо преобразуем число).Вот как может выглядеть упрощенный пример использования "Табличного документа":
// 1. Создаем новый объект "ТабличныйДокумент"
ТабДок = Новый ТабличныйДокумент;
// 2. Указываем путь к файлу Excel, который нужно загрузить
ПутьКФайлуExcel = "C:\МоиДокументы\ВремяРаботы.xlsx"; // Замените на фактический путь
Попытка
// 3. Загружаем данные из файла Excel
ТабДок.Прочитать(ПутьКФайлуExcel);
// Предположим, время находится в колонке 3, начиная со строки 2
Для НомерСтроки = 2 По ТабДок.ВысотаТаблицы Цикл
// 4. Считываем значение ячейки. Часто ТабличныйДокумент уже предоставляет текст.
// Мы можем попробовать получить как текст, так и значение.
ЗначениеЯчейки = ТабДок.Область(НомерСтроки, 3).Значение; // Попробуем получить значение напрямую
ТекстЯчейки = ТабДок.Область(НомерСтроки, 3).Текст; // Если Значение не подошло, берем текст
ВремяДля1С = Неопределено;
// Если Значение уже вернуло Дату/Время (иногда бывает)
Если ТипЗнч(ЗначениеЯчейки) = Тип("Дата") Тогда
ВремяДля1С = ЗначениеЯчейки;
Сообщить("Время загружено как Дата (ТабличныйДокумент.Значение): " + ВремяДля1С);
// Если Значение вернуло число (долю суток)
ИначеЕсли ТипЗнч(ЗначениеЯчейки) = Тип("Число") Тогда
// Применяем метод 2 для преобразования числа в дату
ОбщееКоличествоСекунд = Цел(ЗначениеЯчейки * 86400);
Часы = Цел(ОбщееКоличествоСекунд / 3600);
Минуты = Цел((ОбщееКоличествоСекунд % 3600) / 60);
Секунды = ОбщееКоличествоСекунд % 60;
ВремяДля1С = Дата(1, 1, 1, Часы, Минуты, Секунды);
Сообщить("Время загружено как Число (ТабличныйДокумент.Значение), преобразовано: " + ВремяДля1С);
// Если Значение не подошло, но Текст содержит "ЧЧ:ММ"
ИначеЕсли ТекстЯчейки <> "" И СтрНайти(ТекстЯчейки, ":") > 0 Тогда
// Применяем метод 1 для парсинга строки
МассивЧастейВремени = СтрРазделить(ТекстЯчейки, ":");
Если МассивЧастейВремени.Количество() = 2 Тогда
Часы = Число(МассивЧастейВремени[0]);
Минуты = Число(МассивЧастейВремени[1]);
ВремяДля1С = Дата(1, 1, 1, Часы, Минуты, 0);
Сообщить("Время загружено как Строка (ТабличныйДокумент.Текст), преобразовано: " + ВремяДля1С);
Иначе
Сообщить("Ошибка обработки времени в строке " + НомерСтроки + ": Некорректный текстовый формат '" + ТекстЯчейки + "'");
КонецЕсли;
Иначе
Сообщить("Предупреждение в строке " + НомерСтроки + ": Не удалось определить формат времени для значения '" + Строка(ЗначениеЯчейки) + "' / текста '" + ТекстЯчейки + "'");
КонецЕсли;
// Здесь вы можете использовать ВремяДля1С для записи в вашу таблицу 1С
// Например: НоваяСтрокаТаблицы.ПолеВремя = ВремяДля1С;
КонецЦикла;
Исключение
Сообщить("Ошибка при чтении файла Excel: " + ОписаниеОшибки());
КонецПопытки;
Мы видим, что использование "Табличного документа" позволяет унифицировать процесс загрузки и, в зависимости от того, как 1С интерпретирует данные, применить соответствующий метод преобразования.
Как мы проанализировали, проблема загрузки времени из Excel в 1С, когда Excel возвращает десятичное число, имеет четкое объяснение в способе хранения времени в Excel. Мы рассмотрели три основных подхода к решению этой задачи:
Выбирая метод, всегда начинайте с попытки получить текстовое представление, если это возможно. Если нет, или если вы имеете дело с неформатированными числовыми значениями, используйте математическое преобразование. Для масштабных или регулярных загрузок отдавайте предпочтение "Табличному документу" 1С. Эти подходы помогут вам успешно загружать временные значения из Excel и корректно отображать их в вашей базе 1С.