I have created a procedure which returns time difference in minutes between 2 time i.e. ShiftStartTime, ShiftEndtime.
Now problem is that if i pass 2 date ranges then how i will calculate total shiftTime between those 2 dates e.g. TimeDifference returns me 480 min for today but i want to find total ShiftDifference for 3 days or more, then how i will add TimeDifference for more than 1 day ?
CREATE PROCEDURE GetShiftTotalDuration
#ShiftID int = 9,
#FromDate DateTime,
#ToDate DateTime
AS
BEGIN
Declare #TimeDifference int
Declare #ShiftStartTime time
Declare #ShiftEndTime time
Set #ShiftStartTime = (Select DeparmentShiftsHistory.StartTime from DeparmentShiftsHistory
where DeparmentShiftsHistory.Shift_ID= 9)
Set #ShiftEndTime = (Select DeparmentShiftsHistory.EndTime from DeparmentShiftsHistory
where DeparmentShiftsHistory.Shift_ID= 9)
Set #TimeDifference = (Select DATEDIFF(mi,#ShiftStartTime,#ShiftEndTime)) --Returns time difference in seconds
END
GO
I will calculate total shiftTime between those 2 dates
You mention that you will calculate difference between two dates but in your code you declare the variables as time
Declare #ShiftStartTime time
Declare #ShiftEndTime time
Thus DATEDIFF(mi,#ShiftStartTime,#ShiftEndTime) only the difference between the times not the dates
If you want to get the difference between dates you need use datetime datatype
On a side note, you have declared input parameters which have not been used in the proocedure as mentioned by Pradeep
Related
When I run the following:
DECLARE #date1 datetime = '2017-12-01 23:59:59.998'
DECLARE #date2 datetime = '2017-12-11 00:00:00.000'
SELECT DATEDIFF(day, #date1, #date2)
I get 10 as expected since it only compares the day part
However, if I add one millisecond:
DECLARE #date1 datetime = '2017-12-01 23:59:59.999'
DECLARE #date2 datetime = '2017-12-11 00:00:00.000'
SELECT DATEDIFF(day, #date1, #date2)
I get 9. It seems like SQL Server is rounding 23:59.59.999 to 24:00.00.000 and thus the next day but won't round up anything else. Is there any way to prevent this?
MS SQL Uses
4 bytes to store the days past Jan 1, 1900.
4 bytes to store the clock ticks past midnight. ( a tick is 3.3miliseconds)
What you are seeing is overflow. Since the number can not be represented by the 4 bytes, it will use the 5th byte thus incrementing the day by 1.
SQL Server stores the second integer for the time as the number of
clock ticks after midnight. A second contains 300 ticks, so a tick
equals 3.3 milliseconds (ms). You can see the values for days and
clock ticks by converting a datetime value to a binary(8) value and
using the substring function to extract each set of 4 bytes. The code
in Figure 3 then converts each set of 4 bytes into an integer.
Source: http://www.itprotoday.com/microsoft-sql-server/solving-datetime-mystery
I'm trying to get a query that will multiply a static number by the amount of days in a date range the problem i'm having is that when a single day is selected it returns a result of 0 instead of 1: Ex:
Declare #Startdate DATE
Declare #enddate DATE
SET #Startdate='9/1/2013'
SET #enddate='9/1/2013'
SELECT 1154*(Select DATEDIFF(DAY, #startdate, #enddate))
This example returns 0 instead of 1. Should I be using something other than DateDiff?
Additional clarification - This will be used as part of a report where the date range will be dynamically entered by person calling the report.
Could just add 1:
Declare #Startdate DATE
Declare #enddate DATE
SET #Startdate='9/1/2013'
SET #enddate='9/1/2013'
SELECT (DATEDIFF(day,#Startdate,#enddate)+1)*1154
Update, as noted don't need the inner SELECT
I need to write a store procedure that will return a next friday date on a given date? for example - if the date is 05/12/2011, then it should return next friday date as 05/13/2011. If you pass, 05/16/2011, then it should return the date is 5/20/2011 (Friday). If you pass friday as the date, then it should return the same date.
I'd make this a scalar UDF as it is easier to consume the output.
CREATE FUNCTION dbo.GetNextFriday(
#D DATETIME
)
RETURNS DATETIME
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS
BEGIN
RETURN DATEADD(DAY,(13 - (##DATEFIRST + DATEPART(WEEKDAY,#D)))%7,#D)
END
This is for SQL Server 2008. To use in 2005, just change the date fields to your preference for datetime to date conversions. It also assumes you are not changing the default week begin value.
DECLARE #PassedDate date = '5/21/2011';
SELECT DATEADD(DAY,(CASE DATEPART(DW,#PassedDate) WHEN 7 THEN 6 ELSE 6 - DATEPART(DW,#PassedDate) END),#PassedDate);
Similar to the top answer, but without using ##DATEFIRST in the solution:
DECLARE #Today DATETIME = GETDATE(); -- any date
DECLARE #WeekdayIndex SMALLINT = DATEPART(WEEKDAY, #Today);
DECLARE #DaysUntilFriday SMALLINT = (13 - #WeekdayIndex) % 7;
DECLARE #UpcomingFridayDate DATETIME = DATEADD(DAY, #DaysUntilFriday, #Today);
SELECT #UpcomingFridayDate ;
Great solutions here, but I also recommend looking at time tables: you can generate them easily in Analysis server, and they can be indexed to be very fast, giving you lots of easy ways to get next week days (among other things).
You can find out more about them here
In our case, the same solution would be
Select MIN(PK_Date) from Time Where PK_Date > #SomeDate AND Day_Of_Week= 6
And of course when you're doing this for a large recordset, you can also do joins for maximum speed & efficiency.
I have used date and time validation for scheduling a report...I have to schedule that reports for future date and time only and not previous date and time..I have used this
declare #Dt varchar(50)
declare #Hr varchar(50)
declare #trandate_time_tmp as TIME(0)
select #trandate_time_tmp = getdate()
set #Dt = DATEDIFF (D,#schedule_date ,#trandate_tmp )
set #Hr = DATEDIFF (S,#schedule_date ,#trandate_time_tmp )
if ( #Dt > 0)
begin
raiserror('Schedule Date should not be earlier than system date',16,1)
return
end
if ( #Hr > 0)
begin
raiserror('Schedule Time should not be earlier than system time',16,1)
return
end
For date part it is checking correctly but for time it is throwing error as
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.
Not exactly answering your question, but perhaps a solution to your problem. You don't need to use DATEDIFF and check the results, you could just compare the two dates.
IF ( #schedule_date <= GETDATE() )
BEGIN
RAISERROR('Schedule date should not be earlier than system date', 16, 1)
RETURN
END
I just ran into this same problem when trying to make a Unix timestamp from a date,
Here's an example of what I was trying to do:
select DATEDIFF(second,'1970-01-01','2200-01-11');
It overflows since DATEDIFF is trying to return a signed integer - which can only hold just over 68 years worth of seconds.
In order to get the Unix timestamp (which I need so I can feed it into Sphinx Search), you can get the difference in minutes first, then cast the result as a big integer and then multiply by 60 seconds:
select CAST(DATEDIFF(minute,'1970-01-01','2200-01-11') AS BIGINT) * 60;
Now we should be able to handle dates that vary in difference of up to 4000 years or so. If you need even more room, simply change out minute with bigger and bigger intervals, and change the seconds multiplier accordingly.
I want to limit a report to return records from Date A through Date B. This is what I have been doing:
declare #startDate varchar(20)
declare #endDate varchar(20)
set #startDate = '01/01/2008'
set #endDate = '04/01/2008'
-- test what are the start and end dates
select min(date),max(date) from view_Inspections
where date between #startDate and #endDate
... which I was told returned records from 12 am Jan 1st through 11:59 pm March 31st (that midnight is the default when no time is indicated). But I noticed a discrepancy, which is if a record has a time of 00:00:00 that it will be part of this set.
Is there a more exact way of doing this so it will return exactly the date range I want?*
I tried using time:
declare #startDate varchar(20)
declare #endDate varchar(20)
set #startDate = '01/01/2008 00:00:00'
set #endDate = '04/01/2008 11:59:59'
-- test what are the start and end dates
select min(date),max(date) from view_Inspections
where date between #startDate and #endDate
... but I noticed something wonky: SQL Server will ROUND the hundreth-second up by half. So I get that April 1st record (ha! April Fool's record! grr) if I use any time later than 11:59:29. Why is that?
(I feel sure there is. I'm new at this. Thanks for your help!)
There's always the easy option:
declare #startDate varchar(20)
declare #endDate varchar(20)
set #startDate = '01/01/2008'
set #endDate = '04/01/2008'
-- test what are the start and end dates
select min(date),max(date) from view_Inspections
where date >= #startDate
and date < #endDate
I suspect that the date column in view_Inspections is a SmallDateTime data type. This data type has 1 minute accuracy, which explains your unexpected results (rounding the seconds to the nearest minute).
The method Roland Shaw suggests is the best way to modify your query to accommodate your requirements.
The BETWEEN operator is inclusive, which is why you're seeing the results that you are in your first query. The rounding that you're seeing in your second query is going to be dependent on what exact datetime data type you are using in your table. (BTW, I think you're confusing seconds with hundredths of seconds). It looks like you're probably using a smalldatetime in your table, in which case the time is rounded to the nearest minute.
If your table is using datetime, try explicitly converting your #startDate and #endDate to DATETIME values (CAST(#endDate AS DATETIME)).
A quick note... even for DATETIME values, SQL Server is only accurate to the 3/100ths of a second, so 11:59:59.999 will get rounded up to 12:00:00.000.
You basically have three choices:
1) BETWEEN CAST('01/01/2008 00:00:00.000' AS DATETIME) AND CAST('03/31/2008 12:59:59.997' AS DATETIME)
2) YEAR(my_date) = 2008 AND MONTH(my_date) BETWEEN 1 AND 3
3) my_date >= CAST('01/01/2008 00:00:00.000' AS DATETIME) AND my_date < CAST('04/01/2008 00:00:00.000' AS DATETIME)
The first method isn't very intuitive and is error-prone in my opinion. The second method kills performance since indexes can't be used and it becomes much more complex if you can have searches that span years or begin/end in the middle of months. The third method, which Rowland suggested, is the best I think.
Simply try removing the time from the date field like so:
declare #startDate varchar(20)
declare #endDate varchar(20)
set #startDate = '01/01/2008'
set #endDate = '04/01/2008'
SELECT min(date),max(date) FROM view_Inspections
WHERE CAST(FLOOR(CAST(date AS FLOAT)) AS DATETIME) BETWEEN CAST(#startDate AS DATETIME) And CAST(#startDate AS DATETIME))
This will return everything from 01/01/2008 00:00:00 to 04/01/2008 11:59:59.999.
If you don't want 04/01 included, change your end date to 03/31/2008.
Your best solution is just create a BIGINT(10) field that called "julian", and store it in YYYYMMDD.
Then do the query
where julian >= '20120103' AND julian <= '20120203'