Как вывести название месяца в нужном падеже в 1С
Содержание
Именительный падеж («Январь») даёт формат Формат(Дата, "ДФ=ММММ"). Родительный («января»), который нужен в заголовках вида «за январь 2024», встроенной функции напрямую не отдаёт — его берут из длинной даты Формат(Дата, "ДЛФ=DD") или из своего массива названий.
Разница упирается в одну вещь: токен ММММ в платформе всегда выдаёт месяц в именительном падеже. Поэтому «просклонять месяц» — это либо разобрать строку длинной даты, либо держать 12 названий в нужном падеже и обращаться к ним по номеру месяца. Ниже — оба способа, вывод в запросах и СКД, переключение языка и места, где чаще всего ошибаются.
Встроенные форматы даты: что выдаёт платформа
Функция Формат принимает дату и форматную строку. Для месяца важны два параметра: ДФ (своя форматная строка) и ДЛФ (предопределённый формат).
НазваниеМесяца = Формат('20240115', "ДФ=ММММ"); // "Январь"
КороткоеНазвание = Формат('20240115', "ДФ=МММ"); // "янв"
НомерБезНуля = Формат('20240115', "ДФ=М"); // "1"
НомерМесяца = Формат('20240115', "ДФ=ММ"); // "01"
ДатаПрописью = Формат('20240115', "ДЛФ=DD"); // "15 января 2024 г."
Токены месяца в ДФ отличаются числом букв:
| Токен | Результат для января | Что это |
|---|---|---|
М | 1 | номер без ведущего нуля |
ММ | 01 | номер с ведущим нулём |
МММ | янв | сокращённое название |
ММММ | Январь | полное название, именительный |
Предопределённые форматы ДЛФ задают готовый вид даты целиком: D — короткая (15.01.2024), DD — длинная (15 января 2024 г.), DT — дата и время, DL — дата с днём недели прописью. Из них родительный падеж месяца несёт только DD и DL.
Токены пишутся без одинарных кавычек. Если обернуть ДФ='ММММ', платформа поймёт это как литерал и вернёт буквально текст «ММММ». Одинарные кавычки — только для своего текста внутри строки: "ДФ='за' ММММ yyyy".
Ключевой момент: ММММ — всегда именительный падеж с заглавной буквы. Внутри предложения это выглядит криво («отчёт за Январь»), поэтому первую букву обычно переводят в нижний регистр:
м = Формат(Дата, "ДФ=ММММ");
м = НРег(Лев(м, 1)) + Сред(м, 2); // "январь"
Обратная задача — поднять первую букву, когда месяц стоит в начале строки, — решается функцией ВРег тем же приёмом: ВРег(Лев(м, 1)) + Сред(м, 2). Целиком через ВРег() или НРег() строку обрабатывать не нужно: это испортит остальные буквы.
А вот родительный падеж ММММ не умеет. Именно здесь выручает ДЛФ=DD — длинная дата, где месяц уже стоит в родительном. Из неё можно вырезать нужное слово.
Названия месяцев массивом, когда нужен точный падеж
Если вам нужно только название месяца в родительном (или другом) падеже без числа и года, самый предсказуемый путь — свой массив. Он не зависит от текущего языка интерфейса и работает одинаково на любой платформе.
Функция МесяцРодительный(Дата)
Названия = СтрРазделить(
"января,февраля,марта,апреля,мая,июня,июля,августа,"
+ "сентября,октября,ноября,декабря", ",");
Возврат Названия[Месяц(Дата) - 1];
КонецФункции
Функция Месяц() возвращает число от 1 до 12, поэтому индекс в массиве — на единицу меньше. Это самое частое место ошибки: массив с индексацией от нуля и месяц от единицы.
Второй вариант — разобрать длинную дату, не заводя свой словарь:
Части = СтрРазделить(Формат(Дата, "ДЛФ=DD"), " ");
МесяцРод = Части[1]; // из "15 января 2024 г." берём "января"
Разбор длинной даты короче по коду, но у него есть минус: он зависит от языка сеанса и даёт только родительный падеж. Если в проекте месяц нужен в нескольких падежах (родительный для «за январь», дательный для «к февралю», предложный для «в марте»), удобнее держать один справочник с несколькими строками:
Функция ИмяМесяца(Дата, Падеж = "Р")
Склонения = Новый Соответствие;
Склонения.Вставить("И", "Январь,Февраль,Март,Апрель,Май,Июнь,"
+ "Июль,Август,Сентябрь,Октябрь,Ноябрь,Декабрь");
Склонения.Вставить("Р", "января,февраля,марта,апреля,мая,июня,"
+ "июля,августа,сентября,октября,ноября,декабря");
Склонения.Вставить("Д", "январю,февралю,марту,апрелю,маю,июню,"
+ "июлю,августу,сентябрю,октябрю,ноябрю,декабрю");
Склонения.Вставить("П", "январе,феврале,марте,апреле,мае,июне,"
+ "июле,августе,сентябре,октябре,ноябре,декабре");
Строка = Склонения.Получить(Падеж);
Если Строка = Неопределено Тогда
Строка = Склонения.Получить("Р");
КонецЕсли;
Названия = СтрРазделить(Строка, ",");
Возврат Названия[Месяц(Дата) - 1];
КонецФункции
Такую функцию выносят в общий модуль, доступный на клиенте и сервере, и вызывают из форм, печатных макетов и вычисляемых полей. Падеж передают буквой: И — именительный, Р — родительный, Д — дательный, П — предложный. Это закрывает все случаи, где встроенный формат бессилен.
Какой способ выбрать — зависит от задачи.
Формат(Дата, "ДЛФ=DD") — платформа сама поставит падеж и добавит «г.».Месяц(Дата) - 1.Формат(Дата, "ДФ=ММММ") с переводом первой буквы в нижний регистр.Месяц в заголовках отчётов «за январь»
В отчётах чаще всего нужен родительный падеж: «Оборотно-сальдовая ведомость за январь 2024». Если период задан одной датой внутри месяца, собрать заголовок можно так:
Заголовок = "Отчёт за " + МесяцРодительный(ДатаОтчёта)
+ " " + Формат(Год(ДатаОтчёта), "ЧГ=0") + " г.";
Год соединяйте через Формат(..., "ЧГ=0"). Иначе ЧислоВСтроку подставит разделитель групп и получится «2 024».
Когда период задаётся началом и концом (стандартный реквизит отчёта на СКД), название месяца берут от даты начала периода. Но сперва стоит проверить, что начало и конец лежат в одном месяце:
Если НачалоМесяца(ДатаНачала) = НачалоМесяца(ДатаКонца) Тогда
Заголовок = "за " + ИмяМесяца(ДатаНачала)
+ " " + Формат(Год(ДатаНачала), "ЧГ=0");
Иначе
Заголовок = "с " + Формат(ДатаНачала, "ДЛФ=D")
+ " по " + Формат(ДатаКонца, "ДЛФ=D");
КонецЕсли;
Если период охватывает несколько месяцев, одного названия уже мало — выводится диапазон дат целиком. Это частая недоработка: заголовок склоняет только первый месяц, а отчёт при этом собран за квартал.
Для оформления периода в компоновке есть поле НачалоПериода / КонецПериода стандартного периода — его удобно пропустить через ту же функцию склонения в макете заголовка.
В печатных формах на табличном документе заголовок с месяцем задают параметром области. В макете пишут параметр, например Период, а в модуле заполняют его готовой просклонённой строкой перед выводом области. Так название месяца один раз собирается в коде и аккуратно встаёт в шапку документа.
Склонение месяца в запросах и СКД
В языке запросов форматирование делает та же функция ФОРМАТ с теми же токенами:
ВЫБРАТЬ
ФОРМАТ(ПродажиОбороты.Период, "ДФ=ММММ") КАК МесяцИмен,
ФОРМАТ(ПродажиОбороты.Период, "ДЛФ=DD") КАК ДатаПрописью
ИЗ
РегистрНакопления.Продажи.Обороты КАК ПродажиОбороты
В форматную строку запроса можно вставлять и свой текст — он так же оборачивается одинарными кавычками:
ФОРМАТ(ПродажиОбороты.Период, "ДФ='Итоги за' ММММ гггг") КАК Подпись
Ограничение то же, что в коде: ММММ в запросе — именительный падеж. Родительный в чистом виде запрос не даёт. Если нужен именно он, есть два подхода:
- Вывести
ДЛФ=DDи разобрать строку уже на выходе — в модуле или в поле СКД. - Не склонять в запросе вовсе, а собрать подпись в вычисляемом поле компоновки.
В СКД название месяца удобно считать вычисляемым полем. В выражении поля работает функция Формат, а для своих падежей — общий модуль с функцией-словарём, если она объявлена доступной на сервере и для компоновки.
| Где считаем | Чем склоняем | Что получаем |
|---|---|---|
| Модуль (встроенный язык) | Формат + свой массив | любой падеж |
| Запрос | ФОРМАТ(..., "ДФ=ММММ") | именительный |
| Запрос | ФОРМАТ(..., "ДЛФ=DD") | дата с родительным |
| Вычисляемое поле СКД | Формат или функция общего модуля | любой падеж |
Группировать данные по месяцу лучше по самой дате (началу месяца), а название подставлять отдельным полем для вывода. Если группировать по тексту «январь», порядок строк станет алфавитным, а не хронологическим: «август» окажется выше «января».
Чтобы и группировать по месяцу, и выводить название, в запросе оставляют два поля: НачалоПериода(Дата, "Месяц") для группировки и сортировки, а название считают отдельно. В настройках СКД по полю-дате задают порядок «по возрастанию», а текстовое название выводят ресурсом или вычисляемым полем. Тогда строки идут хронологически, а в шапке стоит правильно просклонённый месяц.
Разные языки: локаль в форматной строке
Название месяца зависит от языка. Внутри форматной строки язык задаётся параметром Л= (локаль):
Рус = Формат(Дата, "ДФ=ММММ; Л=ru_RU"); // "Январь"
Англ = Формат(Дата, "ДФ=ММММ; Л=en_US"); // "January"
Код локали — это пара «язык_страна»: ru_RU, en_US, uk_UA, be_BY. Можно указать только язык (ru, en) — платформа подставит страну по умолчанию. Тот же параметр работает и в запросе, и в вычисляемых полях компоновки.
Без параметра Л= платформа берёт язык сеанса. Язык сеанса зависит от настроек пользователя и от языков, заведённых в конфигурации. Поэтому один и тот же код в базе с английским интерфейсом вернёт «January», и отчёт, собранный «вслепую», внезапно окажется на другом языке. Если язык вывода важен — задавайте локаль явно, не полагаясь на сеанс.
Для многоязычных конфигураций названия, которые вы храните сами (например, массив родительного падежа), выносите в многоязычные строки:
НазваниеЯнваря = НСтр("ru = 'января'; en = 'January'");
Функция НСтр подставит строку под текущий язык сеанса. Так массив падежей тоже можно сделать переключаемым, а не прибивать русские названия гвоздями.
Склонение по падежам — особенность русского и ряда славянских языков. В английском падежей месяца нет, поэтому для en_US «просклонять» нечего — там название одно. Логику склонения через свой словарь имеет смысл включать только для языков, где падежи есть.
Где чаще всего ошибаются с падежом
Ошибки здесь почти всегда одинаковые — вот короткий разбор симптомов.
ММММ — он даёт именительный падеж. Нужен родительный: берите ДЛФ=DD или свой массив.'ММММ' и стал литералом. Уберите кавычки вокруг токена.ММММ всегда даёт заглавную. Переведите первую букву в нижний регистр через НРег(Лев(м,1)) + Сред(м,2).Л=ru_RU.Месяц() считает с единицы, массив — с нуля. Индекс должен быть Месяц(Дата) - 1.Формат(Год, "ЧГ=0").Отдельно про заголовки периода: если отчёт умеет охватывать несколько месяцев, склонение одного названия даст неверную подпись. Проверяйте, что начало и конец периода в одном месяце, иначе выводите диапазон дат целиком через ДЛФ=D.
Частые вопросы
Можно ли получить родительный падеж месяца одним встроенным форматом?
ДЛФ=DD («15 января 2024 г.»). Чтобы получить одно слово «января», строку разбирают через СтрРазделить или берут из своего массива названий.Чем отличаются `ДФ` и `ДЛФ`?
ДФ — ваша форматная строка из токенов (ММММ, yyyy, dd). ДЛФ — предопределённый формат: D — короткая дата, DD — длинная дата с названием месяца в родительном, DT — дата и время. Для склонения полезен именно ДЛФ=DD.Как вывести месяц в предложном падеже «в январе»?
Месяц(Дата) - 1.Почему в запросе `ФОРМАТ` возвращает месяц с заглавной буквы?
ММММ всегда даёт именительный падеж с заглавной. В запросе понизить регистр нельзя — обработайте результат в модуле или в вычисляемом поле компоновки данных.Как сделать склонение в многоязычной базе?
Л=ru_RU), а свои названия храните в строках НСтр с вариантами по языкам. Тогда вывод не зависит от случайного языка сеанса.