В процессе разработки конфигураций платформы 1С:Предприятие 8 программисты часто сталкиваются с необходимостью работы с временными интервалами. Одной из самых востребованных операций является определение границы отчетного периода. Дата начала месяца необходима для формирования выборок в отчетах, расчета зарплаты, анализа продаж и построения различных аналитических срезов.

Платформа предоставляет встроенные средства для манипуляции с датами, которые позволяют избежать сложных математических вычислений. Использование стандартных функций гарантирует корректность работы алгоритмов даже в високосные годы или при переходе через смену столетий. В этой статье мы детально разберем, как получить первый день текущего или любого другого месяца в коде 1С.

Независимо от того, пишете ли вы код в модуле формы, общем модуле или в запросе, подход к решению задачи остается единым. Однако существуют нюансы использования в различных контекстах исполнения, о которых необходимо знать для создания оптимизированного кода.

Функция НачалоМесяца: основной инструмент разработчика

Главным инструментом для решения поставленной задачи является встроенная функция НачалоМесяца. Она принимает на вход значение типа Дата и возвращает новую дату, соответствующую первому числу месяца, в котором находится исходная дата. Время в возвращаемом значении всегда обнуляется до 00:00:00.

Использование этой функции предпочтительнее ручного конструирования даты через оператор Дата. Функция автоматически учитывает особенности календаря и работает значительно быстрее, так как реализована на уровне ядра платформы. Это особенно важно в циклах с большим количеством итераций.

Рассмотрим простейший пример получения даты начала текущего месяца. Для этого нам сначала нужно получить текущую дату системы, а затем передать её в функцию.

ТекущаяДата = ТекущаяДата;

ДатаНачалаМесяца = НачалоМесяца(ТекущаяДата);

В результате выполнения этого кода переменная ДатаНачалаМесяца будет содержать значение, например, 01.10.2023 00:00:00, если сегодня любое число октября.

💡

Вы можете передать в функцию НачалоМесяца не только переменную, но и сразу вызвать ТекущаяДата, сократив код до одной строки: НачалоМесяца(ТекущаяДата).

Существует также возможность получения начала месяца для произвольной даты, хранящейся в базе данных. Это часто требуется при анализе исторических данных или документов прошлых периодов.

Работа с текущей датой и временем

Частой ошибкой начинающих разработчиков является игнорирование временной составляющей даты. В 1С тип Дата всегда содержит и день, и время. Если вы берете дату из документа, где время может быть 15:30:45, то при передаче её в функцию НачалоМесяца вы все равно получите первое число с нулевым временем.

Однако, если ваша цель — установить границу интервала в запросе, критически важно понимать, что"начало месяца" включает в себя 00 часов 00 минут. Это означает, что при условии Где Дата >= НачалоМесяца(Период) в выборку попадут все документы, созданные в 00:00:00 первого числа.

  • 📅 Функция НачалоМесяца всегда сбрасывает время в ноль.
  • ⏱ Для получения конца месяца существует парная функция КонецМесяца, которая устанавливает время 23:59:59.
  • 🔄 Комбинация этих функций позволяет легко сформировать замкнутый интервал для отчета.

Иногда требуется получить дату начала месяца не для текущей даты, а для даты, сдвинутой на определенный интервал. Например, нам нужно начало месяца год назад. Для этого сначала выполняется сдвиг даты, а затем вычисляется граница месяца.

ДатаГодНазад = ДобавлениеМесяца(ТекущаяДата, -12);

НачалоМесяцаГодНазад = НачалоМесяца(ДатаГодНазад);

Такой подход обеспечивает гибкость при формировании динамических отчетов, где пользователь может выбирать произвольные периоды сравнения.

📊 Как часто вы используете функции работы с датой в 1С?
Ежедневно
Раз в неделю
Только при написании отчетов
Редко, использую готовые обработки

Использование в языке запросов 1С

Язык запросов 1С имеет свой синтаксис для работы с датами, который во многом повторяет встроенный язык программирования. Функция НАЧАЛОПЕРИОДА (или её синонимы в разных версиях, но чаще используется именно логика начала периода) позволяет фильтровать данные непосредственно на уровне СУБД.

В запросах важно использовать параметры, чтобы избежать инъекций и обеспечить перекомпиляцию запроса только при изменении структуры, а не значений. Передача даты начала месяца как параметра является лучшей практикой.

Ниже приведен пример формирования запроса, выбирающего документы, созданные с начала текущего месяца.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| РеализацияТоваровУслуг.Ссылка,

| РеализацияТоваровУслуг.Дата

|ИЗ

| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг

|ГДЕ

| РеализацияТоваровУслуг.Дата >= &НачалоПериода";

Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДата));

Результат = Запрос.Выполнить;

Использование такой конструкции гарантирует, что база данных воспользуется индексом по полю Дата, что существенно ускорит выполнение запроса на больших объемах данных.

💡

Всегда передавайте вычисленную дату начала месяца в запрос как параметр. Это позволяет оптимизатору запросов эффективно использовать индексы таблиц.

Не рекомендуется вычислять дату начала месяца прямо в тексте запроса с помощью вложенных функций, если это возможно, так как это может усложнить чтение кода и отладку. Однако синтаксис запросов 1С поддерживает функцию НАЧАЛОМЕГАСЯЦА (в зависимости от версии платформы и, но стандартно — логика та же).

