How to subtract Time Column from DateTime Column in SQL? - sql

I have Crea_Date column which is a DateTime Column. I want to subtract the value in the IST column from crea_date Column and return a new column with the DateTime Value in it. My sample data is like this:
States crea_date IST
AB 2014-12-30 15:01:00.000 12:30:00.0000000
AK 2014-12-29 16:32:00.000 10:30:00.0000000
AZ 2014-12-18 16:07:00.000 11:30:00.0000000
Thanks in Advance

As strange as it might seem, you can add/subtract datetime values and it seems it's "normal" behavior.
Internally, datetime values are stored as the offset from 1/1/1900. If I add 22/1/2015 and 1/1/2015 I get 22/1/2130 because the second value is actually 115 years after 1900.
When you cast a time value to datetime only the time component is copied and the date component is set to 1/1/1900. In effect, you have an interval equal to your original time value.
This way I can subtract 10:30 hours from a specific datetime:
declare #d datetime='2014-11-04 12:51:00', #t time='10:30:00'
select #d -cast(#t as datetime)
//-----------------------
//2014-11-04 02:21:00.000
This behavior isn't an implementation quirk - it is explicitly permitted only for the datetime type. All other datetime types (eg datetime2, datetimeoffset) return the error Operand data type datetimeoffset is invalid for subtract operator.

If IST is an integer number of seconds:
SELECT DATEADD(s, -IST, crea_date)
FROM yourTable
If IST is of the TIME type:
SELECT DATEADD(ms, DATEDIFF(ms, IST, '00:00:00'), crea_date)
FROM yourTable

Try the below if IST is a character based column.
SELECT
Crea_Date, IST,
dateadd(hh,cast(substring(IST,1,2) as int),
dateadd(mi, cast(substring(IST, 4,2) as int),
dateadd(s, cast(substring(IST,7,2 ) as int), crea_date)
)) Final_Date
from [Yourtable]
You will get the added date in Final_Date column.

With slight modification in #0xF Answer I found the final Solution:
convert(varchar(10),
DATEADD(ms, DATEDIFF(ms, '00:00:00', IST), crea_date), 101) + right(convert(varchar(32
DATEADD(ms, DATEDIFF(ms, '00:00:00', IST), crea_date),100),8)

Related

SQL Server - Check if given date+time is between two datetime variables by exact date+time

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)

To subtract two dates without Using DateAdd Function or DateDiff Function

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'.

How to assign current date with specific time to column?

