How to get date difference between two dates in same year with one date is from an input date not from the year - sql

Well this is my case: I have an input date X (dd-mm-yyyy), and I want to count the number of days between it with the year part is changed into current year and today's date in SQL. I t comes with the following condition, after the year is changed temporarily: (Here's my current idea of the logic)
- If date X is earlier than today, then difference = datediff(X,now), with the X year is current year
- If date X is later than today, then difference = datediff(X,now), with the X year is one year before
Sample case:
1st case: The input date is 6-6-1990. Today (automatically generated) is 22-8-2011. Then the difference will be = datediff(6-6-2011,22-08-2011)
2nd case: The input date is 10-10-1990. Today (automatically generated) is 22-8-2011. Then the difference will be = datediff(10-10-2010,22-08-2011)
Any idea how to do this in SQL (in SQL Server)? Or is there any other more simple alternatives for this problem? I'd also like this to be done in the query and not using a stored procedure or function
Sorry if there's already a similar question, I just don't know the exact keyword for this problem :( if there's a question like this previously, feel free to direct me there.
Thanks in advance

Here is the implementation (if I understood the logic you need correctly):
USE YourDbName
GO
CREATE FUNCTION YearPartDiff (#date datetime)
RETURNS int
AS
BEGIN
DECLARE #dateCurrentYear datetime
SET #dateCurrentYear = DATEADD(year, YEAR(GETDATE()) - YEAR(#date), #date)
DECLARE #result int
IF #dateCurrentYear < GETDATE()
SET #result = ABS(DATEDIFF(day, #dateCurrentYear, GETDATE()))
ELSE
SET #result = ABS(DATEDIFF(day, DATEADD(year, -1, #dateCurrentYear), GETDATE()))
RETURN(#result)
END
GO
And the example of usage:
USE YourDbName
GO
DECLARE #someDate datetime
SET #someDate = '2011-06-06'
SELECT dbo.YearPartDiff(#someDate) /*returns 77*/
SET #someDate = '2010-10-10'
SELECT dbo.YearPartDiff(#someDate) /*returns 316*/

Basically, #Andrei's solution, but in a single statement:
SELECT
DayDiff = DATEDIFF(
DAY,
DATEADD(YEAR, CASE WHEN LastOcc > GETDATE() THEN -1 ELSE 0 END, LastOcc),
GETDATE()
)
FROM (
SELECT LastOcc = DATEADD(YEAR, YEAR(GETDATE()) - YEAR(#InputDate), #InputDate)
) s

This seems to do the job
SELECT DATEDIFF(DAY, CONVERT(DATETIME, N'2011-06-06'), CONVERT(DATETIME, N'2011-08-22'))
So the basic syntax is
SELECT DATEDIFF(DAY, CONVERT(DATETIME, N'yyyy-mm-dd'), CONVERT(DATETIME, N'yyyy-mm-dd '))
Alternatively, you can use GETDATE() instead of the string for today's date

I have used "SELECT DATEDIFF( D, "+myDate+", GETDATE())" in my code, on SQL Server 2005. It works for me. The value myDate of course would be the DateTime input value.

you should try this query:
create table #T (inp_date datetime)
insert #T values ('06-06-1990')
insert #T values ('08-22-1990')
insert #T values ('10-10-1990')
--select * from #T
select inp_date, GETDATE(),
CASE
WHEN DATEADD(yy,DATEDIFF(yy,inp_date,GETDATE()),inp_date) <= GETDATE()
THEN DATEDIFF(dd,DATEADD(yy,DATEDIFF(yy,inp_date,GETDATE()),inp_date),GETDATE())
ELSE DATEDIFF(dd,DATEADD(yy,DATEDIFF(yy,inp_date,GETDATE())-1,inp_date),GETDATE())
END
from #T

Related

Check a date (excluding year)

In SQL Server, how can I check if one calendar date consisting of a day and month is older than another certain date, programmatically?
For example: I need to check if TransactionDate is on or before June 30, in all year.
TransactionDate <= (June 30)
Use DATEPART like this:
declare #var1 date = '2016-02-07';
declare #var2 date = '2017-02-06';
SELECT CASE
WHEN DATEPART(MM, #var1 ) * 100 + DATEPART(DD, #var1 )
> DATEPART(MM, #var2 ) * 100 + DATEPART(DD, #var2 ) THEN 'YES'
ELSE 'NO' END AS LARGERDATE;
It compares the dates as two integers in form of MMDD. For example:
'2016-02-07' ==> 207, '2017-02-06' ==> 206
'2010-10-27' ==> 1027, '2017-07-29' ==> 729
Most correct way will be to use DATEPART function; especially because it is available from all versions of SQL server since 2008, Azure SQL Database, Azure SQL Data Warehouse and Parallel Data Warehouse too.
You can check using the expression assuming you have the date to be compared against stored in #yourCheckDate variable
DECLARE #yourCheckDate DATETIME
DECLARE #m INT
DECLARE #d INT
SELECT #yourCheckDate = CAST('2017-6-30 12:15:32' AS DATETIME)
SELECT #m= DATEPART(month, #yourCheckDate)
SELECT #d= DATEPART(day, #yourCheckDate)
-- expression
select 1 where
DATEPART(month,#tranDate) < #m
OR
( DATEPART(month,#tranDate) = #m AND DATEPART(day,#tranDate) <= #d )
A SQL Server 2008 solution which supports any calendar date, derived from #TheEsisia and #Sami answers
WHERE 100*MONTH(TransactionDate) + DAY(TransactionDate) <= 100*MONTH(#checkDate) + DAY(#checkDate)
This should work if you want to get all dates from a date to the end of the year. Basically constructing a 'xxxx-12-31' with the input date (example in Oracle).
BETWEEN yourDate AND TO_DATE(TO_CHAR(yourDate, 'YYYY') ||'12-31', 'YYYY-MM-DD')

SQL query to find employee aniversary

I need to find anniversary date and anniversary year of employees and send email in every 14 days.But I have a problem with last week of December when using the following query if start date and end date are in different years.
Select * from Resource
where (DATEPART(dayofyear,JoinDate)
BETWEEN DATEPART(dayofyear,GETDATE())
AND DATEPART(dayofyear,DateAdd(DAY,14,GETDATE())))
Instead of comparing to a dayofyear (which resets to zero at jan 1st and is the reason your query breaks within 14 days of the end of the year) you could update the employee's joindate to be the current year for the purpose of the query and just compare to actual dates
Select * from Resource
-- Add the number of years difference between joinDate and the current year
where DATEADD(year,DATEDIFF(Year,joinDate,GetDate()),JoinDate)
-- compare to range "today"
BETWEEN GetDate()
-- to 14 days from today
AND DATEADD(Day,14,GetDate())
-- duplicate for following year
OR DATEADD(year,DATEDIFF(Year,joinDate,GetDate())+1,JoinDate) -- 2016-1-1
BETWEEN GetDate()
AND DATEADD(Day,14,GetDate())
Test query:
declare #joindate DATETIME='2012-1-1'
declare #today DATETIME = '2015-12-26'
SELECT #joinDate
where DATEADD(year,DATEDIFF(Year,#joinDate,#today),#JoinDate) -- 2015-1-1
BETWEEN #today -- 2015-12-26
AND DATEADD(Day,14,#today) -- 2016-01-09
OR DATEADD(year,DATEDIFF(Year,#joinDate,#today)+1,#JoinDate) -- 2016-1-1
BETWEEN #today -- 2015-12-26
AND DATEADD(Day,14,#today) -- 2016-01-09
(H/T #Damien_The_Unbeliever for a simple fix)
The above correctly selects the joinDate which is in the first week of Jan (note I've had to fudge #today as Ive not managed to invent time travel).
The above solution should also solve the issue with leap years that was hiding in your original solution.
Update
You expressed in comments the requirement to select AnniversaryDate and Years of service, you need to apply some CASE logic to determine whether to add 1 (year or date) to your select
select *,
CASE
WHEN DATEADD(YEAR,DATEDIFF(Year,JoinDate,GETDATE()),JoinDate) < GetDate()
THEN DATEDIFF(Year,JoinDate,GETDATE())+1
ELSE DATEDIFF(Year,JoinDate,GETDATE())
END as [Years],
CASE WHEN DATEADD(YEAR,DATEDIFF(Year,JoinDate,GETDATE()),JoinDate) < GetDate()
THEN DATEADD(YEAR,DATEDIFF(Year,JoinDate,GETDATE())+1,JoinDate)
ELSE DATEADD(YEAR,DATEDIFF(Year,JoinDate,GETDATE()),JoinDate)
end as [AnniversaryDate]
.... // etc
You could do this:
Select * from Resource
where DATEPART(dayofyear,JoinDate)
BETWEEN DATEPART(dayofyear,GETDATE())
AND DATEPART(dayofyear,DateAdd(DAY,14,GETDATE()))
OR
DATEPART(dayofyear,JoinDate)
BETWEEN (DATEPART(dayofyear,GETDATE()) + 365)
AND (DATEPART(dayofyear,DateAdd(DAY,14,GETDATE())) + 365)
Try this:
DECLARE #Today DATE = GETDATE() --'12/25/2013'
DECLARE #Duration INT = 14
;WITH Recur AS
(
SELECT #Today AS RecurDate
UNION ALL
SELECT DATEADD(DAY, 1, RecurDate)
FROM Recur
WHERE DATEDIFF(DAY, #Today, RecurDate)+1 < #Duration
)
SELECT
r.*
FROM
Resource r
JOIN Recur
ON CONVERT(VARCHAR(5), JoinDate, 101) = CONVERT(VARCHAR(5), RecurDate, 101)
WHERE JoinDate < #Today
You can use the SQL DATEADD() function with week number parameter
Here is how you can use it:
DECLARE #date date = getdate()
Select * from Resource
where
JoinDate BETWEEN #date AND DATEADD(ww,2,#date)

How to get last date of month SQL Server 2008

I created a function "ufngetFirstDateOfMonth" and "ufngetLastDateOfMonth" stored in Microsoft SQL Server 2008. My purpose is to send some date into the function and it will return the first date of month with '00:00:00' or the last date of month with '23:59:59'.
I call the function like this:
exec ufngetLastDateOfMonth('2014-10-15')
and normally it returns '2014-10-31 23:59:59'
but when I send the last date of months that have 31 days (august, january,...):
exec ufngetLastDateOfMonth('2014-10-31')
it return '2014-10-30 23:59:59' whick is not correct Actally, it should be '2014-10-31 23:59:59'
Something goes wrong here...
This is my function:
CREATE FUNCTION [dbo].[ufnLastDateOfMonth](#Date date)
RETURNS varchar(50)
AS
BEGIN
DECLARE #New_Date varchar(50)
select #New_date = cast(dateadd(dd,-(DAY(#Date )),DATEADD(mm,1,#Date ))as varchar(50)) + ' 23:59:59'
RETURN #New_Date
END
To get the last day you can do this:
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,'2014-08-12')+1,0))
Adding to your function:
select #New_date = DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#date)+1,0))
Source:
SQL SERVER – Find Last Day of Any Month – Current Previous Next
For those who are using SQL Server 2012,
EOMONTH function could be an alternative.
DECLARE #date DATETIME = '12/1/2011';
SELECT EOMONTH ( #date ) AS Result;
GO
Source: https://msdn.microsoft.com/en-us/library/hh213020.aspx
Go to the first day of the month. Add one month. Then subtract one day. Or, in your case, one second:
select #New_date = dateadd(second, -1, dateadd(month, 1, dateadd(day, -(DAY(#Date) + 1)) ) )
You should use convert() if you want this as a string. I would instead suggest that the function return a datetime.
Use this
DECLARE #curdate datetime;
SET #curdate = GETDATE(); -- you can pass your date here
--SET #curdate = '2014-10-15'; Example
SELECT DATEADD(MONTH,1+DATEDIFF(MONTH,0,#curdate),-1);
OR
SELECT DATEADD(MONTH,1+DATEDIFF(MONTH,0,GETDATE()),-1);
you can try this
select DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, GETDATE()) + 1, 0)) As EndDateOfCurrentMonth
or this
select DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0) As StartDateOfCurrentMonth
Just try this:
SELECT EOMONTH('2000/2/1') Last_Date
Note: EOMONTH function is available in SQL Server version >= 2012

Update date only in SQL Server [duplicate]

This question already has an answer here:
T-SQL: How to update just date part of datetime field?
(1 answer)
Closed 9 years ago.
I have this row in my database table with a value of 1/5/2013 5:50:00 PM, and I want to update only the date part. Time should be same without any change, need to change only the date in this record.
I have tried the update statement but it change the time as well..but I can do a
UPDATE table1
SET date = '1/10/2013 5:50:00 PM'
WHERE id =1
This not what I'm looking for, different id's have different times, so just need to update the date keeping the time in that record same.
Please give feedback.
Thank you
You can do it this way if you're using SQL Server 2008 or higher
UPDATE table1
SET [date] = cast('1/10/2013' as datetime) + cast(cast([date] as time) as datetime)
WHERE id =1
If you're using SQL Server 2005 or below, you there's no time data type, so you have to do:
UPDATE table1
SET [date] = cast('1/10/2013' as datetime) + ([date] - DATEADD(dd, 0, DATEDIFF(dd, 0, [date])))
WHERE id =1
UPDATE table1
SET date = DATEADD(dd,5,date)-- 5 is the number of days
FROM table1
WHERE id =1
Not the most elegant, but should work. Idea is to extract hours,minutes and seconds from target row and hard code other parts.
update table1 set date = DATEADD(second, DATEPART(second, date), DATEADD(minute, DATEPART(minute, date), DATEADD(hour, DATEPART(hour,date), '2013-01-10')));
Though a bit hackish in appearance, this will do the trick if you ONLY want to change the date part with an arbitary value, and not touch the time part at all:
update table1 set date= '06-dec-2013 ' + cast(datepart(HOUR,date) as varchar(2)) + ':' +
cast(datepart(MINUTE,date) as varchar(2)) + ':' +
cast(DATEPART(SECOND, date) as varchar(2)) + ' ' +
CASE WHEN DATEPART(HOUR, date) < 12 THEN 'AM' ELSE 'PM' END as datetime
where id=1
Replace '06-dec-2013' with the date value you want to replace with.
create table t
(
col1 datetime
)
Insert Into t
values ('1/5/2013 5:50:00 PM')
declare #newDate datetime
set #newDate = '1/10/2013'
update t
Set col1 = convert(datetime,DateAdd(day, DateDiff(day, col1, #newDate), Col1),101)
sql-fiddle demo
Here's the query you want:
declare #TargetDate datetime
set #TargetDate = '20131001' --1st October 2013
update table1 set [date] = DATEADD(day,DATEDIFF(day,[date],#TargetDate),[date])
where id = 1
And here's a complete script to demonstrate it:
declare #t table (dt datetime not null)
insert into #t (dt) values
('2001-01-01T10:53:44.993'),('2012-06-18T15:33:33.333')
declare #TargetDate datetime
set #TargetDate = '20131001' --1st October 2013
update #t set dt = DATEADD(day,DATEDIFF(day,dt,#TargetDate),dt)
select * from #t
Results:
dt
-----------------------
2013-10-01 10:53:44.993
2013-10-01 15:33:33.333
This works by using DATEDIFF to work out how many days different the target date is from each date stored in the table (with appropriate signage) and then adding that difference back onto the date - having the effect of adjusting the date portions of the stored values whilst not affecting the time.

How to get Previous business day in a week with that of current Business Day using sql server

i have an ssis Package which runs on business days (mon-Fri). if i receive file on tuesday , background(DB), it takes previous business day date and does some transactions. If i run the job on friday, it has to fetch mondays date and process the transactions.
i have used the below query to get previous business date
Select Convert(varchar(50), Position_ID) as Position_ID,
TransAmount_Base,
Insert_Date as InsertDate
from tblsample
Where AsOfdate = Dateadd(dd, -1, Convert(datetime, Convert(varchar(10), '03/28/2012', 101), 120))
Order By Position_ID
if i execute this query i'll get the results of yesterdays Transactios. if i ran the same query on monday, it has to fetch the Fridays transactions instead of Sundays.
SELECT DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE())
WHEN 'Sunday' THEN -2
WHEN 'Monday' THEN -3
ELSE -1 END, DATEDIFF(DAY, 0, GETDATE()))
I prefer to use DATENAME for things like this over DATEPART as it removes the need for Setting DATEFIRST And ensures that variations on time/date settings on local machines do not affect the results. Finally DATEDIFF(DAY, 0, GETDATE()) will remove the time part of GETDATE() removing the need to convert to varchar (much slower).
EDIT (almost 2 years on)
This answer was very early in my SO career and it annoys me everytime it gets upvoted because I no longer agree with the sentiment of using DATENAME.
A much more rubust solution would be:
SELECT DATEADD(DAY, CASE (DATEPART(WEEKDAY, GETDATE()) + ##DATEFIRST) % 7
WHEN 1 THEN -2
WHEN 2 THEN -3
ELSE -1
END, DATEDIFF(DAY, 0, GETDATE()));
This will work for all language and DATEFIRST settings.
This function returns last working day and takes into account holidays and weekends. You will need to create a simple holiday table.
-- =============================================
-- Author: Dale Kilian
-- Create date: 2019-04-29
-- Description: recursive function returns last work day for weekends and
-- holidays
-- =============================================
ALTER FUNCTION dbo.fnGetWorkWeekday
(
#theDate DATE
)
RETURNS DATE
AS
BEGIN
DECLARE #importDate DATE = #theDate
DECLARE #returnDate DATE
--Holidays
IF EXISTS(SELECT 1 FROM dbo.Holidays WHERE isDeleted = 0 AND #theDate = Holiday_Date)
BEGIN
SET #importDate = DATEADD(DAY,-1,#theDate);
SET #importDate = (SELECT dbo.fnGetWorkWeekday(#importDate))
END
--Satruday
IF(DATEPART(WEEKDAY,#theDate) = 7)
BEGIN
SET #importDate = DATEADD(DAY,-1,#theDate);
SET #importDate = (SELECT dbo.fnGetWorkWeekday(#importDate))
END
--Sunday
IF(DATEPART(WEEKDAY,#theDate) = 1)
BEGIN
SET #importDate = DATEADD(DAY,-2,#theDate);
SET #importDate = (SELECT dbo.fnGetWorkWeekday(#importDate))
END
RETURN #importDate;
END
GO
Then how about:
declare #dt datetime='1 dec 2012'
select case when 8-##DATEFIRST=DATEPART(dw,#dt)
then DATEADD(d,-2,#dt)
when (9-##DATEFIRST)%7=DATEPART(dw,#dt)%7
then DATEADD(d,-3,#dt)
else DATEADD(d,-1,#dt)
end
The simplest solution to find the previous business day is to use a calendar table with a column called IsBusinessDay or something similar. The your query is something like this:
select max(BaseDate)
from dbo.Calendar c
where c.IsBusinessDay = 0x1 and c.BaseDate < #InputDate
The problem with using functions is that when (not if) you have to create exceptions for any reason (national holidays etc.) the code quickly becomes unmaintainable; with the table, you just UPDATE a single value. A table also makes it much easier to answer questions like "how many business days are there between dates X and Y", which are quite common in reporting tasks.
You can easily make this a function call, adding a second param to replace GetDate() with whatever date you wanted.
It will work for any day of the week, at any date range, if you change GetDate().
It will not change the date if the day of week is the input date (GetDate())
Declare #DayOfWeek As Integer = 2 -- Monday
Select DateAdd(Day, ((DatePart(dw,GetDate()) + (7 - #DayOfWeek)) * -1) % 7, Convert(Date,GetDate()))
More elegant:
select DATEADD(DAY,
CASE when datepart (dw,Getdate()) < 3 then datepart (dw,Getdate()) * -1 + -1 ELSE -1 END,
cast(GETDATE() as date))
select
dateadd(dd,
case DATEPART(dw, getdate())
when 1
then -2
when 2
then -3
else -1
end, GETDATE())
thanks for the tips above, I had a slight variant on the query in that my user needed all values for the previous business date. For example, today is a Monday so he needs everything between last Friday at midnight through to Saturday at Midnight. I did this using a combo of the above, and "between", just if anyone is interested. I'm not a massive techie.
-- Declare a variable for the start and end dates.
declare #StartDate as datetime
declare #EndDate as datetime
SELECT #StartDate = DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE())
WHEN 'Sunday' THEN -2
WHEN 'Monday' THEN -3
ELSE -1 END, DATEDIFF(DAY, 0, GETDATE()))
select #EndDate = #StartDate + 1
select #StartDate , #EndDate
-- Later on in the query use "between"
and mydate between #StartDate and #EndDate