select only hours from date - sql

The below query returns value in this format 2017-11-18 16:00:00.000
How can i return value in hours only
Desired format
16:00:00.000
17:00:00.000
18:00:00.000
Query
SELECT DATEADD(Hour, DATEDIFF(Hour, 0, GetDate()), 0)

You can convert the value to time:
SELECT CONVERT(TIME, DATEADD(Hour, DATEDIFF(Hour, 0, GetDate()), 0))
I would be more inclined to write the logic as:
SELECT dateadd(hour, datepart(hour, getdate()), cast('00:00' as time))
There really is no difference . . . just the logic of adding a certain number of hours to '00:00' seems simpler.

Related

Remove minutes and seconds and then convert to UTC timezone

I have column with time stamp data like this
2021-12-09 08:01:00.520
I want to remove the minutes and second and then convert the date to UTC timezone in one line.
I tried this code
SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, 0, Time_Stamp), 0) From Table1
I get this result
2021-12-09 08:00:00.000
and I tried this code
SELECT DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), GETDATE()), Time_Stamp)From Table1
I get this result
2021-12-09 16:01:00.520
What I expected is
2021-12-09 16:00:00.000
How to combine the select statement into one line in simple way
Here is another way.
To remove the minute, seconds and only keep the hour, you may use the following query
DATEADD(HOUR, DATEDIFF(HOUR, 0, Time_Stamp), 0)
To convert to the UTCDate, just find the different in hour () between GETDATE() and GETUTCDATE() (Since you are not interested in the minute and seconds anyway) and add that to the above query
Putting all together
DATEADD(HOUR, DATEDIFF(HOUR, 0, Time_Stamp) + DATEDIFF(HOUR, GETDATE(), GETUTCDATE()), 0)
Convert the date to a string and truncate to remove the minutes and seconds. Then add the difference in minutes between your timezone and UTC.
select dateadd(minute,datediff(minute,getdate(),getutcdate()),convert(datetime2(0),convert(varchar(13),getdate(),126)+':00:00',126));
SELECT DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), GETDATE()), dateadd(hour, datediff(hour, 0, Time_Stamp), 0)) FROM Table1

SQL specific time with a moving date

