В процессе разработки на платформе 1С:Предприятие 8.3 мы часто сталкиваемся с необходимостью превратить дату в красивую строку для пользователя или внешнего отчета. Для этого существует мощная встроенная функция Формат(). Однако рано или поздно возникает обратная задача: имеется строка, полученная по определенному шаблону (например, "25.12.23" или "2023-12-25"), и нам нужно вернуть ее в тип Дата.
К сожалению, в платформе 1С не предусмотрено прямой функции вроде "Антиформат", которая принимала бы строку и маску формата. Разберем подробно, какие инструменты и подходы мы можем использовать для решения этой задачи, начиная от простых встроенных методов и заканчивая продвинутыми внешними библиотеками.
Прежде чем писать сложные алгоритмы, проанализируем поведение базового конструктора Дата(). Рассмотрим стандартный синтаксис:
// Вариант 1: Канонический формат
МояДата = Дата("20231225000000");
// Вариант 2: Локальный формат (зависит от настроек ОС)
МояДата = Дата("25.12.2023");
Важный нюанс: метод Дата(Строка) крайне капризен. Он понимает либо жесткий стандарт "ГГГГММДДччммсс", либо тот формат, который установлен в региональных настройках Windows на конкретном сервере или компьютере. Если вы передадите строку "25/12/2023" на системе с русским стандартом (где ожидается точка), платформа выдаст ошибку. Поэтому полагаться на этот метод при работе с произвольными форматами нельзя.
Если нам заранее известен формат строки, например "ДФ=dd.MM.yyyy", мы можем самостоятельно "разрезать" строку на части и собрать дату по составляющим. Проанализируем пример реализации такой функции:
Функция СтрокаВДату_РучнойРазбор(Знач СтрокаДаты)
// Допустим, формат всегда "дд.мм.гггг"
ЧастиДаты = СтрРазделить(СтрокаДаты, ".");
Если ЧастиДаты.Количество() <> 3 Тогда
Возврат '00010101'; // Возвращаем пустую дату в случае ошибки
КонецЕсли;
День = Число(ЧастиДаты[0]);
Месяц = Число(ЧастиДаты[1]);
Год = Число(ЧастиДаты[2]);
Попытка
Возврат Дата(Год, Месяц, День);
Исключение
Возврат '00010101';
КонецПопытки;
КонецФункции
Рассмотрим преимущества и недостатки этого метода. Плюс заключается в его полной автономности — код будет работать на любой платформе и в любом режиме. Минус — для каждого нового формата разделителей (тире, слэши, пробелы) придется писать новую логику или усложнять текущую.
Если ваша конфигурация построена на базе БСП (что верно для большинства современных решений вроде ERP, УТ 11 или Бухгалтерии 3.0), мы можем воспользоваться готовым функционалом. В общем модуле СтроковыеФункцииКлиентСервер существует функция СтрокаВДату.
Проанализируем, как она работает. Эта функция пытается распознать дату в строке, используя несколько популярных шаблонов. Она гораздо надежнее стандартного метода Дата(), так как умеет обрабатывать разные разделители и форматы.
// Пример использования БСП
СтрокаДаты = "2023-12-25";
Результат = СтроковыеФункцииКлиентСервер.СтрокаВДату(СтрокаДаты);
Это оптимальный выбор для большинства повседневных задач разработчика 1С, так как он не требует изобретения "велосипеда".
Выясним, как поступить, если формат строки очень специфичный, например "25 числа месяца Декабрь 2023 года". В этом случае на помощь приходят регулярные выражения. Мы можем создать COM-объект, который позволит извлечь только цифры из нужных мест.
Функция ПолучитьДатуИзСложнойСтроки(Знач ВходнаяСтрока)
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.Pattern = "(\d{2}).*?(\d{2}).*?(\d{4})"; // Ищем группы из 2, 2 и 4 цифр
Matches = RegExp.Execute(ВходнаяСтрока);
Если Matches.Count > 0 Тогда
Группы = Matches.Item(0).SubMatches;
День = Число(Группы.Item(0));
Месяц = Число(Группы.Item(1));
Год = Число(Группы.Item(2));
Возврат Дата(Год, Месяц, День);
КонецЕсли;
Возврат '00010101';
КонецФункции
Внимание: данный метод работает только под управлением ОС Windows, так как использует COM-объекты. Он не подойдет для Linux-серверов или работы в веб-клиенте на других ОС.
Для тех, кто ищет максимально точное соответствие вопросу "получить дату по формату", идеальным решением будет использование библиотек .NET через COM. В классе System.DateTime есть метод ParseExact, который принимает строку, маску формата и культуру.
Рассмотрим, как это реализовать в 1С:
Функция Антиформат_Net(Знач СтрокаДаты, Знач МаскаФормата)
// Используем mscorlib для доступа к функциям .NET
ДтПарсер = Новый COMОбъект("System.Globalization.DateTimeFormatInfo");
ДтОбъект = Новый COMОбъект("System.DateTime");
// В .NET форматные строки немного отличаются от 1С (например, yyyy вместо гггг)
// Но логика та же. Это позволяет разобрать строку "25/12/23" по маске "dd/MM/yy"
Попытка
// Для упрощения примера используем упрощенный вызов через посредника
// В реальности потребуется обертка или использование сторонних библиотек
Исключение
// Обработка ошибок
КонецПопытки;
КонецФункции
В ходе обсуждения на форумах иногда проскакивает шуточная, но теоретически рабочая идея: если мы знаем форматную строку (например, "ДФ=dd.MM.yyyy"), мы можем запустить цикл, который будет прибавлять по одному дню к начальной дате (например, с 1900 года), применять к этой дате Формат() и сравнивать результат с нашей строкой.
Функция Антиформат_Перебором(СтрокаДаты, ФорматнаяСтрока)
ТекДата = '19000101';
Пока Формат(ТекДата, ФорматнаяСтрока) <> СтрокаДаты Цикл
ТекДата = ТекДата + 86400; // Прибавляем сутки
// Не забудьте ограничить цикл, чтобы он не стал бесконечным!
КонецЦикла;
Возврат ТекДата;
КонецФункции
Проанализируем ситуацию: этот метод крайне непроизводителен и подходит только для "академических" споров. Для поиска даты за 100 лет программе придется выполнить более 36 000 итераций, что займет значительное время.
При реализации обратного преобразования всегда помните о "деструктивности" формата. Рассмотрим пример: Формат(ТекущаяДата(), "ДФ=MM.yyyy"). Из полученной строки "12.2023" принципиально невозможно восстановить день (он был отброшен). В таких случаях "Антиформат" вернет первое число месяца.
Подведем итоги:
СтроковыеФункцииКлиентСервер.СтрокаВДату из состава БСП.СтрРазделить или Лев/Прав/Сред.ПрочитатьДатуJSON или преобразование через XDTO.Формат() для обратного действия не существует, поэтому выбор метода всегда зависит от конкретной задачи и окружения.