Обработка пользовательского ввода и форм

При разработке форм часто возникает ситуация, когда пользователь вручную вводит дату в поле ввода. Значение может быть неполным или содержать время, которое не важно для отчета. В таких случаях необходимо нормализовать введенные данные перед использованием.

Если пользователь ввел дату 15.10.2023, а отчет должен строиться за октябрь, вам нужно программно заменить введенное значение на 01.10.2023. Это можно сделать в обработчике события изменения поля или перед записью данных в регистр.

⚠️ Внимание: При получении даты из элементов формы всегда проверяйте значение на пустоту. Функция НачалоМесяца не может быть применена к неопределенному значению (Null), что вызовет ошибку выполнения.

Для безопасной обработки используйте проверку типа или значения перед вызовом функции.

Если Не ПустаяДата(ВыбраннаяДата) Тогда

ДатаДляОтчета = НачалоМесяца(ВыбраннаяДата);

Иначе

ДатаДляОтчета = НачалоМесяца(ТекущаяДата);

КонецЕсли;

Такой подход делает интерфейс более дружелюбным и предотвращает аварийное завершение работы приложения при некорректных действиях пользователя.

☑️ Проверка даты перед расчетом

Выполнено: 0 / 4

Сравнение методов вычисления даты

Существует несколько способов получить первое число месяца. Помимо стандартной функции, некоторые разработчики используют арифметические операции или конструктор дат. Давайте сравним их эффективность и читаемость.

Первый метод — использование функции НачалоМесяца. Это наиболее предпочтительный вариант. Второй метод — ручное создание даты через Дата(Год(Д), 1, 1). Третий метод — вычитание дней, что является самым ненадежным способом из-за разной длины месяцев.

В таблице ниже приведено сравнение различных подходов к решению задачи.

Метод Код Надежность Читаемость
Стандартная функция НачалоМесяца(Д) Высокая Отличная
Конструктор даты Дата(Год(Д), Месяц(Д), 1) Высокая Средняя
Арифметика дней Д - День(Д) + 1 Средняя Низкая
Строка + Преобразование ДатаВремя(Строка(Год(Д)) +"." +"01") Низкая Плохая

Как видно из таблицы, использование встроенной функции выигрывает по всем параметрам. Арифметические методы могут дать сбой на границах месяцев или при работе с високосными годами, если логика написана некорректно.

Почему арифметический метод опасен?

Выражение Д - День(Д) + 1 работает корректно в большинстве случаев, но если переменная Д содержит время, отличное от 00:00:00, результат может сместиться на предыдущий день из-за особенностей вычитания временных интервалов.

Типичные ошибки и способы их устранения

При работе с датами в 1С разработчики часто допускают ошибки, связанные с типами данных и часовыми поясами. Особенно это актуально для веб-клиента и распределенных информационных баз.

Одна из распространенных проблем — несоответствие даты сервера и даты клиента. Функция ТекущаяДата возвращает время сервера 1С. Если сервер находится в другом часовом поясе, начало месяца может наступить для сервера раньше или позже, чем для пользователя.

  • 🌍 Учитывайте часовой пояс сервера при критичных к времени расчетах.
  • 💻 В тонком клиенте используйте ТекущаяДатаСеанса, если нужна локальная дата пользователя.
  • ⚙️ Проверьте настройки региональных стандартов в конфигурации.

Еще одна ошибка — попытка записать дату начала месяца в реквизит, имеющий тип Строка. Хотя 1С обладает механизмом автоматического приведения типов, это приводит к потере возможности корректного сравнения дат и сортировки в будущем.

⚠️ Внимание: Никогда не храните даты в строковых полях для последующих вычислений. Это нарушает целостность данных и усложняет поддержку конфигурации. Всегда используйте тип Дата.

Также стоит помнить о производительности. Вызов функции НачалоМесяца внутри цикла по большой таблице значений может замедлить работу. Лучше вынести вычисление за пределы цикла, если дата периода не меняется.

💡

Если вам нужно получить начало месяца для каждой строки таблицы значений, используйте вычисляемое поле или обработайте таблицу одним запросом через временную таблицу, а не циклом в коде 1С.

Часто задаваемые вопросы (FAQ)

Как получить дату начала предыдущего месяца?

Для этого нужно сначала вычесть один месяц из текущей даты, а затем взять начало месяца от полученного результата. Пример кода: НачалоМесяца(ДобавлениеМесяца(ТекущаяДата, -1)).

Можно ли использовать функцию НачалоМесяца в условии отбора СКД?

Да, в системах компоновки данных (СКД) можно использовать эту функцию в выражениях отборов. Синтаксис будет аналогичен языку запросов: НачалоПериода(&Период,"Месяц") или прямое использование функции в зависимости от версии платформы.

Что вернет функция, если передать ей дату 1-го числа?

Функция вернет ту же самую дату (с обнуленным временем). Она является идемпотентной для дат, которые уже являются началом месяца.

Как получить начало месяца в запросе без параметров?

В тексте запроса можно написать: ГДЕ Дата >= НАЧАЛОМЕГАСЯЦА(&Период). Однако использование параметров предпочтительнее для производительности и безопасности.

Влияет ли календарь (производственный) на работу функции НачалоМесяца?

Нет, функция работает исключительно с календарной датой. Она не учитывает производственные календари, праздники или переносы выходных. Для работы с рабочими днями нужны отдельные механизмы.