4.3 Date Arithmetic & Date Manipulation Functions
Key Takeaways
Oracle stores DATE values in an internal 7-byte binary format containing century, year, month, day, hours, minutes, and seconds.
Date arithmetic operates in units of days: Date + Number adds days, Date - Number subtracts days, Date - Date returns the fractional difference in days, and Date + Date is illegal (ORA-00975).
MONTHS_BETWEEN(d1, d2) returns an exact integer if both dates have the same day of the month or if both dates represent the final day of their respective months.
ADD_MONTHS preserves end-of-month status: adding months to the last day of a month always returns the last day of the resulting target month.
ROUND(date, 'MONTH') rounds up to the 1st of the next month if the day is 16 or greater, while ROUND(date, 'YEAR') rounds up to Jan 1 of the next year if the month is July 1 or later.
4.3 Date Arithmetic & Date Manipulation Functions
Quick Answer: Oracle's
DATEdatatype stores century, year, month, day, hour, minute, and second in a fixed 7-byte structure. Date arithmetic is expressed in days (date + 1adds 24 hours;date1 - date2returns the difference in days). Key date functions:MONTHS_BETWEEN(d1, d2)returns exact integers when days match or both dates are month-end;ADD_MONTHSpreserves month-end dates;NEXT_DAYreturns the next occurrence of a named weekday; andROUND/TRUNCround or truncate dates using format models ('MONTH','YEAR'). Note:Date + Dateis invalid and raisesORA-00975.
Oracle Internal DATE Representation
In Oracle Database, the DATE datatype is stored internally as a 7-byte fixed-length binary structure. It always contains both date and time components, even if the client display format hides the time.
7-Byte Internal Structure Breakdown:
- Byte 1: Century + 100
- Byte 2: Year in century + 100
- Byte 3: Month (1–12)
- Byte 4: Day of month (1–31)
- Byte 5: Hour + 1 (1–24, representing 0–23 hours)
- Byte 6: Minute + 1 (1–60, representing 0–59 minutes)
- Byte 7: Second + 1 (1–60, representing 0–59 seconds)
System Date Functions
SYSDATE: Returns the current date and time of the database server operating system.CURRENT_DATE: Returns the current date and time in the session's time zone.
-- Display full date and time components
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') AS current_server_time
FROM dual;
Date Arithmetic Operations
Date arithmetic is performed using integer and fractional values of days (where 1.0 represents 24 hours).
| Operation | Expression | Result Datatype | Meaning |
|---|---|---|---|
Date + Number | hire_date + 7 | DATE | Adds 7 days to hire_date |
Date - Number | hire_date - 30 | DATE | Subtracts 30 days from hire_date |
Date + Fractional | SYSDATE + (5/24) | DATE | Adds 5 hours to current time |
Date + Fractional | SYSDATE + (10/1440) | DATE | Adds 10 minutes to current time |
Date + Fractional | SYSDATE + (30/86400) | DATE | Adds 30 seconds to current time |
Date - Date | end_date - start_date | NUMBER | Difference between two dates in number of days (including fractional decimals) |
Date + Date | date1 + date2 | ERROR | ORA-00975: date + date not allowed |
SELECT
SYSDATE + 1 AS tomorrow,
SYSDATE - 7 AS one_week_ago,
SYSDATE + (2 / 24) AS two_hours_later,
SYSDATE + (15 / 1440) AS fifteen_minutes_later
FROM dual;
Date Manipulation Functions
Oracle provides six dedicated single-row functions for date calculations:
1. MONTHS_BETWEEN(date1, date2)
Calculates the number of months between date1 and date2.
- If
date1 > date2, returns a positive number. - If
date1 < date2, returns a negative number. - The Exact Integer Rule: If
date1anddate2have the same day of the month OR if both dates are the last day of their respective months,MONTHS_BETWEENreturns an exact integer. - If the days differ and are not both month-end, Oracle computes a fractional result based on a 31-day month divisor.
SELECT
MONTHS_BETWEEN('01-SEP-2026', '01-JUN-2026') AS m1, -- 3.0 (Exact day match: 1st to 1st)
MONTHS_BETWEEN('30-JUN-2026', '28-FEB-2026') AS m2, -- 4.0 (Both are last day of month!)
MONTHS_BETWEEN('31-MAY-2026', '28-FEB-2026') AS m3, -- 3.0 (Both are last day of month!)
MONTHS_BETWEEN('01-JUN-2026', '01-SEP-2026') AS m4, -- -3.0 (date1 < date2 yields negative)
MONTHS_BETWEEN('15-JUL-2026', '01-JUN-2026') AS m5 -- 1.4516 (Fractional calculation)
FROM dual;
2. ADD_MONTHS(date, n)
Adds n calendar months to date (n can be positive or negative).
The End-of-Month Preservation Rule:
- If
dateis the last day of the month,ADD_MONTHSalways returns the last day of the resulting target month, even if the months have different lengths (e.g., 28, 30, or 31 days). - If the target month has fewer days than the day of
date, the result automatically rolls back to the last day of the target month.
SELECT
ADD_MONTHS('31-JAN-2026', 1) AS a1, -- 28-FEB-2026 (Last day of Feb)
ADD_MONTHS('28-FEB-2026', 1) AS a2, -- 31-MAR-2026 (28-FEB was month-end -> returns month-end!)
ADD_MONTHS('31-MAR-2026', 1) AS a3, -- 30-APR-2026 (Apr has only 30 days)
ADD_MONTHS('15-JAN-2026', 2) AS a4, -- 15-MAR-2026 (Normal day matching)
ADD_MONTHS('15-MAR-2026', -2) AS a5 -- 15-JAN-2026 (Negative n subtracts months)
FROM dual;
3. NEXT_DAY(date, 'day_name')
Returns the date of the next specified day of the week strictly after date.
'day_name'can be the full name ('FRIDAY') or standard abbreviation ('FRI'), governed by session NLS settings.- Strict Future Rule: If
dateis already Friday,NEXT_DAY(date, 'FRIDAY')returns the date of the following Friday (7 days later).
-- Assuming today is Monday, 15-JUN-2026
SELECT NEXT_DAY('15-JUN-2026', 'FRIDAY') FROM dual; -- Returns 19-JUN-2026
SELECT NEXT_DAY('19-JUN-2026', 'FRIDAY') FROM dual; -- Returns 26-JUN-2026 (Strictly future)
4. LAST_DAY(date)
Returns the date of the final day of the month that contains date.
SELECT
LAST_DAY('14-FEB-2024') AS leap_year_feb, -- 29-FEB-2024 (Leap year)
LAST_DAY('14-FEB-2025') AS non_leap_feb, -- 28-FEB-2025
LAST_DAY('05-JUN-2026') AS june_end -- 30-JUN-2026
FROM dual;
Rounding & Truncating Dates: ROUND and TRUNC
ROUND(date [, format]) and TRUNC(date [, format]) adjust dates based on format models.
Format Models for Date Rounding and Truncation:
'MONTH'or'MON':TRUNC(d, 'MONTH'): Returns the 1st day of the current month (01-MON-YYYY 00:00:00).ROUND(d, 'MONTH'): If day is 1 to 15, rounds down to 1st of current month. If day is 16 to 31, rounds up to 1st of next month.
'YEAR','YYYY', or'YY':TRUNC(d, 'YEAR'): Returns January 1st of the current year (01-JAN-YYYY 00:00:00).ROUND(d, 'YEAR'): If month is January through June (1–6), rounds down to Jan 1 of current year. If month is July through December (7–12), rounds up to Jan 1 of next year.
'DAY'or'DY':TRUNC(d, 'DAY'): Returns the Sunday of the current week (assuming Sunday start).ROUND(d, 'DAY'): Rounds to nearest Sunday (Wednesday noon is the midpoint cutoff).
- Omitted Format Model: Truncates or rounds to the nearest day, effectively resetting the time component to
00:00:00.
SELECT
TRUNC(TO_DATE('18-JUN-2026', 'DD-MON-YYYY'), 'MONTH') AS t_mon, -- 01-JUN-2026
ROUND(TO_DATE('18-JUN-2026', 'DD-MON-YYYY'), 'MONTH') AS r_mon, -- 01-JUL-2026 (18 >= 16 rounds up)
ROUND(TO_DATE('15-JUN-2026', 'DD-MON-YYYY'), 'MONTH') AS r_mon2,-- 01-JUN-2026 (15 <= 15 rounds down)
TRUNC(TO_DATE('18-JUN-2026', 'DD-MON-YYYY'), 'YEAR') AS t_yr, -- 01-JAN-2026
ROUND(TO_DATE('18-JUN-2026', 'DD-MON-YYYY'), 'YEAR') AS r_yr, -- 01-JAN-2026 (June <= 6 rounds down)
ROUND(TO_DATE('01-JUL-2026', 'DD-MON-YYYY'), 'YEAR') AS r_yr2 -- 01-JAN-2027 (July >= 7 rounds up)
FROM dual;
Summary of 1Z0-071 Date Function Traps
| Function / Operation | Common Exam Trap | Correct Rule |
|---|---|---|
Date + Date | Believing two dates can be added | Date + Date is invalid (ORA-00975). Only Date - Date is valid. |
Date - Date | Expecting an interval or integer | Returns a NUMBER representing days (with decimal fractions). |
MONTHS_BETWEEN | Expecting decimals when comparing month-ends | Returns exact integer if both dates are the last day of their month (e.g. 28-FEB and 31-MAY). |
ADD_MONTHS | Adding 1 month to 28-FEB gives 28-MAR | Adding to the last day of a month returns the last day of the target month (31-MAR). |
NEXT_DAY | Querying next day on the current day returns today | Returns the next occurrence in the strict future (+7 days). |
ROUND(d, 'MONTH') | Cutoff is the 15th | Days 1–15 round down to current month; days 16–31 round up to next month. |
ROUND(d, 'YEAR') | Cutoff is June 1st | Months 1–6 (Jan–Jun) round down to Jan 1; Months 7–12 (Jul–Dec) round up to Jan 1 next year. |
A database developer executes the following query on a table containing project milestones:
SELECT end_date - start_date AS duration FROM project_tasks;
If start_date is '01-JUN-2026 09:00:00' and end_date is '03-JUN-2026 21:00:00', what is the value and datatype returned for duration?
INTERVAL DAY TO SECOND value of '+02 12:00:00'
An integer value of 2
A NUMBER value of 2.5
A VARCHAR2 value of '2 days 12 hours'
Consider the following SQL expression evaluated in Oracle Database:
SELECT MONTHS_BETWEEN('31-AUG-2026', '28-FEB-2026') AS result FROM dual;
What is the value returned by this query?
6.0967
5.9677
6.1
6
Evaluate the following query:
SELECT ROUND(TO_DATE('16-SEP-2026', 'DD-MON-YYYY'), 'MONTH') AS r_mon, ROUND(TO_DATE('01-JUL-2026', 'DD-MON-YYYY'), 'YEAR') AS r_yr FROM dual;
What values are returned for r_mon and r_yr?
r_mon = '01-OCT-2026', r_yr = '01-JAN-2027'
r_mon = '01-SEP-2026', r_yr = '01-JAN-2026'
r_mon = '01-OCT-2026', r_yr = '01-JAN-2026'
r_mon = '16-SEP-2026', r_yr = '01-JUL-2026'
Sections you finish are checked off in the contents.