Beginner: asking questions · Functions, CASE and NULL · topic 13 of 62 · 35 min
Working with dates
Explanation
Why dates need special care
Almost every business question has a date in it: orders this month, customers who joined last year, invoices overdue by 30 days. Dates look simple, but months have different lengths, years can be leap years, and people write dates in many forms (15/03/2025, 03-15-2025, 15 Mar 2025). The database needs one clear form to work with.
ISO dates in SQLite
SQLite stores dates as text in the ISO 8601 form: YYYY-MM-DD, for example '2025-03-15', and date-times as 'YYYY-MM-DD HH:MM:SS'. ISO means the international standard. Because the biggest part (the year) comes first and every part has a fixed width, ISO dates sort and compare correctly as plain text, which is why WHERE order_date >= '2025-03-01' worked in module 2.
The SQLite date functions
| Expression | Result | Meaning |
|---|---|---|
| date('2025-03-15', '+30 days') | 2025-04-14 | Add days (also months, years; use − to go back) |
| date('2025-03-15', 'start of month') | 2025-03-01 | First day of that month |
| date('2025-03-15', 'start of month', '+1 month', '-1 day') | 2025-03-31 | Last day of that month |
| strftime('%Y', '2025-03-15') | 2025 | The year, as text |
| strftime('%m', '2025-03-15') | 03 | The month, as two-digit text |
| strftime('%Y-%m', '2025-03-15') | 2025-03 | Year and month: great for grouping by month |
| julianday('2025-03-15') - julianday('2025-01-01') | 73 | Number of days between two dates |
strftime means "string from time": its first argument is a format with codes like %Y (year), %m (month), %d (day), %H (hour) and %M (minute), and it returns text. julianday turns a date into a day number counted from a fixed start, so subtracting two of them gives the days between. The result is a real number; wrap it in CAST(... AS INTEGER) for whole days.
SELECT id, order_date, status
FROM orders
WHERE strftime('%Y-%m', order_date) = '2025-03';
-- 105 | 2025-03-02 | Shipped
-- 106 | 2025-03-15 | Delivered
-- 107 | 2025-03-28 | PlacedSELECT id, order_date, date(order_date, '+7 days') AS deliver_by
FROM orders WHERE status IN ('Placed', 'Shipped');
-- 105 | 2025-03-02 | 2025-03-09
-- 107 | 2025-03-28 | 2025-04-04
-- 108 | 2025-04-02 | 2025-04-09Today's date
date('now') gives today's date and datetime('now') the current date and time, in UTC (world time, 5 hours 30 minutes behind India). Add 'localtime' for the computer's own time zone: datetime('now', 'localtime'). Because the answer changes every day, practice tasks in this course use a fixed date such as '2025-12-31' instead.
The same jobs in other databases
| Job | PostgreSQL | MySQL | SQL Server |
|---|---|---|---|
| Year of a date | EXTRACT(YEAR FROM d) | YEAR(d) | YEAR(d) |
| First day of the month | DATE_TRUNC('month', d) | DATE_FORMAT(d, '%Y-%m-01') | DATETRUNC(month, d) (2022+) |
| Year-month text | TO_CHAR(d, 'YYYY-MM') | DATE_FORMAT(d, '%Y-%m') | FORMAT(d, 'yyyy-MM') |
| Add 30 days | d + INTERVAL '30 days' | DATE_ADD(d, INTERVAL 30 DAY) | DATEADD(day, 30, d) |
| Days between | d2 - d1 (for DATE values) | DATEDIFF(d2, d1) | DATEDIFF(day, d1, d2) |
| Today | CURRENT_DATE | CURDATE() | CAST(GETDATE() AS date) |
-- PostgreSQL only
SELECT DATE_TRUNC('month', order_date) AS month, COUNT(*)
FROM orders GROUP BY 1 ORDER BY 1;
-- MySQL only
SELECT DATEDIFF('2025-12-31', joined) AS days_member FROM customers;Common mistakes
- Comparing strftime('%m', d) with the number 3. strftime returns the text '03', and in SQLite '03' = 3 is false. Compare with '03', or CAST it to INTEGER.
- Adding a month to 31 January. date('2025-01-31', '+1 month') gives 2025-03-03 in SQLite, because 31 February does not exist. Check month-end logic, or use 'start of month' first.
- Forgetting that julianday differences are real numbers. Use CAST(... AS INTEGER) or ROUND for whole days.
- Storing dates as '15/03/2025'. They sort wrongly and the date functions return NULL. Store ISO dates and format them only for display.
- Using date('now') in a report without thinking about time zones: just after midnight in India, UTC is still on the previous day.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Working with dates · 1/8
Most business questions have a date in them: this month, last year, overdue by thirty days.
Prefer a video by a teacher? Find free videos on “sqlite date functions strftime julianday tutorial” on YouTube ↗
In real life: Overdue fees at a school
A school office keeps the due date of each fee instalment. Each morning a query lists students whose instalment is unpaid and more than 15 days past the due date, with the number of days overdue worked out from julianday. The same idea runs in libraries (overdue books), banks (EMI reminders) and online stores (orders not shipped within 2 days).
SELECT id, order_date,
CAST(julianday('2025-04-05') - julianday(order_date) AS INTEGER) AS days_open
FROM orders
WHERE status IN ('Placed', 'Shipped');Practice (0/4 done)
Which orders were placed in March 2025? From orders, return id, order_date and status. Use strftime.
How long has each customer been with the shop on 31 December 2025? Return name, joined, and the whole number of days from joined to '2025-12-31', named days_member.
Long-serving staff: from employees (COMPANY), return name and the year of hire_date named hire_year, for employees hired before 2018.
Orders that are Placed or Shipped must be delivered within 7 days. Return id, order_date and the date 7 days after order_date, named deliver_by.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- CASE expressionsFunctions, CASE and NULL · same module
- Text functionsFunctions, CASE and NULL · same module
- Dates and times with datetimePython Programming · Errors, modules and the standard library
- Dates and timesJavaScript Programming (language in depth) · Modules, errors, JSON and dates
- Days, months and datesSpoken English: Zero to Fluent · Numbers, time and money
- MySQL vs PostgreSQL vs SQLite vs SQL ServerProcedures, triggers, SQL engines and NoSQL
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
Why are dates stored as 'YYYY-MM-DD' text in SQLite?
Answer: Because the date functions understand it and it sorts correctly as text
Year first and fixed widths make text order equal to date order.
In SQLite, what does strftime('%m', '2025-03-15') return?
Answer: '03'
strftime returns text, and %m is the two-digit month.
What does date('2025-03-15', '+30 days') return?
Answer: 2025-04-14
March has 31 days: 16 days to the end of March, then 14 more in April.
Which is the PostgreSQL way to get the year of a date d?
Answer: EXTRACT(YEAR FROM d)
EXTRACT is the standard SQL form, used by PostgreSQL. YEAR(d) is MySQL and SQL Server.
Why do practice tasks use '2025-12-31' instead of date('now')?
Answer: A fixed date gives the same answer every day, so the result can be checked
Today changes, so the expected rows would change too.
What does date(2025, 1, 26).strftime("%d-%m-%Y") give?Related
Answer: 26-01-2025
%d is the day, %m the month and %Y the four-digit year, joined by dashes.
What does Date.now() return?Related
Answer: Milliseconds since 1 Jan 1970 UTC
Date.now() gives the current time as a number of milliseconds.
From Dates and times
You write to a US client. Which date is clearest?Related
Answer: 4 May 2026
Writing the month as a word avoids confusion between Indian and US date order.
How should you store the date 5 January 2025 in SQLite so it sorts correctly?Related
Answer: '2025-01-05'
The YYYY-MM-DD form sorts in date order and works with SQLite date functions.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 2 more topics in “Functions, CASE and NULL” before its exam: CASE expressions, NULL: the missing value.
- Module 3 exam: Functions, CASE and NULL · 15 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Aggregation: GROUP BY and HAVING. 62 topics left in the course before the final exam.