I want to get the Time from a SQL Server DateTime column. I want to only time between calculation.Date not important only important hour,minute and seconds
Workstart
Personelnum
01.01.2022 07:35:13
13021
01.01.2022 08:12:15
17058
My query:
Select case when cast(time,workstart) between '07:15:00' and '08:30:00' then 08:00:00 end ,Personelnum
from table;
Should be Result:
Workstart
Personelnum
01.01.2022 08:00:00
13021
01.01.2022 08:00:00
17058
How can I do this?
As long as you're using SQL Server 2012 or newer you can use the TIME datatype to get what you're looking for.
DECLARE #PunchClock TABLE (PunchID INT IDENTITY, WorkStart DATETIME, PersonelNum INT)
INSERT INTO #PunchClock(WorkStart, PersonelNum) VALUES
('2022-01-01 07:35:13.000', 13021),
('2022-01-01 08:12:15.000', 17058),
('2022-01-01 07:14:59.000', 12345),
('2022-01-01 08:30:01.000', 12345)
SELECT DATEADD(SECOND,CASE WHEN CAST(WorkStart AS TIME) BETWEEN '07:15' AND '08:30' THEN DATEDIFF(SECOND,CAST(WorkStart AS TIME),'08:00') ELSE 0 END,WorkStart) AS WorkStart, PersonelNum
FROM #PunchClock
WorkStart PersonelNum
-----------------------------------
2022-01-01 08:00:00.000 13021
2022-01-01 08:00:00.000 17058
2022-01-01 07:14:59.000 12345
2022-01-01 08:30:01.000 12345
This case expression converts the DATETIME to a TIME and produces the DATEDIFF in SECONDS to your specified time when it falls within your range. We then just added the difference is seconds to the DATETIME from the table. I added an extra couple of rows to show how rows outside of the range are not affected.
Edit:
If you want to get really clever, you could also use a lookup table to define the adjustments you want, like this:
DECLARE #PunchClock TABLE (PunchID INT IDENTITY, WorkStart DATETIME, PersonelNum INT)
INSERT INTO #PunchClock(WorkStart, PersonelNum) VALUES
('2022-01-01 07:35:13.000', 13021),
('2022-01-01 08:12:15.000', 17058),
('2022-01-01 07:14:59.000', 12345),
('2022-01-01 08:30:01.000', 12345),
('2022-01-01 23:35:00.000', 12345),
('2022-01-01 23:59:01.000', 12345)
DECLARE #AdjustmentTimes TABLE (StartTime TIME, EndTime TIME, AdjustToTime TIME, Modifier INT)
INSERT INTO #AdjustmentTimes (StartTime, EndTime, AdjustToTime, Modifier) VALUES
('07:15', '08:30', '08:00', 0),
('23:35', '23:59:59', '23:59:59', 1)
SELECT DATEADD(SECOND,DATEDIFF(SECOND,CAST(WorkStart AS TIME),COALESCE(a.AdjustToTime,CAST(WorkStart AS TIME)))+COALESCE(a.Modifier,0),WorkStart) AS WorkStart, PersonelNum
FROM #PunchClock p
LEFT OUTER JOIN #AdjustmentTimes a
ON CAST(p.WorkStart AS TIME) BETWEEN a.StartTime AND a.EndTime
To add new adjustments you'd just need a corresponding row in the adjustments table.
cast(time,workstart) is not the correct syntax. A cast operation is cast(value as type), so it should be cast(workstart as time). This is basic stuff you should be able to do on your own.
The other issue is you have to add the time back to base date value.
I'd tend solve this by converting to seconds since midnight, like this:
dateadd(second, case when datediff(second, cast(workstart as date), workstart) between 26100 and 30600 then 28800 else datediff(second, cast(workstart as date), workstart) end, cast(cast(workstart as date) as datetime))
This is because I've been working with SQL since long before the time data type existed, and because time is explicitly defined as a time of day and not as a timespan, meaning it's still a little weird to compose a datetime result from separate date and time values (you have to make sure they are both datetime values first):
cast(cast(workstart as date) as datetime) + cast(case when cast(workstart as time(0)) between '07:15:00' and '08:30:00' then '08:00:00' else cast(workstart as time(0)) end as datetime) as TimeOfDayFinal
See both options work here:
https://dbfiddle.uk/z8EGuDkH
The link also shows how I found the seconds values to use in the first sample.
Related
I have two datetime columns in a DB table: #Start and #End.
Both columns contain the date and time, for example:
#Start: 2018-10-01 19:00:00
#End: 2018-10-10 23:59:00
I want to know if the current date is exactly between both datetimes considering the dates and the times.
So, 2018-10-08 16:37 and 2018-10-10 23:59:00 would match this range
and 2018-10-11 00:00:00 would not.
(In this case this date is one minute later than the End date, so it is not between my datetime range).
SELECT Id FROM Table1 WHERE GETDATE() BETWEEN Start AND End
I don't use GETDATE() in real code, I use an argument. The problem is that current date argument may contain seconds and milliseconds like 23:59:59.123. My code treats such date as not conforming given range. But I don't care about s/ms.
Is there a workaround?
Update:
The precision I want to achieve is in minutes. So I do not even need to take in account the seconds nor the milliseconds. The date time format I would be working on would be 'yyyy-MM-dd hh-mm' but I do not know how to use the BETWEEN clause converting the Start and End to the shown format so I can compare the dates.
You would seem to want this logic:
WHERE GETDATE() >= Start
AND GETDATE() < DATEADD(minute, 1, End)
Assuming that the time part of End is 23:59:00 it covers all possible values between 23:59:00 and 23:59:59.999...999.
SELECT Id FROM Table1 WHERE GETDATE() BETWEEN '2018-10-01 19:00:00' AND '2018-10-10 23:59:00'
TRY
SELECT Id FROM Table1 WHERE
CONVERT(varchar(16),GETDATE(),121) BETWEEN
CONVERT(varchar(16),[Start], 121)
AND
CONVERT(varchar(16),[END],121);
Example of rounding without strings
DECLARE #GetDateMinutes as datetime2;
DECLARE #X as datetime2 = getdate();
--round to minutes, could be made into a function
SET #GetDateMinutes = dateadd(minute,datepart(minute,#x),dateadd(hour, datepart(hour,#x),cast(CAST(#x as date) as datetime2)))
select #x, #GetDateMinutes
Truncate the seconds using the technique described here to avoid all string conversions, then just do your comparison. Here's a fully contained example that uses cross apply and values to encapsulate the truncation logic for start and end:
-- truncate minutes from current date time
declare #currentDateTime datetime2(0) = DateAdd(minute, DateDiff(minute, 0, Convert(datetime2(0), N'2018-10-01 23:58:32.912')), 0);
select #currentDateTime as CurrentDateTime
, a.*
from (values -- create a table of dummy values
(Convert(datetime2(3), N'2018-10-01 19:48:14.735'), Convert(datetime2(3), N'2018-10-10 02:00:00.000'))
, (Convert(datetime2(3), N'2018-10-01 22:43:19.532'), Convert(datetime2(3), N'2018-11-01 12:17:26.663'))
) as a (StartDateTime, EndDateTime)
cross apply (values(
-- truncate minutes from start date time
DateAdd(minute, DateDiff(minute, 0, Convert(datetime2(0), a.StartDateTime)), 0)
-- truncate minutes from end date time
, DateAdd(minute, DateDiff(minute, 0, Convert(datetime2(0), a.EndDateTime)), 0)
)) as b (StartDateTimeWithoutSeconds, EndDateTimeWithoutSeconds)
where #currentDateTime between b.StartDateTimeWithoutSeconds and b.EndDateTimeWithoutSeconds;
Your data appears to already have the s/ms truncated from start and end but figured I'd apply the same logic to all values involved just to be consistent. Here's the formula for stripping s/ms without all the "noise" from the example:
DateAdd(minute, DateDiff(minute, 0, Convert(datetime2(0), <SomeDateTime>)), 0)
I try to set the time and date in my query based one the following conditions:
if time in MyDate < 9:00 then set the time to 9:00
If time in 9:00 < MyDate < 15:00 then set the time to 16:00
If time is MyDate > 15:00 then set the time to 9:00 and the day to day+1
I have the two first conditions in place and works fine, but cannot combine changes in both time and date. How can I do that?
The code below works fine for the two first conditions!
Case When cast(MyDate as TIME) < '09:00:00' Then DATEADD(Hour, 9, CAST(CAST(PayoutDtApplication As Date) As Datetime))
Case When cast(MyDate as TIME) < '09:00:00' Then DATEADD(Hour, 9, CAST(CAST(PayoutDtApplication As Date) As Datetime))
THanks
This is a guess, based on the following comment:
this numbers can varries based on the data I get, just wanted to say I need to set the time to 9:00 and day+1 for all dates I get. I have different dates.
I'm guessing that regardless of the time, the OP wants to change the value to the following date at 09:00:00.
If so, one way to achieve it would be:
SELECT DATEADD(HOUR, 33, CONVERT(date,YourDateColumn)) AS NewDate
FROM YourTable;
Again, this is guesswork. If the OP elaborates, I'll be happy to expand my answer, or remove it if it's irrelevant.
Edit: Based on the OP's new logic from their edit:
CREATE TABLE #Sample (YourDate datetime2(0));
INSERT INTO #Sample
VALUES ('2018-05-09T08:57:00'),
('2018-05-09T14:26:37'),
('2018-05-09T19:24:01');
GO
SELECT YourDate,
CASE WHEN CONVERT(time, YourDate) < '09:00:00' THEN DATEADD(HOUR,9,CONVERT(datetime2(0),CONVERT(date,YourDate)))
WHEN CONVERT(time, YourDate) > '15:00:00' THEN DATEADD(HOUR,33,CONVERT(datetime2(0),CONVERT(date,YourDate)))
ELSE DATEADD(HOUR,15,CONVERT(datetime2(0),CONVERT(date,YourDate))) END AS NewDate
FROM #Sample;
GO
DROP TABLE #Sample;
The double CONVERT (CONVERT(datetime2(0),CONVERT(date...) is because the data type date isn't compatible with DATEADD(HOUR.... I have used datetime2 as this should be used over datetime now.
How i got this output, can you please explain the reason behind it?
declare #a datetime = '2017-06-08 16:02:22.467',
#b datetime = '2017-10-23 00:00:00.000'
select DAY(#a - #b)
select #a - #b
Output:
17
1899-08-17 16:02:22.467
Disclaimer: The information in this answer is relevant only to the DateTime data type. It doesn't apply to the newer data types (DateTime2 , Date and Time).
Well, dates in sql server are stored as the number of days since 1900-01-01.
You can see it if you run this query:
SELECT CAST(0 as datetime)
You'll get 1900-01-01 00:00:00 as the result.
Time is stored as the number of ticks since midnight.
There are 300 ticks per second.
Since the date in #a is before the date in #b, you get a negative result for the date (-137), and that number is then added to 01-01-1900 to give you 1899-08-17. The time in #a is after the time in #b, and since the time in #b is midnight, you get the time of #a in the result.
declare #a datetime = '2017-06-08 16:02:22.467',
#b datetime = '2017-10-23 00:00:00.000'
select datediff(day, #a, #b)
it returns 137, so difference between these two days are 137.
declare #c as datetime = null;
select isnull(#c, 0)
it return 1900-01-01 00:00:00.000, it means the default value for the datetime is 1900-01-01 00:00:00.000
In your case this select #a-#b minus operation is subtracting the actual difference of 137 days with the default value.
select dateadd(day, -137, '1900-01-01 00:00:00.000')
it returns 1899-08-17 00:00:00.000
if it is select #b-#a, it will return 1900-05-17 07:57:37.533 i.e, it will add 137 days from the default value.
and DAY() function simply returns the day of the given date.
So for the 1899-08-17 the DAY() should be 17
Well when you substracting 2 dates zero value for datetime type is 1900-01-01 00:00:00.00.
But from SQL 2008 microsoft created new type datetime2 and as far as you get overflow (negative value) in here it casts result to datetime2 that statrs from 0001-01-01 00:00:00.00
DAY function only get date part from your datetime or datetime2 type.
This will subtract the two date and will add it to Minimum Date in SQL which is '1900-01-01 00:00:00.000'. So after subtracting both dates and getting the difference, it will add it in subsequent minimum date which is '1900-01-01 00:00:00.000'.
I am trying to get the accesstime between two times.
Example
accesstime starttime endtime
23:00 22:00 00:00:00
My query look like this
select accesstime
from myTable
where accesstime between '22:00:00'and '00:00:00'
When I run the query I get no results
Why?
Because the time goes from 00:00:00 to 23:59:59
so, 22:00 is bigger than 00:00:00 in the same day
edit: This considering as a DateTime. If they are Varchar, you have the same problem, because 22:00 as a Varchar is bigger than 00:00:00
Information about BETWEEN:
BETWEEN returns TRUE if the value of test_expression is greater than
or equal to the value of begin_expression and less than or equal to
the value of end_expression.
In your table, accesstime '23:00' (test expression) is greater than '22:00:00' (begin expression) but is not less than '00:00:00' (end expression) and so it returns false.
In order to see results, change your query to:
select accesstime from myTable
where accesstime between '00:00:00' and '23:00:01'
i think you can Convert times to datetime and by dateadd function add ONE day to time '00:00:00' and then it works true.
the sample code is here:
CREATE table EX_Time (accesstime nvarchar(100),starttime nvarchar(100),endtime nvarchar(100))
INSERT INTO EX_Time(accesstime,starttime,endtime)
VALUES (N'23:00:00',N'22:00:00',N'00:00:00')
select *
FROM Ex_Time
Where convert(datetime,accesstime) BETWEEN convert(datetime,'22:00:00')
AND dateadd(day,1,convert(datetime,'00:00:00'))
Goal:
To display data with this list:
Hour
-----
2
2,5
1
Problem:
Is it any possibiltiy to convert column StartTime and EndTime into specific datatype and then doing a calculacution of X1- X2
CREATE TABLE Data
(
StartTime VARCHAR(5),
EndTime VARCHAR(5),
)
GO
INSERT INTO Data(StartTime,EndTime)
SELECT '10:00','12:00' UNION ALL
SELECT '13:30','16:00' UNION ALL
SELECT '14:00','15:00' UNION ALL
GO
EDITED: To get mins in decimals
SELECT ROUND(CAST( Mins AS FLOAT)/60,2) AS [hour]
FROM (
SELECT DATEDIFF(minute, CAST(StartTime AS TIME),CAST(EndTime AS TIME)) AS Mins
FROM Data
) A
SELECT DATEDIFF(mi, CONVERT(DATETIME, StartTime), CONVERT(DATETIME, EndTime))
/ 60.0 AS Hour
FROM Data
It work's for your example data, but you should check if EndTime could be the next day, like:
StarTime: 22:30
EndTime: 01:20
Is that escenario possible? If it is, you must store the date for both Start and End times, not only the hour.
If you are using SQL-SERVER 2008, then why not just use the time object. You could then run the appropriate time comparison functions. If not, you can still make it work by converting to a datetime and running comparison functions. I believe a convert with just a time to a datetime will result in the date as the minimum date.