Работа с датами — одна из самых частых задач при разработке отчетов и обработок данных в системе 1С:Предприятие 8. Часто требуется отфильтровать данные за текущий год, сгруппировать записи по годам или рассчитать остатки на начало года. Для решения этих задач в языке запросов 1С предназначена функция НАЧАЛОПЕРИОДА.
В этой статье мы подробно разберем, как правильно получить начало года в запросе, рассмотрим синтаксис, примеры использования, типичные ошибки и рекомендации по производительности.
Функция НАЧАЛОПЕРИОДА — базовый синтаксис
Функция возвращает дату, соответствующую началу указанного периода для переданной даты.
НАЧАЛОПЕРИОДА(<Дата>, <Период>) Параметры:
- <Дата>, значение типа
Дата(или поле таблицы/параметр запроса типа Дата), для которого нужно найти начало периода. - <Период> — строковый литерал (ключевое слово), определяющий тип периода. Для получения начала года используется значение ГОД.
Допустимые значения параметра Период:
МИНУТАЧАСДЕНЬНЕДЕЛЯДЕКАДАМЕСЯЦКВАРТАЛПОЛУГОДИЕГОД
Простейший пример: жестко заданная дата
Если в запросе используется литерал даты (например, через функцию ДАТАВРЕМЯ), получение начала года выглядит так:
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(ДАТАВРЕМЯ(2024, 09, 15, 12, 30, 00), ГОД) КАК НачалоГода
ИЗ
Справочник.Номенклатура КАК Номенклатура
// Результат: 2024-01-01 00:00:00 Важно: В языке запросов 1С ключевое слово ГОД пишется без кавычек. Это не строковый литерал, а специальный идентификатор периода.
Работа с параметрами запроса (Best Practice)
В реальных задачах дату обычно передают через параметр запроса. Это позволяет повторно использовать план запроса и защищает от инъекций кода.
Пример кода на встроенном языке (модуль менеджера/формы):
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Продажи.Номенклатура,
| СУММА(Продажи.Сумма) КАК Оборот
|ИЗ
| РегистрНакопления.Продажи КАК Продажи
|ГДЕ
| Продажи.Период МЕЖДУ &НачалоГода И &КонецГода";
Запрос.УстановитьПараметр("НачалоГода", НачалоГода(ТекущаяДата));
Запрос.УстановитьПараметр("КонецГода", КонецГода(ТекущаяДата));
Результат = Запрос.Выполнить; Почему лучше вычислять дату на стороне 1С (функция НачалоГода), а не в запросе?
- Производительность: СУБД (PostgreSQL, MS SQL, Oracle) не может заранее вычислить значение выражения
НАЧАЛОПЕРИОДА(&Дата, ГОД)при построении плана запроса, так как параметр&Датанеизвестен на этапе компиляции. Это может привести к неоптимальному плану (например, сканированию всей таблицы вместо поиска по индексу). - Читаемость: Условие
Период МЕЖДУ &НачалоГода И &КонецГодапозволяет СУБД эффективно использовать индексы по полюПериод.
Группировка данных по годам
Частая задача — построить отчет с группировкой по годам. Здесь НАЧАЛОПЕРИОДА незаменима в секции СГРУППИРОВАТЬ ПО.
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(Продажи.Период, ГОД) КАК ГодПродаж,
Продажи.Номенклатура,
СУММА(Продажи.Сумма) КАК СуммаПродаж
ИЗ
РегистрНакопления.Продажи КАК Продажи
СГРУППИРОВАТЬ ПО
НАЧАЛОПЕРИОДА(Продажи.Период, ГОД),
Продажи.Номенклатура
УПОРЯДОЧИТЬ ПО
ГодПродаж Результат запроса будет содержать строки, сгруппированные по 1 января каждого года (00:00:00), что удобно для вывода в СКД или табличный документ.
Работа с полями составного типа (Ссылки)
Если поле имеет составной тип (например, ДокументСсылка.РеализацияТоваровУслуг или СправочникСсылка.Договоры), прямой вызов НАЧАЛОПЕРИОДА(Поле, ГОД) вызовет ошибку компиляции запроса, так как функция ожидает тип Дата.
Решение: приведение типа через ВЫРАЗИТЬ КАК
Необходимо явно привести поле к типу Дата, зная, что у ссылочных типов есть поле Дата (для документов) или использовать поле даты связанного объекта.
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(ВЫРАЗИТЬ(Документ.Дата КАК ДАТА), ГОД) КАК ГодДокумента
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ Или, если это измерение регистра сведений/накопления, имеющее тип СправочникСсылка (у которого нет поля Дата), группировка по году возможна только через присоединение к справочнику или использование поля регистратора (если это регистр накопления).
Начало года относительно текущей даты (внутри запроса)
Иногда требуется вычислить начало текущего года прямо в тексте запроса, не передавая параметр. Для этого комбинируют ТЕКУЩАЯДАТА (или ДАТАВРЕМЯТЕКУЩАЯ в новых версиях) и НАЧАЛОПЕРИОДА.
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(ТЕКУЩАЯДАТА, ГОД) КАК НачалоТекущегоГода
ИЗ
Справочник.Номенклатура КАК Номенклатура
// Вернет 01.01.ГОД_ТЕКУЩЕЙ_ДАТЫ 00:00:00 Осторожно: Использование
ТЕКУЩАЯДАТАв условии отбора (ГДЕ) может негативно сказаться на производительности по той же причине, что и параметры, СУБД не знает значение заранее. Для отборов лучше передавать вычисленную дату параметром.
Пара функция: КОНЕЦПЕРИОДА
Для закрытия интервала «весь год» используется парная функция КОНЕЦПЕРИОДА.
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(&Дата, ГОД) КАК НачалоГода,
КОНЕЦПЕРИОДА(&Дата, ГОД) КАК КонецГода
// КонецГода = 31.12.ГОД 23:59:59 Это позволяет корректно сформировать условие МЕЖДУ для выборки данных за целый календарный год.
Типичные ошибки и нюансы
- Кавычки вокруг периода: Ошибка:
НАЧАЛОПЕРИОДА(Дата, "ГОД"). Правильно:НАЧАЛОПЕРИОДА(Дата, ГОД). - Тип данных: Передача строки вместо даты. Функция требует строго тип
Дата. ИспользуйтеДАТАВРЕМЯили параметры типа Дата. - Часовые пояса: Результат функции — дата с временем
00:00:00в часовом поясе информационной базы (или сервера БД). При сравнении с полямиПериодрегистров накопления (которые также хранят дату с точностью до секунды в часовом поясе БД) проблем обычно не возникает. - Виртуальные таблицы: При обращении к виртуальным таблицам (например,
Остатки(&НачалоГода, )) параметрНачалоПериодаожидает дату начала периода. ПередачаНачалоГода(Дата)вычисленного на клиенте — единственно верный вариант.
Резюме: чек-лист правильного использования
| Сценарий | Рекомендация |
|---|---|
| Отбор записей за год (ГДЕ) | Вычислить НачалоГода и КонецГода на встроенном языке, передать параметрами. Использовать Период МЕЖДУ &Нач И &Кон. |
| Группировка по годам (СГРУППИРОВАТЬ ПО) | Использовать НАЧАЛОПЕРИОДА(ПолеДаты, ГОД) прямо в запросе. |
НАЧАЛОПЕРИОДА(ПолеДаты, ГОД) или ГОД(ПолеДаты) (если нужно только число года). | |
| Поле составного типа (Ссылка на документ) | НАЧАЛОПЕРИОДА(ВЫРАЗИТЬ(Ссылка.Дата КАК ДАТА), ГОД). |
| Виртуальные таблицы (Остатки/Обороты) | Параметры НачалоПериода/КонецПериода заполнять значениями из функций встроенного языка НачалоГода/КонецГода. |
Функция НАЧАЛОПЕРИОДА(<Дата>, ГОД) — это стандартный и эффективный инструмент языка запросов 1С для работы с годовыми срезами данных. Главное правило профессиональной разработки: вычисляйте границы периодов (начало/конец года) на стороне клиента (встроенный язык) и передавайте их в запрос как параметры типа Дата. Это гарантирует оптимальное использование индексов СУБД и высокую производительность отчетов.
Используйте функцию внутри запроса (в секциях ВЫБРАТЬ, СГРУППИРОВАТЬ ПО) для преобразования дат уже отобранных записей в удобный для анализа формат.