Tier 3 · Intermediate

Date Truncation and Extraction in SQL

By Owen Middleton · Updated September 2026 · Examples run on PostgreSQL 17

What are DATE_TRUNC and EXTRACT in SQL?

DATE_TRUNC collapses timestamps into calendar period groups. EXTRACT pulls a single numeric component out of a timestamp.

Both work on date/time values, but they answer different questions. DATE_TRUNC is a grouping tool: it rounds a timestamp down to the nearest period boundary — month, week, year, day, hour. Every timestamp within March 2024 truncated to month becomes 2024-03-01 00:00:00. Group by that value and you get one row per month. EXTRACT is a decomposition tool: it pulls out one component of a timestamp as a number — the year, the month number (1–12), the day of the week, the hour. The outputs are different types: DATE_TRUNC returns a timestamp type — a TIMESTAMPTZ column comes back as TIMESTAMPTZ, not as a date — and EXTRACT returns a number.

How do you group rows by month in PostgreSQL?

You're building a monthly revenue report. You want one row per calendar month with the revenue total for that month. DATE_TRUNC is the right tool:

SELECT
  DATE_TRUNC('month', ordered_at) AS month,
  SUM(total_amount) AS revenue
FROM orders
GROUP BY DATE_TRUNC('month', ordered_at)
ORDER BY month

Every order from January 2024 truncates to 2024-01-01 00:00:00. Every order from February truncates to 2024-02-01 00:00:00. The GROUP BY collapses them into monthly buckets. You get one row per month.

What does EXTRACT return in PostgreSQL?

EXTRACT does something different. It pulls out one numeric component:

SELECT
  EXTRACT(year FROM ordered_at) AS year,
  EXTRACT(month FROM ordered_at) AS month_number,
  EXTRACT(dow FROM ordered_at) AS day_of_week
FROM orders

year gives you the four-digit year. month_number gives you 1 through 12. dow gives you the day of week, where 0 is Sunday and 6 is Saturday. These are numbers — useful for filtering (orders placed on Tuesdays), comparisons, or further arithmetic. Two other fields worth knowing: quarter returns 1 through 4, and epoch returns the number of seconds since January 1, 1970 as a decimal — useful for computing precise durations or interfacing with systems that store time as a Unix timestamp.

What is the difference between EXTRACT and DATE_TRUNC?

The one thing that trips people up: using EXTRACT(month ...) when you mean DATE_TRUNC('month', ...).

EXTRACT(month FROM ordered_at) returns a number between 1 and 12 with no year attached. An order from March 2023 and an order from March 2024 both return 3. Group by that value and you collapse all Marches from all years into one row. That's occasionally the intent. Usually, it's a bug.

DATE_TRUNC('month', ordered_at) includes the year in the boundary value. 2024-03-01 and 2023-03-01 are different values, so they stay in different groups. For time-series reports, DATE_TRUNC is almost always the right tool.

Check your understanding

You want to group sales by calendar month and show one row per month per year. Which function do you use?

Practice DATE_TRUNC and EXTRACT in SQL

Practice · easy ecommerce · Brightlane

Brightlane's reporting pipeline assigns each event to its calendar month for period-based grouping.

Write a query to return the month boundary produced by truncating the timestamp '2024-03-15 14:32:07' to month precision.

Output:

  • A single row with one column, month_start, typed as a timezone-naive timestamp.
Schema · ecommerce5 tables? = nullable
categories
idinteger
nametext
parent_id?integer
products
idinteger
nametext
category_id?integer
pricenumeric
stock_qtyinteger
attributes?jsonb
order_items
idinteger
order_id?integer
product_id?integer
quantityinteger
unit_pricenumeric
customers
idinteger
nametext
emailtext
city?text
countrytext
created_attimestamptz
is_activeboolean
orders
idinteger
customer_id?integer
ordered_attimestamptz
statustext
total_amountnumeric

Run previews · Check grades

Write a query, then run it to see results here.

Worked solution

The full breakdown walks through the shape, each clause, why this approach beats the alternatives, and the trap to avoid.

See the full worked solution

10 DATE_TRUNC and EXTRACT practice problems

Start learning to practice all 10 DATE_TRUNC and EXTRACT problems, with instant grading and mastery tracking.

Deeper guides on DATE_TRUNC and EXTRACT

Common questions about DATE_TRUNC and EXTRACT

Does DATE_TRUNC round or truncate?

It truncates. DATE_TRUNC always moves a value down to the start of its period and never up, so 23:59 on January 31st truncates to January 1st, not February 1st. Nothing below the period survives: the day, hours and minutes are all reset.

Does DATE_TRUNC return a date or a timestamp?

Always a timestamp, even when you give it a date. Pass a TIMESTAMP and you get a TIMESTAMP back; pass a DATE and PostgreSQL promotes it, so you get a TIMESTAMPTZ. When you want a plain calendar day for display or for joining, cast the result with ::date.

What does EXTRACT return?

A single number, not a point in time. EXTRACT(MONTH FROM order_date) returns 1 for January, and the result is a numeric value that knows nothing about the year or the day it came from. Reach for EXTRACT when you need one field as a number, and DATE_TRUNC when you need a period you can still sort as a date.

Can DATE_TRUNC truncate to a quarter?

Yes. DATE_TRUNC('quarter', value) returns the first moment of the calendar quarter: January 1st, April 1st, July 1st or October 1st. A date in late May truncates to April 1st.

How you actually get good at SQL

Reading explains SQL. Writing it, over and over with instant feedback, is what makes you fluent.

That's the whole SQLMaxx loop: 600+ real problems, instant AI feedback, mastery you can actually see, and spaced review that won't let you forget.

A stack of SQL practice problem cards, the top card showing an employees table.
615 problems · 66 concepts

Real problems. Not toy examples.

615 hand-built problems spanning all 66 concepts, from basic SELECTs to window functions, built on real schemas and real business questions, the kind you'll actually get asked on the job. Enough reps to make SQL automatic.

A retro computer showing a SQL query marked correct with a green checkmark.
Instant AI feedback

Write a query. Know if it's right in one second.

No copying an answer and hoping it clicked. The AI grader checks your real query against real data, catches exactly what's wrong, and explains the fix in plain English, like a senior analyst reading over your shoulder on every problem.

A circular mastery progress dial filling from blue to green, the SQLMaxx diamond at its center.
Mastery tracking

Stop guessing whether you actually know it.

SQLMaxx tracks every concept and shows you what you've mastered and what's still shaky. Your skills fill in one concept at a time, so 'I think I get joins' becomes something you can prove.

A SQL query editor circled by a blue return arrow with a clock, scheduled to come back for review.
Spaced review

Learn it once. Keep it for good.

Most of what you learn this week fades by next week. So when a concept comes due for review, SQLMaxx hands you a fresh problem to solve from a blank editor, not a flashcard to re-read. A research-backed spaced-repetition algorithm (FSRS) times each return for right before you'd forget, so your SQL is still there months later, when the interview or the job actually needs it.