Skip to Content

# Just When You Thought You Knew Everything about ABAP Date CalculationsÂ…

#### The Problem

I was working on a project that required me to calculate a date three months in the future and then take the last day of the month. Pretty simple huh? Do something like:

The above example produces:

Using FM RP_CALC_DATE_IN_INTERVAL
15.09.2010 – end of the month 3 months in the future -> 31.12.2010

This appears correct to me.

Changing old_dt to ‘20100901’ produces the same results, as does ‘20100930’.
So for any date in September, we get the results we expect.

Now, try it with ‘20107015’. You should see:

Using FM RP_CALC_DATE_IN_INTERVAL
15.07.2010 – end of the month 3 months in the future -> 31.10.2010

Using ‘20100701’ gives the same results. But what happens if you use ‘20100731’?
Remarkably, you get:

Using FM RP_CALC_DATE_IN_INTERVAL
31.07.2010 – end of the month 3 months in the future -> 30.11.2010

This is because when the function module is asked to calculate a date X months in the future and the day of the starting date is greater than the end day of the month that it would normally calculate, instead of returning the end of that month it returns the first day of the following month. Well, you might say that this is what you want. On the other hand, in the project I was working on, it was not.

Consider a completely different case. Suppose you want to add some months to a date and also some days. RP_CALC_DATE_IN_INTERVAL can do this. It has parameters for days, months and years and you can tell it whether you want to go forward or backward. But before looking at how the FM would do this, let’s work through an example. Let’s say your starting date is ‘20100930’ and you want to add one month and one day to it:

‘20100930’ plus 1 day gives ‘20101001’. Adding one month to that gives ‘20101101’.

But let’s do it the other way:

‘20100930’ plus 1 month gives ‘20101030’. Adding one day to that gives ‘20101031’.

So even without using any ABAP function module, you can see that the results of date calculations are not necessarily deterministic. That’s not to say they are incorrect, just that you can’t say for sure what you are going to get.

This is because although we can use numbers to represent dates, these numerical representations are not real numbers. I mean “real numbers” in the mathematical sense that they do not obey the associative law: A + B + C does not necessarily equal A + C + B.

### So what does this mean?

First of all, this should not be a big problem. It will only crop up when doing calculations around the ends of certain months. But programming needs to be done accurately and must accommodate all cases; otherwise, you get angry calls from impatient users. So we should not blindly plug dates and numbers into ABAP and expect the results to be what you and your users want. You have to look at the requirements or specifications and determine exactly what they imply. This may mean that you have to go back to the user, explain the problem and get clarification. But in the end, we live in the real world and we will have to calculate dates that are days months and/or years in the future (or past).

We can start by not using function modules that try to do the additions of different units such as RP_CALC_DATE_IN_INTERVAL. (There are others as well.) I think a better approach is to use the methods of class cl_hrpt_date_tools. They allow only one operation at a time and they also give better results than RP_CALC_DATE_IN_INTERVAL for the first case I showed. If you do:

You will at least get:

Using method add_date
31.07.2010 – end of the month 3 months in the future -> 31.10.2010

To me, this is the correct answer.

Another thing to bear in mind is that function module RP_CALC_DATE_IN_INTERVAL (and its clones) are neither documented nor released. So caveat emptor.

But whatever method you choose, test to make sure the results are what you want.

### Assigned Tags

9 Comments
You must be Logged on to comment or reply to a post.
Hello Robert

Even though fm RP_CALC_DATE_IN_INTERVAL is used quite frequently I would have been alerted by its package assignment:
- Function group RPPA (HR: Generate personal calendar (Austria))
- Package PB03 (HR Master Data: Austria)

Given the fact that you are located in Toronto I guess you did NOT work on a project for an Austrian company.

You could have solved your problem easier (and in a more deterministic way) on ERP 6.0 using the following class:

REPORT  zus_sdn_calculate_date.

DATA:
gd_date_c(10)   type c,
go_date         TYPE REF TO cl_hrpy_date.

PARAMETERS:
p_date    TYPE datab  DEFAULT '20100830'.

START-OF-SELECTION.

CREATE OBJECT go_date
EXPORTING
imp_date = p_date.

go_date->add_months( 3 ).
go_date->set_end_of_month( ).

write p_date to gd_date_c DD/MM/YYYY.
write: / 'Start Date =', gd_date_c.

write go_date->date to gd_date_c DD/MM/YYYY.
write: / 'Start Date =', gd_date_c.

END-OF-SELECTION.

Regards
Uwe

