Разработка и Конфигурация · 10 мин
Как определить високосный год в 1С
Как определить високосный год в 1С: готовая функция на встроенном языке, проверка через ДобавитьМесяц, типичные ошибки и примеры для 1С 8.3.
Во встроенном языке 1С нет готовой функции вида «ЭтоВисокосныйГод», поэтому проверку разработчики реализуют самостоятельно. Задача встречается чаще, чем кажется: при расчёте отпусков и стажа, при формировании календарных графиков, при проверке корректности даты 29 февраля, при выгрузке данных во внешние системы, где правила календаря могут отличаться.
Существует два рабочих подхода. Первый — арифметический: год високосный, если он делится на 4, но не делится на 100, либо делится на 400. Второй — платформенный: попросить 1С прибавить год к дате 29 февраля и посмотреть, что получилось. Оба способа дают одинаковый результат, но различаются по читаемости и устойчивости к ошибкам.
Ниже разобраны готовые функции, которые можно вставить в общий модуль, особенности работы с датами в 1С, типичные ошибки и способы проверить корректность решения.
Как устроено правило високосного года
Григорианский календарь, по которому работает 1С, использует трёхступенчатое правило. Год считается високосным, если его номер делится на 4 без остатка. Исключение — годы, делящиеся на 100: они невисокосные. Но из этого исключения есть обратное исключение: годы, делящиеся на 400, снова високосные.
На практике это означает: 2020 и 2026 — високосные, 1900 и 2100 — нет (делятся на 100, но не на 400), 2000 — високосный (делится на 400). Ошибка в любом из трёх условий приводит к неверному результату на граничных годах, поэтому «сокращённая» проверка только на делимость на 4 — распространённый источник дефектов.
Способ 1: арифметическая проверка делимости
Самый прямой вариант — функция с оператором остатка от деления. Во встроенном языке 1С для этого используется символ процента % (в англоязычном синтаксисе — ключевое слово, но % работает в обоих режимах).
Функция ЭтоВисокосныйГод(Год) Экспорт
Возврат (Год % 4 = 0 И Год % 100 <> 0) ИЛИ Год % 400 = 0;
КонецФункции
Функция принимает число — номер года — и возвращает булево. Если в распоряжении есть не число, а дата, год извлекается стандартной функцией Год(Дата):
ДатаПроверки = ТекущаяДатаСеанса();
Если ЭтоВисокосныйГод(Год(ДатаПроверки)) Тогда
Сообщить("В феврале 29 дней");
КонецЕсли;
Такую функцию удобно разместить в общем модуле работы с датами, чтобы не дублировать логику в документах и отчётах. Если модуль вызывается с клиента, пометьте его соответствующими флагами доступности (сервер, тонкий клиент, веб-клиент) в зависимости от места вызова.
Функция ЭтоВисокосныйГод(Год) Экспорт
Возврат (Год % 4 = 0 И Год % 100 <> 0) ИЛИ Год % 400 = 0;
КонецФункцииСпособ 2: проверка через ДобавитьМесяц
Альтернатива без арифметики — использовать штатную функцию ДобавитьМесяц. Идея: взять дату 28 февраля проверяемого года, прибавить один день через конструкцию с датой и посмотреть, какой день получился. Более надёжный вариант — прибавить к 1 марта минус один день или проверить конец февраля.
Практичная реализация выглядит так: формируем дату 28 февраля нужного года, прибавляем месяц — получаем 28 марта, вычитаем один день (86400 секунд) и смотрим на день результата. Если получилось 29 февраля — год високосный.
Функция ЭтоВисокосныйГодЧерезДату(Год) Экспорт
ДатаПроверки = Дата(Год, 3, 1) - 86400; // последний день февраля
Возврат День(ДатаПроверки) = 29;
КонецФункции
Здесь используется важное свойство типа «Дата» в 1С: вычитание целого числа означает вычитание секунд. Отнимая 86400 секунд (одни сутки) от 1 марта, мы всегда получаем последний день февраля — 28-е в обычном году и 29-е в високосном. Этот приём заодно решает смежную задачу — определение количества дней в любом месяце.
Сравнение двух подходов
Оба способа дают идентичный результат для всего диапазона дат, поддерживаемого платформой. Выбор — вопрос читаемости кода и контекста, в котором функция применяется.
Сравнение вариантов
Быстрый и явный код, легко читается тем, кто знает правило. Требует аккуратности с тремя условиями — легко потерять проверку на 400.
Не требует знания правила календаря, заодно даёт последний день февраля. Менее очевиден для читающего код, опирается на арифметику секунд.
Если в конфигурации уже есть регистр календарных дней, количество дней в феврале можно взять оттуда. Подходит, когда логика и так завязана на календарь, но избыточен ради одной проверки.
Для разовой проверки в отчёте достаточно арифметической функции. Если код уже оперирует датами и количеством дней в месяце, вариант через вычитание суток органичнее и убивает двух зайцев: вы получаете и признак високосности, и саму дату 29 февраля.
Где это применяется на практике
Наиболее частый сценарий — валидация вводимой даты. Если пользователь или внешняя система передаёт 29 февраля, нужно убедиться, что год допускает такую дату, иначе функция Дата(Год, 2, 29) в невисокосный год вернёт некорректное значение или вызовет ошибку при строгой проверке.
Второй сценарий — расчёт годовых показателей с точностью до дня: среднедневной заработок, проценты по договорам, нормы времени. Деление на 365 вместо фактических 366 дней даёт систематическую погрешность, которая в високосный год искажает результат.
Третий сценарий — формирование производственных календарей и графиков. При автоматической генерации календаря на год количество дней февраля определяется именно такой проверкой, иначе в невисокосный год в график попадёт несуществующая дата.
Функция ДнейВГоду(Год) Экспорт
Если ЭтоВисокосныйГод(Год) Тогда
Возврат 366;
Иначе
Возврат 365;
КонецЕсли;
КонецФункции
Как проверить корректность функции
После внедрения функции прогоните её на граничных значениях. Достаточно короткой процедуры в модуле или консоли кода, которая выводит результат для контрольных лет.
КонтрольныеГода = Новый Массив;
КонтрольныеГода.Добавить(2000); // високосный (делится на 400)
КонтрольныеГода.Добавить(1900); // невисокосный (делится на 100)
КонтрольныеГода.Добавить(2026); // високосный
КонтрольныеГода.Добавить(2023); // невисокосный
КонтрольныеГода.Добавить(2100); // невисокосный
Для Каждого Год Из КонтрольныеГода Цикл
Сообщить(Строка(Год) + ": " + ЭтоВисокосныйГод(Год));
КонецЦикла;
Ожидаемый результат: Истина для 2000 и 2026, Ложь для 1900, 2023 и 2100. Если на 1900 или 2100 функция возвращает Истина — потеряна проверка делимости на 100. Если на 2000 возвращает Ложь — потеряна проверка делимости на 400.
Как проверить результат
Функция возвращает Истина
Ложь — отсутствует условие делимости на 400
Функция возвращает Ложь
Истина — отсутствует условие делимости на 100
Истина, последний день февраля — 29
Ложь или 28 февраля — ошибка в базовом условии
Код не создаёт такую дату без проверки
Дата формируется без валидации — риск ошибки исполнения
Типичные ошибки и ограничения
Главная ошибка — упрощённая проверка только на делимость на 4. На ближайшие десятилетия она будет работать корректно, и дефект проявится только в 2100 году, поэтому такой код спокойно проходит тестирование и живёт в конфигурациях годами.
Вторая ошибка — путаница с типами. Если в функцию передать строку «2026» вместо числа, оператор % может отработать неочевидно или вызвать ошибку преобразования. Перед проверкой стоит явно привести значение к числу или проверить тип.
Третья ошибка — использование арифметики секунд без учёта её природы. Начинающие разработчики иногда пишут Дата + 1, ожидая прибавления одного дня, а получают прибавление одной секунды. Для суток нужно 86400, либо используйте ДобавитьМесяц для месячных сдвигов.
Отдельно стоит помнить про границу безопасной самостоятельной работы: если функция используется в регламентных расчётах зарплаты, отпускных или процентов, изменения общего модуля нужно тестировать на копии базы. Правка общего модуля мгновенно влияет на все места вызова, и откат в рабочей базе может потребовать восстановления из резервной копии.
FAQ
Есть ли в 1С готовая функция определения високосного года?
Нет, в стандартном синтаксисе встроенного языка такой функции нет. В типовых конфигурациях встречаются собственные реализации в общих модулях работы с датами, но полагаться на их наличие в конкретной конфигурации нельзя — надёжнее добавить свою функцию из трёх условий делимости.
Как узнать количество дней в феврале конкретного года?
Вычтите одни сутки из 1 марта: Дата(Год, 3, 1) - 86400. День получившейся даты — 28 или 29 — и есть количество дней в феврале. Тот же приём работает для любого месяца: возьмите первое число следующего месяца и отнимите сутки.
Что будет, если создать дату Дата(2023, 2, 29)?
2023 год невисокосный, и такая дата недопустима. В зависимости от контекста платформа либо выдаст ошибку исполнения, либо значение будет приведено некорректно. Поэтому перед формированием даты 29 февраля всегда проверяйте високосность года.
Работает ли оператор % в английском синтаксисе 1С?
Да, символ процента для остатка от деления работает в обоих вариантах синтаксиса. В англоязычном варианте также допустимо написание через встроенный оператор языка, но % остаётся универсальным и самым коротким способом.
Нужно ли учитывать високосный год при расчёте среднедневного заработка?
Да, если методика расчёта делит годовую сумму на количество календарных дней. В високосный год делитель равен 366, и использование 365 занижает среднедневное значение. Конкретный делитель определяется методикой расчёта, закреплённой в учётной политике и нормативных документах.
Можно ли определить високосность через запрос к базе данных?
Да, в языке запросов доступны функции работы с датами, включая ГОД и ДЕНЬ. Можно построить выражение: взять дату 1 марта нужного года, добавить -1 день через ДОБАВИТЬКДАТЕ и проверить день результата. Однако для разовой проверки проще выполнить расчёт в коде, а запрос использовать, когда проверка нужна прямо в выборке данных.
Что важно запомнить
Готовой функции в 1С нет — используйте проверку (Год % 4 = 0 И Год % 100 <> 0) ИЛИ Год % 400 = 0, либо приём Дата(Год,3,1) - 86400. Всегда тестируйте на граничных годах 1900, 2000 и 2100, а изменения в общих модулях внедряйте через копию базы.