I am working on formating a report of overdue items. One of the requirements is to list the elapsed time between the due date and the current date, expressed in terms of years and days. I have ran across some curious findings in the results from the REMAINDER function which has led me to use the MOD function instead. Consider the following:
DECLARE
d1 DATE;
d2 DATE;
d3 DATE;
years NUMBER(38,12);
years2 NUMBER(38,12);
v_raw NUMBER(38,12);
v_raw2 NUMBER(38,12);
v_remainder NUMBER(38,12);
v_mod NUMBER(38,12);
v_mod2 NUMBER(38,12);
v_rem2 NUMBER(38,12);
BEGIN
d1 := to_date( '09-JUL-2007', 'DD-MON-YYYY' );--SYSDATE;
d2 := to_date( '24-JUL-1995', 'DD-MON-YYYY' );
d3 := to_date( '24-JUN-1995', 'DD-MON-YYYY' );
years := TRUNC( ( d1 - d2 )/365 );
years2 := TRUNC( ( d1 - d2 )/365 );
v_raw := d1 - d2;
v_raw2 := d1 - d3;
v_remainder := TRUNC( REMAINDER( d1 - d2, 365) );
v_rem2 := TRUNC( REMAINDER( d1 - d3, 365) );
v_mod := TRUNC( MOD( d1 - d2, 365 ) );
v_mod2 := TRUNC( MOD( d1 - d3, 365 ) );
dbms_output.put_line( 'D1 is '||to_char( d1, 'DD-MON-YYYY' )||'.');
dbms_output.put_line( 'D2 is '||to_char( d2, 'DD-MON-YYYY' )||'.');
dbms_output.put_line( 'D3 is '||to_char( d3, 'DD-MON-YYYY' )||'.');
dbms_output.put_line( 'Raw difference between d1 and d2 is '||v_raw||'.');
dbms_output.put_line( 'Number whole years difference between d1 and d2 is '||years||'.');
dbms_output.put_line( 'Number whole days difference, using the remainder function, between d1 and d2 is '||v_remainder||'.');
dbms_output.put_line( 'Number whole days difference, using the modulus function, between d1 and d2 is '||v_mod||'.');
dbms_output.put_line( 'Raw difference between d1 and d3 is '||v_raw2||'.');
dbms_output.put_line( 'Number whole years difference between d1 and d3 is '||years2||'.');
dbms_output.put_line( 'Number whole days difference, using the remainder function, between d1 and d3 is '||v_rem2||'.');
dbms_output.put_line( 'Number whole days difference, using the modulus function, between d1 and d3 is '||v_mod2||'.');
END;
The code above produces the following output:
D1 is 09-JUL-2007.
D2 is 24-JUL-1995.
D3 is 24-JUN-1995.
Raw difference between d1 and d2 is 4368.
Number whole years difference between d1 and d2 is 11.
Number whole days difference, using the remainder function, between d1 and d2 is -12.
Number whole days difference, using the modulus function, between d1 and d2 is 353.
Raw difference between d1 and d3 is 4398.
Number whole years difference between d1 and d3 is 11.
Number whole days difference, using the remainder function, between d1 and d3 is 18.
Number whole days difference, using the modulus function, between d1 and d3 is 18.
D1 represents the current date (SYSDATE was not used to preserve consistency in the results). Although D1 is greater than both D2 and D3, the REMAINDER function is somehow producing a negative result for D2 (D3 calculations come out fine). I would not have expected that a negative result is possible since D2 occurs almost 12 years prior to D1!
It appears that, for some reason, REMAINDER is converting the dates to the Julian dates (day of the year) and somehow ignores the year for the calculations. This is clearly incorrect. I could not find any reference to this anomaly in the SQL reference; I am uncertain whether this is a known issue.
Your insight would be appreciated. Thanks in advance.
first, I would not use 365 - that is just wrong.
You need to use months between at best.
You should could use intervals as well.
neither of your answers is technically correct
ops$tkyte%ORA10GR2> DECLARE
2 d1 DATE;
3 d2 DATE;
4 d3 DATE;
5 years number;
6 days number;
7 BEGIN
8 d1 := to_date( '09-JUL-2007', 'DD-MON-YYYY' );--SYSDATE;
9 d2 := to_date( '24-JUL-1995', 'DD-MON-YYYY' );
10 d3 := to_date( '24-JUN-1995', 'DD-MON-YYYY' );
11
12 years := trunc( months_between( d1, d2 ) / 12 );
13 days := d1 - add_months( d2, years*12 );
14
15 dbms_output.put_line( 'years = ' || years || ' days = ' || days );
16 end;
17 /
years = 11 days = 350
PL/SQL procedure successfully completed.
mixing days and years is wrought with dangers (like months with days is) since neither a year nor a month is of fixed duration.....