MySQL
SQL Queries
Datetime Functions
Database Management
SQL Syntax

MySQL SELECT WHERE datetime matches day and not necessarily time

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Filtering rows by day in a DATETIME column is a common SQL task, but many queries become slow or incorrect when time and time zone details are ignored. The key is to separate correctness from performance and design a predicate that gives both. This guide explains practical query patterns, why some are faster, and how to avoid hidden date bugs.

Why Day Matching Is Tricky

A DATETIME value includes both date and clock time. If you compare directly to a date string, only rows at midnight will match exactly.

sql
1-- Usually returns rows only at 00:00:00
2SELECT *
3FROM orders
4WHERE created_at = '2026-03-04';

Most rows have non-zero time, so direct equality is rarely what you want.

Correct and Fast Pattern: Half-Open Range

The most reliable approach is a half-open interval from the start of day to the start of next day.

sql
1SELECT id, customer_id, created_at
2FROM orders
3WHERE created_at >= '2026-03-04 00:00:00'
4  AND created_at <  '2026-03-05 00:00:00';

This pattern has two major advantages:

  • It is exact for the full day.
  • It is index friendly on created_at.

When an index exists, MySQL can use range scans efficiently.

sql
CREATE INDEX idx_orders_created_at ON orders(created_at);

Convenient but Slower Pattern: DATE()

You can also wrap the column in DATE().

sql
SELECT id, customer_id, created_at
FROM orders
WHERE DATE(created_at) = '2026-03-04';

This is readable, but often slower on large tables because function wrapping can prevent index range use on the original column. It may still be acceptable for small datasets or ad hoc analysis, but it is usually not ideal for hot paths.

Parameterized Query Pattern from Application Code

In applications, build day boundaries once and pass them as parameters.

python
1from datetime import datetime, timedelta
2import mysql.connector
3
4day = datetime(2026, 3, 4)
5start = day.replace(hour=0, minute=0, second=0, microsecond=0)
6end = start + timedelta(days=1)
7
8conn = mysql.connector.connect(host="localhost", user="app", password="secret", database="shop")
9cur = conn.cursor(dictionary=True)
10cur.execute(
11    """
12    SELECT id, created_at
13    FROM orders
14    WHERE created_at >= %s AND created_at < %s
15    """,
16    (start, end),
17)
18rows = cur.fetchall()
19print(len(rows))

This keeps SQL safe and reusable, and it avoids string concatenation mistakes.

Time Zone Considerations

If values are stored in UTC but users filter by local day, translate the requested local day to UTC boundaries before querying. For example, a local date in Toronto does not always map to midnight UTC because of offset and daylight savings changes.

Practical workflow:

  • Convert user local day start to UTC.
  • Convert next local day start to UTC.
  • Query with the same half-open range in UTC.

This avoids ambiguous local timestamps during daylight savings transitions.

Generated Columns for Heavy Analytics

If day-level filtering is extremely frequent, consider a generated date column and index it.

sql
1ALTER TABLE orders
2ADD COLUMN created_date DATE GENERATED ALWAYS AS (DATE(created_at)) STORED,
3ADD INDEX idx_orders_created_date (created_date);
4
5SELECT id, created_at
6FROM orders
7WHERE created_date = '2026-03-04';

This can provide convenient syntax with strong performance, but it adds storage and schema complexity. Use only if profiling justifies it.

Common Pitfalls

Using DATE(created_at) in every production query is a common performance mistake. It looks simple but may force full scans as data grows. Prefer boundary ranges for primary paths.

Another issue is mixing local date strings with UTC-stored data. This creates off-by-one-day bugs near midnight and daylight savings boundaries. Normalize date boundaries to one time zone before querying.

Developers also misuse BETWEEN with full timestamps and accidentally include next-day midnight. Half-open range logic is usually clearer and less error-prone.

Finally, avoid dynamic SQL date string interpolation. Always use bound parameters to prevent formatting issues and security risks.

Summary

  • Use a half-open day range for both correctness and index efficiency.
  • Keep an index on the DATETIME column for fast scans.
  • Use DATE() only when convenience outweighs performance concerns.
  • Convert local day boundaries to the storage time zone before querying.
  • Use generated date columns only for proven high-frequency day filtering needs.

Course illustration
Course illustration

All Rights Reserved.