DATE_BUCKET (Transact-SQL)

Applies to: SQL Server 2022 (16.x) Azure SQL Database Azure SQL Managed Instance Azure SQL Edge

This function returns the date-time value corresponding to the start of each date-time bucket from the timestamp defined by the origin parameter, or the default origin value of 1900-01-01 00:00:00.000 if the origin parameter isn't specified.

See Date and Time Data Types and Functions (Transact-SQL) for an overview of all Transact-SQL date and time data types and functions.

Transact-SQL syntax conventions

Syntax

DATE_BUCKET (datepart, number, date [, origin ] )

Arguments

datepart

The part of date that is used with the number parameter, for example, year, month, day, minute, second.

DATE_BUCKET doesn't accept user-defined variable equivalents for the datepart arguments.

datepart Abbreviations
day dd, d
week wk, ww
month mm, m
quarter qq, q
year yy, yyyy
hour hh
minute mi, n
second ss, s
millisecond ms

number

The integer number that decides the width of the bucket combined with datepart argument. This represents the width of the datepart buckets from the origin time. This argument can't be a negative integer value.

date

An expression that can resolve to one of the following values:

  • date
  • datetime
  • datetime2
  • datetimeoffset
  • smalldatetime
  • time

For date, DATE_BUCKET will accept a column expression, expression, or user-defined variable if they resolve to any of the data types mentioned above.

origin

An optional expression that can resolve to one of the following values:

  • date
  • datetime
  • datetime2
  • datetimeoffset
  • smalldatetime
  • time

The data type for origin should match the data type of the date parameter.

DATE_BUCKET uses a default origin date value of 1900-01-01 00:00:00.000 that is, 12:00 AM on Monday, January 1, 1900, if no origin value is specified for the function.

Return type

The return value data type for this method is dynamic. The return type depends on the argument supplied for date. If a valid input data type is supplied for date, DATE_BUCKET returns the same data type. DATE_BUCKET raises an error if a string literal is specified for the date parameter.

Return values

Understanding the output from DATE_BUCKET

DATE_BUCKET returns the latest date or time value, corresponding to the datepart and number parameter. For example, in the expressions below, DATE_BUCKET will return the output value of 2020-04-13 00:00:00.0000000, as the output is calculated based on one week buckets from the default origin time of 1900-01-01 00:00:00.000. The value 2020-04-13 00:00:00.0000000 is 6,276 weeks from the origin value of 1900-01-01 00:00:00.000.

DECLARE @date DATETIME2 = '2020-04-15 21:22:11';
SELECT DATE_BUCKET(WEEK, 1, @date);

For all the expressions below, the same output value of 2020-04-13 00:00:00.0000000 will be returned. This is because 2020-04-13 00:00:00.0000000 is 6,276 weeks from the origin date, and 6,276 is divisible by 2, 3, 4 and 6.

DECLARE @date DATETIME2 = '2020-04-15 21:22:11';
SELECT DATE_BUCKET(WEEK, 2, @date);
SELECT DATE_BUCKET(WEEK, 3, @date);
SELECT DATE_BUCKET(WEEK, 4, @date);
SELECT DATE_BUCKET(WEEK, 6, @date);

The output for the expression below is 2020-04-06 00:00:00.0000000, which is 6275 weeks from the default origin time 1900-01-01 00:00:00.000.

DECLARE @date DATETIME2 = '2020-04-15 21:22:11';
SELECT DATE_BUCKET(WEEK, 5, @date);

The output for the expression below is 2020-06-09 00:00:00.0000000, which is 75 weeks from the specified origin time 2019-01-01 00:00:00.

DECLARE @date DATETIME2 = '2020-06-15 21:22:11';
DECLARE @origin DATETIME2 = '2019-01-01 00:00:00';
SELECT DATE_BUCKET(WEEK, 5, @date, @origin);

datepart argument

dayofyear, day, and weekday return the same value. Each datepart and its abbreviations return the same value.

number argument

The number argument can't exceed the range of positive int values. In the following statements, the argument for number exceeds the range of int by 1. The following statement returns the error message, Msg 8115, Level 16, State 2, Line 2. Arithmetic overflow error converting expression to data type int.

DECLARE @date DATETIME2 = '2020-04-30 00:00:00';
SELECT DATE_BUCKET(DAY, 2147483648, @date);

If a negative value for number is passed to the DATE_BUCKET function, the following error will be returned.

Msg 9834, Level 16, State 1, Line 1
Invalid bucket width value passed to DATE_BUCKET function. Only positive values are allowed.

date argument

DATE_BUCKET return the base value corresponding to the data type of the date argument. In the following example, an output value with datetime2 datatype is returned.

SELECT DATE_BUCKET(DAY, 10, SYSUTCDATETIME());

origin argument

The data type of the origin and date arguments in must be the same. If different data types are used, an error will be generated.

Remarks

Use DATE_BUCKET in the following clauses:

  • GROUP BY
  • HAVING
  • ORDER BY
  • SELECT <list>
  • WHERE

Examples

A. Calculate DATE_BUCKET with a bucket width of 1 from the origin time

