Как вывести название месяца в нужном падеже в 1С

· 9 мин

Содержание

Именительный падеж («Январь») даёт формат Формат(Дата, "ДФ=ММММ"). Родительный («января»), который нужен в заголовках вида «за январь 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];
КонецФункции

Такую функцию выносят в общий модуль, доступный на клиенте и сервере, и вызывают из форм, печатных макетов и вычисляемых полей. Падеж передают буквой: И — именительный, Р — родительный, Д — дательный, П — предложный. Это закрывает все случаи, где встроенный формат бессилен.

Какой способ выбрать — зависит от задачи.

Что вам нужно вывести?

Месяц в заголовках отчётов «за январь»

В отчётах чаще всего нужен родительный падеж: «Оборотно-сальдовая ведомость за январь 2024». Если период задан одной датой внутри месяца, собрать заголовок можно так:

Заголовок = "Отчёт за " + МесяцРодительный(ДатаОтчёта)
            + " " + Формат(Год(ДатаОтчёта), "ЧГ=0") + " г.";

Год соединяйте через Формат(..., "ЧГ=0"). Иначе ЧислоВСтроку подставит разделитель групп и получится «2 024».

Когда период задаётся началом и концом (стандартный реквизит отчёта на СКД), название месяца берут от даты начала периода. Но сперва стоит проверить, что начало и конец лежат в одном месяце:

Если НачалоМесяца(ДатаНачала) = НачалоМесяца(ДатаКонца) Тогда
    Заголовок = "за " + ИмяМесяца(ДатаНачала)
                + " " + Формат(Год(ДатаНачала), "ЧГ=0");
Иначе
    Заголовок = "с " + Формат(ДатаНачала, "ДЛФ=D")
                + " по " + Формат(ДатаКонца, "ДЛФ=D");
КонецЕсли;

Если период охватывает несколько месяцев, одного названия уже мало — выводится диапазон дат целиком. Это частая недоработка: заголовок склоняет только первый месяц, а отчёт при этом собран за квартал.

Для оформления периода в компоновке есть поле НачалоПериода / КонецПериода стандартного периода — его удобно пропустить через ту же функцию склонения в макете заголовка.

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

Склонение месяца в запросах и СКД

В языке запросов форматирование делает та же функция ФОРМАТ с теми же токенами:

ВЫБРАТЬ
    ФОРМАТ(ПродажиОбороты.Период, "ДФ=ММММ") КАК МесяцИмен,
    ФОРМАТ(ПродажиОбороты.Период, "ДЛФ=DD") КАК ДатаПрописью
ИЗ
    РегистрНакопления.Продажи.Обороты КАК ПродажиОбороты

В форматную строку запроса можно вставлять и свой текст — он так же оборачивается одинарными кавычками:

ФОРМАТ(ПродажиОбороты.Период, "ДФ='Итоги за' ММММ гггг") КАК Подпись

Ограничение то же, что в коде: ММММ в запросе — именительный падеж. Родительный в чистом виде запрос не даёт. Если нужен именно он, есть два подхода:

  1. Вывести ДЛФ=DD и разобрать строку уже на выходе — в модуле или в поле СКД.
  2. Не склонять в запросе вовсе, а собрать подпись в вычисляемом поле компоновки.

В СКД название месяца удобно считать вычисляемым полем. В выражении поля работает функция Формат, а для своих падежей — общий модуль с функцией-словарём, если она объявлена доступной на сервере и для компоновки.

Где считаемЧем склоняемЧто получаем
Модуль (встроенный язык)Формат + свой массивлюбой падеж
ЗапросФОРМАТ(..., "ДФ=ММММ")именительный
ЗапросФОРМАТ(..., "ДЛФ=DD")дата с родительным
Вычисляемое поле СКДФормат или функция общего модулялюбой падеж

Группировать данные по месяцу лучше по самой дате (началу месяца), а название подставлять отдельным полем для вывода. Если группировать по тексту «январь», порядок строк станет алфавитным, а не хронологическим: «август» окажется выше «января».

Чтобы и группировать по месяцу, и выводить название, в запросе оставляют два поля: НачалоПериода(Дата, "Месяц") для группировки и сортировки, а название считают отдельно. В настройках СКД по полю-дате задают порядок «по возрастанию», а текстовое название выводят ресурсом или вычисляемым полем. Тогда строки идут хронологически, а в шапке стоит правильно просклонённый месяц.

Разные языки: локаль в форматной строке

Название месяца зависит от языка. Внутри форматной строки язык задаётся параметром Л= (локаль):

Рус = Формат(Дата, "ДФ=ММММ; Л=ru_RU");   // "Январь"
Англ = Формат(Дата, "ДФ=ММММ; Л=en_US");  // "January"

Код локали — это пара «язык_страна»: ru_RU, en_US, uk_UA, be_BY. Можно указать только язык (ru, en) — платформа подставит страну по умолчанию. Тот же параметр работает и в запросе, и в вычисляемых полях компоновки.

Без параметра Л= платформа берёт язык сеанса. Язык сеанса зависит от настроек пользователя и от языков, заведённых в конфигурации. Поэтому один и тот же код в базе с английским интерфейсом вернёт «January», и отчёт, собранный «вслепую», внезапно окажется на другом языке. Если язык вывода важен — задавайте локаль явно, не полагаясь на сеанс.

Для многоязычных конфигураций названия, которые вы храните сами (например, массив родительного падежа), выносите в многоязычные строки:

НазваниеЯнваря = НСтр("ru = 'января'; en = 'January'");

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

Склонение по падежам — особенность русского и ряда славянских языков. В английском падежей месяца нет, поэтому для en_US «просклонять» нечего — там название одно. Логику склонения через свой словарь имеет смысл включать только для языков, где падежи есть.

Где чаще всего ошибаются с падежом

Ошибки здесь почти всегда одинаковые — вот короткий разбор симптомов.

Диагностика: выберите симптом

Отдельно про заголовки периода: если отчёт умеет охватывать несколько месяцев, склонение одного названия даст неверную подпись. Проверяйте, что начало и конец периода в одном месяце, иначе выводите диапазон дат целиком через ДЛФ=D.

Частые вопросы

Можно ли получить родительный падеж месяца одним встроенным форматом?
Отдельным токеном — нет. Родительный падеж платформа отдаёт только в составе длинной даты ДЛФ=DD («15 января 2024 г.»). Чтобы получить одно слово «января», строку разбирают через СтрРазделить или берут из своего массива названий.
Чем отличаются `ДФ` и `ДЛФ`?
ДФ — ваша форматная строка из токенов (ММММ, yyyy, dd). ДЛФ — предопределённый формат: D — короткая дата, DD — длинная дата с названием месяца в родительном, DT — дата и время. Для склонения полезен именно ДЛФ=DD.
Как вывести месяц в предложном падеже «в январе»?
Встроенного формата для предложного падежа нет. Заведите свой массив из 12 названий в нужном падеже и обращайтесь по номеру месяца Месяц(Дата) - 1.
Почему в запросе `ФОРМАТ` возвращает месяц с заглавной буквы?
Токен ММММ всегда даёт именительный падеж с заглавной. В запросе понизить регистр нельзя — обработайте результат в модуле или в вычисляемом поле компоновки данных.
Как сделать склонение в многоязычной базе?
Задавайте локаль явно (Л=ru_RU), а свои названия храните в строках НСтр с вариантами по языкам. Тогда вывод не зависит от случайного языка сеанса.