ποΈ SQL Β· Topic 10 of 20
Date & Time Functions β SQL Questions with Answers
30 practice questions on Date & Time Functions, each with the correct answer and a clear explanation of why it is right. Read through them as revision notes, or take this topic as an interactive quiz to test yourself.
2 easy Β· 17 medium Β· 11 hard Β· Part of SQL: Databases from basics to window functions - 20 topics.
Medium questions (17)
Q3. medium
How do you extract just the YEAR from a date?
SELECT EXTRACT(YEAR FROM order_date), EXTRACT(MONTH FROM order_date);
- A EXTRACT(YEAR FROM order_date) or YEAR(order_date)
- B GET_YEAR(order_date)
- C order_date.year
- D DATEYEAR(order_date)
Answer: A β EXTRACT(YEAR FROM order_date) or YEAR(order_date)
EXTRACT is standard SQL; MySQL and SQL Server also have YEAR(), MONTH(), DAY() shortcuts. EXTRACT(DOW FROM d) even gives the day of week.
EXTRACTYEAR
Q4. medium
How do you add 7 days to a date?
SELECT order_date + INTERVAL '7 days' AS due_date FROM orders;
- A order_date + INTERVAL '7 days' or DATE_ADD(order_date, INTERVAL 7 DAY)
- B order_date + 7 (always works)
- C ADD_DAYS(order_date, 7)
- D order_date.plus(7)
Answer: A β order_date + INTERVAL '7 days' or DATE_ADD(order_date, INTERVAL 7 DAY)
PostgreSQL/Oracle use INTERVAL; MySQL uses DATE_ADD; SQL Server uses DATEADD(DAY, 7, order_date). Plain + 7 works on DATE in some databases but is not portable.
DATE_ADDINTERVAL
Q5. medium
How do you find the number of days between two dates?
SELECT DATEDIFF(delivered_at, ordered_at) AS days_to_deliver FROM orders;
- A DATEDIFF(end_date, start_date) or end_date - start_date
- B DAYS_BETWEEN only
- C SUBTRACT(end, start)
- D end.minus(start)
Answer: A β DATEDIFF(end_date, start_date) or end_date - start_date
In PostgreSQL, subtracting two DATEs gives an integer number of days. MySQL uses DATEDIFF(end, start); SQL Server uses DATEDIFF(DAY, start, end) - note the argument order differs.
DATEDIFFDate arithmetic
Q7. medium
How do you get the first day of the current month?
SELECT DATE_TRUNC('month', order_date) AS month, COUNT(*)
FROM orders GROUP BY 1;
- A DATE_TRUNC('month', CURRENT_DATE) in PostgreSQL
- B MONTH_START()
- C FIRST_DAY()
- D CURRENT_DATE - 30
Answer: A β DATE_TRUNC('month', CURRENT_DATE) in PostgreSQL
DATE_TRUNC rounds a date down to a unit (month, year, hour). It is the cleanest way to bucket timestamps for reporting. MySQL uses DATE_FORMAT or arithmetic.
DATE_TRUNCReporting
Q9. medium
How do you extract the day of the week?
- A EXTRACT(DOW FROM date) or DAYOFWEEK(date) - returns a number for the weekday
- B WEEKDAY_NAME(date)
- C DAY(date)
- D There is no way
Answer: A β EXTRACT(DOW FROM date) or DAYOFWEEK(date) - returns a number for the weekday
Beware the numbering differs: PostgreSQL DOW is 0=Sunday, MySQL DAYOFWEEK is 1=Sunday, and ISODOW is 1=Monday. Check your database before filtering on weekdays.
Day of weekEXTRACT
Q10. medium
What does DATE(order_datetime) return?
SELECT DATE(created_at) AS day, COUNT(*) FROM events GROUP BY 1;
- A The date portion only, dropping the time
- B The full timestamp
- C Just the year
- D An error
Answer: A β The date portion only, dropping the time
Casting a DATETIME to DATE (via DATE() or CAST(x AS DATE)) strips the time - handy for grouping all of a day's events together.
DATECAST
Q12. medium
How do you calculate age in years from a birthdate?
- A AGE(birthdate) in PostgreSQL, or DATEDIFF-based arithmetic elsewhere
- B birthdate - NOW()
- C YEARS(birthdate)
- D birthdate.age()
Answer: A β AGE(birthdate) in PostgreSQL, or DATEDIFF-based arithmetic elsewhere
PostgreSQL's AGE() returns an interval; extract the years. Elsewhere: FLOOR(DATEDIFF(NOW(), birthdate) / 365.25), being careful about leap years and exact birthdays.
AGEDATEDIFF
Q13. medium
How do you filter for records from the last 30 days?
WHERE created_at >= NOW() - INTERVAL '30 days';
- A WHERE created_at >= CURRENT_DATE - INTERVAL '30 days'
- B WHERE created_at = LAST_30_DAYS
- C WHERE created_at IN (30 days)
- D WHERE RECENT(created_at, 30)
Answer: A β WHERE created_at >= CURRENT_DATE - INTERVAL '30 days'
Compute the cutoff by subtracting an interval from today, then compare. Keeping the function on the constant side (not the column) lets the index on created_at work.
INTERVALDate ranges
Q15. medium
How do you format a date as 'July 04, 2026'?
- A TO_CHAR(order_date, 'Month DD, YYYY') in PostgreSQL/Oracle
- B FORMAT(order_date)
- C STRING(order_date)
- D Dates cannot be formatted
Answer: A β TO_CHAR(order_date, 'Month DD, YYYY') in PostgreSQL/Oracle
TO_CHAR with a format model handles custom display. MySQL uses DATE_FORMAT(date, '%M %d, %Y'); SQL Server uses FORMAT(). Prefer formatting in the app layer where possible.
TO_CHARDATE_FORMAT
Q17. medium
How do you get yesterday's date?
- A CURRENT_DATE - INTERVAL '1 day' (or CURRENT_DATE - 1 in some databases)
- B YESTERDAY()
- C NOW() - 1
- D PREVIOUS(CURRENT_DATE)
Answer: A β CURRENT_DATE - INTERVAL '1 day' (or CURRENT_DATE - 1 in some databases)
Subtracting an interval is the portable form. In PostgreSQL and MySQL, CURRENT_DATE - 1 also works because a DATE minus an integer subtracts days.
INTERVALDate arithmetic
Q19. medium
What does EXTRACT(EPOCH FROM interval) give in PostgreSQL?
- A The interval expressed in total SECONDS
- B The year
- C The month name
- D An error
Answer: A β The interval expressed in total SECONDS
EPOCH converts an interval or timestamp to seconds - useful for computing precise durations like average response time: EXTRACT(EPOCH FROM (ended - started)).
EPOCHDuration
Q20. medium
How do you get the last day of a month?
- A LAST_DAY(date) in MySQL/Oracle, or date-arithmetic with DATE_TRUNC in PostgreSQL
- B MONTH_END(date)
- C date + 30
- D FINAL_DAY(date)
Answer: A β LAST_DAY(date) in MySQL/Oracle, or date-arithmetic with DATE_TRUNC in PostgreSQL
LAST_DAY handles varying month lengths and leap years automatically. In PostgreSQL: (DATE_TRUNC('month', d) + INTERVAL '1 month - 1 day').
LAST_DAYMonth boundaries
Q22. medium
How would you count orders per weekday name?
SELECT TO_CHAR(order_date, 'Day') AS weekday, COUNT(*)
FROM orders GROUP BY 1;
- A GROUP BY the weekday using TO_CHAR(date, 'Day') or DAYNAME(date)
- B GROUP BY date
- C GROUP BY hour
- D It cannot be done
Answer: A β GROUP BY the weekday using TO_CHAR(date, 'Day') or DAYNAME(date)
Extract the weekday name (or number) and group by it. To order Monday-Sunday correctly, group by the numeric day of week and format the label separately.
WeekdayGROUP BY
Q24. medium
What does DATE_TRUNC('hour', ts) do?
- A Rounds the timestamp DOWN to the start of the hour (minutes and seconds become 0)
- B Rounds to the nearest hour
- C Returns the hour number only
- D Adds an hour
Answer: A β Rounds the timestamp DOWN to the start of the hour (minutes and seconds become 0)
Truncation always rounds down, making it perfect for bucketing events into hourly (or minutely) intervals for time-series charts.
DATE_TRUNCTime series
Q26. medium
How do you extract the hour from a timestamp?
- A EXTRACT(HOUR FROM ts) or HOUR(ts)
- B ts.hour
- C GET_HOUR(ts)
- D TIMEPART(ts)
Answer: A β EXTRACT(HOUR FROM ts) or HOUR(ts)
Extracting the hour is common for finding peak-traffic times: GROUP BY EXTRACT(HOUR FROM created_at) to see activity by hour of day.
EXTRACTHOUR
Q28. medium
How do you find records from the current year?
- A WHERE order_date >= DATE_TRUNC('year', CURRENT_DATE)
- B WHERE YEAR(order_date) = THIS_YEAR
- C WHERE order_date = 2026
- D WHERE order_date CONTAINS 2026
Answer: A β WHERE order_date >= DATE_TRUNC('year', CURRENT_DATE)
Truncating today's date to the year gives January 1st, and comparing with >= keeps the index usable - better than wrapping the column in YEAR().
DATE_TRUNCSargability
Q30. medium
Which is the safest, most portable literal for a specific date-time?
- A '2026-07-04 14:30:00' - ISO format, understood everywhere
- B 'July 4 2026 2:30pm'
- C '04-07-26'
- D '7/4/26 14:30'
Answer: A β '2026-07-04 14:30:00' - ISO format, understood everywhere
ISO 8601 (YYYY-MM-DD HH:MM:SS) is unambiguous and sorts correctly. The other formats depend on locale settings and are a frequent source of silent misreads.
ISO 8601Literals
Hard questions (11)
Q6. hard
Why does 'WHERE order_date = '2026-07-04'' sometimes miss rows?
- A If the column stores a time too, only rows at exactly midnight match; use a date range instead
- B The date format is wrong
- C Dates cannot be compared with =
- D It never misses rows
Answer: A β If the column stores a time too, only rows at exactly midnight match; use a date range instead
A DATETIME of 2026-07-04 14:30 is not equal to 2026-07-04 00:00. Use a half-open range: order_date >= '2026-07-04' AND order_date < '2026-07-05'.
- One of the most common real-world SQL bugs.
DATETIMERangesGotchas
Q8. hard
How do you group sales by month correctly across multiple years?
- A GROUP BY DATE_TRUNC('month', sale_date) - keeps year and month together
- B GROUP BY MONTH(sale_date) - merges same months across years
- C GROUP BY sale_date
- D GROUP BY YEAR(sale_date) only
Answer: A β GROUP BY DATE_TRUNC('month', sale_date) - keeps year and month together
GROUP BY MONTH() alone would merge January 2025 and January 2026 into one bucket. DATE_TRUNC (or grouping by both YEAR and MONTH) keeps them separate.
DATE_TRUNCGROUP BY
Q11. hard
Why is storing timestamps in UTC recommended?
- A It avoids ambiguity across timezones and daylight-saving changes; convert to local time only for display
- B UTC is faster to store
- C Local time never changes
- D It uses less space
Answer: A β It avoids ambiguity across timezones and daylight-saving changes; convert to local time only for display
Storing local times means a value can be ambiguous (a clock hour can occur twice) or missing (during a spring-forward). UTC is a single monotonic reference; format it per-user at display time.
UTCTimezonesBest practices
Q14. hard
Why avoid WHERE YEAR(order_date) = 2026 on a large table?
- A The function on the column blocks index usage; use a date range instead
- B YEAR() is inaccurate
- C It returns duplicates
- D There is no downside
Answer: A β The function on the column blocks index usage; use a date range instead
Rewrite as order_date >= '2026-01-01' AND order_date < '2027-01-01'. The range compares the raw column, so an index can seek directly to the matching rows.
SargabilityIndexes
Q16. hard
What is the difference between TIMESTAMP and TIMESTAMPTZ (PostgreSQL)?
- A TIMESTAMPTZ is timezone-aware and stores an absolute instant; TIMESTAMP stores a 'wall clock' with no zone
- B They are identical
- C TIMESTAMPTZ cannot store time
- D TIMESTAMP is newer
Answer: A β TIMESTAMPTZ is timezone-aware and stores an absolute instant; TIMESTAMP stores a 'wall clock' with no zone
TIMESTAMPTZ converts input to UTC on storage and back to the session zone on display. For anything user-facing across regions, TIMESTAMPTZ is usually the right choice.
TIMESTAMPTZTimezones
Q18. hard
How do you find records created 'today' regardless of time?
- A WHERE created_at >= CURRENT_DATE AND created_at < CURRENT_DATE + INTERVAL '1 day'
- B WHERE created_at = CURRENT_DATE
- C WHERE DATE(created_at) = TODAY
- D WHERE created_at LIKE '%today%'
Answer: A β WHERE created_at >= CURRENT_DATE AND created_at < CURRENT_DATE + INTERVAL '1 day'
The half-open range captures every moment of today while keeping the index usable. Option B fails because a timestamped value rarely equals midnight exactly.
Date rangesCURRENT_DATE
Q21. hard
What can go wrong comparing a DATE column to a string literal?
- A Implicit conversion depends on locale/format settings and can misread the date or block the index
- B Nothing ever goes wrong
- C It always errors
- D Strings are always faster
Answer: A β Implicit conversion depends on locale/format settings and can misread the date or block the index
Always use ISO format 'YYYY-MM-DD', which every database interprets unambiguously. Ambiguous forms like '04/07/2026' may be read as April 7 or July 4.
Implicit conversionISO 8601
Q23. hard
How do you compute a running date range for 'this quarter'?
- A DATE_TRUNC('quarter', CURRENT_DATE) for the start, plus INTERVAL '3 months' for the end
- B QUARTER(CURRENT_DATE)
- C CURRENT_DATE / 4
- D It is impossible
Answer: A β DATE_TRUNC('quarter', CURRENT_DATE) for the start, plus INTERVAL '3 months' for the end
DATE_TRUNC supports 'quarter', giving the first day of the current quarter. Add three months for a clean half-open upper bound.
DATE_TRUNCQuarters
Q25. hard
Why can date arithmetic across daylight-saving boundaries surprise you?
- A Adding '1 day' vs '24 hours' can differ, because a DST day has 23 or 25 hours
- B Dates never change length
- C SQL ignores DST always
- D It only affects leap years
Answer: A β Adding '1 day' vs '24 hours' can differ, because a DST day has 23 or 25 hours
With timezone-aware types, '+ INTERVAL 1 day' keeps the same wall-clock time, while '+ INTERVAL 24 hours' adds exactly 24 hours. Know which you need for scheduling.
DSTTimezones
Q27. hard
What is a common way to store dates that avoids timezone issues entirely?
- A Use a plain DATE type when time-of-day is irrelevant (e.g. a birthday or invoice date)
- B Always store as text
- C Store as an integer offset
- D Never store dates
Answer: A β Use a plain DATE type when time-of-day is irrelevant (e.g. a birthday or invoice date)
A birthday has no meaningful time or timezone, so a DATE is correct and simplest. Reserve timezone-aware timestamps for genuine instants like 'order placed at'.
DATEModelling
Q29. hard
How do you calculate business days between two dates?
- A There is no built-in function - you count days and subtract weekends (and holidays) with a calendar table or a generated series
- B BUSINESS_DAYS(a, b)
- C DATEDIFF handles it automatically
- D It is impossible in SQL
Answer: A β There is no built-in function - you count days and subtract weekends (and holidays) with a calendar table or a generated series
Most databases lack a business-day function. The robust approach is a 'calendar' or 'dim_date' table flagging weekends and holidays, then joining and counting working days.
Calendar tableBusiness days