При обмене данными между различными системами через текстовые форматы, такие как CSV, одной из наиболее частых проблем становится несовпадение форматов дат. Внутренний стандарт 1С требует определенной структуры (ГГГГММДДччммсс), в то время как в исходном файле дата может быть представлена как 02.12.1977, 1/5/80 или даже в виде числа. В этой статье мы подробно разберем, как преобразовать эти данные, рассмотрим классические и современные методы парсинга, а также обсудим подводные камни, связанные с кодировками и региональными настройками.
Лев(), Прав() и Сред()Рассмотрим ситуацию, когда дата в файле представлена в привычном российском формате ДД.ММ.ГГГГ (например, 02.12.1977). Конструктор Дата() в 1С при передаче строки ожидает формат без разделителей. Проанализируем, как можно «собрать» нужную строку из исходной.
Для этого мы воспользуемся функциями манипуляции строками. Нам нужно извлечь год, месяц и день, а затем соединить их в правильном порядке, добавив время (даже если оно нулевое). Разберем по шагам логику, предложенную нашими коллегами:
Прав(ИсходнаяДата, 4).Сред(ИсходнаяДата, 4, 2).Лев(ИсходнаяДата, 2).Посмотрим на пример кода, который реализует эту логику:
// Предположим, Стр.Дата содержит "02.12.1977"
ИсходнаяДата = Стр.Дата;
Если ЗначениеЗаполнено(ИсходнаяДата) Тогда
// Собираем строку вида "19771202000000"
СтрокаДляПреобразования = Прав(ИсходнаяДата, 4) + Сред(ИсходнаяДата, 4, 2) + Лев(ИсходнаяДата, 2) + "000000";
ИтоговаяДата = Дата(СтрокаДляПреобразования);
КонецЕсли;
Важное замечание: этот метод отлично работает, если вы на 100% уверены в стабильности формата. Однако он «ломается», если в дате отсутствуют ведущие нули (например, 1.5.1980 вместо 01.05.1980), так как позиции символов смещаются.
СтрРазделить() для универсального парсингаЧтобы сделать код более устойчивым к разной длине частей даты, мы рекомендуем использовать функцию СтрРазделить(). Проанализируем ситуацию: части даты разделены точкой. Мы можем разбить строку в массив, и тогда нам не важно, сколько знаков в дне или месяце.
Рассмотрим пример реализации:
ИсходнаяСтрока = "2.12.1977"; // Дата без ведущего нуля
ЧастиДаты = СтрРазделить(ИсходнаяСтрока, ".");
Если ЧастиДаты.Количество() = 3 Тогда
День = Формат(Число(ЧастиДаты[0]), "ЧГ=0; ЧВН=");
Месяц = Формат(Число(ЧастиДаты[1]), "ЧГ=0; ЧВН=");
Год = Формат(Число(ЧастиДаты[2]), "ЧГ=0; ЧВН=");
// Используем конструктор Дата(Год, Месяц, День)
ИтоговаяДата = Дата(Год, Месяц, День);
КонецЕсли;
Этот способ гораздо надежнее, так как он корректно обрабатывает и 02.12.1977, и 2.12.1977.
Если данные в вашем CSV-файле следуют международному стандарту ГГГГ-ММ-ДД, то 1С предоставляет еще более быстрый способ импорта. Выясним, как использовать встроенные механизмы XML для этих целей. Функция XMLЗначение() работает на уровне платформы и крайне эффективно преобразует типизированные данные.
Посмотрим на пример:
// СтрДата в формате "1977-12-02"
ИтоговаяДата = XMLЗначение(Тип("Дата"), СтрДата);
Этот метод считается наиболее производительным при обработке больших массивов данных, но он строго привязан к формату с дефисами.
Иногда встречается совет использовать простую склейку: Дата(Стр.Дата + " 00:00:00"). Мы должны предостеречь вас от этого подхода. Результат выполнения этой функции напрямую зависит от региональных настроек операционной системы.
Если на сервере, где выполняется код, установлены настройки США (MM/DD/YYYY), а в файле данные записаны по-русски (ДД.ММ.ГГГГ), система выдаст ошибку или, что еще хуже, перепутает день с месяцем. Поэтому явный ручной разбор строки, который мы рассмотрели выше, считается «золотым стандартом» для надежных решений.
Часто в CSV-файлах встречаются «пустые» даты. В текстовом виде это может быть пустая строка "" или несколько пробелов. Попытка применить функцию Дата() к такой строке вызовет исключение и остановку программы.
Разберем, как правильно обрабатывать такие случаи:
Если ПустаяСтрока(Стр.Дата) Тогда
НовыйКлиент.ДатаРождения = '00010101'; // Пустая дата в 1С
Иначе
// Тут выполняем один из методов парсинга
КонецЕсли;
Также стоит учитывать специфику Microsoft Excel. Если CSV-файл перед загрузкой открывали и сохраняли в Excel, программа могла автоматически преобразовать даты в числа (количество дней с 1900 года). В таком случае вместо 02.12.1977 в файле окажется число 28461.
Для пересчета такого числа обратно в дату используем следующую формулу:
Дата1С = Дата(1899, 12, 30) + ЧислоИзCSV * 86400;
Где 86400 — это количество секунд в сутках. Обратите внимание на базовую дату 30.12.1899, это связано с особенностями обработки високосных лет в ранних версиях табличных процессоров.
При чтении CSV-файла мы часто сталкиваемся с проблемой BOM (Byte Order Mark). Это невидимые символы в начале файла, которые указывают на кодировку UTF-8. Если начать читать первую строку файла обычным методом, эти символы попадут в первую ячейку (где может быть дата) и функция Лев() вернет мусор.
Чтобы избежать этого, всегда явно указывайте кодировку при открытии файла:
Текст = Новый ЧтениеТекста(ПутьКФайлу, КодировкаТекста.UTF8);
Проанализировав все вышеперечисленные методы, мы видим, что наиболее сбалансированным решением является сочетание проверки на пустое значение и использования функции СтрРазделить(). Это обеспечивает гибкость, надежность и независимость от настроек сервера.