Any date should be converted to end of the month date in cobol?
I have a requirement where any date (DD.MM.YYYY) should be converted to last date of month (ex: If date is 20.01.1999 then it should convert in开发者_StackOverflow中文版to 31.01.1999) ?
Exactly what are you having trouble with? COBOL or the algorithm? I'm guessing its COBOL.
I'm not going to give you a direct answer because you are obviously leaning the language and there is value in working out the specific details for yourself.
Here are a couple of hints:
Define a date field in WORKING-STORAGE
so that you can pick out the day, month and year as separate items. Something like:
01 TEST-DATE.
05 TEST-DAY PIC 99.
05 PIC X.
05 TEST-MONTH PIC 99.
05 PIC X.
05 TEST-YEAR PIC 9999.
Note the unnamed PIC X
fields. These contain the day/month/year delimiters. They do not need to be given data names because
you do not need to reference them. Sometimes this type of data item is given
the name FILLER
, but the name is optional.
Read up on the EVALUATE
statement. Here is a link to
the IBM Enterprise COBOL manual. This description of EVALUATE
should be similar in all versions of COBOL.
MOVE
the date of interest TO TEST-DATE
. Now you can reference the year, month and day as individual items: TEST-DAY
, TEST-MONTH
and TEST-YEAR
.
Use EVALUATE
to test the month (TEST-MONTH
). If the month is a 30 day month then MOVE
30 to TEST-DAY
. Do the same for
31 day months. February is a special case because of leap years. Once you have determined that the month is February,
test TEST-YEAR
to determine if it is a leap year
and MOVE
28 or 29 TO TEST-DAY
depending on the outcome of the test.
Now TEST-DATE
will contain the date you are looking for. MOVE
it to wherever it is needed.
You can use function integer-of-date which gives returns an integral value corresponding to any date. Assuming your input date is in ddmmyyyy format and you expect hte output in the same format. Lets say date is 20011999 and you want as 31011999. You can follow the below steps.
- Increase the month of the input date by one. (20*02*1999)
- Make the day as 01 and use function integer-of-date (*01*021999)
- subtract one from the integer returned.
- use function date-of-integer which will give you the required result.
Note here you will have to add one more check for handling December month.
Here you go! Run the code here
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.
This solution goes hand in hand with @NealB's answer.
The procedure "compute-month-end-date" does not require any checks for leap year or December.
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.
Results:
20.01.1999 to 31.01.1999
20.02.2004 to 29.02.2004
20.12.2005 to 31.12.2005
While this might be a bit daunting to the novice COBOL programmer, there is a simple explanation. The procedure "compute-month-end-date" consists of two identical parts with the exception of the "+32".
Taking the second part first, it subtracts the day of month from the integer of a date giving the integer value for the 'zeroth' day of the month. This is precisely the integer value for the last day of the prior month. The following compute gives the date in 'yyyymmdd' format.
The first part does the same, except that it adds 32 to get a date in the following month, the 1st through the 4th, depending on the number of days in the original month.
Taken togther 19990120
is first changed to 19990201
, then changed to 19990131
. And 20040220
to 20040303
, then 20040229
. 20051220
to 20060101
, then 20051231
.
精彩评论