Count differnce of two Date's with Respect that every month has EXACT 30 days - tsql

I thought it was clear, but doesn't seem so.
This question is about T-SQL (since it's tagged with tsql :) )
So I couldn't find any out-of-the-box solution to calculate my problem.
Let's assume you have these two dateTimes:
DECLARE #start DATETIME = '2011-01-01',
#end DATETIME = '2011-04-15'
The difference of these two datetimes in Days should be quivalent to 105.
The calculation works as follows: For every full month add 30 days, for the rest add the days till the date is achieved.
I could program this, but it would be an enormous SQL-statement, which I find find kinda ugly.
Is there any simple solution for this, like a built-in function or something short?
Thanks in advance.

Does this do the trick?
;with dates as
(
SELECT
CAST ('2011-01-01' AS DATETIME) as start_date
,CAST('2011-04-15' AS DATETIME) as end_date
)
SELECT
start_date
,end_date
,CASE WHEN DATEDIFF(MM,start_date,end_date) = 0 THEN DAY(end_date) - DAY(start_date)
WHEN DAY(start_date) = 1 THEN (30 * (DATEDIFF(MM,start_date,end_date))) + DAY(end_date)
WHEN DAY(start_date) <> 1 THEN 30 * DATEDIFF(MM,start_date,end_date) + (DAY(end_date) - DAY(start_date))
END AS gap_in_days
FROM dates

Short Answer
There's no built in function, but you could pretty easily create your own to handle converting a datetime to an int. From there, the SQL you would have to write would be trivial.
Long Answer
There's no built in function that will do this, probably because every month doesn't have 30 days. :)
You can start with this:
DECLARE #start DATETIME = '2011-01-01',
#end DATETIME = '2011-04-15'
DECLARE #endConverted INT
SELECT #endConverted = DATEPART(month, #end) * 30
+ CASE
WHEN DATEPART(DAY, #end) <= 30
THEN datepart(DAY, #end)
ELSE 30
END
DECLARE #startConverted INT
SELECT #startConverted = DATEPART(MONTH, #start) * 30
+ CASE
WHEN DATEPART(DAY, #start) <= 30
THEN DATEPART(DAY, #start)
ELSE 30
END
SELECT #endConverted - #startConverted
This isn't beautiful SQL, but it works. Note that it returns 104 (because 15 days - 1 day = 14 days), but simple enough to tack on a + 1 to the end of the final select if you want to handle the boundry days differently.
Note that the math here could pretty easily be moved into a function, which would allow you to clean your SQL up. Let's assume you created a function called GetDateTimeAsInt which holds the math; your SQL could be as simple as
DECLARE #start INT = GetDateTimeAsInt('2011-01-01'),
#end INT = GetDateTimeAsInt('2011-04-15')
SELECT #end - #start -- may need to add 1 here
In my testing, this seems to work. It will return the same result as the DATEDIFF function for the date range you specify in your post, but this is because there are 2 days with 31 days and 1 day with 28, so effectively, Jan - April have 30 days each. If you use it with a wider date range, you'll begin to get different results with my code vs. the DATEDIFF function.
Hope this helps.

I use PERIODDIFF. To get the year and the month of the date, I use the function EXTRACT:
SELECT PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM NOW()), EXTRACT(YEAR_MONTH FROM time)) AS months FROM your_table;
T-sql
SELECT DATEDIFF(dd, "2011-01-01","2011-04-15")

Related

I got one problem in SQL,i need to get start of next minute value

I need to get the start of next Minute value, that means suppose I got the output for GETDATE() is 19.11.2019 12:52:51 but I need to get 19.11.2019 12:53:00
This is my code:
DECLARE #date DATETIME
SET #date = GETDATE()
DECLARE #increase int = 1;
SELECT DATEADD(mi, #increase,#date) as nextminutedate;
You want to round the date down. One method in SQL Server is:
select dateadd(minute, 1+datediff(minute, 0, getdate()), 0)
This is a little inscrutable. The datediff() calculates the number of minutes from a time of 0 for the current date/time. The dateadd() adds this back in.
Note: This works for minutes. You might have overflow problems with seconds or milliseconds.
For this reason, I rather prefer:
select dateadd(minute, 1+datediff(minute, '2000-01-01', getdate()), '2000-01-01')
I find this is clearer in the intention.

How to find out Number of Workdays between two dates in HANA?

How to find out Number of Workdays(Monday to Friday) between two dates in SAP HANA ? We do not have to consider holidays.
We cant use WORKDAYS_BETWEEN() as we do not have TFACS table.
Here is how you can so ist in sql:
Calculate the number of whole weeks, multiply by 5
Add the remaining days: subtract weekday start date from weekday end date, correct for weekends (least...), Correct for carry-over (+5)
The second part can be simplified a little so that you don't have to write the subtraction twice.
Here an example with start date '2015-12-04' and end date '2015-12-19):
SELECT ROUND( DAYS_BETWEEN (TO_DATE ('2015-12-04', 'YYYY-MM-DD'), TO_DATE('2015-12-19', 'YYYY-MM-DD')) / 7, 0, ROUND_DOWN) * 5
+ ( case
when WEEKDAY (TO_DATE('2015-12-19', 'YYYY-MM-DD') ) - WEEKDAY (TO_DATE('2015-12-04', 'YYYY-MM-DD')) >= 0
then least( WEEKDAY (TO_DATE('2015-12-19', 'YYYY-MM-DD')), 5) - least( WEEKDAY (TO_DATE('2015-12-04', 'YYYY-MM-DD')), 5)
else
least( WEEKDAY (TO_DATE('2015-12-19', 'YYYY-MM-DD')), 5) - least( WEEKDAY (TO_DATE('2015-12-04', 'YYYY-MM-DD')), 5) + 5
end )
"Workdays" FROM DUMMY;
--> 11
I preferred to create a user defined function here to use in HANA SQLScript codes as follows
Create Function CalculateWorkDays (startdate date, enddate date)
returns cnt integer
LANGUAGE SQLSCRIPT AS
begin
declare i int;
cnt := 0;
i := 0;
while :i <= days_between(:startdate, :enddate)
do
if WEEKDAY( ADD_DAYS(:startdate,:i) ) < 5
then
cnt := :cnt + 1;
end if;
i := :i + 1;
end while;
end;
Please note that the above code block seems to contain an unnecessary loop.
On the other hand, if you have additional tables like department holidays, or personal holidays, etc. It might be useful to check these tables in the WHILE loop. Please refer to following SQL tutorial Calculate the Count of Working Days Between Two Dates where I created a similar SQL function checking custom work calendars or holiday calendars.
Here is how you call the function as sample
select CalculateWorkDays('20170101', '20170131') as i from dummy;
I hope it helps,

Dynamic statement for Yesterday in Microsoft SQL Server Management Studio

I run the below query to check if something ran the previous day. The below query works, but I have to change the date each day to get the results I want. I've tried multiple things that I've found that seem like they should return results, but they don't quite seem to work.
select * from Linking_Results
where Evaluated between '2015-02-04 00:00:01.001' and '2015-02-04 23:59:00.999'
and Linked = '1' order by Evaluated
So my question is, how do I make a dynamic statement for yesterday and keep from having to change the date daily?
You can use the dateadd and getdate functions.
declare #start datetime,
#end datetime
-- subtract one day and cast it as a date to drop the time portion
select #start = cast(dateadd(day, -1, getdate()) as date)
-- add one day and subtract 3ms to get the end of yesterday (apparently SQL rounds)
select #end = dateadd(ms, -3, dateadd(day, 1, #start))
The values would then be
2015-02-04 00:00:00.000
2015-02-04 23:59:59.997
and you can do a between on these two variables. Since you use between which is inclusive, you need to account for the time portion. You could change the where clause to go to the next day and do an exclusive check on #end
select #end = dateadd(day, 1, #start)
where Evaluated >= #start and Evaluated < #end

T-sql IF Condition date evaluation

I have a simple question regarding T-SQL. I have a stored procedure which calls a Function which returns a date. I want to use an IF condition to compare todays date with the Functions returned date. IF true to return data.
Any ideas on the best way to handle this. I am learning t-sql at the moment and I am more familar with logical conditions from using C#.
ALTER FUNCTION [dbo].[monday_new_period](#p_date as datetime) -- Parameter to find current date
RETURNS datetime
BEGIN
-- 1 find the year and period given the current date
-- create parameters to store period and year of given date
declare #p_date_period int, #p_date_period_year int
-- assign the values to the period and year parameters
select
#p_date_period=period,
#p_date_period_year = [year]
from client_week_uk where #p_date between start_dt and end_dt
-- 2 determine the first monday given the period and year, by adding days to the first day of the period
-- this only works on the assumption a period lasts a least one week
-- create parameter to store the first day of the period
declare #p_start_date_for_period_x datetime
select #p_start_date_for_period_x = min(start_dt)
from client_week_uk where period = #p_date_period and [year] = #p_date_period_year
-- create parameter to store result
declare #p_result datetime
-- add x days to the first day to get a monday
select #p_result = dateadd(d,
case datename(dw, #p_start_date_for_period_x)
when 'Monday' then 0
when 'Tuesday' then 6
when 'Wednesday' then 5
when 'Thursday' then 4
when 'Friday' then 3
when 'Saturday' then 2
when 'Sunday' then 1 end,
#p_start_date_for_period_x)
Return #p_result
END
ALTER PROCEDURE [dbo].[usp_data_to_retrieve]
-- Add the parameters for the stored procedure here
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
IF monday_new_period(dbo.trimdate(getutcdate()) = getutcdate()
BEGIN
-- SQL GOES HERE --
END
Thanks!!
I assume you are working on Sql2008. See documentation of IF and CASE keywords for more details.
CREATE FUNCTION dbo.GetSomeDate()
RETURNS datetime
AS
BEGIN
RETURN '2012-03-05 13:12:14'
END
GO
IF CAST(GETDATE() AS DATE) = CAST(dbo.GetSomeDate() AS DATE)
BEGIN
PRINT 'The same date'
END
ELSE
BEGIN
PRINT 'Different dates'
END
-- in the select query
SELECT CASE WHEN CAST(GETDATE() AS DATE) = CAST(dbo.GetSomeDate() AS DATE) THEN 1 ELSE 0 END AS IsTheSame
This is the basic syntax for a T-SQL IF and a date compare.
If you are comparing just the date portion for equality you will need to use:
select dateadd(dd,0, datediff(dd,0, getDate()))
This snippet will effectively set the time portion to 00:00:00 so you can compare just dates. So in use it will look something like this.
IF dateadd(dd,0, datediff(dd,0, fn_yourFunction())) = dateadd(dd,0, datediff(dd,0, GETDATE()))
BEGIN
RETURN SELECT * FROM SOMEDATA
END
Hope that helps!

How can I compare two datetime fields but ignore the year?

I get to dust off my VBScript hat and write some classic ASP to query a SQL Server 2000 database.
Here's the scenario:
I have two datetime fields called fieldA and fieldB.
fieldB will never have a year value that's greater than the year of fieldA
It is possible the that two fields will have the same year.
What I want is all records where fieldA >= fieldB, independent of the year. Just pretend that each field is just a month & day.
How can I get this? My knowledge of T-SQL date/time functions is spotty at best.
You may want to use the built in time functions such as DAY and MONTH. e.g.
SELECT * from table where
MONTH(fieldA) > MONTH(fieldB) OR(
MONTH(fieldA) = MONTH(fieldB) AND DAY(fieldA) >= DAY(fieldB))
Selecting all rows where either the fieldA's month is greater or the months are the same and fieldA's day is greater.
select *
from t
where datepart(month,t.fieldA) >= datepart(month,t.fieldB)
or (datepart(month,t.fieldA) = datepart(month,t.fieldB)
and datepart(day,t.fieldA) >= datepart(day,t.fieldB))
If you care about hours, minutes, seconds, you'll need to extend this to cover the cases, although it may be faster to cast to a suitable string, remove the year and compare.
select *
from t
where substring(convert(varchar,t.fieldA,21),5,20)
>= substring(convert(varchar,t.fieldB,21),5,20)
SELECT *
FROM SOME_TABLE
WHERE MONTH(fieldA) > MONTH(fieldB)
OR ( MONTH(fieldA) = MONTH(fieldB) AND DAY(fieldA) >= DAY(fieldB) )
I would approach this from a Julian date perspective, convert each field into the Julian date (number of days after the first of year), then compare those values.
This may or may not produce desired results with respect to leap years.
If you were worried about hours, minutes, seconds, etc., you could adjust the DateDiff functions to calculate the number of hours (or minutes or seconds) since the beginning of the year.
SELECT *
FROM SOME_Table
WHERE DateDiff(d, '1/01/' + Cast(DatePart(yy, fieldA) AS VarChar(5)), fieldA) >=
DateDiff(d, '1/01/' + Cast(DatePart(yy, fieldB) AS VarChar(5)), fieldB)
Temp table for testing
Create table #t (calDate date)
Declare #curDate date = '2010-01-01'
while #curDate < '2021-01-01'
begin
insert into #t values (#curDate)
Set #curDate = dateadd(dd,1,#curDate)
end
Example of any date greater than or equal to today
Declare #testDate date = getdate()
SELECT *
FROM #t
WHERE datediff(dd,dateadd(yy,1900 - year(#testDate),#testDate),dateadd(yy,1900 - year(calDate),calDate)) >= 0
One more example with any day less than today
Declare #testDate date = getdate()
SELECT *
FROM #t
WHERE datediff(dd,dateadd(yy,1900 - year(#testDate),#testDate),dateadd(yy,1900 - year(calDate),calDate)) < 0