I'm using MS SQL and I'd like to have a query that is basically
SELECT * FROM Data Where TimeStamp <= 06:30:00 Last Saturday
Anyone have anything functional to achieve this?
You can get that time for last Saturday using 30 minutes and 6*60 for minutes in 6 hours (you can get this a few ways but I hard coded it using that:
DATEADD(MINUTE,(30 + (6 * 60) ), DATEADD(WEEK, DATEDIFF(WEEK, -1, CURRENT_TIMESTAMP), -2))
Then you can use that in the where clause:
SELECT
*
FROM dbo.Data AS d
WHERE
d.TimeStamp <= DATEADD(MINUTE,(30 + (6 * 60) ), DATEADD(WEEK, DATEDIFF(WEEK, -1, CURRENT_TIMESTAMP), -2))
UPDATE: TLDR; Break this down using a sample query: (hopefully it helps)
DECLARE #MyDatetime AS DATETIME = '2021-09-12 03:02:05.257' --CURRENT_TIMESTAMP;
SELECT
#MyDatetime AS FromWhen,
/* all these are The int difference between the startdate and enddate, expressed in the boundary set by datepart (WEEK)) */
DATEDIFF(WEEK, 0, #MyDatetime) AS MyWeek0,
DATEDIFF(WEEK, -1, #MyDatetime) AS MyWeek1,
DATEDIFF(WEEK, -2, #MyDatetime) AS MyWeek2,
DATEDIFF(WEEK, -3, #MyDatetime) AS MyWeek3,
DATEDIFF(WEEK, -4, #MyDatetime) AS MyWeek4,
DATEDIFF(WEEK, -5, #MyDatetime) AS MyWeek5,
DATEDIFF(WEEK, -6, #MyDatetime) AS MyWeek6,
DATEDIFF(WEEK, -7, #MyDatetime) AS MyWeek7,
DATEDIFF(WEEK, -8, #MyDatetime) AS MyWeek8,
DATEDIFF(WEEK, -1, #MyDatetime) AS AWeekBack, -- get the week a week from RightNow DATEDIFF ( datepart , startdate , enddate )
DATEADD(WEEK, DATEDIFF(WEEK, -1, #MyDatetime), -2) AS Saturday0000, -- Get the Saturday date from that (-2 is saturday, -1 sunday, ...-7 monday)
DATEADD(MINUTE,(30 + (6 * 60) ), DATEADD(WEEK, DATEDIFF(WEEK, -1, #MyDatetime), -2)) AS Saturday0630 -- now add the minutes for 6:30 AM to that saturday date
Values for a given set from that query:
FromWhen MyWeek0 MyWeek1 MyWeek2 MyWeek3 MyWeek4 MyWeek5 MyWeek6 MyWeek7 MyWeek8 AWeekBack Saturday0000 Saturday0630
2021-09-12 03:02:05.257 6350 6350 6351 6351 6351 6351 6351 6351 6351 6350 2021-09-11 00:00:00.000 2021-09-11 06:30:00.000
Broken down:
Go back a week (-1) from NOW
DATEDIFF always uses Sunday as the first day of the week to ensure the function operates in a deterministic way this -2 is Saturday.
DATEDIFF(WEEK, -1, CURRENT_TIMESTAMP)
For example this is one query I use often get get those few thousand rows from a 120 second range on a given DATETIME column:
SELECT *
FROM SomeTable AS st
WHERE
st.DateColumn >= DATEADD(SECOND, -60, #SomeDateTime)
AND st.DateColumn < DATEADD(SECOND, 60, #SomeDateTime)
With a calendar table, this is quite logical. Get me the highest row from the table that is a Saturday before today.
DECLARE #d smalldatetime;
SELECT #d = DATEADD(MINUTE, 390, MAX(TheDate))
FROM dbo.CalendarTable
WHERE TheDayName = 'Saturday'
AND TheDate < CONVERT(date, GETDATE());
SELECT ... FROM dbo.Data WHERE [TimeStamp]/*shudder*/ <= #d;
Without a calendar table, you can do this in a slightly less intuitive way, by picking a known Saturday in the past, and adding the number of weeks that have passed since that date, less 1:
DECLARE #KnownSat smalldatetime = '20110101';
SELECT #d = DATEADD(MINUTE, 390, DATEADD
(
WEEK,
DATEDIFF(WEEK, #KnownSat, GETDATE()) - 1,
#KnownSat
));
SELECT ... FROM dbo.Data WHERE [TimeStamp]/*shudder*/ <= #d;
Note that both solutions will return the previous Saturday when run on a Saturday.

Combine Queries where one is recursive

I have a recursive query that creates a row for each hour of the previous month as follows;
WITH a AS (
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0) AS [DateTime]
UNION ALL
SELECT dateadd(hour, 1, [DateTime])
FROM a
WHERE dateadd(hour, 1, [DateTime]) < EOMONTH(GETDATE(), -1)
)
SELECT
a.*
FROM a
OPTION (maxrecursion 0);
This produces these results;
DateTime
2020-11-01 00:00:00.000
2020-11-01 01:00:00.000
2020-11-01 02:00:00.000
etc.....
Next I have a query that calculates the number of calls per customer, per hour, for the previous month, as a 4 week average as follows;
SELECT
DATEADD(hour, DATEDIFF(hour, 0,
DATEADD(minute, 30 - DATEPART(minute, Timestamp + '00:30:00.000'),
Timestamp)), 0) as RoundedToHour,
Campaign,
COUNT(*)/4 AS Average
FROM [Reporting].[dbo].[New_Five9_CallLog] WITH (NOLOCK)
WHERE DATEDIFF(mm, Timestamp, GETDATE()) = 1
AND Call_Type = 'Inbound'
GROUP BY Campaign,
DATEADD(hour, DATEDIFF(hour, 0,
DATEADD(minute, 30 - DATEPART(minute, Timestamp + '00:30:00.000'),
Timestamp)), 0)
This produces the following results;
RoundedToHour Campaign Average
2020-11-01 02:00:00.000 Client1 0
2020-11-01 04:00:00.000 Client2 2
etc....
What I am having trouble doing is combining these two. My initial thoughts were to use a CTE of the recursive query as basically a where clause in my second query, but since you have to use a WITH for CTE's, and I have to use a WITH for my recursive query, that won't directly work, because you can't have nested WITH's.
My final result I am looking for is a single query that produces the 4 week average of calls for each hour of the previous month, for each client. I am open to changing how I am doing any of this if someone has a better suggestion on how to reach my ultimate goal.
You can't declare a CTE in a sub-query but you can declare multiple CTEs together. So declare both and then LEFT JOIN them.
WITH a AS (
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0) AS [DateTime]
UNION ALL
SELECT dateadd(hour, 1, [DateTime])
FROM a
WHERE dateadd(hour, 1, [DateTime]) < EOMONTH(GETDATE(), -1)
), b AS (
SELECT
DATEADD(hour, DATEDIFF(hour, 0,
DATEADD(minute, 30 - DATEPART(minute, Timestamp + '00:30:00.000'),
Timestamp)), 0) as RoundedToHour,
Campaign,
COUNT(*)/4 AS Average
FROM [Reporting].[dbo].[New_Five9_CallLog] WITH (NOLOCK)
WHERE DATEDIFF(mm, Timestamp, GETDATE()) = 1
AND Call_Type = 'Inbound'
GROUP BY Campaign,
DATEADD(hour, DATEDIFF(hour, 0,
DATEADD(minute, 30 - DATEPART(minute, Timestamp + '00:30:00.000'),
Timestamp)), 0)
)
SELECT a.*, b.*
FROM a
LEFT JOIN b on b.RoundedToHour = a.DateTime
OPTION (maxrecursion 0);

Truncate timestamp

I would like into a stored procedure, truncate timestamp input values at the top hour or at the lower hour.
For example, if my input values are 2020-02-12 06:56:00 and 2020-02-12 07:14:00, I would like to transforme it in 2020-02-12 06:00:00 and 2020-02-12 08:00:00
Is a cast function can work?
You can construct the new datetimes from the parts that you want of your original datetimes.
declare #start datetime = '2020-02-12 06:56:00'
declare #end datetime = '2020-02-12 07:14:00'
select #start as OriginalStart,
#end as OriginalEnd,
datetimefromparts(year(#start), month(#start), day(#start), datepart(hour, #start), 0, 0, 0) as TruncatedStart,
dateadd(hour, 1, datetimefromparts(year(#end), month(#end), day(#end), datepart(hour, #end), 0, 0, 0)) as TruncatedEnd
The first truncation of the interval is the lower hour, and the second one adds an additional hour so it returns the higher hour.
PS: If what you want is to round to the nearest hour, then you can add 30 minutes and truncate :
declare #date datetime = '2020-02-12 06:56:00'
set #date = dateadd(minute, 30, #date)
select datetimefromparts(year(#date), month(#date), day(#date), datepart(hour, #date), 0, 0, 0) as NearestHour
or in a single step (using Lepetit's shortcut for truncation) :
declare #date datetime = '2020-02-12 06:56:00'
select dateadd(hour, datediff(hour, 0, dateadd(minute, 30, #date)), 0) AS NearestHour
This is a simpler solution:
declare #start datetime = '2020-02-12 06:56:00'
declare #end datetime = '2020-02-12 07:14:00'
select #start as OriginalStart,
#end as OriginalEnd,
dateadd(hour, datediff(hour, 0, #start), 0) as TruncatedStart,
dateadd(hour, datediff(hour, 0, dateadd(hour, 1, #end)), 0) as TruncatedEnd
In both cases the function substracts the hour part from the original timestamp. For the TruncatedEnd, one hour is added, so that the result is the subsequent hour.
Using a bit of arithmetic calculation, convert to hours with decimal and use floor() and ceiling() to perform the round up / down
first it find the time different with 00:00:00 in terms of second. convert(date, date_col) convert the datetime to date, so effectively it is 00:00:00
datediff(second, convert(date, date_col), date_col)
then you divide by 60 x 60 = 3600 seconds. Gives you fraction of hours
then you use floor() or ceiling() to perform the rounding
and lastly you add that back to the date (convert(date, date_col))
Final query
select *,
RoundDown = convert(datetime, convert(date, date_col))
+ dateadd(hour, floor(datediff(second, convert(date, date_col), date_col) / (3600.0)), 0),
RoundUp = convert(datetime, convert(date, date_col))
+ dateadd(hour, ceiling(datediff(second, convert(date, date_col), date_col) / (3600.0)), 0)
from (
values
('2020-02-12 06:56:00'),
('2020-02-12 07:14:00')
) d (date_col)
/*
2020-02-12 06:56:00 2020-02-12 06:00:00 2020-02-12 07:00:00
2020-02-12 07:14:00 2020-02-12 07:00:00 2020-02-12 08:00:00
*/
EDIT : a much simpler query below
find the different in minute divide by 60.0 minutes to get different in terms of hour (with decimal places) and then apply floor or ceiling. Finally add that result back
select getdate() as Now,
dateadd(hour, floor(datediff(minute, 0, getdate()) / 60.0), 0) as RoundDown,
dateadd(hour, ceiling(datediff(minute, 0, getdate()) / 60.0), 0) as RoundUp

Using DATEADD and DATEDIFF truncates the time

I am using the following to get to get the 1st day of next month with time:
select DATEADD(m, DATEDIFF(m, -1, getdate()), 0)
But the output is:
2018-12-01 00:00:00.000
And the expected result is:
2018-12-01 11:53:30.677
I have tried various approaches but not able to get required output. I am using SQL Server 2008.
You can add two datetime values, one for the date and the other for the time:
select DATEADD(month, DATEDIFF(month, -1, getdate()), 0) + cast(cast(getdate() as time) as datetime)
I am guessing that you want the time value from the current time.
Subtract DAY(#date) - 1 days from #date to get first day of that month including time. Then add one month:
SELECT DATEADD(MONTH, 1, DATEADD(DAY, -DAY(GETDATE()) + 1, GETDATE()))
-- 2018-12-01 04:52:33.403
try like below
select DATEADD(m, DATEDIFF(m, -1, getdate()), 0)+ convert(DATETIME,'11:53:30.677')
in case of current time it would be like below
select DATEADD(m, DATEDIFF(m, -1, getdate()), 0)+ convert(datetime, convert(time,getdate()))