Truncate timestamp - sql

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

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.

Rounding time untill in SQL

I have a table with timestamp that I want to round off at 15 min. interval. I can round off using the below Query but it rounds off both 11:58 and 12:02 to 12:00 which is not what I want. I would like to round off timestamp at 15 min. interval which gives me time_untill ie for anything between 11:45 to 11:59 should be rounded off to 12 and anything between 12:00 to 12:14 should be rounded off to 12:15. Please let me know how can I achieve that? Thanks
SELECT transaction_id,
CONVERT(smalldatetime, ROUND(CONVERT(float, CONVERT(datetime, entry_date_time)) * 96.0, 0, 1) /96.0) as transaction_datetime
FROM <table>
You can use datetimefromparts():
select dateadd(minute,
15,
datetimefromparts(year(entry_date_time), month(entry_date_time), day(entry_date_time),
datepart(hour, entry_date_time),
15 * (datepart(minute, entry_date_time) / 15), 0, 0
)
) as roundup15
You could use the DATEADD/DATEDIFF method to truncate date/time values that's been available for a long time.
SELECT transaction_id,
entry_date_time,
DATEADD( MI, DATEDIFF( MI, '2010', entry_date_time)/15*15, '2010') as transaction_datetime
--FROM Sample Data
FROM (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) transaction_id,
DATEADD( SS, CHECKSUM(NEWID())%10000, CAST( GETDATE() AS smalldatetime)) AS entry_date_time
FROM sys.columns)x;
Something like this...
DECLARE #time TIME(0) = GETDATE();
SELECT
DATEADD(MINUTE,
(((DATEDIFF(MINUTE, '00:00:00', #time) % 60) / 15) * 15),
DATEADD(HOUR, DATEDIFF(HOUR, '00:00:00', #time), '00:00:00')
);

Does Transact-SQL have a similar function to MS Logparser Quantize?

If you are familiar with Microsoft Log Parser you probably recognize the Quantize function which will truncate a value to the nearest multiple of another value. It is quite handy for grouping date-time fields into increments.
Date-Time Count
1/1/2010 00:00 100
1/1/2010 00:15 134
1/1/2010 00:30 56
....
I'm trying to find a similar function in Transaction-SQL (specifically SQL Server 2005 or 2008) that will allow me to do a similar grouping on date-time.
You can round to any given number of minutes like so:
DateAdd(Minute, (DateDiff(minute, 0, getutcdate() )/15) * 15, 0)
Instead of using getutcdate() you can use your date column, variable or expression. In addition the number of minutes can be a variable.
declare #minutesQuantize int set #minutesQuantize = 15
DateAdd(Minute, (DateDiff(minute, 0, getutcdate() )/#minutesQuantize) * #minutesQuantize, 0)
The only rule is that the date difference must fit into an integer, I.e. be less than 2 billion. That means you can't do seconds or milliseconds without a more complicated expression.
If you need seconds or milliseconds do this:
dateadd(ms, (datediff(ms, dateadd(day, datediff(day, 0, #date), 0), #date)/#msInterval)*#msInterval, dateadd(day, datediff(day, 0, #date), 0))
Or, if you want to wrap this into a function:
create function dbo.DateRoundMinutes(#dt datetime, #minutes int)
returns datetime
as begin
return DateAdd(Minute, (DateDiff(minute, 0, #dt )/#minutes) * #minutes, 0)
end
go
create function dbo.DateRoundMilliseconds(#dt datetime, #ms int)
returns datetime
as begin
return dateadd(ms, (datediff(ms, dateadd(day, datediff(day, 0, #dt), 0), #dt)/#ms)*#ms, dateadd(day, datediff(day, 0, #dt), 0))
end
Which you can use like this:
select t.dt,
dbo.DateRoundMilliseconds(dt, 500) dt0_5Second, -- Half second
dbo.DateRoundMilliseconds(dt, 5000) dt5second, -- 5 second
dbo.DateRoundMilliseconds(dt, 15000) dt15Second,
dbo.DateRoundMilliseconds(dt, 90000) dt90Second,
dbo.DateRoundMinutes(dt, 2) dt2Minute,
dbo.DateRoundMinutes(dt, 5) dt5Minute,
dbo.DateRoundMinutes(dt, 15) dt15Minute,
dbo.DateRoundMinutes(dt, 90) dt90Minute
from
/* some table having a column dt */
Not directly, it doesn't. But you can group by a function (that you write) that rounds the datetime column to its nearest quarter-hour (or whatever Quantize does).
SELECT
dbo.QuarterHour(DateColumn) AS Date-Time
, COUNT(*) AS Count
FROM MyTable
GROUP BY dbo.QuarterHour(DateColumn)

How do I add Hours, mins, seconds to dateadd sql?

I want to get an entire date
So today would be 7/7/2010 12:00:00 am to 7/7/2010 11:59:59 pm
So that should be the full 24 hours since 12:00:00 am would be the 8th then.
So I have this
select DATEADD(??, ??, DATEDIFF(dd, 0, GETUTCDATE()))
How do I make it add 23 hours 59mins and 59seconds to it?
DECLARE #start DATETIME
DECLARE #end DATETIME
SET #start = DATEADD(dd, 0, DATEDIFF(dd, 0, GETUTCDATE()))
SET #end = DATEADD(dd, 1, DATEADD(ms, -3, #start))
Try this:
DATEADD(second, -1, DATEADD(DAY, 1,"7/7/2010 12:00:00"))