All 40 lessons
Lesson 11 of 40 · SQL Functions
SQL Date Functions
By Skillancy Editorial Team
Every example runs on the ShopKart dataset, already loaded in the free SQL Compiler. Click Try it in the SQL Compiler under a query to open it there, then press Run.
Date functions let you pull out parts of a date, round dates to a month or week, and measure the time between two events. Almost every business report is organised by time, so these are must-know functions for analysts.
The examples use PostgreSQL. Function names differ between databases more for dates than for anything else; the FAQ lists the common MySQL and SQL Server equivalents.
Quick reference
| Function | What it does | Example | Result |
|---|---|---|---|
CURRENT_DATE | today's date | CURRENT_DATE | today |
NOW() | current date and time | NOW() | now |
EXTRACT(part FROM d) | year, month, day, dow, quarter… | EXTRACT(MONTH FROM DATE '2025-08-19') | 8 |
DATE_TRUNC('unit', d) | round down to month, week, year… | DATE_TRUNC('month', DATE '2025-08-19') | 2025-08-01 (as a timestamp) |
d2 - d1 | days between two dates | DATE '2025-01-08' - DATE '2025-01-05' | 3 |
d + INTERVAL '...' | add time | DATE '2025-01-31' + INTERVAL '1 month' | 2025-02-28 (as a timestamp) |
TO_CHAR(d, 'format') | format as text | TO_CHAR(DATE '2025-08-19', 'Mon YYYY') | Aug 2025 |
AGE(d2, d1) | difference as years/months/days | AGE(DATE '2026-01-01', DATE '2024-03-15') | 1 year 9 mons 17 days |
Examples
1. Extract parts of a date
SELECT order_id,
order_date,
EXTRACT(YEAR FROM order_date) AS order_year,
EXTRACT(MONTH FROM order_date) AS order_month,
EXTRACT(QUARTER FROM order_date) AS order_qtr
FROM orders
LIMIT 4;Try it in the SQL CompilerResult:
| order_id | order_date | order_year | order_month | order_qtr |
|---|---|---|---|---|
| 1001 | 2025-01-05 | 2025 | 1 | 1 |
| 1002 | 2025-01-18 | 2025 | 1 | 1 |
| 1003 | 2025-02-02 | 2025 | 2 | 1 |
| 1004 | 2025-02-20 | 2025 | 2 | 1 |
(4 rows)
2. Day of the week
EXTRACT(DOW ...) returns 0 for Sunday through 6 for Saturday. TO_CHAR gives the name (the FM prefix removes padding spaces):
SELECT order_id,
order_date,
EXTRACT(DOW FROM order_date) AS dow_number,
TO_CHAR(order_date, 'FMDay') AS day_name
FROM orders
LIMIT 4;Try it in the SQL CompilerResult:
| order_id | order_date | dow_number | day_name |
|---|---|---|---|
| 1001 | 2025-01-05 | 0 | Sunday |
| 1002 | 2025-01-18 | 6 | Saturday |
| 1003 | 2025-02-02 | 0 | Sunday |
| 1004 | 2025-02-20 | 4 | Thursday |
(4 rows)
3. Days to deliver
Subtracting two dates gives a whole number of days:
SELECT order_id,
order_date,
delivery_date,
delivery_date - order_date AS days_to_deliver
FROM orders
WHERE status = 'Delivered'
ORDER BY days_to_deliver DESC
LIMIT 5;Try it in the SQL CompilerResult:
| order_id | order_date | delivery_date | days_to_deliver |
|---|---|---|---|
| 1010 | 2025-06-09 | 2025-06-15 | 6 |
| 1016 | 2025-09-25 | 2025-09-30 | 5 |
| 1002 | 2025-01-18 | 2025-01-23 | 5 |
| 1018 | 2025-10-28 | 2025-11-02 | 5 |
| 1007 | 2025-04-15 | 2025-04-19 | 4 |
(5 rows)
4. Monthly order counts with DATE_TRUNC
DATE_TRUNC('month', ...) maps every date to the first of its month, so you can group by it:
SELECT DATE_TRUNC('month', order_date)::date AS order_month,
COUNT(*) AS orders
FROM orders
WHERE order_date < '2025-07-01'
GROUP BY order_month
ORDER BY order_month;Try it in the SQL CompilerResult:
| order_month | orders |
|---|---|
| 2025-01-01 | 2 |
| 2025-02-01 | 2 |
| 2025-03-01 | 2 |
| 2025-04-01 | 1 |
| 2025-05-01 | 2 |
| 2025-06-01 | 2 |
(6 rows)
You'll learn GROUP BY properly in lesson 14. ::date drops the time part from the output.
5. Format dates for reports
SELECT order_id,
TO_CHAR(order_date, 'DD Mon YYYY') AS order_date_label,
TO_CHAR(order_date, 'YYYY-MM') AS year_month
FROM orders
LIMIT 3;Try it in the SQL CompilerResult:
| order_id | order_date_label | year_month |
|---|---|---|
| 1001 | 05 Jan 2025 | 2025-01 |
| 1002 | 18 Jan 2025 | 2025-01 |
| 1003 | 02 Feb 2025 | 2025-02 |
(3 rows)
6. Add and subtract intervals
A 7-day return window from the delivery date:
SELECT order_id,
delivery_date,
(delivery_date + INTERVAL '7 days')::date AS return_window_ends
FROM orders
WHERE status = 'Delivered'
LIMIT 3;Try it in the SQL CompilerResult:
| order_id | delivery_date | return_window_ends |
|---|---|---|
| 1001 | 2025-01-08 | 2025-01-15 |
| 1002 | 2025-01-23 | 2025-01-30 |
| 1003 | 2025-02-05 | 2025-02-12 |
(3 rows)
7. Relative to today
Queries using CURRENT_DATE give different results every day, so their output isn't shown here. Try them in the compiler:
-- Orders placed in the last 30 days
SELECT order_id, order_date
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '30 days';
-- How long each customer has been with ShopKart
SELECT customer_name, AGE(CURRENT_DATE, signup_date) AS tenure
FROM customers;Common mistakes
- Text that looks like a date.
'05/01/2025'is ambiguous (5 January or 1 May?). Always use'YYYY-MM-DD'. - Grouping by
EXTRACT(MONTH ...)across years. January 2025 and January 2026 get merged. UseDATE_TRUNC('month', ...)or group by year and month together. - BETWEEN on timestamps. Use
>= start AND < next_dayso you don't miss events late on the last day.
Practice question
Count how many orders ShopKart received in each quarter of 2025.
Show solution
SELECT EXTRACT(QUARTER FROM order_date) AS quarter,
COUNT(*) AS orders
FROM orders
WHERE order_date >= '2025-01-01' AND order_date < '2026-01-01'
GROUP BY quarter
ORDER BY quarter;Try it in the SQL CompilerResult:
| quarter | orders |
|---|---|
| 1 | 6 |
| 2 | 5 |
| 3 | 5 |
| 4 | 5 |
(4 rows)
Key takeaways
EXTRACTpulls out year, month, quarter, day of week and more.DATE_TRUNCrounds dates down and is the best way to group by month or week.- Subtracting dates gives days;
INTERVALadds or removes time. TO_CHARformats dates as readable text.
Frequently asked questions
How do I get the difference between two dates in SQL?
In PostgreSQL, subtracting two DATE values returns the number of days: delivery_date - order_date. MySQL uses DATEDIFF(end, start) and SQL Server uses DATEDIFF(day, start, end).
How do I group by month in SQL?
Use DATE_TRUNC('month', order_date) in PostgreSQL, which turns every date into the first day of its month. MySQL users often use DATE_FORMAT(order_date, '%Y-%m').
What is the difference between DATE and TIMESTAMP?
DATE stores only the calendar day. TIMESTAMP stores date and time. TIMESTAMPTZ also records the time zone, which matters when users are in different regions.
Keep learning SQL
One email a week with SQL and analytics guides, new practice questions and cohort dates. No spam, unsubscribe anytime.
Prefer a one-page summary? Download the free SQL cheat sheet (PDF)