Работа с датами — одна из самых частых задач при программировании в 1С:Предприятие. Определение текущего месяца может понадобиться для формирования отчетов, фильтрации данных, автоматизации расчетов зарплаты или анализа продаж по периодам. Казалось бы, простая операция, но даже здесь есть нюансы: разница между ТекущейДатой() и РабочейДатой(), учет временных зон при работе с сервером, или необходимость получить не просто номер месяца, а его название на русском языке.
В этой статье мы разберем все актуальные способы получения текущего месяца в 1С 8.3 и 8.2, включая редко документированные приемы для специфических задач. Вы узнаете, как избежать типичных ошибок (например, когда функция возвращает не тот месяц из-за неверного формата даты), как работать с многопользовательскими базами, и почему иногда лучше использовать НачалоМесяца() вместо прямого извлечения номера. Материал будет полезен как начинающим разработчикам, так и опытным программистам, столкнувшимся с неочевидными багами при работе с календарем.
1. Базовый способ: функция ТекущаяДата()
Самый простой и универсальный метод — использование встроенной функции ТекущаяДата(). Она возвращает текущие дату и время с учетом системных настроек сервера или клиента (в зависимости от контекста выполнения). Чтобы извлечь из этой даты номер месяца, используйте метод Месяц():
ТекущийМесяц = ТекущаяДата().Месяц();
Этот код вернет число от 1 до 12, где 1 — январь, а 12 — декабрь. Важно помнить, что:
- 📅 Функция зависит от временной зоны сервера 1С (если код выполняется на сервере) или локального компьютера (при клиентском выполнении).
- ⚡ В многопользовательских базах все клиенты получат одинаковый результат, если код выполняется на сервере.
- 🔄 Если вам нужно название месяца (например, "Июнь"), потребуется дополнительная обработка (см. раздел 4).
Пример использования в реальном коде:
Если ТекущаяДата().Месяц() = 12 Тогда
Сообщить("Сейчас декабрь — пора готовить годовой отчет!");
КонецЕсли;
⚠️ Внимание: В управляемых формах функция ТекущаяДата() на клиенте может возвращать время с учетом локальных настроек пользователя, что приведет к расхождениям с серверным временем. Для критичных операций всегда используйте серверный контекст.
2. Рабочая дата vs Текущая дата: в чем разница?
Многие разработчики путают ТекущаяДата() и РабочаяДата(). Последняя возвращает дату, установленную в настройках 1С:Предприятия как "рабочую" (например, для тестирования отчетов за прошлые периоды). Это критично для бухгалтерских задач, где требуется эмуляция исторических данных.
Чтобы получить месяц из рабочей даты:
МесяцРабочейДаты = РабочаяДата().Месяц();
Ключевые отличия:
| Функция | Источник данных | Применение | Зависит от пользователя? |
|---|---|---|---|
ТекущаяДата() |
Системное время | Реальные операции (например, создание документа "сейчас") | Да (если клиентский контекст) |
РабочаяДата() |
Настройки 1С | Тестирование, отчеты за прошлые периоды | Нет |
НачалоМесяца() |
Любая переданная дата | Периодические расчеты (зарплата, налоги) | Зависит от входного параметра |
Пример, когда важно использовать РабочаяДата():
// Проверяем, что отчет формируется за текущий рабочий месяц
Если РабочаяДата().Месяц() <> ТекущаяДата().Месяц() Тогда
Предупреждение("Внимание! Рабочая дата не совпадает с текущей!");
КонецЕсли;
3. Получение месяца для произвольной даты
Если вам нужно извлечь месяц не из текущей даты, а из произвольной (например, даты документа или поля в базе), используйте тот же метод .Месяц(), но применительно к переменной типа Дата:
ДатаДокумента = Документы.ЗаказПокупателя.Даты.Дата;
МесяцДокумента = ДатаДокумента.Месяц();
Типичные сценарии:
- 📊 Фильтрация отчетов по месяцу создания документа.
- 💰 Расчет зарплаты за конкретный месяц.
- 📦 Анализ складских остатков по периодам.
Важный нюанс: если дата хранится в строковом формате (например, в файле обмена), сначала преобразуйте её в тип Дата:
СтрокаДаты = "2026-06-15";
ДатаИзСтроки = Дата(СтрокаДаты);
Месяц = ДатаИзСтроки.Месяц();
⚠️ Внимание: При парсинге строковых дат учитывайте региональные настройки 1С. Формат "ГГГГ-ММ-ДД" универсален, но "ДД.ММ.ГГГГ" может интерпретироваться некорректно в некоторых конфигурациях.
Используется ли тип Данные.Дата (не строка)?|Учтена ли временная зона при серверных вызовах?|Проверены ли граничные случаи (1 января, 31 декабря)?|Документированы ли различия между ТекущейДатой и РабочейДатой?-->
4. Как получить название месяца (не номер)
Часто требуется вывести не номер месяца (1–12), а его название на русском языке (например, "Июнь"). Для этого в 1С есть функция Формат() с параметром форматирования "ММММ":
НазваниеМесяца = Формат(ТекущаяДата(), "ММММ"); // Вернет "июнь"
НазваниеМесяцаСЗаглавной = СтрЗаменить(Формат(ТекущаяДата(), "ММММ"), "и", "И"); // "Июнь"
Другие варианты форматирования:
- 🔢
"ММ"— номер месяца с ведущим нулем (01–12). - 🔤
"МММ"— краткое название (янв, фев, мар). - 📅
"ММММ"— полное название (январь, февраль).
Пример использования в отчете:
ЗаголовокОтчета = "Отчет по продажам за " + Формат(ТекущаяДата(), "ММММ yyyy");
Сообщить(ЗаголовокОтчета); // "Отчет по продажам за июнь 2026"
Как локализовать названия месяцев для других языков?
Для многоязычных баз используйте функцию НСтр() с указанием языка:
НазваниеНаАнглийском = НСтр("ru = 'ММММ'; en = 'MMMM'", ТекущаяДата());
Это вернет название месяца на языке интерфейса текущего пользователя.
5. Работа с началом и концом месяца
Для многих задач (например, расчета зарплаты или закрытия месяца в бухучете) важно получить не просто номер месяца, а дату его начала или окончания. В 1С для этого есть специализированные функции:
НачалоТекущегоМесяца = НачалоМесяца(ТекущаяДата()); // 01.06.2026 00:00:00
КонецТекущегоМесяца = КонецМесяца(ТекущаяДата()); // 30.06.2026 23:59:59
Практическое применение:
- 📈 Фильтрация данных в запросах по диапазону дат.
- 💼 Автоматическое создание документов на начало/конец месяца (например, начисление аванса).
- 📊 Сравнение периодов (текущий месяц vs предыдущий).
Пример запроса с использованием НачалоМесяца():
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Сумма(Документ.Сумма) КАК Итого
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Документ
|ГДЕ
| Документ.Дата МЕЖДУ &НачалоПериода И &КонецПериода";
Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДата()));
Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДата()));
⚠️ Внимание: ФункцияКонецМесяца()возвращает последний момент последнего дня (23:59:59). Если вам нужна дата без времени, используйтеНачалоДня(КонецМесяца(ТекущаяДата())).
ДнейВМесяце = КонецМесяца(ТекущаяДата()).День();
Это актуально для расчета дневной зарплаты или амортизации.-->
6. Типовые ошибки и как их избежать
Даже опытные разработчики иногда сталкиваются с неочевидными багами при работе с месяцами в 1С. Вот самые распространенные ловушки:
- Путаница с временными зонами: Если сервер и клиент находятся в разных часовых поясах,
ТекущаяДата()может вернуть разные результаты. Решение — всегда использовать серверный контекст для критичных операций. - Неучет рабочей даты: Забывают, что
РабочаяДата()может отличаться от текущей, из-за чего отчеты формируются не за тот период. - Ошибки при парсинге строк: Попытка извлечь месяц из строки без преобразования в тип Дата приводит к ошибкам или некорректным результатам.
- Граничные даты: Код ломается на 1 января или 31 декабря из-за неверной обработки перехода между годами.
Пример кода с потенциальной ошибкой:
// ОШИБКА: если ДатаВСтроке = "31.12.2023", то Месяц будет 12, но год — 2023
СтрокаДаты = "31.12.2023";
Месяц = Сред(СтрокаДаты, 4, 2); // "12" — но это строка, а не число!
Правильный вариант:
ДатаИзСтроки = Дата(СтрокаДаты);
Месяц = ДатаИзСтроки.Месяц(); // 12 (число)
Всегда проверяйте тип данных перед извлечением месяца. Если переменная не является Датой, сначала преобразуйте её с помощью функции Дата().
7. Продвинутые приемы: месяц в запросах и динамические периоды
Для сложных отчетов часто требуется получить месяц непосредственно в тексте запроса. В языке запросов 1С есть специальные функции:
Запрос.Текст =
"ВЫБРАТЬ
| МЕСЯЦ(Документ.Дата) КАК НомерМесяца,
| СУММА(Документ.Сумма) КАК Итого
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Документ
|СГРУППИРОВАТЬ ПО
| МЕСЯЦ(Документ.Дата)";
Другие полезные функции в запросах:
- 📅
НАЧАЛОПЕРИОДА(, "МЕСЯЦ")— начало месяца для каждой записи. - 🔙
ГОД()— извлечение года (полезно для группировки по годам и месяцам). - 📊
ДЕНЬ()— день месяца (например, для анализа пиковых продаж).
Пример динамического формирования периода "с начала месяца по сегодня":
НачалоПериода = НачалоМесяца(ТекущаяДата());
КонецПериода = ТекущаяДата();
Запрос.Текст =
"ВЫБРАТЬ
| Документ.Номер КАК НомерДокумента
|ИЗ
| Документ.ПоступлениеТоваров КАК Документ
|ГДЕ
| Документ.Дата МЕЖДУ &Начало И &Конец";
Запрос.УстановитьПараметр("Начало", НачалоПериода);
Запрос.УстановитьПараметр("Конец", КонецПериода);
Часто задаваемые вопросы
Как получить месяц на английском языке?
Используйте функцию НСтр() с указанием языка:
МесяцНаАнглийском = НСтр("ru = 'ММММ'; en = 'MMMM'", ТекущаяДата());
Это вернет название месяца на языке интерфейса текущего пользователя. Для принудительного выбора языка укажите его явно, например: НСтр("en = 'MMMM'", ТекущаяДата()).
Почему ТекущаяДата().Месяц() возвращает неверный месяц?
Наиболее вероятные причины:
- Код выполняется на клиенте, а системное время пользователя отличается от серверного.
- В базе установлена рабочая дата, отличная от текущей (проверьте
РабочаяДата()). - Переменная, из которой извлекается месяц, не является типом Дата (например, строка в неверном формате).
Решение: используйте серверные процедуры для критичных операций и проверяйте типы данных.
Как получить месяц в формате "01" (с ведущим нулем)?
Используйте функцию Формат() с параметром "ММ":
МесяцСНулем = Формат(ТекущаяДата(), "ММ"); // "06" для июня
Альтернативно можно использовать СтрДлина():
Месяц = ТекущаяДата().Месяц();
МесяцСНулем = ?(СтрДлина(Месяц) = 1, "0" + Месяц, Месяц);
Можно ли получить месяц для даты в будущем?
Да, никаких ограничений нет. Просто передайте нужную дату в функцию:
БудущаяДата = Дата(2026, 12, 31);
Месяц = БудущаяДата.Месяц(); // 12
Это полезно для планирования или тестирования сценариев на будущие периоды.
Как сравнить месяцы двух разных дат?
Сравнивайте числовые значения, извлеченные через .Месяц():
Дата1 = Дата(2026, 6, 15);
Дата2 = Дата(2026, 7, 10);
Если Дата1.Месяц() < Дата2.Месяц() Тогда
Сообщить("Июнь раньше июля");
КонецЕсли;
Для сравнения с учетом года используйте полную дату или функцию НачалоМесяца().