Date Arithmetic: Intermediate
EXTRACT, Fiscal Calendars, and ISO Weeks
Spot date arithmetic needs: "last 30 days," "same day last year," "business days only," "fiscal quarter."
The question that sets the tone: 'compute monthly revenue per region for our fiscal year, where Q1 starts in April, the warehouse stores transactions in UTC, and the consumer wants the report in the region's local timezone.' The candidate who reaches for DATE_TRUNC('month', txn_ts) and stops there is producing a report whose monthly boundaries are wrong for every region except UTC. The candidate who pre-converts to each region's timezone, then truncates, then aggregates is producing a report that matches what each region's finance team will reconcile against. The mechanical difference is two function calls; the production difference is whether finance ever questions the dashboard.
Where production reporting actually breaks
- UTC source, local-time consumer; conversion happens at a named point in the pipeline.
- Q1 starts in April, June, or October; calendar tables hold the per-date mapping.
- exclude weekends and holidays; calendar table's is_business_day flag drives the count.
- streaming and near-real-time pipelines; pick one convention per query and stay consistent.
- ▸"daily revenue, but the consumer is in Tokyo and the data is in UTC"
- ▸"fiscal year ending June 30; show me Q3 numbers"
- ▸"hours of customer support response time, business days only"
- ▸"event time vs server time, which one should drive the report?"
- ▸"how does daylight saving affect this hourly aggregate?"
- ▸"the dashboard shows Sunday revenue twice in November; what happened?"
The three timezone conventions
- Dashboard buckets must align with local days/weeks/months
- Consumer is a finance or analytics team that reconciles against local-time records
- The source is UTC but the report is a per-region report
- Example: monthly revenue per region for finance reporting
- Report is global; one bucket per UTC day, regardless of consumer geography
- The consumer is an engineering or product team thinking in UTC
- Multiple regions need to compare on a common axis
- Example: hourly system metrics for SRE dashboards
The mental model: storage / computation / display
- ▸Storage: what the database actually holds (UTC for new systems)
- ▸Computation: what the query operates on (UTC or local, picked per query)
- ▸Display: what the dashboard renders (local, at the BI layer)
- ▸Wrong-layer conversion is the source of every production timezone bug
Timestamps, Timezones, and AT TIME ZONE
Write date manipulation using the three core functions and handle dialect differences (DATEADD vs INTERVAL).
The canonical timezone-aware aggregate
Reading the conversion
Where the conversion can go wrong
- ▸AT TIME ZONE applied to TIMESTAMP (assumes UTC; wrong if column is not)
- ▸Conversion at display instead of aggregation (buckets don't realign)
- ▸Hardcoded single timezone for a multi-region report
- ▸Each is silent: query runs, numbers look like data, finance reconciles and finds the gap
Daylight saving time
The discipline: convert once, at the right layer
DST Boundaries and the Missing Hour
Pull date parts with EXTRACT, handle fiscal year offsets, and explain ISO week numbering.
Fiscal year arithmetic
When the arithmetic shift breaks
Business-day arithmetic
Calendar tables in production
- date (PK), day_of_week, week_of_year, month_of_year, quarter, year
- fiscal_year, fiscal_quarter, fiscal_month, fiscal_week (per company's fiscal convention)
- is_weekend, is_business_day, is_holiday, holiday_name (per region or per company)
- precomputed for a wide range (1970-2070); refresh when next year's holidays are confirmed
- Works for first-of-month fiscal years
- No table dependency; query is self-contained
- Right tool for one-off ad-hoc queries
- Wrong tool for production reporting; fiscal-year edge cases break it
- Handles any fiscal calendar shape (4-4-5, custom, multi-fiscal)
- Holiday and business-day logic is in one place
- Right tool for production reporting and audit
- Requires the table to be maintained; new holidays added per year
Edge cases the calendar table fixes
Aligning to Week-Start and Month-End
Convert between UTC and local time, explain why comparing timestamps across zones requires explicit conversion.
generate_series for Postgres-style spines
- ▸Postgres: generate_series (one line, native)
- ▸BigQuery: GENERATE_DATE_ARRAY + UNNEST
- ▸Snowflake: GENERATOR + DATEADD arithmetic
- ▸Portable: recursive CTE (5-7 lines, works on every modern engine)
- ▸Production: calendar table (free fiscal and business-day metadata)
Recursive CTE for portability
Calendar table for production reporting
Picking between the three
- Simplest syntax; one line for a date range
- Engine-specific; not portable
- Right for ad-hoc Postgres queries
- No fiscal or business-day metadata
- Portable across engines that support recursive CTE
- More verbose; 5-7 lines for the same range
- Right for multi-engine codebases
- No fiscal or business-day metadata
The spine joined to actuals
On a date spine for a multi-dimensional query (region × day, product × day), the spine becomes a cross-join of dimensions. Generate the spine, CROSS JOIN with the distinct dimensions, LEFT JOIN actuals. The cardinality grows multiplicatively; for production reporting, restrict to dimension combinations that have ever been populated, not the full cross product.
Dialect Differences in Date Functions
Create a date spine using recursive CTE or GENERATE_SERIES and LEFT JOIN to fill calendar gaps in sparse data.
Indexing date columns
A WHERE clause on txn_date benefits from an index on txn_date. A WHERE clause on DATE_TRUNC('month', txn_date) does not benefit from a plain index on txn_date; the function call hides the column from the optimizer. The fix: index the expression itself (expression indexes on Postgres) or restructure the query to use a range predicate the optimizer can use.
Partition pruning
EXPLAIN as the diagnostic
- WHERE DATE_TRUNC('month', txn_date) = '2024-03-01' (function on column)
- WHERE EXTRACT(YEAR FROM txn_date) = 2024 (function on column)
- WHERE txn_date::TEXT LIKE '2024-03%' (cast plus pattern match)
- Each one hides txn_date from the optimizer; no index use, no partition pruning
- WHERE txn_date >= '2024-03-01' AND txn_date < '2024-04-01'
- WHERE txn_date >= '2024-01-01' AND txn_date < '2025-01-01'
- Each one is a plain column comparison; the optimizer uses indexes and partitions
- Same logical result; orders of magnitude faster on large tables
Window function performance
Story call-back: the fiscal-year question from s0
> You are in a data engineering interview at a multi-region SaaS company. The interviewer asks: 'Compute monthly revenue per region for our fiscal year, where Q1 starts in April. Transactions are in UTC; finance wants local-time month boundaries.'
txn_ts AT TIME ZONE region_timezone AS local_ts before the DATE_TRUNC. Truncating in UTC and relabeling as local moves the numbers without realigning the bucket boundaries.DATE_TRUNC('year', txn_date - INTERVAL '3 months'), only holds when the fiscal year starts on the first of a month. Non-first-of-month starts, 4-4-5 retail calendars, regional holidays, and half-days all need dim_calendar with precomputed fiscal and is_business_day columns.generate_series for a one-off on Postgres, WITH RECURSIVE for a multi-engine codebase, and a calendar table in production because the spine then inherits fiscal, business-day, and holiday columns for free. The spine is only useful LEFT JOINed to actuals with COALESCE(SUM(amount), 0) so gap days appear as explicit zeros.WHERE DATE_TRUNC('month', txn_date) = '2024-03-01' with the half-open range txn_date >= '2024-03-01' AND txn_date < '2024-04-01'; partition pruning skips whole files and is routinely a 10x to 100x difference.Every data engineering question involves dates; most candidates fumble timezone math
- Category
- SQL
- Difficulty
- intermediate
- Duration
- 25 minutes
- Challenges
- 0 hands-on challenges
Topics covered: EXTRACT, Fiscal Calendars, and ISO Weeks, Timestamps, Timezones, and AT TIME ZONE, DST Boundaries and the Missing Hour, Aligning to Week-Start and Month-End, Dialect Differences in Date Functions
Lesson Sections
- EXTRACT, Fiscal Calendars, and ISO Weeks (concepts: sqlTimezones)
Where production reporting actually breaks Four areas catch out every engineer who hasn't yet shipped through them. First: timezone-aware aggregation when the source is UTC and the consumer is local. The fix is the AT TIME ZONE conversion at the right point in the pipeline. Second: fiscal calendars where the company's year does not start on January 1. The fix is a calendar table or arithmetic that subtracts the fiscal-offset months. Third: SLA timing that has to subtract weekends and holidays. T
- Timestamps, Timezones, and AT TIME ZONE (concepts: sqlTimezones)
Timezone-aware aggregation is the area where code most often graduates from working-for-the-easy-case to surviving-the-edge-cases. The discipline is consistent: storage is UTC, queries are explicit about which zone they aggregate in, conversions happen at named points in the query. Once you write this consistently, the edge-case bugs stop shipping; until you do, they keep showing up in the dashboards finance reconciles against. The canonical timezone-aware aggregate Reading the conversion The tr
- DST Boundaries and the Missing Hour (concepts: sqlDateTrunc)
Most companies do not align their fiscal year with the calendar year. Apple's fiscal year ends in September; many retailers end in January or February; the US government ends in September. A query that uses DATE_TRUNC('year', date) for fiscal reporting is wrong for any company except those with calendar-year fiscal alignment. Knowing the patterns for fiscal calendars and business-day windows before the interviewer asks is what tells the room you've reported against a real company's books. Fiscal
- Aligning to Week-Start and Month-End (concepts: sqlRecursiveCte)
A date spine is a complete enumeration of dates over a window, used to LEFT JOIN actuals onto so missing dates appear as explicit zero rows. Every period-over-period query, every retention curve, every monitoring metric uses a date spine. The question is which tool to use: generate_series (Postgres-specific, simplest), a recursive CTE (portable across engines), or a calendar table (production-grade). Each has a cost and a use case. generate_series for Postgres-style spines Postgres's generate_se
- Dialect Differences in Date Functions (concepts: sqlRecursiveCte)
Past correctness, the interviewer escalates to cost: 'this query is slow; what would you change?' Date arithmetic queries have specific performance levers, and the deeper answer names each one rather than gesturing at 'add an index.' Indexing the date column, partition pruning, function-call rewrites to expose predicates to the optimizer, and the EXPLAIN-then-tune discipline. Indexing date columns Partition pruning Most analytical warehouses partition fact tables by date. Snowflake clusters; Big