Advertisement Space

Working with dates in Oracle

Date arithmetic is one of the most commonly needed skills in Oracle. Dates can be added, subtracted, truncated, and formatted, but there are some Oracle-specific quirks that trip up even experienced developers.

Recipe #1 - Basic date arithmetic

In Oracle, adding a number to a date adds days. Fractions of a day work for hours, minutes, and seconds:

SELECT SYSDATE                    AS now,
       SYSDATE + 1                AS tomorrow,
       SYSDATE - 7                AS one_week_ago,
       SYSDATE + 1/24             AS one_hour_later,
       SYSDATE + 30/1440          AS thirty_minutes_later,
       SYSDATE + 45/86400         AS forty_five_seconds_later
FROM DUAL;

Recipe #2 - Difference between two dates

Subtracting two dates gives the difference in days as a number:

SELECT hiredate,
       SYSDATE - hiredate AS days_employed,
       ROUND((SYSDATE - hiredate) / 365.25, 1) AS years_employed
FROM emp
WHERE empno = 7839;

Recipe #3 - TO_CHAR for date formatting

Oracle's TO_CHAR is extremely flexible for formatting dates:

SELECT TO_CHAR(SYSDATE, 'DD.MM.YYYY')          AS european,
       TO_CHAR(SYSDATE, 'MM/DD/YYYY')          AS american,
       TO_CHAR(SYSDATE, 'YYYY-MM-DD')          AS iso,
       TO_CHAR(SYSDATE, 'Day, DD Month YYYY')  AS full_text,
       TO_CHAR(SYSDATE, 'HH24:MI:SS')          AS time_only,
       TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') AS timestamp_like
FROM DUAL;

Recipe #4 - TRUNC and ROUND for dates

TRUNC removes the time component; ROUND rounds to the nearest unit:

SELECT SYSDATE                               AS current_time,
       TRUNC(SYSDATE)                        AS start_of_day,
       TRUNC(SYSDATE, 'MM')                  AS start_of_month,
       TRUNC(SYSDATE, 'YYYY')                AS start_of_year,
       TRUNC(SYSDATE, 'IW')                  AS start_of_week,
       LAST_DAY(SYSDATE)                     AS end_of_month,
       ADD_MONTHS(TRUNC(SYSDATE, 'MM'), 1) - 1 AS last_day_alt
FROM DUAL;

Recipe #5 - ADD_MONTHS and MONTHS_BETWEEN

For month-based arithmetic, never multiply by 30 — use ADD_MONTHS instead:

SELECT ADD_MONTHS(SYSDATE, 3)    AS three_months_later,
       ADD_MONTHS(SYSDATE, -6)   AS six_months_ago,
       MONTHS_BETWEEN(
         TO_DATE('2024-12-31', 'YYYY-MM-DD'),
         TO_DATE('2024-01-01', 'YYYY-MM-DD')
       ) AS months_diff
FROM DUAL;

Recipe #6 - Generate a list of dates

Need every day of the current month? Combine CONNECT BY with date functions:

SELECT TRUNC(SYSDATE, 'MM') + LEVEL - 1 AS day_of_month,
       TO_CHAR(TRUNC(SYSDATE, 'MM') + LEVEL - 1, 'Day') AS day_name
FROM DUAL
CONNECT BY LEVEL <= EXTRACT(DAY FROM LAST_DAY(SYSDATE));