Функция CBIH_RP02_GET_END_MONTH.
Через конструкцию CASE анализирует номер месяца. Для всех месяцев, кроме февраля, присваивает своей локальной переменной end_month1 соответствующее значение 30 или 31. Для февраля вызывает форму CHECK_DATE, передаёт ей дату и анализирует возвращаемую переменную L_ERROR. В зависимости от её значения устанавливает своей переменной end_month1 значение 28 или 29. Из исходного года и месяца и вычисленного дня формирует возвращаемую дату. Форма CHECK_DATE у переданной даты меняет число на 29, эта новая дата передаётся функции DATE_CHECK_PLAUSIBILITY, по возвращении из которой форма анализирует код возврата (была ли ошибка) и возвращает эту информацию в вызвавшую функцию. Функция DATE_CHECK_PLAUSIBILITY тщательно проверяет дату на корректность по григорианскому календарю (71 строчка исходного кода) и генерирует ошибку, если дата неправильная.
Функция FIMA_END_OF_MONTH_DETERMINE.
Ничего особенного — честно проверяет для февраля високосность года по григорианскому календарю. Впечатлило использование констант. Видимо, автору кто-то сказал, что хороший стиль программирования — никогда не использовать константы напрямую, а всегда их описывать в отдельно отведённом месте. Идея, конечно, здравая, но доведена до абсурда. Все необходимые группе функций константы описаны в отдельном инклюде FIMA_CONSTANTS (135 строк исходного кода). Я ещё понимаю описание констант для номера месяца типа CON_FEBRUARY(2) TYPE N VALUE '02'. Но это скорее исключение. Типичное описание:
CON_FIRST_DAY_OF_MONTH(2) TYPE N VALUE '01',
CON_DAYS_OF_MONTH_27(2) TYPE N VALUE '27',
CON_SBERFIMA_TLRA TYPE SBEWFIMA VALUE 'TLRA',
А код для присвоения числа, соответственно, такой:
CASE I_DATE+4(2).
WHEN CON_JANUARY. E_DAYS_OF_MONTH = CON_DAYS_OF_MONTH_31.
Функции, начинающиеся на «FKK».
Две из них, FKK_DTE_DAYS_PER_MONTH и FKK_DTE_GET_LASTDAY_OF_MONTH, находятся в одной группе FKDATE, причём рядом. В группе всего семь функций — трудно не заметить существующую тому, кто писал позже. Однако детали реализации отличаются — похоже, что каждой автор писал сам, хотя концептуально алгоритмы одинаковые. За исключением того, что вторая функция для дат до 1582 года вычисляет високосность года по юлианскому календарю. В обеих честно анализируются компоненты даты. Есть отличия в формате вызова.
Для первой нужно передавать один параметр — дату. Потом функция вызывает форму, в которой выполняются все вычисления. Для второй нужно передать два параметра — год и месяц, и она ещё проверяет корректность даты и генерит исключение, если дата неправильная. Первая подразумевает, что ей всегда передают корректную дату, и может вызывать прерывание программы, если переданная дата некорректна. Интересно, столкнулись ли эти функции хотя бы раз хотя бы в какой-нибудь системе с необходимостью вычислять последний день месяца для дат до 1582 года? А если столкнулась, то в курсе ли их разработчики, что в разных странах переход на григорианский календарь происходил в разное время?
Третья функция FKK_GET_LAST_DAY_OF_MONTH находится в группе FKB3A. Вычисляет последний день месяца с использованием встроенной операции над датами — прибавления и вычитания дней. Сначала она формирует дату на 28 число того же месяца и года, потом прибавляет к ней 4, получает дату заведомо в следующем месяце, устанавливает там день в «01» и вычитает единицу из всей даты. Простенько и со вкусом. Для дат в декабре 9999 года будет ошибка из-за переполнения года по ходу вычислений. Ну да кого это сейчас волнует?
Четвёртая функция FKK_LAST_DAY_OF_MONTH находится в третьей группе FKKPERIOD. Алгоритм компромиссный. Номер следующего месяца и года вычисляется «честно», потом формируется дата на первое число этого месяца и уже от неё отнимается единица. Функция корректно обрабатывает даты в декабре 9999 года, специально анализируя этот случай и возвращая константу «31.12.9999». Но при этом все даты до 1800 года считает некорректными и генерит на них исключения, как и на даты с неправильным месяцем. Если передана дата с неправильным днём, не замечает этого.
Функция HR_RU_DAQ_GET_DAYS_IN_MONTH.
Имеет 8 входных параметров, 2 выходных и 2 одновременно входных и выходных. При этом состоит всего из 58 строк кода (из них 26 выполняемых). Алгоритм вполне аскетичный, как у FKK_GET_LAST_DAY_OF_MONTH, только прибавляет не 4 к двадцать восьмому числу, а 31 к первому. Некоторые входные параметры помечены как необязательные и никак не участвуют в алгоритме. В некоторых функциях, не вошедших в этот краткий обзор, использовались вариации — например, к первому числу прибалялось 35 или 32. Видимо, 31 побоялись прибавлять — а вдруг не хватит? 32 и 35 — надёжнее. Или, может, они так округляли? Разницы-то действительно нет, сколько конкретно прибавлять, лишь бы попало куда-нибудь в следующий месяц.