Skip to content

Beginner: asking questions · Functions, CASE and NULL · topic 13 of 62 · 35 min

Working with dates

Explanation

SQLite has no separate date type: dates are stored as ISO text like '2025-03-15', which sorts and compares correctly. date(), strftime(), julianday() and modifiers such as '+30 days' pull out the year or month, count days between dates and add time. PostgreSQL, MySQL and SQL Server have real date types and their own functions, shown here side by side.

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.

Careful: SQLite's date functions only understand ISO text. date('15-03-2025') returns NULL, and so does strftime on '15/03/2025'. And '2025-3-5' (no leading zeros) compares wrongly as text. Always store dates as 'YYYY-MM-DD'.

The SQLite date functions

ExpressionResultMeaning
date('2025-03-15', '+30 days')2025-04-14Add days (also months, years; use − to go back)
date('2025-03-15', 'start of month')2025-03-01First day of that month
date('2025-03-15', 'start of month', '+1 month', '-1 day')2025-03-31Last day of that month
strftime('%Y', '2025-03-15')2025The year, as text
strftime('%m', '2025-03-15')03The month, as two-digit text
strftime('%Y-%m', '2025-03-15')2025-03Year and month: great for grouping by month
julianday('2025-03-15') - julianday('2025-01-01')73Number 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.

sql
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 | Placed
All orders in March 2025.
sql
SELECT 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-09
Date arithmetic with a modifier. The month changes by itself.

Today'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

JobPostgreSQLMySQLSQL Server
Year of a dateEXTRACT(YEAR FROM d)YEAR(d)YEAR(d)
First day of the monthDATE_TRUNC('month', d)DATE_FORMAT(d, '%Y-%m-01')DATETRUNC(month, d) (2022+)
Year-month textTO_CHAR(d, 'YYYY-MM')DATE_FORMAT(d, '%Y-%m')FORMAT(d, 'yyyy-MM')
Add 30 daysd + INTERVAL '30 days'DATE_ADD(d, INTERVAL 30 DAY)DATEADD(day, 30, d)
Days betweend2 - d1 (for DATE values)DATEDIFF(d2, d1)DATEDIFF(day, d1, d2)
TodayCURRENT_DATECURDATE()CAST(GETDATE() AS date)
sql
-- 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;
Shown, not run here. Note the argument order: MySQL DATEDIFF(later, earlier); SQL Server DATEDIFF(day, earlier, later).

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

Working with dates

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).

sql
SELECT id, order_date,
       CAST(julianday('2025-04-05') - julianday(order_date) AS INTEGER) AS days_open
FROM orders
WHERE status IN ('Placed', 'Shipped');
On 5 April 2025: order 105 has been open 34 days, 107 for 8 days and 108 for 3 days. A live report would use date('now') instead of the fixed date.

Practice (0/4 done)

Task 1 · Code · SQL

Which orders were placed in March 2025? From orders, return id, order_date and status. Use strftime.

Task 2 · Code · SQL

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.

Task 3 · Code · SQL

Long-serving staff: from employees (COMPANY), return name and the year of hire_date named hire_year, for employees hired before 2018.

Task 4 · Code · SQL

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

Question 1

1.Why are dates stored as 'YYYY-MM-DD' text in SQLite?

Question 2

2.In SQLite, what does strftime('%m', '2025-03-15') return?

Question 3

3.What does date('2025-03-15', '+30 days') return?

Question 4

4.Which is the PostgreSQL way to get the year of a date d?

Question 5

5.Why do practice tasks use '2025-12-31' instead of date('now')?

Read more (free)

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.

From Dates and times with datetime

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.

From Days, months and dates

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.

From Tables, rows, columns and data types

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

  1. 2 more topics in “Functions, CASE and NULL” before its exam: CASE expressions, NULL: the missing value.
  2. Module 3 exam: Functions, CASE and NULL · 15 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Aggregation: GROUP BY and HAVING. 62 topics left in the course before the final exam.

← Previous: Numbers and maths