Hello Uwe,

My fav class for Date Calculations is CL_HRPAD_DATE_COMPUTATIONS( more options than CL_HRPY_DATE :-))

Algo for this:
1. Get 3 months later date using CL_HRPAD_DATE_COMPUTATIONS=>ADD_MONTHS_TO_DATE.

2. Use the date from (1) & pass to CL_HRPAD_DATE_COMPUTATIONS=>GET_LAST_DAY_IN_MONTH.

What say?

BR,
Suhas

Hello Suhas

I have to repeat myself:
"Watch out when relying on 'odd' packages".

Admittedly, on ERP 6.0 both classes are not used at all (Where-Used-List). However, there is major difference when looking at the package assigment:

(1) CL_HRPAD_DATE_COMPUTATIONS:
- Package = PAOC_PAD_DATE_COMPUTATIONS (contains a single object, namely this class)
- ApplComponent = PA-PA (Personnel Administration)
- SW Component = EA-HR (SAP Enterprise Extension HR)

(2) CL_HRPY_DATE:
- Package = PCAL (SAP HR Payroll Application Development) -> huge number of objects
- ApplComponent = PY-XX (Payroll: General Parts)
- SW Component = SAP_HR (Human Resources)

CONCLUSION:
It seems to me that the developer(s) of package CL_HRPAD_DATE_COMPUTATIONS were not aware that almost the same functionality was already around (class CL_HRPY_DATE). I will not be surprised if the package will be deleted from later releases.

In contrast, class CL_HRPY_DATE is much "closer" to the core of the SAP ERP system and, therefore, should be preferred.

Regards
Uwe

Point noted!
Former Member
Blog Post Author
Hi Uwe - apologies for not responding sooner. I had some other things to take care of.

I have to admit that I hadn't looked at the package assignment until now. But then I looked at the package assignments for all of the RP_CALC_DATE_IN_INTERVAL* FMs (there are four of them). They all appear to be copies of the original RP_CALC_DATE_IN_INTERVAL and adapted for new use in the international HR arena.

Since they aren't released for customer use, I guess the old adage "buyer beware" applies here.

I am a bit confused. Dates and numbers are two different data types. Of course, dates are not real numbers and that's why we've two data types.
If you don't get deterministic results, I would call it 'bug'.
Adding a month and then adding a day is not the same as adding a day and then adding a month. We can prove it without a computer.
Once again date is not a real number so we can't apply associative rule.
Thanks,
Bala
Former Member
Blog Post Author
Yes, dates and numbers are different, but in some cases, we treat dates like numbers; we add and subtract them.

And yes, once I found the problem with fm RP_CALC_DATE_IN_INTERVAL, I solved it with the method I mentioned.

Rob

I would like to respectfully disagree. When we add or subtract dates, we perform date subtraction/addition, not number subtraction.
Examples: (created in all_objects is of type DATE)
1)  select object_name, created from all_objects
where object_name = 'USR02';
OBJECT_NAME                    CREATED
------------------------------ ---------------
USR02                          25-MAY-08

This query adds 2 to created. The result is 27-MAY-08:
2)  select object_name, created+2 from all_objects
where object_name = 'USR02';

OBJECT_NAME                    CREATED+2
------------------------------ ---------------
USR02                          27-MAY-08

This query adds 7 to created. The result is 01-JUN-08:
3) select object_name, created+7
from all_objects
where object_name = 'USR02';

OBJECT_NAME                    CREATED+7
------------------------------ ---------------
USR02                          01-JUN-08

----------------------------------------------
This query adds 1375 to created. The result is 29-FEB-12: (this shows leap year effect)

4) select object_name, created+1375  from all_objects where object_name = 'USR02';

OBJECT_NAME                    CREATED+1375
------------------------------ ---------------
USR02                          29-FEB-12

This query adds 1376 to created. The result is 01-MAR-12:
SQL> select object_name, created+1376 from all_objects
2  where object_name = 'USR02';

OBJECT_NAME                    CREATED+1376
------------------------------ ---------------
USR02                          01-MAR-12
=================================================

PS:databases(Oracle) however internally store dates in numbers format, the number of days elapsed from 1/1/1900).

Thanks,
Bala

Former Member
Blog Post Author
Sorry to take so long to get back to you. I was busy with some other things.

I'm not sure exactly what you're disagreeing with. I know you can add days to dates and get the correct date in return.

The problem I am pointing out is when you try to add months to a date. ABAP provides a number of routines, the output of which needs to be checked thoroughly.