I am working on a sql query where i need to get datetime of any specific date.
For this i used the following query:-
DECLARE #RandomDate datetime
DECLARE #fromDate datetime='2018-04-07'
SELECT #RandomDate= (DATEADD(day, ROUND(DATEDIFF(day, #fromDate, #fromDate)
* RAND(CHECKSUM(NEWID())), 5),DATEADD(second, CHECKSUM(NEWID()) % 24000,
#fromDate)))
SELECT #RandomDate
Here in the above example i want to get datetime of date '2018-04-07' i.e 7 April. But sometime it is showing datetime of 6 april also. How to solve it?
CHECKSUM can return negative as well as positive values and % applied to a negative value will produce a negative result. Finally, DATEADD is perfectly happy to add a negative number of seconds onto a date and will produce a result earlier than its passed in date argument.
If you want a value strictly in the range 0 - 23999, then do two mods and an addition:
((valueToConvert % 24000) + 24000) % 24000
(Incidentally - 24000 seems like an odd number to be using here. There are 86400 seconds in a day. Is there a reason why your random time has to fall between midnight and 6:40am?)
Related
doing something like this:
select *
from INVOICE_HEADING
where INVOICE_DATE >= '06 Dec 2018 00:00:00'
INVOICE_DATE <= '16 Dec 2018 00:00:00'
and I get this message:
"The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart."
How can I write it in a different way (or how can I use datediff here?) to get the result?
The function DATEDIFF returns a signed integer, which can hold values from -2.147.483.648 to 2.147.483.647. If the dates you are applying the function to and the unit you are using (month, day, second, etc.) generate a difference outside these bounds then an error is thrown.
There are a few workarounds:
Use DATEDIFF_BIG if you are using SQL Server 2016+.
Move to a "higher" unit (milliseconds -> seconds -> minutes -> hours and so on) until the value you get can be cast into a integer and make sure that all the values you might apply the function to in the future will still be inside the bounds of an integer. You can then drill down the unit to the one you need by multiplying and handling the value as BIGINT (for example).
It's common for this error to pop up when comparing dates that are not valid to the business or generated by default as 1900-01-01. You can filter these with a WHERE clause, supply a decent default value or convert to NULL. Can also avoid applying the DATEDIFF function with a CASE before it when dates aren't reasonable.
Examples:
DECLARE #OldDate DATE = '1900-01-01'
DECLARE #Now DATE = GETDATE()
SELECT DATEDIFF(SECOND, #OldDate, #Now) AS DateDiffResult
--Msg 535, Level 16, State 0, Line 5
--The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart.
Change the unit from second to minute:
DECLARE #OldDate DATE = '1900-01-01'
DECLARE #Now DATE = GETDATE()
SELECT DATEDIFF(MINUTE, #OldDate, #Now) AS DateDiffResult
-- DateDiffResult: 62599680
Revert the minute to second with a "bigger" data type:
DECLARE #OldDate DATE = '1900-01-01'
DECLARE #Now DATE = GETDATE()
SELECT
CONVERT(BIGINT, DATEDIFF(MINUTE, #OldDate, #Now)) * 60 AS DateDiffResult
-- DateDiffResult: 3755980800
select DATENAME(month,29*5)
Can any one please tell me logic behind the above query.
How it always returns correct month name when provided month number as integer.
Datetime values in Sql server are stored on 8 bytes.
The first 4 bytes represents the date and the last 4 byte represents the time.
On the date part, date is stored as the number of days since 1900-01-01.
On the time part, it's the number of clock ticks since midnight.
There are 300 clock ticks per second, so a tick is 3.33333 milliseconds.
That's also the reason why datetime is only accurate to .003 of a second.
This query will hopefully help to explain:
SELECT CAST(0 As datetime) As Date_0,
29*5 As NumberOfDays,
CAST(29*5 as datetime) As TheDate,
DATENAME(month,29*5) As TheMonthName
Results:
Date_0 NumberOfDays TheDate TheMonthName
----------------------- ------------ ----------------------- ------------
1900-01-01 00:00:00.000 145 1900-05-26 00:00:00.000 May
As for the last part of your question, 29 (28 would work as well) is the magic number here - 30 is too big (May would be returned for 4 and 5) and 27 is too small - (September would be returned for 9 and 10).
Basically i'ts just math - get the number correctly so that each time you double it with any number between 1 and 12 will give you a number of days that sums up to a day that belongs to the correct month.
You can test it yourself using this script:
DECLARE #MagicNumber int = 28
;With cte as
(
select 1 as num
union all
select num + 1
from cte
where num < 12
)
SELECT num, DATENAME(month, #MagicNumber * num ) As TheMonthName
from cte
Just change the value of #MagicNumber and see the results you get.
I think I will able to explain.
The default year-month-day for any date data type is 1900-01-01. If we consider above select query, it add 29*5 days into default date and gives the MONTHNAME.
Select DATENAME(month,29*5)
Now understand the DATENAME
DateName - Returns a character string that represents the specified datepart of the specified date. Its have different -2 argument and give the different-2 result as per datepart.
Argument 1 - Is the part of the date to return.
Argument 2 - Is a any date (Is an expression that can be resolved to a
time, date, smalldatetime, datetime, datetime2, or datetimeoffset
value.)
Here we given month as a first argument. Which means it return monthname.
The calculation of 29*5 gives 145 answer and if we simply cast into date it consider as a days and calculate as 1900-01-01 + 145 and gives the date 1900-05-26 00:00:00.000.
Means if we get the month of this will give the 5 - MAY as a answer.
Execute this query and check the answer for the above logic.
Select DATENAME(month,29*5), (29*5) , DATENAME(month, '12:10:30.123'), DATENAME(month, getdate())
select cast (145 as datetime)
DECLARE #t datetime = '12:10:30.123';
SELECT DATENAME(month, 29*5), 145/30.00;
Check for further.
MSDN Link
Convert Month Number to Month Name Function in SQL (check the #user275683 answer)
If you are simply want to show the month corresponding to month number then you should have to use like this.
declare #intMonth as int
set #intMonth = 5
Select DateName( month , DateAdd( month , #intMonth , -1 ))
I have two computed columns (MonthsInService and YearsInService) with the following expressions.
MonthsInService = (datediff(month,[DateEngaged],getdate()))
YearsInService = (datediff(month,[DateEngaged],getdate())/(12))
Now if for example DateEngaged = 2012-April-09 and getdate() is 2013-April-08, MonthsInService returns 12 and YearsInService is 1.
My application requires that YearsInService be Zero since there is still one day to go before the employees first Anniversary.
Am not even sure how to best handle the MonthsInService column since months have varying number of days.
Unfortunately, DATEDIFF computes the number of transitions of the element, rather than the usual, human intuition of the difference between two dates (e.g. DATEDIFF(year,'20121231','20130101') is 1, even though not many people would say that there's a difference of a year).
The solution I'd use is a bit repetitive, but doesn't need a separate function, and always gets e.g. leap years correct:
declare #T table (
DateEngaged datetime not null,
MonthsInService as CASE
WHEN DATEADD(month,DATEDIFF(month,DateEngaged,GETDATE()),DateEngaged) > GETDATE()
THEN DATEDIFF(month,DateEngaged,GETDATE()) - 1
ELSE DATEDIFF(month,DateEngaged,GETDATE())
END,
YearsInService as CASE
WHEN DATEADD(year,DATEDIFF(year,DateEngaged,GETDATE()),DateEngaged) > GETDATE()
THEN DATEDIFF(year,DateEngaged,GETDATE()) - 1
ELSE DATEDIFF(year,DateEngaged,GETDATE())
END
)
insert into #T (DateEngaged) values ('20120409'),('20120408')
select * from #T
Produces:
DateEngaged MonthsInService YearsInService
----------------------- --------------- --------------
2012-04-09 00:00:00.000 11 0
2012-04-08 00:00:00.000 12 1
It works by asking "If we take the naive answer produced by DATEDIFF, does it given an answer that's too high by 1?" - and if so, we just subtract one from the answer it gives. DATEDIFF should only ever be over by 1.
Via using day you can reach the result:
select
datediff(month,'2012-April-09','2013-April-08') MonthsInService
,datediff(day,'2012-April-09','2013-April-08')/365 YearsInService
Output:
12 0
or use function for maximum precision:
CREATE FUNCTION [dbo].[getFullYears]
(
#dateX datetime,
#dateY datetime
)
RETURNS int
AS
BEGIN
DECLARE #y int
SET #y =DATEDIFF(year,#dateX,#dateY)
IF (#dateY < DATEADD(year, #y, #dateX)) SET #y = #y -1
RETURN #y
END
select dbo.getFullYears('2012-April-09','2013-April-09') --1
select dbo.getFullYears('2012-April-09','2013-April-08') --0
For months calculation you can refer here: Calculating number of full months between two dates in SQL
Try this query :
DATEDIFF(DAY, CONVERT(date, dtmDOB),
CONVERT(date, GETDATE()))*(12.0/365.25)),1))
AS TotalMonths,
I'm having a little trouble getting a count of dates in SQL SERVER. I require the number of calender days between 2 dates start and ends dates included. The problem with the example below is that it always returns 10 when I believe it should be 11.
DECLARE #FROM DATETIME, #TO DATETIME
SET #FROM = '18/12/2011 00:00:00'
SET #TO = '28/12/2011 00:00:00'
SELECT
DATEDIFF(MINUTE,#FROM,#TO), -- Returns 14459
DATEDIFF(HOUR,#FROM,#TO), -- Returns 241
DATEDIFF(DAY,#FROM,#TO), -- Returns 10
CEILING(CAST((DATEDIFF(HOUR,#FROM,#TO) / 24) as DECIMAL(9,5))) --Returns 10
CEILING(CAST(CEILING(CEILING(CAST(DATEDIFF(SECOND,#FROM,#TO) as DECIMAL(18,5))) / 60) / 60 as DECIMAL(9,5)) / 24) --Returns 10
The bottom line works if there is at least 1 second between the times but I must account for all scenarios.
My only other thought was to simply add one to the date diff to account for the part days? Is that reliable?
DATEDIFF(DAY,#FROM,#TO) + 1
I came across when answering this question How to find the total between the dates for each values
Is an expression that can be resolved to a time, date, smalldatetime,
datetime, datetime2, or datetimeoffset value. date can be an
expression, column expression, user-defined variable or string
literal. startdate is subtracted from end date.
This is taken from MSDN here.
28-18 = 10. I think you will always have to add 1 in the scenario you have because of the definition for DATEDIFF.
You need to set the #TO date to:
SET #TO = '28/12/2011 23:59:59'
To get the number of days between two dates (ignoring the time of day), including the start and end date, try;
SELECT FLOOR(CONVERT(FLOAT, #TO))-FLOOR(CONVERT(FLOAT, #FROM))+1
Edit:
SELECT DATEDIFF(d, #FROM, #TO)+1
seems to return the exact same results, which would indeed make it a more elegant way of doing it. Always thought DATEDIFF timeparts were about truncating after the calculation (which would give the wrong result if the start time was later in the day than the end time) and not truncating before the calculation which gives the correct result for your case. You learn something new every day :)
If you want a close equivalent of the C# DateTime.TotalDays() function (i.e. to know fractional days) you can use the following:
DECLARE #start DATETIME = '10 Apr 2012 15:00'
DECLARE #end DATETIME = '12 Apr 2012 16:00'
SELECT CONVERT(FLOAT, DATEDIFF(SECOND, #start, #end)) / 86400
*Note: 86400 = seconds in a day = 24 hours x 60 mins x 60 seconds
I have to calculate the difference in hours (decimal type) between two dates in SQL Server 2008.
I couldn't find any useful technique to convert datetime to decimal with 'CONVERT' on MSDN.
Can anybody help me with that?
UPDATE:
To be clear, I need the fractional part as well (thus decimal type). So from 9:00 to 10:30 it should return me 1.5.
DATEDIFF(hour, start_date, end_date) will give you the number of hour boundaries crossed between start_date and end_date.
If you need the number of fractional hours, you can use DATEDIFF at a higher resolution and divide the result:
DATEDIFF(second, start_date, end_date) / 3600.0
The documentation for DATEDIFF is available on MSDN:
http://msdn.microsoft.com/en-us/library/ms189794%28SQL.105%29.aspx
Just subtract the two datetime values and multiply by 24:
Select Cast((#DateTime2 - #DateTime1) as Float) * 24.0
a test script might be:
Declare #Dt1 dateTime Set #Dt1 = '12 Jan 2009 11:34:12'
Declare #Dt2 dateTime Set #Dt2 = getdate()
Select Cast((#Dt2 - #Dt1) as Float) * 24.0
This works because all datetimes are stored internally as a pair of integers, the first integer is the number of days since 1 Jan 1900, and the second integer (representing the time) is the number of (1) ticks since Midnight. (For SmallDatetimes the time portion integer is the number of minutes since midnight). Any arithmetic done on the values uses the time portion as a fraction of a day. 6am = 0.25, noon = 0.5, etc... See MSDN link here for more details.
So Cast((#Dt2 - #Dt1) as Float) gives you total days between two datetimes. Multiply by 24 to convert to hours. If you need total minutes, Multiple by Minutes per day (24 * 60 = 1440) instead of 24...
NOTE 1: This is not the same as a dotNet or javaScript tick - this tick is about 3.33 milliseconds.
DATEDIFF but note it returns an integer so if you need fractions of hours use something like this:-
CAST(DATEDIFF(ss, startDate, endDate) AS decimal(precision, scale)) / 3600
Using Postgres I had issues with DATEDIFF, but had success with this:
DATE_PART('day',(delivery_time)::timestamp - (placed_time)::timestamp) * 24 +
DATE_PART('hour',(delivery_time)::timestamp - (placed_time)::timestamp) +
DATE_PART('minute',(delivery_time)::timestamp - (placed_time)::timestamp) / 60
which gave me an output like "14.3"
You are probably looking for the DATEDIFF function.
DATEDIFF ( datepart , startdate , enddate )
Where you code might look like this:
DATEDIFF ( hh , startdate , enddate )
DATEDIFF(minute,startdate,enddate)/60.0)
Or use this for 2 decimal places:
CAST(DATEDIFF(minute,startdate,enddate)/60.0 as decimal(18,2))
Declare #date1 datetime
Declare #date2 datetime
Set #date1 = '11/20/2009 11:00:00 AM'
Set #date2 = '11/20/2009 12:00:00 PM'
Select Cast(DateDiff(hh, #date1, #date2) as decimal(3,2)) as HoursApart
Result = 1.00
SELECT DATEDIFF(hh, firstDate, secondDate)
FROM tableName
WHERE ...