How do i assign current date with a specific time?
let's say 8:00:00 AM to Column EXIT_DT of datatype datetime??
I have tried GETDATE() AS EXIT_DT but it gives me current datetime. I am using Sql server 2005. Any help?
Lets say Today is 1/3/2013 and i want my result to return as a datetime datatype with value 1/3/2013 8:00:00 AM. If i run the statement ytd, the result will be 1/2/2013 8:00:00 AM
This formula will always produce 08:00 for the day it is called, and avoids string manipulation:
select DATEADD(day,DATEDIFF(day,'20010101',GETDATE()),'2001-01-01T08:00:00')
Try to avoid solutions that convert to and from strings - treating datetime values as strings is one of the largest sources of bugs.
It works by computing the number of days (as an integer) that have elapsed since 1st January 2001. It then adds that same number of days to 08:00 on 1st January 2001.
You can try this :
DECLARE #dt datetime;
SET #dt=CONVERT(DateTime, CONVERT(VARCHAR,GETDATE(),101)+' 8:00:00')
SELECT CONVERT(VARCHAR, #dt, 101)+' '+ LTRIM(RIGHT(CONVERT(VARCHAR(20),#dt, 100), 7))
Visit http://www.sql-server-helper.com/tips/date-formats.aspx for datetime formats.
Use Convert along with getdate() to get specific formats.
ex:
SELECT CONVERT(VARCHAR(30),GETDATE(),113)
This is a bit stupid, but it works
select cast(cast(getdate() as date) as datetime) + '08:00:00'
it casts the getdate() to date thus losing the hours, than it casts it to datetime and adds 8 hours.
If you want to avoid implicit conversion of varchar to datetime, you could use this version:
select cast(cast(getdate() as date) as datetime)
+ convert(datetime,'08:00:00',114)
This is also working. (1). convert today's date to ISO format (yyyymmdd) (2). add the time, (3). convert back to datetime
Select convert(datetime, convert(varchar, getdate(),112) + ' ' + '8:00:00AM')
--Results
2013-01-03 08:00:00.000
If you need in specific format you need to convert back to varchar again.
-- AM/PM --
SELECT TO_CHAR(sysdate, 'MM/DD/YYYY HH:MI:SS AM') FROM dual
/
-- 24 hrs format --
SELECT TO_CHAR(sysdate, 'MM/DD/YYYY HH24:MI:SS') FROM dual
/

Convert seconds to datetime in SQL Server

How to convert seconds to datetime? I try this, but results are not correct:
CONVERT(datetime, DATEADD(ms, dateTimeInSeconds, 0))
Here is an example: 1900-01-15 21:58:16.287 it's should be something like this 2010-11-02 14:56:50.997
Given your example, try this:
select DATEADD(s, dateTimeInMilliseconds, '19700101')
When you use the value zero for date, this is converted to 1900-01-01. Use the specific date that you have selected as epoch:
convert(datetime, dateadd(ms, dateTimeInMilliseconds, '2010-01-01'))
Note that the datetime data type doesn't have millisecond precision, the resolution is 1/300 second. If you for example have four milliseconds and convert it, you get 2010-01-01 00:00:00.003 rather than 2010-01-01 00:00:00.004. If you need to preserve the millisecond resolution, you need to use the datetime2 data type:
convert(datetime2, dateadd(ms, dateTimeInMilliseconds, cast('2010-01-01' as datetime2)))
Edit:
To use seconds instead of milliseconds, use s instead of ms in the dateadd call:
convert(datetime, dateadd(ms, dateTimeInSeconds, '1970-01-01'))
Informative time span string:
declare #seconds int = 93825
convert(varchar,(#seconds/86400)) + 'd:' + format(dateadd(ss,#seconds,0),'HH\h:mm\m:ss\s')
Result: 1d:02h:03m:45s

sql server: what's wrong with my date data?

i have a column with dates, but it is a varchar:
8/31/2010 9:48
8/31/2010 9:49
8/31/2010 9:51
8/31/2010 9:52
8/31/2010 9:55
8/31/2010 9:59
8/31/2010 10:11
8/31/2010 10:13
8/31/2010 10:16
8/31/2010 10:37
8/31/2010 10:42
i made sure that none of these will be a BAD date:
SELECT *
FROM qcvalues.dbo.batchinfo
WHERE ISDATE(reporttime) <> 1
this returned 0 results
question:
i need to return dates between a certain range:
select rowid from qcvalues.dbo.batchinfo where CONVERT(DATE, Substring( reporttime, 1, LEN(reporttime)), 103)
between cast('2010-08-01' as datetime) and CAST('2010-08-31' as datetime)
and i am getting this error;
Msg 241, Level 16, State 1, Line 2
Conversion failed when converting date and/or time from character string.
what is wrong with my conversion?
If you need to store dates then use a datetime column in the future
does this work?
WHERE CONVERT(DATE,RTRIM(reporttime))
BETWEEN '2010-08-01' and '2010-08-31'
If not use SET DATEFORMAT MDY before running it
And if you have to store it in a varchar column then use YYYYMMDD format...that way you can do
WHERE reporttime like '201008%' if you want August 2010
This will solve your problem:
select rowid
from qcvalues.dbo.batchinfo
where
CONVERT(DATE, reporttime, 101) >= '20100801'
-- style 101, not 103
-- also notice date conversion invariant format YYYYMMDD with no separators
AND CONVERT(DATE, reporttime, 101) < '20100901'
-- using BETWEEN with an end date of '8/31/2010' will skip
-- times between '8/31/2010 00:00:00.003' and '8/31/2010 23:59:59.997'
Try this to see what the problem is:
select convert(datetime, '8/31/2010 9:48', 103)
select convert(datetime, '8/31/2010 9:48', 101)
put SET DATEFORMAT MDY before your query.
This will strip out the time portion too
select rowid
from qcvalues.dbo.batchinfo
Where cast(floor(cast(cast(reportTime as datetime)as float))as datetime)
between cast('2010-08-01' as datetime)
and cast('2010-08-31' as datetime)
Remember, this CAST('2010-08-31' as datetime) will have its time portion as 00:00.
Consider casting your varchar data as smalldatetime, and being specific about the boundaries of times in your between. No need to be converting, substring, etc. Just one CAST will do.
Consider this as a potential solution:
SELECT rowid from qcvalues.dbo.batchinfo
WHERE CAST(reporttime as smalldatetime)
BETWEEN '2010-08-01' AND '2010-08-31 23:59'