I am having some difficulty in trying to figure out something, lets say I have a date and time;
And I want to add 180 minutes to it so;
SELECT DATEADD(MINUTE,180,'2018-05-24 15:00')
This would give me answer of "2018-05-24 18:00" but I want to do it in a range so ADD the minutes if you are between 09:00 - 17:00 so something like this;
SELECT DATEADD(MINUTES,180,'2018-05-24 15:00') WHERE '2018-05-24 15:00' BETWEEN '2018-05-24 09:00' AND '2018-05-24 17:00'
So the answer to this would be "2018-05-25 10:00"
Was hard, but this should work for all your cases. This solution works for any amount of (positive) minutes and result will always be inside the parametrized hours, adding the corresponding amount of days.
DECLARE #RangeHourStart INT = 9
DECLARE #RangeHourEnd INT = 17
DECLARE #MinutesToAdd INT = 120
DECLARE #Date DATETIME = '2018-05-24 15:00'
SELECT
FinalDate = CASE
WHEN -- When final hour exceeds the range hour
DATEPART(HOUR, #Date) * 60 +
DATEPART(MINUTE, #Date) +
#MinutesToAdd % ((#RangeHourEnd - #RangeHourStart) * 60) > #RangeHourEnd * 60
THEN
DATEADD(HOUR, -1 * (#RangeHourStart - 1),
DATEADD(DAY, 1,
DATEADD(MINUTE, #MinutesToAdd % ((#RangeHourEnd - #RangeHourStart) * 60),
DATEADD(
DAY,
#MinutesToAdd / ((#RangeHourEnd - #RangeHourStart) * 60),
#Date))))
ELSE
DATEADD(MINUTE, #MinutesToAdd % ((#RangeHourEnd - #RangeHourStart) * 60),
DATEADD(
DAY,
#MinutesToAdd / ((#RangeHourEnd - #RangeHourStart) * 60),
#Date))
END
I made it so you don't need to hard-code any value.
This doesn't look particularly pretty, however...
USE Sandbox;
GO
CREATE TABLE Times (DateNTime datetime2(0));
INSERT INTO Times
VALUES ('20180520 10:00:00'),
('20180520 15:20:00'),
('20180521 09:32:00'),
('20180521 14:17:00'),
('20180522 16:54:00'),
('20180523 12:46:00'),
('20180524 15:32:00');
GO
SELECT *
FROM Times;
GO
SELECT T.DateNTime,
CASE WHEN CONVERT(time,T.DateNTime) <= '14:00' THEN DATEADD(MINUTE, 180,T.DateNTime)
ELSE DATEADD(MINUTE, 180 - DATEDIFF(MINUTE,T.DateNTime,DATEADD(HOUR,17,DATEADD(DAY, DATEDIFF(DAY, 0, T.DateNTime),0))), DATEADD(HOUR,9,DATEADD(DAY, DATEDIFF(DAY, 0, T.DateNTime) + 1,0))) END
FROM Times T;
GO
DROP TABLE Times;
you can try this:
DECLARE #input DATETIME='2018-05-24 15:00'
DECLARE #min INT=180
SELECT CASE WHEN DATEADD(MINUTE,#min,#input)>DATEADD(HOUR, 17,DateAdd(Day, Datediff(Day,0, #input), 0))
THEN DATEADD(MINUTE,
DATEDIFF(MINUTE,
DATEADD(HOUR, 17,
DATEADD(Day,
DATEDIFF(Day,0, #input),
0)
),
DATEADD(MINUTE,#min,#input)),
DATEADD(Hour,9,
DATEADD(Day,1,
DateAdd(Day,
Datediff(Day,0, #input),
0)
)
)
)
ELSE DATEADD(MINUTE,#min,#input)
END
Related
I am trying to aggregate the data for last 24 hours on 5 min interval basis. I had written following query:
select
DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', t.datetime) / 5 * 5, '2000')
as datetimevalue,
cast(sum(t.value) as decimal(10,2)) as value
from
dbo.data t
where
t.datetime <= '2020-09-12 19:23:00.000'
and t.datetime > DATEADD(day,-1,'2020-09-12 19:23:00.000')
group by
DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', t.datetime) / 5 * 5, '2000')
order by
datetimevalue asc
The result is returned like this:
datetimevalue value
------------------------------------
2020-09-12 18:45:00.000, 54227.16
2020-09-12 18:50:00.000, 53681.54
2020-09-12 18:55:00.000, 49379.01
2020-09-12 19:00:00.000, 50751.53
2020-09-12 19:05:00.000, 55033.14
2020-09-12 19:10:00.000, 55858.37
2020-09-12 19:15:00.000, 54236.57
2020-09-12 19:20:00.000, 26731.36
I need aggregation of last 5 minute starting from current timestamp insteead of above which is aggregating last 3 minutes and then 5 minutes after that.
For example
datetimevalue value
--------------------------------------
2020-09-12 19:03:00.000, 22444.47
2020-09-12 19:08:00.000, 45674.46
2020-09-12 19:13:00.000, 35737.23
2020-09-12 19:18:00.000, 34675.34
Any assistance appreciated.
You need to calculate the offset to the aggregation time window (5 minutes), substract it while calculating values and the add it again to the final times:
DECLARE #dt DATETIME = GETDATE()
DECLARE #offset INT = (DATEDIFF(SECOND, CAST(CAST(#dt AS DATE) AS DATETIME), #dt) % (60 * 5)) / 60 * 60
-- In case you want an offset in seconds
--DECLARE #diff INT = DATEDIFF(SECOND, CAST(CAST(#dt AS DATE) AS DATETIME), #dt) % (60 * 5)
SELECT DATEADD(SECOND, #offset, datetimevalue) AS datetimevalue, value
FROM (
SELECT
DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', DATEADD(SECOND, -#offset, t.DATETIME)) / 5 * 5, '2000') AS datetimevalue
,cast(sum(t.value) AS DECIMAL(10, 2)) AS value
FROM dbo.data t
WHERE t.DATETIME <= #dt
-- in case you want only for last 24 hours
-- AND t.DATETIME > DATEADD(DAY, - 1, #dt)
-- in case if you want to include offset in last timestamp
AND t.DATETIME > DATEADD(SECOND, -#offset, DATEADD(DAY, - 1, #dt))
GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', DATEADD(SECOND, -#offset, t.DATETIME)) / 5 * 5, '2000')
) T
ORDER BY datetimevalue DESC
My dates stored in a float column, I tried to change it to timestamp with no luck,
now I want to calculate the age from that field, I have tried all sorts of combinations using CONVERT and CAST functions, but it does not seem to work.
DoB
-434419200000
606960000000
1332806400000
1395878400000
-87350400000
890956800000
I tried:
SELECT DATEADD(ss, dob, '19700101')
from tbl
//Result
Error overflow .. arithmetique for type int, value= -434419200000.000000
SELECT DATEADD(ss, CONVERT(bigint, dob, 101), '19700101')
from tbl
//Result
Error while conversion from expression to type int.
UPDATE
NOTE that the data here is from milliseconds from the date"1970/1/1 00:00:00"
Thank you.
As I mention in the comments, this is a combined duplicate of the questions converting Epoch timestamp to sql server(human readable format) and How to calculate age (in years) based on Date of Birth and getDate().
Sample data:
CREATE TABLE dbo.YourTable (DoB float);
INSERT INTO dbo.YourTable (DoB)
VALUES (-434419200000),
(606960000000),
(1332806400000),
(1395878400000),
(-87350400000),
(890956800000);
Then using the first link we get:
SELECT DATEADD(SECOND, DoB / 1000,'19700101') --As yours is milliseconds, not seconds.
FROM dbo.YourTable;
Then we can use the answer from the second link:
SELECT YT.DoB,
V.DateOfBirth,
CONVERT(int,DATEDIFF(yy, V.DateOfBirth, GETDATE()) +
CASE WHEN GETDATE() >= DATEFROMPARTS(DATEPART(yyyy, GETDATE()), DATEPART(m, V.DateOfBirth), DATEPART(d, V.DateOfBirth)) THEN (1.0 * DATEDIFF(DAY, DATEFROMPARTS(DATEPART(yyyy, GETDATE()), DATEPART(m, V.DateOfBirth), DATEPART(d, V.DateOfBirth)), GETDATE()) / DATEDIFF(DAY, DATEFROMPARTS(DATEPART(yyyy, GETDATE()), 1, 1), DATEFROMPARTS(DATEPART(yyyy, GETDATE()) + 1, 1, 1)))
ELSE -1 * (-1.0 * DATEDIFF(DAY, DATEFROMPARTS(DATEPART(yyyy, GETDATE()), DATEPART(m, V.DateOfBirth), DATEPART(d, V.DateOfBirth)), GETDATE()) / DATEDIFF(DAY, DATEFROMPARTS(DATEPART(yyyy, GETDATE()), 1, 1), DATEFROMPARTS(DATEPART(yyyy, GETDATE()) + 1, 1, 1)))
END) AS Age
FROM dbo.YourTable YT
CROSS APPLY (VALUES (DATEADD(SECOND, YT.DoB / 1000, '19700101'))) V (DateOfBirth);
If this answer helps, I suggest upvoting the answers that I link above as well, as this is a combination of those said answers.
The correct datatype would be bigint instead of float. In fact I would rather import the timestamps in a date column.
Having said that, divide the number by 1000 to avoid overflow error:
select dateadd(second, -434419200000e0 / 1000, '1970-01-01')
-- 1956-03-27 00:00:00.000
I have a table with 7 columns:
Start_hour | Start_minute | Start_second | End_hour | End_minute | end_second | date
My task is to sum the differences between start and end times on current day. And my query already does that. Sadly I need the output to be in minutes:seconds only. For Example the total sum of time differences is 2 hour 26 minutes and 52 seconds.
I need my output to like this:
126:52
My query right now looks like this:
SELECT
RIGHT(CONVERT(CHAR(8),
DATEADD(SECOND,
SUM(DATEDIFF(SECOND,
Timefromparts(start_hour, start_minute, start_second, 0, 0),
Timefromparts(end_hour, end_minute, end_second, 0, 0))
), 0), 108), 5)
FROM
opoznienia
WHERE
YEAR(data) = YEAR(GETDATE())
AND MONTH(data) = MONTH(GETDATE())
AND DAY(data) = DAY(GETDATE())
Sample data:
Start_hour | Start_minute | Start_second | End_hour | End_minute | end_second | date
10 15 0 10 30 30 2018-11-27 14:40:53.680
10 15 0 10 30 30 2018-11-30 10:16:20.610
6 10 30 6 23 45 2018-12-02 01:00:27.243
8 10 0 8 53 45 2018-12-02 14:42:48.663
10 5 13 10 55 23 2018-12-02 14:53:03.560
Output of the query above:
47:13 (without RIGHT command it would be 01:47:13)
The wanted output:
107:13
You need to calculate the number of seconds and then format it as you want. From number of seconds you can calculate the minutes as division by 60, where the remainder are the seconds:
declare #NumberOfSeconds int = 7612
-- Returns 126:52
select concat(#NumberOfSeconds / 60, ':', FORMAT(#NumberOfSeconds % 60, 'D2'))
Here is one option:
SELECT
numSeconds,
CASE WHEN numSeconds / 60 <= 100
THEN RIGHT('00' + CONVERT(VARCHAR(20), numSeconds / 60), 2)
ELSE CONVERT(VARCHAR(20), numSeconds / 60) END
+ ':' +
CASE WHEN numSeconds / 60 <= 100
THEN RIGHT('00' + CONVERT(VARCHAR(20), numSeconds % 60), 2)
ELSE CONVERT(VARCHAR(20), numSeconds % 60) END AS output
FROM yourTable;
Demo
The ugliness in the code has to do with that you expect a minimum of two digits for the minute and second components. So, we have to pad each component with zeroes in the case where minutes or seconds happens to be just a single digit.
The other answers are better, but to understand what may be missing in what you're trying to do - you can look at following where DatePart is used.
-->"
..(without RIGHT command it would be 01:47:13)
" This is your clue that you that you need to work with the parts and not the whole...
SELECT Cast
(
Datepart
(
hour,
DATEADD(second,sum(datediff(second,
TIMEFROMPARTS ( Start_hour, Start_minute, Start_second, 0, 0),
TIMEFROMPARTS ( End_hour, End_minute, End_second, 0, 0))),0)
) * 60
+
Datepart
(
minute,
DATEADD(second,sum(datediff(second,
TIMEFROMPARTS ( Start_hour, Start_minute, Start_second, 0, 0),
TIMEFROMPARTS ( End_hour, End_minute, End_second, 0, 0))),0)
) As varchar)
+
':'
+
Cast
(
Datepart
(
second,
DATEADD(second,sum(datediff(second,
TIMEFROMPARTS ( Start_hour, Start_minute, Start_second, 0, 0),
TIMEFROMPARTS ( End_hour, End_minute, End_second, 0, 0))),0)
) As varchar) as result
from minsec
Try the following
CREATE TABLE T(
StartHour INT,
StartMinute INT,
StartSecond INT,
EndHour INT,
EndMinute INT,
EndSecond INT,
[Date] DATE
);
INSERT INTO T VALUES
(10, 15, 0 , 10, 30, 30, '2018-11-27'),
(10, 15, 0 , 10, 30, 30, '2018-11-30'),
(6 , 10, 30, 6 , 23, 45, '2018-12-02'),
(8 , 10, 0 , 8 , 53, 45, '2018-12-02'),
(10, 5 , 13, 10, 55, 23, '2018-12-02');
SELECT *,
CAST( (DATEDIFF(Hour, StartTime, EndTime) * 60) +
(DATEDIFF(Minute, StartTime, EndTime) % 60) AS VARCHAR
) + ':' +
CAST(DATEDIFF(Second, StartTime, EndTime) % 60 AS VARCHAR)
FROM
(
SELECT [Date],
TIMEFROMPARTS(StartHour, StartMinute, StartSecond, 0, 0) StartTime,
TIMEFROMPARTS(EndHour, EndMinute, EndSecond, 0, 0) EndTime
FROM T
) TT
You can also SUM() and GROUP BY [Date] if you want to.
SELECT [Date],
CAST( SUM( (DATEDIFF(Hour, StartTime, EndTime) * 60) +
(DATEDIFF(Minute, StartTime, EndTime) % 60)
) AS VARCHAR
) + ':' +
CAST(SUM(DATEDIFF(Second, StartTime, EndTime) % 60) AS VARCHAR)
FROM
(
SELECT [Date],
TIMEFROMPARTS(StartHour, StartMinute, StartSecond, 0, 0) StartTime,
TIMEFROMPARTS(EndHour, EndMinute, EndSecond, 0, 0) EndTime
FROM T
) TT
GROUP BY [Date]
Demo
UPDATE
It seems like you are looking for
SELECT [Date],
CAST(SUM(DATEDIFF(Second, StartTime, EndTime)) / 60 AS VARCHAR) + ':' +
CAST(SUM(DATEDIFF(Second, StartTime, EndTime)) % 60 AS VARCHAR) [MM:SS]
FROM
(
SELECT [Date],
TIMEFROMPARTS(StartHour, StartMinute, StartSecond, 0, 0) StartTime,
TIMEFROMPARTS(EndHour, EndMinute, EndSecond, 0, 0) EndTime
FROM T
) TT
GROUP BY [Date];
Returns:
+---------------------+--------+
| Date | MM:SS |
+---------------------+--------+
| 27/11/2018 00:00:00 | 15:30 |
| 30/11/2018 00:00:00 | 15:30 |
| 02/12/2018 00:00:00 | 107:10 |
+---------------------+--------+
Demo
I have a query that monitors connection process. Now I'm stuck and need to set a proper monitoring for weekday and time range.
The process starts on Sunday 22:00, and goes down for 5 min. at 21:55 - every day to Friday. (not goes up from Friday 21:55 till 22:00 on Sunday)
Below is the SQL Query I tried:
IF CASE
WHEN (100 * DATEPART(hh, GETDATE()))
+ DATEPART(MINUTE, GETDATE())
BETWEEN 2155 AND 2200 -- Monitoring for whole day, wen connection is up
AND DATEPART(dw,GETDATE()), (100 * DATEPART(hh, GETDATE()))
+ DATEPART(MINUTE, GETDATE())
NOT BETWEEN (5, 2155) AND (0, 2200) --except trough Friday night to Sunday (weekdays and time).
THEN 1 ELSE 0 END = 0
You needed to add some SELECT statements into the parts of the case where you were getting the values to range between. Try this:
SELECT
CASE
WHEN(100 * DATEPART(hh, GETDATE())) + DATEPART(MINUTE, GETDATE()) -- = 731
BETWEEN 2155 AND 2200 -- Monitoring for whole day, wen connection is up
AND (
(
SELECT
DATEPART(dw, GETDATE())
) NOT BETWEEN(5) AND(0)
AND
(
SELECT
(100 * DATEPART(hh, GETDATE())) + DATEPART(MINUTE, GETDATE())
) NOT BETWEEN(2155) AND(2200)
)
THEN 1
ELSE 0
END;
The first calculation equals 731 so looking at the query I would except it to return '0' which it does
I'm trying to calculate the difference between two dates excluding the weekends and only count the time from 8pm - 6am. I want to calculate that difference in Days, Hours and Minutes.
For that I have this:
DECLARE #Start_Date DATETIME
DECLARE #End_Date DATETIME
SET #Start_Date = '2017-06-23 10:43:41.000'
SET #End_Date = '2017-06-27 11:58:52.000'
SELECT (DATEDIFF(dd, #Start_Date, #End_Date) + 1)
-(DATEDIFF(wk, #Start_Date, #End_Date) * 2)
-(CASE WHEN DATENAME(dw, #Start_Date) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, #End_Date) = 'Saturday' THEN 1 ELSE 0 END) AS [Time to First Atualization- Days],
datediff(hour, #Start_Date, #End_Date) - (datediff(wk, #Start_Date, #End_Date) * 48) -
case when datepart(dw, #Start_Date) = 1 then 1 else 0 end +
case when datepart(dw, #End_Date) = 1 then 1 else 0 end AS [Time to First Atualization- Hours],
datediff(minute, #Start_Date, #End_Date) - (datediff(wk, #Start_Date, #End_Date) * 2880) -
case when datepart(dw, #Start_Date) = 1 then 1 else 0 end +
case when datepart(dw, #End_Date) = 1 then 1 else 0 end AS [Time to First Atualization- Minutes]
The number of days the query return the correct value but to calculate the number of hours and minutes it's wrong...
How can I solve this?
Thanks!
I worked out something from scratch, and it seems to cover all your needs, though you can update us back if something's missing.
Considering it's a fresh start and coming from a different angle, you might discover certain techniques or ideas out of it. Also, it does seem simpler to me but maybe that's because I'm reviewing my own work...
One last note, I'll be relying on a trick I read before, that applies MIN and MAX in a row-wise fashion, abstract example:
SELECT MAX([value]) AS [MAX], MIN([value]) AS [MIN]
FROM (
VALUES (CURRENT_TIMESTAMP), (#Start_Date), (#End_Date), (NULL), (0)
) AS [data]([value])
First off, thought of figuring the amount of time outside start & end days:
SELECT MinutesExcludingStartAndEndDays = MAX([value])
FROM (VALUES (0), ((DATEDIFF(DAY, #Start_Date, #End_Date) - 1) * 840)) AS [data]([value])
Second, figuring the time during starting day, against 8pm (or end time if both days match):
SELECT MinutesOnStartDay = DATEDIFF(MINUTE, #Start_Date, MIN([value]))
FROM (VALUES (#End_Date), (DATETIMEFROMPARTS(YEAR(#Start_Date), MONTH(#Start_Date), DAY(#Start_Date), 20, 0, 0, 0))) AS [data]([value])
Third is very similar to second, however note that if start and end days were the same, we should not count both second and third. I decided to handle that with a CASE statement within third:
SELECT MinutesOnEndDayIfNotStartDay = CASE DATEDIFF(DAY, #Start_Date, #End_Date) WHEN 0 THEN 0 ELSE DATEDIFF(MINUTE, MAX([value]), #End_Date) END
FROM (VALUES (#Start_Date), (DATETIMEFROMPARTS(YEAR(#End_Date), MONTH(#End_Date), DAY(#End_Date), 6, 0, 0, 0))) AS [data]([value])
Fourth, if either start or end dates land on a weekend, it should be pushed away from there:
DECLARE #Mod int
SET #Mod = CONVERT(int, #Start_Date) % 7
IF #Mod IN (5, 6)
SET #Start_Date = DATEADD(DAY, CASE #Mod WHEN 5 THEN 2 WHEN 6 THEN 1 ELSE 0/0 END, DATETIMEFROMPARTS(YEAR(#Start_Date), MONTH(#Start_Date), DAY(#Start_Date), 6, 0, 0, 0))
SET #Mod = CONVERT(int, #End_Date) % 7
IF #Mod IN (5, 6)
SET #End_Date = DATEADD(DAY, CASE #Mod WHEN 5 THEN -1 WHEN 6 THEN -2 ELSE 0/0 END, DATETIMEFROMPARTS(YEAR(#End_Date), MONTH(#End_Date), DAY(#End_Date), 20, 0, 0, 0))
Lastly, the issue of having weekend days fully encompassed within your target period, for that have a look at this question, from the votes there I can only guess they worked it out already.