У меня есть требование, согласно которому любая дата (ДД.ММ.ГГГГ) должна быть преобразована в последнюю дату месяца (например, если дата 20.01.1999, то она должна быть преобразована в 31.01.1999)?
Любая дата должна быть преобразована в дату конца месяца в коболе?
Ответы (4)
С чем именно у вас проблемы? КОБОЛ или алгоритм? Я предполагаю, что это COBOL.
Я не собираюсь давать вам прямой ответ, потому что вы, очевидно, склоняетесь к языку, и есть смысл проработать конкретные детали для себя.
Вот несколько советов:
Определите поле даты в WORKING-STORAGE
, чтобы вы могли выбрать день, месяц и год как отдельные элементы. Что-то типа:
01 TEST-DATE.
05 TEST-DAY PIC 99.
05 PIC X.
05 TEST-MONTH PIC 99.
05 PIC X.
05 TEST-YEAR PIC 9999.
Обратите внимание на безымянные поля PIC X
. Они содержат разделители дня/месяца/года. Им не нужно давать имена данных, потому что вам не нужно ссылаться на них. Иногда этому типу элемента данных дается имя FILLER
, но это имя необязательно.
Прочтите заявление EVALUATE
. Вот ссылка на руководство IBM Enterprise COBOL. Это описание EVALUATE
должно быть одинаковым во всех версиях COBOL.
MOVE
интересующая дата TO TEST-DATE
. Теперь вы можете ссылаться на год, месяц и день как на отдельные элементы: TEST-DAY
, TEST-MONTH
и TEST-YEAR
.
Используйте EVALUATE
для проверки месяца (TEST-MONTH
). Если месяц 30-дневный, то MOVE
от 30 до TEST-DAY
. Сделайте то же самое для 31-дневного месяца. Февраль — особый случай из-за високосных лет. Как только вы определили, что это февраль, проверьте TEST-YEAR
, чтобы определить, является ли это високосным годом, и MOVE
28 или 29 ДО TEST-DAY
в зависимости от результатов теста.
Теперь TEST-DATE
будет содержать искомую дату. MOVE
туда, где это необходимо.
Вы можете использовать функцию integer-of-date, которая возвращает целочисленное значение, соответствующее любой дате. Предполагая, что ваша дата ввода находится в формате ддммгггг, и вы ожидаете, что вывод будет в том же формате. Допустим, дата 20011999, а вы хотите 31011999. Вы можете выполнить следующие шаги.
- Увеличьте месяц входной даты на единицу. (20*02*1999)
- Сделайте день равным 01 и используйте функцию integer-of-date (*01*021999)
- вычесть единицу из возвращаемого целого числа.
- используйте функцию date-of-integer, которая даст вам требуемый результат.
Обратите внимание, что здесь вам нужно будет добавить еще один чек для обработки декабрьского месяца.
Ну вот! Запустите код здесь
IDENTIFICATION DIVISION.
PROGRAM-ID. STACK2.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-DATE PIC X(10).
01 WORK-DATE.
05 WORK-DAY PIC 9(2).
05 PIC X.
05 WORK-MONTH PIC 9(2).
05 PIC X.
05 WORK-YEAR PIC 9(4).
01 MONTH-31 PIC 9(2).
88 IS-MONTH-31 VALUES 01, 03, 05, 07, 08, 10, 12.
88 IS-MONTH-30 VALUES 04, 06, 09, 11.
01 WS-C PIC 9(4) VALUE 0.
01 WS-D PIC 9(4) VALUE 0.
PROCEDURE DIVISION.
ACCEPT WS-DATE.
MOVE WS-DATE TO WORK-DATE.
DISPLAY 'ACTUALE TEST-DATE: ' WORK-DATE.
MOVE WORK-MONTH TO MONTH-31.
EVALUATE TRUE
WHEN IS-MONTH-31
MOVE 31 TO WORK-DAY
WHEN IS-MONTH-30
MOVE 30 TO WORK-DAY
WHEN OTHER
DIVIDE WORK-YEAR BY 4 GIVING WS-C REMAINDER WS-D
IF WS-D NOT EQUAL 0
MOVE 28 TO WORK-DAY
ELSE
MOVE 29 TO WORK-DAY
END-IF
END-EVALUATE.
DISPLAY 'MODIFIED TEST-DATE: ' WORK-DATE
STOP RUN.
Это решение идет рука об руку с ответом @NealB.
Процедура «вычислить дату окончания месяца» не требует проверки високосного года или декабря.
identification division.
program-id. last-day.
data division.
working-storage section.
1 test-date.
88 test-1 value "20.01.1999".
88 test-2 value "20.02.2004".
88 test-3 value "20.12.2005".
2 dd pic 99.
2 pic x.
2 mm pic 99.
2 pic x.
2 yyyy pic 9999.
1 month-end-date binary pic 9(8) value 0.
procedure division.
begin.
set test-1 to true
perform run-test
set test-2 to true
perform run-test
set test-3 to true
perform run-test
stop run
.
run-test.
display test-date " to " with no advancing
perform test-date-to-iso
perform compute-month-end-date
perform iso-to-test-date
display test-date
.
compute-month-end-date.
*> get date in following month
compute month-end-date = function
integer-of-date (month-end-date) + 32
- function mod (month-end-date 100)
compute month-end-date = function
date-of-integer (month-end-date)
*> get last day of target month
compute month-end-date = function
integer-of-date (month-end-date)
- function mod (month-end-date 100)
compute month-end-date = function
date-of-integer (month-end-date)
.
test-date-to-iso.
compute month-end-date = yyyy * 10000
+ mm * 100 + dd
.
iso-to-test-date.
move month-end-date to dd
.
end program last-day.
Полученные результаты:
20.01.1999 to 31.01.1999
20.02.2004 to 29.02.2004
20.12.2005 to 31.12.2005
Хотя это может показаться немного пугающим для начинающего программиста на языке COBOL, этому есть простое объяснение. Процедура «вычислить-месяц-конец-даты» состоит из двух одинаковых частей, за исключением «+32».
Беря сначала вторую часть, он вычитает день месяца из целого числа даты, давая целочисленное значение для «нулевого» дня месяца. Это в точности целочисленное значение последнего дня предыдущего месяца. Следующее вычисление дает дату в формате «ггггммдд».
Первая часть делает то же самое, за исключением того, что добавляет 32, чтобы получить дату в следующем месяце, с 1-го по 4-й, в зависимости от количества дней в исходном месяце.
В совокупности 19990120
сначала заменяется на 19990201
, а затем заменяется на 19990131
. И 20040220
до 20040303
, потом 20040229
. 20051220
до 20060101
, затем 20051231
.