В практике разработки на платформе 1С:Предприятие часто встречаются ситуации, когда данные в информационных базах хранятся в не совсем оптимальном виде. Одной из таких задач является хранение периода в виде строки, например, «Январь 2010». При построении отчетов или выполнении расчетов программисту необходимо не только преобразовать эту строку в полноценную дату, но и вычислить на её основе предыдущий или последующий периоды. Разберем пошагово, как решить эту задачу, используя встроенные инструменты платформы.
Прежде чем выполнять математические операции с периодами, нам необходимо перевести строковое значение в тип Дата. Рассмотрим ситуацию, когда у нас есть строка формата «НазваниеМесяца ГГГГ». Для работы нам потребуется разделить эту строку на две части: название месяца и год. Проанализируем алгоритм преобразования.
Для разделения строки мы можем воспользоваться функцией общего модуля или встроенной функцией платформы. В современных конфигурациях на базе 8.3 рекомендуется использовать СтрРазделить. После получения массива подстрок, нам нужно сопоставить название месяца с его порядковым номером (от 1 до 12). Для этого удобнее всего заранее подготовить объект Соответствие.
Рассмотрим пример реализации функции преобразования:
// Создадим соответствие названий месяцев их номерам
НомерМесяцаПоСтроке = Новый Соответствие;
НомерМесяцаПоСтроке.Вставить("Январь", 1);
НомерМесяцаПоСтроке.Вставить("Февраль", 2);
НомерМесяцаПоСтроке.Вставить("Март", 3);
НомерМесяцаПоСтроке.Вставить("Апрель", 4);
НомерМесяцаПоСтроке.Вставить("Май", 5);
НомерМесяцаПоСтроке.Вставить("Июнь", 6);
НомерМесяцаПоСтроке.Вставить("Июль", 7);
НомерМесяцаПоСтроке.Вставить("Август", 8);
НомерМесяцаПоСтроке.Вставить("Сентябрь", 9);
НомерМесяцаПоСтроке.Вставить("Октябрь", 10);
НомерМесяцаПоСтроке.Вставить("Ноябрь", 11);
НомерМесяцаПоСтроке.Вставить("Декабрь", 12);
// Исходная строка
СтрокаМесяца = "Март 2010";
// Разделяем строку по пробелу
МассивЧастей = СтрРазделить(СтрокаМесяца, " ");
Если МассивЧастей.Количество() = 2 Тогда
НазваниеМесяца = МассивЧастей[0];
ГодЧислом = Число(МассивЧастей[1]);
// Получаем номер месяца из нашего соответствия
НомерМесяца = НомерМесяцаПоСтроке.Получить(НазваниеМесяца);
Если НомерМесяца <> Неопределено Тогда
// Формируем дату на начало месяца
ДатаПериода = Дата(ГодЧислом, НомерМесяца, 1);
КонецЕсли;
КонецЕсли;
Когда мы успешно получили объект типа Дата, работа с периодами становится тривиальной задачей благодаря встроенной функции ДобавитьМесяц. Эта функция принимает два параметра: исходную дату и количество месяцев, которое нужно прибавить (или отнять, если число отрицательное).
Рассмотрим подробнее, как получить дату начала предыдущего месяца. Для этого мы вычтем один месяц из нашей полученной даты. Проанализируем следующий фрагмент кода:
// Вычисляем дату предыдущего месяца
ДатаПредыдущегоМесяца = ДобавитьМесяц(ДатаПериода, -1);
// Теперь у нас есть дата, соответствующая 01.02.2010
// Если нужно получить строковое представление обратно:
ПредыдущийМесяцСтрокой = Формат(ДатаПредыдущегоМесяца, "ДФ='MMMM yyyy'");
Важный нюанс: использование функции ДобавитьМесяц гарантирует корректный переход через границы года. Например, если исходная дата была «Январь 2010», функция вернет дату, соответствующую декабрю 2009 года, автоматически уменьшив значение года. Это избавляет разработчика от написания сложных условий с проверкой на первый месяц года.
Если задача стоит не просто в преобразовании одной строки, а в выборке документов за предыдущий месяц непосредственно в запросе, нам следует использовать параметры. Не рекомендуется пытаться парсить строки внутри текста запроса, так как это крайне негативно сказывается на производительности и читаемости кода.
Правильным подходом будет предварительный расчет дат начала и окончания периода в коде на языке 1С и передача их в запрос. Выясним причину: функции НАЧАЛОПЕРИОДА и ДОБАВИТЬКДАТЕ в языке запросов работают гораздо эффективнее с типом Дата, чем любые манипуляции со строками.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Продажи.Ссылка КАК Документ
|ИЗ
| Документ.Продажи КАК Продажи
|ГДЕ
| Продажи.Дата МЕЖДУ &НачалоПериода И &КонецПериода";
// Рассчитываем границы для февраля 2010 (если выбран март)
НачалоПрошлогоМесяца = НачалоМесяца(ДобавитьМесяц(ДатаПериода, -1));
КонецПрошлогоМесяца = КонецМесяца(НачалоПрошлогоМесяца);
Запрос.УстановитьПараметр("НачалоПериода", НачалоПрошлогоМесяца);
Запрос.УстановитьПараметр("КонецПериода", КонецПрошлогоМесяца);
Результат = Запрос.Выполнить();
Проанализируем ситуацию с хранением данных. Хранение месяца строкой («Январь 2010») считается «плохим тоном» в архитектуре 1С по нескольким причинам:
Решение: всегда храните дату (тип Дата), установленную на первое число месяца. Чтобы пользователь видел привычное «Январь 2010», просто настройте формат отображения в поле ввода или колонке списка, используя форматную строку ДФ='MMMM yyyy'. Это позволит выполнять любые операции с периодами мгновенно, без использования промежуточных Соответствий и парсинга строк.
Мы рассмотрели, как преобразовать строковое представление месяца в дату и получить предыдущий период. Посмотрим на основные функции, которые мы использовали:
СтрРазделить — для разбиения строки на значимые части.Соответствие — для связи текстового названия месяца с его числовым кодом.ДобавитьМесяц — основной инструмент для арифметики периодов.НачалоМесяца и КонецМесяца — для определения границ временных интервалов.Используя эти методы, вы сможете гибко управлять периодами в ваших отчетах и обработках, обеспечивая точность данных и корректность расчетов.