SQL-Engineering-Handbook

03 — Date Calculations

Introduction

Extraction tells you what part of a date you’re looking at. Calculation tells you how far apart two dates are, or where a date lands after moving forward or backward in time. This is the module where SQL starts answering questions like “how many days has this employee worked here?” and “what date is 90 days from now?” — the arithmetic backbone of tenure, aging, SLA, and rolling-window reporting.


Concept Overview

Date calculation functions fall into two families:

  1. Interval arithmetic — moving a date forward or backward by a specified amount (DATE_ADD, DATE_SUB, ADDDATE, SUBDATE).
  2. Differencing — measuring the gap between two dates or timestamps (DATEDIFF, TIMESTAMPDIFF).

Both families depend on the INTERVAL keyword, which lets SQL reason in calendar units (days, months, years) rather than a fixed number of days — critical, since months and years don’t have a constant length.


Why This Exists

Business logic is rarely about an absolute date — it’s about a relationship between two dates. “90 days after hire,” “48 hours after order placement,” “the gap between signup and first purchase” are all calculation problems, not extraction problems. Getting this wrong — for example, treating a month as a fixed 30 days — produces subtly incorrect dates that drift further wrong the more they compound.


Business Context

An HR system computing a “1-year anniversary” date must add exactly one calendar year, correctly handling leap years — DATE_ADD(hire_date, INTERVAL 1 YEAR), not hire_date + 365. An SLA monitoring system measuring delivery time in hours, not whole days, must use TIMESTAMPDIFF(HOUR, ...) rather than DATEDIFF(), which truncates to whole calendar days and would hide same-day delays.


Real Company Examples


Where It Is Used


Functions Covered

Function Purpose
DATE_ADD(date, INTERVAL n unit) Add a calendar-aware interval to a date
DATE_SUB(date, INTERVAL n unit) Subtract a calendar-aware interval from a date
ADDDATE(date, INTERVAL n unit) Alias for DATE_ADD()
SUBDATE(date, INTERVAL n unit) Alias for DATE_SUB()
DATEDIFF(date1, date2) Whole calendar days between two dates (date1 − date2)
TIMESTAMPDIFF(unit, dt1, dt2) Difference between two datetimes in a specified unit (hour, day, month, year)

Syntax Explanation

-- Add / subtract calendar-aware intervals
SELECT DATE_ADD(hire_date, INTERVAL 90 DAY)  AS probation_end   FROM employes;
SELECT DATE_SUB(hire_date, INTERVAL 1 MONTH) AS pre_hire_marker FROM employes;

-- Difference in whole days
SELECT DATEDIFF(CURRENT_DATE, hire_date) AS days_employed FROM employes;

-- Difference in a specific unit (hour/day/month/year)
SELECT TIMESTAMPDIFF(MONTH, hire_date, CURRENT_DATE) AS months_employed FROM employes;

INTERVAL accepts a numeric value and a unit keyword: DAY, WEEK, MONTH, QUARTER, YEAR, HOUR, MINUTE, SECOND. Using INTERVAL instead of raw integer addition (hire_date + 30) ensures MySQL applies calendar-correct arithmetic — a month added to January 31 correctly rolls to the last valid day of February, not an invalid or silently-adjusted date.


Visual Explanation

Date arithmetic timeline — DATE_ADD, DATE_SUB, DATEDIFF, TIMESTAMPDIFF

                    DATE_SUB(d, INTERVAL 1 MONTH)     DATE_ADD(d, INTERVAL 90 DAY)
                              │                                    │
                              ▼                                    ▼
   ◄─────────────────────────┼────────────── d ──────────────────┼─────────────────►
                          (past)                               (future)

   DATEDIFF(CURRENT_DATE, d)         →  whole days between d and today
   TIMESTAMPDIFF(HOUR, d, CURRENT_TIMESTAMP)  →  precise hour-level gap

Step-by-Step Walkthrough

  1. Identify whether the business question is “move a date” (interval arithmetic) or “measure a gap” (differencing).
  2. For interval arithmetic, choose DATE_ADD or DATE_SUB and specify the correct calendar unit — never approximate months as 30 days or years as 365 days.
  3. For differencing, decide the required precision. Whole days only? Use DATEDIFF(). Hours, months, or years? Use TIMESTAMPDIFF() with the appropriate unit.
  4. Watch the argument orderDATEDIFF(date1, date2) computes date1 − date2; reversing the arguments silently flips the sign, turning “days employed” into a negative number.

Production Considerations


Performance Notes


Edge Cases


Common Mistakes


Interview Questions

  1. “How would you calculate an employee’s tenure in exact months, not days?” TIMESTAMPDIFF(MONTH, hire_date, CURRENT_DATE) — it accounts for calendar month boundaries correctly, unlike dividing DATEDIFF() by 30.

  2. “What’s the difference between DATEDIFF() and TIMESTAMPDIFF()?” DATEDIFF() always returns whole calendar days and ignores time-of-day; TIMESTAMPDIFF() lets you specify the unit (hour, day, month, year) and respects full datetime precision.

  3. “A report shows a negative number of days since signup. What’s the most likely cause?” The arguments to DATEDIFF() are reversed — the earlier date is being subtracted from, rather than subtracting.


Summary

Date calculations are how SQL reasons about relationships between two points in time — moving a date with DATE_ADD/DATE_SUB, and measuring a gap with DATEDIFF/TIMESTAMPDIFF. The engineering discipline here is: always use calendar-aware INTERVAL arithmetic instead of fixed day-count approximations, choose the differencing function that matches the required precision, and double-check argument order.


Practice Challenges

  1. Write a query that computes each employee’s probation end date (90 days after hire) and their 1-year anniversary date (1 calendar year after hire) in the same result set.
  2. Write a query that computes tenure in whole days, whole months, and whole years for every employee, using the correct function for each grain.
  3. Explain why DATEDIFF(hire_date, CURRENT_DATE) produces negative tenure values, and correct it.

Further Reading


Previous: ← 02 — Date Extraction Next: 04 — Date Formatting →