SELECT MONTHS_BETWEEN(LAST_DAY('15-JAN-12') + 1, '01-APR-12')
FROM DUAL;
ERROR : not a valid month
SELECT MONTHS_BETWEEN(LAST_DAY('15-JAN-12') + 1, '01-APR-12')
FROM DUAL;
ERROR : not a valid month
'15-JAN-12' is not a date; it is a string literal that happens to look like a date. Oracle will try to be helpful and will try to convert the string to a date and will implicitly convert your query to the equivalent of:
SELECT MONTHS_BETWEEN(
LAST_DAY(
TO_DATE(
'15-JAN-12',
(SELECT value FROM NLS_SESSION_PARAMETERS WHERE parameter = 'NLS_DATE_FORMAT')
)
) + 1,
TO_DATE(
'01-APR-12',
(SELECT value FROM NLS_SESSION_PARAMETERS WHERE parameter = 'NLS_DATE_FORMAT')
)
)
FROM DUAL;
Which may give you the correct answer if the NLS_DATE_FORMAT is DD-MON-RR.
However, if you use:
ALTER SESSION SET NLS_DATE_FORMAT = 'fxDD-MM-YYYY';
Then the same query outputs:
ORA-01858: a non-numeric character was found where a numeric was expected
and if you use:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
then it is even worse, the query doesn't fail it outputs the unexpected value 165.6451612903226.
What you should do is not rely on implicit conversions and always use explicit conversion (and, if you are using a specific language then specify the language as well):
SELECT MONTHS_BETWEEN(
LAST_DAY(
TO_DATE('15-JAN-12', 'DD-MON-RR', 'NLS_DATE_LANGUAGE=English')
) + 1,
TO_DATE('01-APR-12', 'DD-MON-RR', 'NLS_DATE_LANGUAGE=English')
)
FROM DUAL;
Or, you can use a date literal:
SELECT MONTHS_BETWEEN(
LAST_DAY(
DATE '2012-01-15'
) + 1,
DATE '2012-04-01'
)
FROM DUAL;
You need to use the TO_DATE() function to convert a string to a date literal.
SELECT MONTHS_BETWEEN(LAST_DAY(TO_DATE('15-JAN-12', 'dd-mmm-yyy')) + 1, TO_DATE('01-APR-12', 'dd-mmm-yyy'))
FROM DUAL;
You can also use date literals, which are written as DATE 'YYYY-MM-DD'
SELECT MONTHS_BETWEEN(LAST_DAY(DATE '2012-01-15') + 1, DATE '2012-04-01')
FROM DUAL;
Usually Oracle expects the month part to be written in full form (e.g. JANUARY, APRIL). Try this: SELECT MONTHS_BETWEEN(LAST_DAY('15-JANUARY-12') + 1, '01-APRIL-12') FROM DUAL;