Generate a Time Series in SQL Server

SQL Server’s GENERATE_SERIES() function returns a series of numbers within a given interval. But just because it returns numbers, doesn’t mean we can’t leverage its functionality in order to generate a series of time values.

If you need to create a series of time values with evenly spaced intervals between a start and end point, maybe the following technique can help.

Example

Here’s a simple example of how we can use SQL Server’s GENERATE_SERIES() function/relational operator in conjunction with the DATEADD() function to generate a time series:

SELECT 
  DATEADD(minute, value, '2024-10-02 00:00:00.000') AS "Time Series"
FROM GENERATE_SERIES(0, 5, 1);

Result:

Time Series            
-----------------------
2024-10-02 00:00:00.000
2024-10-02 00:01:00.000
2024-10-02 00:02:00.000
2024-10-02 00:03:00.000
2024-10-02 00:04:00.000
2024-10-02 00:05:00.000

In this case I created a time series based on a string literal datetime value. The DATEADD() function is what actually modifies the datetime value, whereas the GENERATE_SERIES() relational operator is used to define the actual series for which the datetime value will be incremented in accordance with (i.e. start point, stop point, step amount).

Just to be clear, let’s add a column that shows what’s returned by GENERATE_SERIES() itself:

SELECT 
  value,
  DATEADD(minute, value, '2024-10-02 00:00:00.000') AS "Time Series"
FROM GENERATE_SERIES(0, 5, 1);

Result:

value       Time Series            
----------- -----------------------
          0 2024-10-02 00:00:00.000
          1 2024-10-02 00:01:00.000
          2 2024-10-02 00:02:00.000
          3 2024-10-02 00:03:00.000
          4 2024-10-02 00:04:00.000
          5 2024-10-02 00:05:00.000

The GENERATE_SERIES() function returns its result in a single-column called value. Therefore, we can use value to show us the output of the GENERATE_SERIES(). This in turn allows us to see the value in which we’re incrementing the current time value by.

Convert to a time Value

The above example returns a datetime value. The function does this whenever we pass a string literal date/time value. If we don’t want the date portion, we can use CONVERT() or CAST() to convert the result:

SELECT 
  CONVERT(
    time(0), 
    DATEADD(hour, value, '2024-10-02 00:00:00.000')
    ) AS "Time Series"
FROM GENERATE_SERIES(0, 5, 1);

Result:

Time Series           
----------------------
              00:00:00
              01:00:00
              02:00:00
              03:00:00
              04:00:00
              05:00:00

In this case I incremented the hour portion and converted to a time(0) value.

If we pass an actual date/time data type, then its return value uses that type:

DECLARE @time time = '00:00:00';
SELECT
  value,
  DATEADD(second, value, @time) AS Result
FROM GENERATE_SERIES(0, 70, 10);

Result:

value       Result                
----------- ----------------------
          0       00:00:00.0000000
         10       00:00:10.0000000
         20       00:00:20.0000000
         30       00:00:30.0000000
         40       00:00:40.0000000
         50       00:00:50.0000000
         60       00:01:00.0000000
         70       00:01:10.0000000

Therefore, there’s no need to convert the values if they’re already in the required format.

In this example, the original value is of a time type, which is the equivalent of time(7).

The increments in our time series can go right down to the nanosecond if required:

DECLARE @time time = '00:00:00';
SELECT
  value,
  DATEADD(ns, value, @time) AS Result
FROM GENERATE_SERIES(0, 3500, 700);

Result:

value       Result                
----------- ----------------------
          0       00:00:00.0000000
        700       00:00:00.0000007
       1400       00:00:00.0000014
       2100       00:00:00.0000021
       2800       00:00:00.0000028
       3500       00:00:00.0000035

Create a Decrementing time Series

We can use negative values to create a decrementing time series.

Example:

SELECT 
  value,
  DATEADD(hour, value, '2024-10-02 00:00:00.000') AS "Time Series"
FROM GENERATE_SERIES(5, -5, -1);

Result:

value       Time Series            
----------- -----------------------
          5 2024-10-02 05:00:00.000
          4 2024-10-02 04:00:00.000
          3 2024-10-02 03:00:00.000
          2 2024-10-02 02:00:00.000
          1 2024-10-02 01:00:00.000
          0 2024-10-02 00:00:00.000
         -1 2024-10-01 23:00:00.000
         -2 2024-10-01 22:00:00.000
         -3 2024-10-01 21:00:00.000
         -4 2024-10-01 20:00:00.000
         -5 2024-10-01 19:00:00.000