Reputation: 3351
I need to get how many of a specific hour have occurred between two dates in TSQL. Some examples:
The following would give the result = 1
declare @date1 datetime = '2019-10-01 00:00:00.000';
declare @date2 datetime = '2019-10-02 00:00:00.000';
The following would give the result = 0, as there has been 0 4AMs in between
declare @date1 datetime = '2019-10-01 05:00:00.000';
declare @date2 datetime = '2019-10-02 00:00:00.000';
The following would give the result = 2, as there has been 2 4AMs in between
declare @date1 datetime = '2019-10-01 03:00:00.000';
declare @date2 datetime = '2019-10-02 05:00:00.000';
The following would give the result = 2, as there has been 2 4AMs even though they are just on the 4:00AM time
declare @date1 datetime = '2019-10-01 04:00:00.000';
declare @date2 datetime = '2019-10-02 04:00:00.000';
I have tried something like this... but it is giving an incorrect answer
DECLARE @startdate AS DATETIME = '2019-10-01 03:00:00.000'
DECLARE @enddate AS DATETIME = '2019-10-02 00:00:00.000'
DECLARE @hour int = 4
SELECT DATEDIFF(HOUR, @startdate, @endDate) / 24
+ 1
+ CASE WHEN DATEPART(HOUR, @startdate) <= @hour AND
DATEPART(HOUR, @endDate) >= @hour
THEN 0
ELSE -1
END
Anyone who can shed some light I would appreciate it
Upvotes: 1
Views: 125
Reputation: 272406
If two dates are n
hours apart then there are FLOOR(n / 24)
4AMs between them; plus an additional one if 4AM lies between hour of start and end date (checking if 04:00 is between 03:00 - 05:00 is easy, checking if 04:00 is between 05:00 - 03:00 is hard):
SELECT date1
, date2
, DATEDIFF(HOUR, date1, date2) / 24 + CASE
WHEN H1 <= H2 AND (H1 <= 4 AND 4 <= H2) OR H1 > H2 AND (H1 <= 4 OR 4 <= H2) THEN 1
ELSE 0
END AS result
FROM tests
CROSS APPLY (SELECT DATEPART(HOUR, date1), DATEPART(HOUR, date2)) AS x(h1, h2)
Upvotes: 1
Reputation: 172
DECLARE @date1 datetime = '2019-10-01 04:00:00.000';
DECLARE @date2 datetime = '2019-10-02 04:00:00.000';
DECLARE @Hr INT=4
DECLARE @AMorPM CHAR(2)='PM'
;WITH CTE AS
(
SELECT @date1 AS DateStart
UNION ALL
SELECT DATEADD(HOUR,1,DateStart)
FROM CTE
WHERE DateStart < @date2
)
SELECT COUNT(CASE WHEN DateStart > 12 THEN DateStart-12 ELSE DateStart END) AS TotalTimes
FROM CTE
WHERE (
(@AMorPM='AM' AND DATEPART(HOUR,DateStart)=@Hr) OR
(@AMorPM='PM' AND DATEPART(HOUR,DateStart)-12=@Hr)
)
Upvotes: 0
Reputation: 131729
This sounds like an attempt to count days in one timezone when the values are stored in another, probably UTC.
One option is to use TODATETIMEOFFSET
to convert the UTC date to the target timezone :
SELECT datediff(d,todatetimeoffset(@date1,'+04:00'), todatetimeoffset(@date2,'+04:00'))
This makes the timezone calculation explicit. It won't handle daylight changes though as the offset has to be specified explicitly. Should the DST rules change, the application itself will have to be modified to change the offsets.
In SQL Server 2016 and later, AT TIME ZONE allows specifying the timezone name directly and applies any timezone rules specified for that timezone.
select
datediff(d, @date1 at time zone 'Caucasus Standard Time',
@date2 at time zone 'Caucasus Standard Time')
Timezone rules are distributed through Windows Updates, which means rule changes no longer require modifications to the application or the database.
Upvotes: -1
Reputation: 96028
The easiest way would be to remove 4 hours from both values, and then get the difference in days:
DECLARE @date1 datetime = '2019-10-01 00:00:00.000';
DECLARE @date2 datetime = '2019-10-02 00:00:00.000';
SELECT DATEDIFF(DAY,DATEADD(HOUR, -4, @date1),DATEADD(HOUR, -4, @date2)); --RETURNS 31, as there are 31 days bewteen 10 Jan and 10 Feb
GO
DECLARE @date1 datetime = '2019-10-01T04:30:00.000';
DECLARE @date2 datetime = '2019-10-02T03:59:00.000';
SELECT DATEDIFF(DAY,DATEADD(HOUR, -4, @date1),DATEADD(HOUR, -4, @date2)); --RETURNS 0, as 04:00 never got to
GO
DECLARE @date1 datetime = '2019-10-01T03:30:00.000';
DECLARE @date2 datetime = '2019-10-03T04:30:00.000';
SELECT DATEDIFF(DAY,DATEADD(HOUR, -4, @date1),DATEADD(HOUR, -4, @date2)); --RETURNS 3, as 04:00 occurs on 01, 02 and 03 of October
Seems the OP wants to count the event of 04:00
as well. I therefore remove a further second from the start time:
DECLARE @date1 datetime = '2019-10-01T04:00:00.000';
DECLARE @date2 datetime = '2019-10-02T04:00:00.000';
SELECT DATEDIFF(DAY,DATEADD(SECOND,-1,DATEADD(HOUR, -4, @date1)),DATEADD(HOUR, -4, @date2)); --returns 2
DECLARE @date1 datetime = '2019-10-01T04:00:00.000';
DECLARE @date2 datetime = '2019-10-01T04:00:01.000';
SELECT DATEDIFF(DAY,DATEADD(SECOND,-1,DATEADD(HOUR, -4, @date1)),DATEADD(HOUR, -4, @date2)); --Returns 1
If you're actually storing values accurate to 1/300 of a second, then don't use 1 second, use 3 millseconds, to ensure utmost accuracy.
Upvotes: 5