SQL Tutorial › Functions & Grouping › Date & Time Functions

SQL Date and Time Functions

IntermediateLesson 28 of 6913 min read9 queries run on MySQL 8.4

Dates drive most business questions: orders this month, customers who joined last year, employees’ years of service, days until delivery. MySQL has a rich set of date and time functions. This lesson shows the ones you will reach for every week, run on the sample orders and employees.

Advertisement
In this lesson
  • Get the current date and time
  • Extract parts with YEAR, MONTH, DAYNAME and EXTRACT
  • Calculate with DATE_ADD, DATEDIFF and TIMESTAMPDIFF
  • Format with DATE_FORMAT and group by month

Current date and time

MySQL
SELECT NOW(), CURDATE(), CURTIME(), UTC_TIMESTAMP();
ResultMySQL 8.4
NOW()CURDATE()CURTIME()UTC_TIMESTAMP()
2026-11-02 09:34:542026-11-0209:34:542026-11-02 09:34:54
1 row in set
FunctionReturns
NOW()date and time when the statement started
CURDATE()date only
CURTIME()time only
UTC_TIMESTAMP()date and time in UTC (the server above runs in UTC, so it equals NOW())

The result above is from the moment this page was built. The values change every time you run the query, so the examples below use fixed dates and the dates stored in the sample tables.

Sample data

orders · 10 rows
order_idcustomer_idorder_datestatus
100112025-01-05Delivered
100222025-01-17Delivered
100312025-02-02Delivered
100432025-02-14Cancelled
100542025-03-08Delivered
100652025-03-22Shipped
100722025-04-10Delivered
100812025-04-28Pending
100932025-05-15Delivered
101052025-06-01Delivered

Extract parts of a date

MySQL
SELECT order_id, order_date,       YEAR(order_date)    AS yr,       MONTH(order_date)   AS mon,       MONTHNAME(order_date) AS month_name,       DAY(order_date)     AS dy,       DAYNAME(order_date) AS weekday,       QUARTER(order_date) AS qtrFROM ordersLIMIT 4;
ResultMySQL 8.4
order_idorder_dateyrmonmonth_namedyweekdayqtr
10012025-01-0520251January5Sunday1
10022025-01-1720251January17Friday1
10032025-02-0220252February2Sunday1
10042025-02-1420252February14Friday1
4 rows in set
How this query works, step by step
  1. YEAR, MONTH and DAY return numbers.
  2. MONTHNAME and DAYNAME return English names.
  3. QUARTER returns 1 to 4. EXTRACT(MONTH FROM order_date) is the standard-SQL way to write MONTH(order_date).

Add and subtract time

Expected delivery is 5 days after the order; the return window ends 1 month after delivery:

MySQL
SELECT order_id, order_date,       DATE_ADD(order_date, INTERVAL 5 DAY)                    AS expected_delivery,       order_date + INTERVAL 5 DAY + INTERVAL 1 MONTH           AS return_deadline,       DATE_SUB(order_date, INTERVAL 1 WEEK)                    AS week_beforeFROM ordersWHERE order_id IN (1001, 1002, 1004);
ResultMySQL 8.4
order_idorder_dateexpected_deliveryreturn_deadlineweek_before
10012025-01-052025-01-102025-02-102024-12-29
10022025-01-172025-01-222025-02-222025-01-10
10042025-02-142025-02-192025-03-192025-02-07
3 rows in set
How this query works, step by step
  1. DATE_ADD(date, INTERVAL n unit) adds; DATE_SUB subtracts.
  2. date + INTERVAL ... is a shorter way to write the same thing.
  3. Units include DAY, WEEK, MONTH, QUARTER, YEAR, HOUR, MINUTE and SECOND.

Difference between dates

Years of service on a fixed reference date, 31 Dec 2025:

MySQL
SELECT first_name, hire_date,       DATEDIFF('2025-12-31', hire_date)                AS days_employed,       TIMESTAMPDIFF(MONTH, hire_date, '2025-12-31')     AS months_employed,       TIMESTAMPDIFF(YEAR, hire_date, '2025-12-31')      AS full_yearsFROM employeesORDER BY hire_dateLIMIT 5;
ResultMySQL 8.4
first_namehire_datedays_employedmonths_employedfull_years
Meera2015-01-05401313110
Vikram2017-11-202963978
Asha2018-04-122820927
Sneha2019-02-252501826
Rahul2019-07-012375776
5 rows in set
How this query works, step by step
  1. DATEDIFF(later, earlier) returns whole days.
  2. TIMESTAMPDIFF(unit, earlier, later) counts complete units. Note the reversed argument order.
  3. TIMESTAMPDIFF(YEAR, ...) counts only full years, so it is the right way to calculate age or service.
Tip

In a live system, replace '2025-12-31' with CURDATE().

Format dates with DATE_FORMAT

