Checking if a Time is Between Two Times in SQL: Practical Approaches for Handling Cross-Midnight Scenarios

Dec 01, 2025 · Programming · 16 views · 7.8

Keywords: SQL time query | cross-midnight time range | CAST function

Abstract: This article explores the common challenge of checking if a time falls between two specified times in SQL queries, particularly when the time range spans midnight. Through a case study where a user attempts to query records with creation times between 11 PM and 7 AM, but the initial query fails to return results, the article delves into the root cause of the issue. The core solution involves using logical operators to combine conditions, effectively handling time ranges that cross days. It details the use of the CAST function to convert datetime to time types and compares different query strategies. Code examples and best practices are provided to help readers avoid similar pitfalls and optimize the performance and accuracy of time-range queries.

Problem Background and Challenges

In database management, filtering data based on time conditions is a frequent requirement, such as querying records created within specific time intervals. A common scenario involves checking if a time is between two points, but when this range crosses midnight, the query logic becomes complex. This article examines this issue through a practical case: a user has a table with a Created column (of datetime data type) and wants to query records where the creation time is between 11 PM (23:00) and 7 AM (07:00). The initial query uses the BETWEEN operator but fails to return expected results, highlighting a key pitfall in time handling.

Analysis of the Initial Query Issue

The user's initial query is as follows:

SELECT *
FROM MyTable
WHERE CAST(Created AS TIME) BETWEEN '23:00:00' AND '06:59:59'

This query attempts to convert the datetime values in the Created column to time type and then check if they fall between 23:00:00 and 06:59:59. However, the BETWEEN operator requires a continuous range, and 23:00 to 06:59 spans midnight, making it logically invalid. For example, time 00:00:00 (midnight) is numerically less than 23:00:00, so it is not included by BETWEEN, even though it falls within the target range on the actual timeline. This explains why the query returns no results, even if qualifying data exists.

Core Solution: Combining Conditions with Logical Operators

To address cross-midnight time ranges, the best approach is to use the logical operator OR to combine two conditions. Referencing the top answer (score 10.0), the query should be rewritten as:

SELECT *
FROM MyTable
WHERE CAST(Created AS TIME) >= '23:00:00'
   OR CAST(Created AS TIME) < '07:00:00'

The logic of this query is: select records where the time is greater than or equal to 23:00:00 (i.e., 11 PM or later) or less than 07:00:00 (i.e., before 7 AM). This effectively covers the entire period from 11 PM to 7 AM the next day, including the cross-midnight portion. By splitting the time range into two continuous sub-ranges, it avoids the limitations of BETWEEN.

Code Explanation and Optimization

In the query, the CAST(Created AS TIME) function converts datetime values to time type, retaining only the time portion, which is crucial for time-based comparisons. For instance, for a Created value of '2013-07-01 00:00:00.000', conversion yields '00:00:00', which is then compared to '23:00:00' and '07:00:00'. For optimization, ensuring consistent time formats (e.g., using 'HH:MM:SS') can improve query performance and prevent errors due to format mismatches. Additionally, if the table has indexes, consider creating a function-based index on the Created column to speed up conversion operations.

Comparison of Alternative Methods

Another answer (score 2.5) proposes an alternative using NOT BETWEEN:

SELECT *
FROM MyTable
WHERE CAST(Created AS TIME) NOT BETWEEN '07:00' AND '22:59:59 997'

This method indirectly selects nighttime hours by excluding daytime hours (07:00 to 22:59:59.997). While logically viable, it relies on precise time boundaries and may miss data due to millisecond precision issues (e.g., time 22:59:59.998 might be incorrectly excluded). In contrast, the OR-based solution is more intuitive, easier to maintain, and avoids boundary complexities, making it the recommended best practice.

Practical Applications and Extensions

This solution applies not only to cross-midnight time ranges but can also be extended to other discontinuous time intervals. For example, to query records during lunch (12:00-13:00) and dinner (18:00-20:00) hours, similar logic can be used: WHERE time BETWEEN '12:00' AND '13:00' OR time BETWEEN '18:00' AND '20:00'. For performance, with large datasets, it is advisable to preprocess time logic at the application layer or use database-specific time functions (e.g., SQL Server's DATEPART) to reduce conversion overhead. In summary, understanding the nature of time data and the behavior of query operators is key to writing efficient and accurate SQL queries.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.