Each of these statements increments DATE_BUCKET with a bucket width of 1 from the origin time:

DECLARE @date DATETIME2 = '2020-04-30 21:21:21';
SELECT 'Week', DATE_BUCKET(WEEK, 1, @date)
UNION ALL
SELECT 'Day', DATE_BUCKET(DAY, 1, @date)
UNION ALL
SELECT 'Hour', DATE_BUCKET(HOUR, 1, @date)
UNION ALL
SELECT 'Minutes', DATE_BUCKET(MINUTE, 1, @date)
UNION ALL
SELECT 'Seconds', DATE_BUCKET(SECOND, 1, @date);

Here's the result set.

Week    2020-04-27 00:00:00.0000000
Day     2020-04-30 00:00:00.0000000
Hour    2020-04-30 21:00:00.0000000
Minutes 2020-04-30 21:21:00.0000000
Seconds 2020-04-30 21:21:21.0000000

B. Use expressions as arguments for the number and date parameters

These examples use different types of expressions as arguments for the number and date parameters.

These examples are built using the AdventureWorksDW2022 database.

Specify user-defined variables as number and date

This example specifies user-defined variables as arguments for number and date:

DECLARE @days INT = 365,
    @datetime DATETIME2 = '2000-01-01 01:01:01.1110000';
    /* 2000 was a leap year */;
SELECT DATE_BUCKET(DAY, @days, @datetime);

Here's the result set.

1999-12-08 00:00:00.0000000

Specify a column as date

In the example below, we're calculating the sum of OrderQuantity and sum of UnitPrice grouped over weekly date buckets.

SELECT DATE_BUCKET(WEEK, 1, CAST(ShipDate AS DATETIME2)) AS ShippedDateBucket
    , SUM(OrderQuantity) AS SumOrderQuantity
    , SUM(UnitPrice) AS SumUnitPrice
FROM dbo.FactInternetSales FIS
WHERE ShipDate BETWEEN '2011-01-03 00:00:00.000'
        AND '2011-02-28 00:00:00.000'
GROUP BY DATE_BUCKET(WEEK, 1, CAST(ShipDate AS DATETIME2))
ORDER BY ShippedDateBucket;

Here's the result set.

ShippedDateBucket           SumOrderQuantity SumUnitPrice
--------------------------- ---------------- ---------------------
2011-01-03 00:00:00.0000000 21               65589.7546
2011-01-10 00:00:00.0000000 27               89938.5464
2011-01-17 00:00:00.0000000 31               104404.9064
2011-01-24 00:00:00.0000000 36               118525.6846
2011-01-31 00:00:00.0000000 39               123555.431
2011-02-07 00:00:00.0000000 35               109342.351
2011-02-14 00:00:00.0000000 32               107804.8964
2011-02-21 00:00:00.0000000 37               119456.3428
2011-02-28 00:00:00.0000000 9                28968.6982

Specify scalar system function as date

This example specifies SYSDATETIME for date. The exact value returned depends on the day and time of statement execution:

SELECT DATE_BUCKET(WEEK, 10, SYSDATETIME());

Here's the result set.

2020-03-02 00:00:00.0000000

Specify scalar subqueries and scalar functions as number and date

This example uses scalar subqueries, MAX(OrderDate), as arguments for number and date. (SELECT top 1 CustomerKey FROM dbo.DimCustomer where GeographyKey > 100) serves as an artificial argument for the number parameter, to show how to select a number argument from a value list.

SELECT DATE_BUCKET(WEEK, (
    SELECT TOP 1 CustomerKey
    FROM dbo.DimCustomer
    WHERE GeographyKey > 100
    ), (
    SELECT MAX(OrderDate)
    FROM dbo.FactInternetSales
));

Specify numeric expressions and scalar system functions as number and date

This example uses a numeric expression ((10/2)), and scalar system functions (SYSDATETIME) as arguments for number and date.

SELECT DATE_BUCKET(WEEK, (10/2), SYSDATETIME());

Specify an aggregate window function as number

This example uses an aggregate window function as an argument for number.

SELECT DISTINCT DATE_BUCKET(DAY, 30, CAST([ShipDate] AS DATETIME2)) AS DateBucket
    , FIRST_VALUE([SalesOrderNumber]) OVER (
        ORDER BY DATE_BUCKET(DAY, 30, CAST([ShipDate] AS DATETIME2))
        ) AS First_Value_In_Bucket
    , LAST_VALUE([SalesOrderNumber]) OVER (
        ORDER BY DATE_BUCKET(DAY, 30, CAST([ShipDate] AS DATETIME2))
        ) AS Last_Value_In_Bucket
FROM [dbo].[FactInternetSales]
WHERE ShipDate BETWEEN '2011-01-03 00:00:00.000'
        AND '2011-02-28 00:00:00.000'
ORDER BY DateBucket;
GO

C. Use a non-default origin value

This example uses a non-default origin value to generate the date buckets.

DECLARE @date DATETIME2 = '2020-06-15 21:22:11';
DECLARE @origin DATETIME2 = '2019-01-01 00:00:00';
SELECT DATE_BUCKET(HOUR, 2, @date, @origin);

See also