MySQL
SELECT order_date,       DATE_FORMAT(order_date, '%d/%m/%Y')     AS indian_style,       DATE_FORMAT(order_date, '%d %b %Y')     AS short_text,       DATE_FORMAT(order_date, '%W, %M %e')    AS long_text,       DATE_FORMAT(order_date, '%Y-%m')        AS month_labelFROM ordersWHERE order_id IN (1001, 1006);
ResultMySQL 8.4
order_dateindian_styleshort_textlong_textmonth_label
2025-01-0505/01/202505 Jan 2025Sunday, January 52025-01
2025-03-2222/03/202522 Mar 2025Saturday, March 222025-03
2 rows in set
Note

year_month would be a natural alias here, but it is a reserved word in MySQL (it is an INTERVAL unit), so it would cause a syntax error.

SpecifierMeaningExample
%Y / %y4- / 2-digit year2025 / 25
%m / %cmonth 01-12 / 1-1203 / 3
%M / %bmonth name / shortMarch / Mar
%d / %eday 01-31 / 1-3108 / 8
%W / %aweekday / shortSaturday / Sat
%H:%i:%s24-hour time14:05:09

STR_TO_DATE does the reverse, turning text into a date:

MySQL
SELECT STR_TO_DATE('31/01/2026', '%d/%m/%Y') AS parsed_date;
ResultMySQL 8.4
parsed_date
2026-01-31
1 row in set

Group by month

Orders and revenue per month, the most common date report:

MySQL
SELECT DATE_FORMAT(o.order_date, '%Y-%m') AS month,       COUNT(DISTINCT o.order_id)          AS orders,       SUM(oi.quantity * p.price)          AS revenueFROM orders oJOIN order_items oi ON oi.order_id = o.order_idJOIN products p     ON p.product_id = oi.product_idWHERE o.status <> 'Cancelled'GROUP BY monthORDER BY month;
ResultMySQL 8.4
monthordersrevenue
2025-01213743
2025-0214298
2025-0328783
2025-04221795
2025-0513499
2025-0611145
6 rows in set
How this query works, step by step
  1. Each order date becomes a 'YYYY-MM' label.
  2. Rows with the same label form one group.
  3. COUNT(DISTINCT o.order_id) counts orders, not lines; SUM totals the revenue.

Filter a date range efficiently

Orders in March 2025:

SQL
SELECT order_id, order_dateFROM ordersWHERE order_date >= '2025-03-01' AND order_date < '2025-04-01';
ResultMySQL 8.4
order_idorder_date
10052025-03-08
10062025-03-22
2 rows in set
Watch out

WHERE MONTH(order_date) = 3 gives the same rows here, but wrapping the column in a function stops MySQL from using an index on order_date, and it would also match March of every year. Use a range on the raw column.

Useful helpers

MySQL
SELECT LAST_DAY('2024-02-10')                      AS last_day_feb_2024,       DAYOFWEEK('2025-03-08')                     AS day_of_week,       WEEK('2025-03-08')                          AS week_no,       DATE('2025-03-08 17:45:00')                 AS date_part,       MAKEDATE(2026, 32)                          AS day_32_of_2026;
ResultMySQL 8.4
last_day_feb_2024day_of_weekweek_nodate_partday_32_of_2026
2024-02-29792025-03-082026-02-01
1 row in set
How this query works, step by step
  1. LAST_DAY returns the last day of the month: 2024 is a leap year, so 29 February.
  2. DAYOFWEEK returns 1 for Sunday to 7 for Saturday; 8 March 2025 was a Saturday.
  3. DATE() strips the time from a datetime.
  4. MAKEDATE(year, n) builds the nth day of a year: day 32 is 1 February.

Exercise: Orders per weekday

Count the orders placed on each weekday name.

Expected resultMySQL 8.4
weekdayorders
Sunday3
Friday2
Saturday2
Thursday2
Monday1
5 rows in set
Hint 1

Group by DAYNAME(order_date).

Exercise: Joined in 2024

List customers who joined in 2024, with the month name they joined.

Expected resultMySQL 8.4
customer_namejoined_onjoined_month
Ananya Sharma2024-01-15January
Rohit Kumar2024-02-03February
Fatima Khan2024-03-21March
David Fernandes2024-05-09May
Ishita Bose2024-07-30July
5 rows in set
Hint 1

Filter with a date range, show MONTHNAME(joined_on).

Quick quiz

1. Which function returns today’s date without the time?

2. What does DATEDIFF('2025-03-10', '2025-03-01') return?

3. Which is the best way to calculate full years of service?

4. Which format string produces 08/03/2025?

Date functions FAQ

How do I get the current date in MySQL?

CURDATE() returns the current date; NOW() returns the date and time.

How do I calculate the difference between two dates in SQL?

In MySQL use DATEDIFF(end, start) for days, or TIMESTAMPDIFF(unit, start, end) for months, years, hours and other units.

How do I format a date in MySQL?

Use DATE_FORMAT(date, format), for example DATE_FORMAT(order_date, '%d/%m/%Y').

How do I group rows by month in SQL?

Group by DATE_FORMAT(date_col, '%Y-%m'), or by YEAR(date_col), MONTH(date_col).