Find last sunday - sql

How will you find last sunday of a month in sql 2000?

SELECT
DATEADD(day,DATEDIFF(day,'19000107',DATEADD(month,DATEDIFF(MONTH,0,GETDATE() /*YourValuehere*/),30))/7*7,'19000107')
Edit: A correct, final, working answer from my colleague.

select dateadd(day,1-datepart(dw, getdate()), getdate())

An alternative approach, borrowed from data warehousing practice. Create a date-dimension table and pre-load it for 10 years, or so.
TABLE dimDate (DateKey, FullDate, Day, Month, Year, DayOfWeek,
DayInEpoch, MonthName, LastDayInMonthIndicator, many more..)
The easiest way to fill-in the dimDate is to spend an afternoon with Excel and then import to DB from there. A half-decent dimDate table has 50+ columns -- anything you ever wanted to know about a date.
With this in place, the question becomes something like:
SELECT max(FullDate)
FROM dimDate
WHERE DayOfWeek = 'Sunday'
AND Month = 11
AND Year = 2009;
Essentially, all date related queries become simpler.

Next sunday in SQL, regardless which day is first day of week: returns 2011-01-02 23:59:59.000 on 22-dec-2010:
select DateADD(ss, -1, DATEADD(week, DATEDIFF(week, 0, getdate()), 14))

I find some of these solutions hard to understand so here's my version with variables to explain the steps.
ALTER FUNCTION dbo.fn_LastSundayInMonth
(
#StartDate DATETIME
,#RequiredDayOfWeek INT /* 1= Sunday */
)
RETURNS DATETIME
AS
/*
A detailed step by step way to get the answer...
SELECT dbo.fn_LastSundayInMonth(getdate()-31,1)
SELECT dbo.fn_LastSundayInMonth(getdate()-31,2)
SELECT dbo.fn_LastSundayInMonth(getdate()-31,3)
SELECT dbo.fn_LastSundayInMonth(getdate()-31,4)
SELECT dbo.fn_LastSundayInMonth(getdate()-31,5)
SELECT dbo.fn_LastSundayInMonth(getdate()-31,6)
SELECT dbo.fn_LastSundayInMonth(getdate()-31,7)
*/
BEGIN
DECLARE #MonthsSince1900 INTEGER
DECLARE #NextMonth INTEGER
DECLARE #DaysToSubtract INTEGER
DECLARE #FirstDayOfNextMonth DATETIME
DECLARE #LastDayOfMonthDayOfWeek INTEGER
DECLARE #LastDayOfMonth DATETIME
DECLARE #ReturnValue DATETIME
SET #MonthsSince1900=DateDiff(month, 0, #StartDate)
SET #NextMonth=#MonthsSince1900+1
SET #FirstDayOfNextMonth = DateAdd(month,#NextMonth, 0)
SET #LastDayOfMonth = DateAdd(day, -1, #FirstDayOfNextMonth)
SET #ReturnValue = #LastDayOfMonth
WHILE DATEPART(dw, #ReturnValue) <> #RequiredDayOfWeek
BEGIN
SET #ReturnValue = DATEADD(DAY,-1, #ReturnValue)
END
RETURN #ReturnValue
END

DECLARE #LastDateOfMonth smalldatetime
SELECT #LastDateOfMonth = DATEADD(month, DATEDIFF(month, -1, GETDATE()), 0) -1
Select DATEADD(dd,-( CASE WHEN DATEPART(weekday,#LastDateOfMonth) = 1 THEN 0 ELSE DATEPART(weekday,#LastDateOfMonth) - 1 END ),#LastDateOfMonth)

Holy cow, this is ugly, but here goes:
DECLARE #dtDate DATETIME
SET #dtDate = '2009-11-05'
SELECT DATEADD(dd, -1*(DATEPART(dw, DateAdd(day, -1, DateAdd(month, DateDiff(month, 0, #dtDate)+1, 0)))-1),
DateAdd(day, -1, DateAdd(month, DateDiff(month, 0, #dtDate)+1, 0)))

First built a tally table.
http://www.sqlservercentral.com/articles/T-SQL/62867/
then get what you want..
http://www.sqlservercentral.com/Forums/Topic515226-1291-1.aspx
DECLARE #DateStart DATETIME,
#DateEnd DATETIME
SELECT #DateStart = '20080131',
#DateEnd = '20101201'
SELECT DATEADD(wk,DATEDIFF(wk,6,DATEADD(mm,DATEDIFF(mm,-1,DATEADD(mm,t.N-1,#DateStart)),-1)),6)
FROM dbo.Tally t
WHERE t.N <= DATEDIFF(mm,#DateStart,#DateEnd)

Here's the correct way, accounting for ##DATEFIRST
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[fu_dtLastSundayInMonth]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
BEGIN
EXECUTE(N'CREATE FUNCTION [dbo].[fu_dtLastSundayInMonth]() RETURNS int BEGIN RETURN 0 END ')
END
GO
/*
SET DATEFIRST 3; -- Monday
WITH CTE AS (
SELECT 1 AS i, CAST('20190101' AS datetime) AS mydate
UNION ALL
SELECT i+1 AS i, DATEADD(month, 1, CTE.mydate) AS mydate
FROM CTE WHERE i < 100
)
SELECT -666 AS i, dbo.fu_dtLastSundayInMonth('17530101') AS lastSundayInMonth, dbo.fu_dtLastSundayInMonth('17530101') AS Control
UNION ALL
SELECT -666 AS i, dbo.fu_dtLastSundayInMonth('99991231') AS lastSundayInMonth, dbo.fu_dtLastSundayInMonth('99991231') AS Control
UNION ALL
SELECT
mydate
,dbo.fu_dtLastSundayInMonth(mydate) AS lastSundayInMonth
,dbo.fu_dtLastSundayInMonth(mydate) AS lastSundayInMonth
,DATEADD(day,DATEDIFF(day,'19000107', DATEADD(MONTH, DATEDIFF(MONTH, 0, mydate, 30))/7*7,'19000107') AS Control
FROM CTE
*/
-- =====================================================================
-- Description: Return date of last sunday in month
-- of the same year and month as #in_DateTime
-- =====================================================================
ALTER FUNCTION [dbo].[fu_dtLastSundayInMonth](#in_DateTime datetime )
RETURNS DateTime
AS
BEGIN
-- Abrunden des Eingabedatums auf 00:00:00 Uhr
DECLARE #dtReturnValue AS DateTime
-- 26.12.9999 SO
IF #in_DateTime >= CAST('99991201' AS datetime)
RETURN CAST('99991226' AS datetime);
-- #dtReturnValue is now last day of month
SET #dtReturnValue = DATEADD
(
DAY
,-1
,DATEADD
(
MONTH
,1
,CAST(CAST(YEAR(#in_DateTime) AS varchar(4)) + RIGHT('00' + CAST(MONTH(#in_DateTime) AS varchar(2)), 2) + '01' AS datetime)
)
)
;
-- SET DATEFIRST 1 -- Monday - Super easy !
-- SET DATEFIRST != 1 - PHUK THIS !
SET #dtReturnValue = DATEADD
(
day
,
-
(
(
-- DATEPART(WEEKDAY, #lastDayofMonth) -- with SET DATEFIRST 1
DATEPART(WEEKDAY, #dtReturnValue) + ##DATEFIRST - 2 % 7 + 1
)
%7
)
, #dtReturnValue
);
RETURN #dtReturnValue;
END
GO

select next_day(last_day(sysdate)-7, 'Sunday') from dual

Related

Find the Same day of Previous Year Given by Current Year Date in SQL Server

I am working with SQL Server, The scenario is to find out the Same Day's Date of Previous Year as of Today's Day.
Suppose 2014-03-06 is Today Date and Day is Thursday I want to Find the Same day in Previous lies in the same week .which is 2013-03-07
can any body help?
HERE is what i Have Written:
DECLARE #DateFrom AS DATETIME
DECLARE #DateTo AS DATETIME
SET #DateFrom = '2014-01-01'
SET #DateTo = '2014-02-10'
DECLARE #Count AS INT
SET #Count = DATEDIFF(DAY, #DateFrom, #DateTo)
CREATE TABLE #current_year /*This Year*/
(
[Date] DATETIME ,
WeekNum INT,
[Day] VARCHAR(20),
Data INT
)
CREATE TABLE #last_year /*This Year -1*/
(
[Date] DATETIME ,
WeekNum INT,
[Day] VARCHAR(20),
Data INT
)
WHILE ( #Count > 0 )
BEGIN
INSERT INTO #current_year
VALUES ( CONVERT(VARCHAR(10), #DateFrom, 101),
DATEPART(week,#DateFrom),
DATENAME(weekday, #DateFrom),#Count)
INSERT INTO #last_year
VALUES ( CONVERT(VARCHAR(10), DATEADD(YEAR, -1, #DateFrom), 101),
DATEPART(week,DATEADD(YEAR,1,#DateFrom)),
DATENAME(weekday, DATEADD(YEAR, -1, #DateFrom)),#Count)
SET #DateFrom = DATEADD(day, 1, #DateFrom)
SET #Count = #Count - 1
END
SELECT * from #current_year
SELECT * from #last_year
SELECT CONVERT(varchar(10),#current_year.[Date],111) AS CYDate,
--ISNULL(CONVERT(varchar(10),#last_year.[Date],111) ,/*CONVERT(varchar(10),DateAdd(dd, 1, DATEADD(yy, -1, #current_year.Date)),111)*/) AS LYDate
--CONVERT(varchar(10),#last_year.[Date],111) AS LYDate
Coalesce(CONVERT(varchar(10),#last_year.[Date],111) ,DateAdd(dd, 1, DATEADD(yy, -1, #current_year.Date))) AS LYDate,
#current_year.Data AS CD,
#last_year.Data AS LD
FROM #current_year
--LEFT JOIN #last_year ON #last_year.WeekNum = #current_year.WeekNum
-- AND #last_year.[Day] = #current_year.[Day]
Left JOIN #last_year ON #last_year.WeekNum = DatePart(wk, GETDATE())
DROP TABLE #current_year
DROP TABLE #last_year
Here is the Output:
Here is the output after adding your solution, now in left join it excludes (NULL) data of previous year
Basically you need to find difference in days between same dates in this and previous years, then understand "day difference" by mod 7, and sum it with date in previous year:
DECLARE #now DATETIME
SET #now = '2014-03-06'
SELECT CAST (DATEADD(YEAR, -1, #now) + (CAST (#now as INT) - CAST (DATEADD(YEAR, -1, #now) AS INT)) % 7 AS DATE)
Returns
2013-03-07
Try
DECLARE #now Date
SET #now = '2014-06-03'
SELECT DATEADD(week, -52, #now)
SELECT DateName(dw, DATEADD(yy, -1, GETDATE()))
gives Wednesday
SELECT DateName(dw, DateAdd(dd, 1, DATEADD(yy, -1, GETDATE())))
gives Thursday
edit:
SELECT DateAdd(dd, 1, DATEADD(yy, -1, GETDATE()))
gives '2013-03-07 17:30:16.590'
you need to cast the date as per you requirement..
update:
change this part with,
Left JOIN #last_year ON #last_year.WeekNum = DatePart(wk, GETDATE())
in your case:
Left JOIN #last_year ON DatePart(wk, #last_year.[Date]) = DatePart(wk, #current_year.[Date])
update 2:
Left JOIN #last_year ON (MONTH(#last_year.[Date])=MONTH(#current_year.[Date]) and Day(#last_year.[Date])=Day(#current_year.[Date]))
Output:
or
output:
Left JOIN #last_year ON (#last_year.WeekNum = #current_year.WeekNum and #last_year.[Day] = #current_year.[Day])
choose which ever is your required output.
DECLARE #Date DATE = '2014-03-06'
SELECT DATEADD(WEEK,-52,#Date)
Retrun value :
2013-03-07

SQL Set Time to Midnight in function

I have This function
ALTER FUNCTION [General].[GetWeekEnding]
(
#Date DATETIME
)
RETURNS DATETIME
AS
BEGIN
-- Return the result of the function
RETURN (DATEADD(day, -1 - (DATEPART(dw, #Date) + ##DATEFIRST - 2) % 7, #Date) + 7)
END
I need to also set the time to 00:00:00.000 as well as finding the week ending of a provided date any thoughts?
I use a UDF for adding time components to dates e.g.
CREATE FUNCTION [dbo].[DateTimeAdd]
(
#datepart date,
#timepart time
)
RETURNS datetime2
AS
BEGIN
RETURN DATEADD(dd, DATEDIFF(dd, 0, #datepart), CAST(#timepart AS datetime2));
END
Then in your case you can use it like this:
SELECT dbo.DateTimeAdd(DATEADD (D, -1 * DatePart (DW, GetDate()) + 7, GetDate()), DATEADD(hh, 0, CAST(DATEADD(DAY, DATEDIFF(DAY, -1, GETDATE()), -1) AS TIME)))
Since SQL Server 2005, the best way to remove time is to cast to the date data type:
select cast(#Date as date)
I would suggest that you have your function return a date instead of a datetime.
To get to the week ending, you need a lookup table to map days of the week to integers. You can do this with datepart. However, that is subject to system settings. Here is a function:
Create FUNCTION [GetWeekEnding] (
#Date DATETIME,
#WeekEndingDOW varchar(10)
)
RETURNS DATE
AS
BEGIN
-- Return the result of the function
declare #newdate datetime;
with lookup as (
select 'Sunday' as dow, 0 as daynum union all
select 'Monday' as dow, 1 as daynum union all
select 'Tuesday' as dow, 2 as daynum union all
select 'Wednesday' as dow, 3 as daynum union all
select 'Thursday' as dow, 4 as daynum union all
select 'Friday' as dow, 5 as daynum union all
select 'Saturday' as dow, 6 as daynum
)
select #newdate = #Date - (select daynum from lookup where datename(dw, #date) = dow) + (select daynum from lookup where #WeekEndingDOW = dow);
select #newdate = (case when #newdate < #date then #newdate + 7 else #newdate end)
RETURN cast(#newdate as date)
END;
Note that this function does use datetime internally. For some reason that I cannot fathom, you can say "#date + 1" to mean "add one day to the date value" when #date is a datetime. However, this does not work when #date is a date. (This is also true of the dateadd function.)

How can I rewrite this as a select statement using group by instead of using a loop

I am revisiting some old code I wrote for a report when I was still very new to SQL (MSSQL). It does what it is supposed to but its not the prettiest or most efficient.
The dummy code below mimics what I currently have in place. Here I am trying to get counts for the number of contracts that are open over the last 5 weeks. For this example a contract is considered open if the start date of the contract happens before of during the given week and the end date happens during or after the given week.
dbo.GetWeekStart(#Date DATETIME, #NumOfWeeks INT, #FirstDayOfWeek CHAR(3)) is a function that will return the first day of each week based on the date provided for a specified number of weeks. ie SELECT * FROM dbo.GetWeekStart('20120719', -2, 'MON') will return the 2 mondays prior to July 19, 2012.
How can I simplify this? I think there is someone to do this without a loop but I have not been able to figure it out.
DECLARE #RunDate DATETIME,
#Index INT,
#RowCount INT,
#WeekStart DATETIME,
#WeekEnd DATETIME
DECLARE #Weeks TABLE
(
WeekNum INT IDENTITY(0,1),
WeekStart DATETIME,
WeekEnd DATETIME
)
DECLARE #Output TABLE
(
WeekStart DATETIME,
OpenContractCount INT
)
SET #RunDate = GETDATE()
INSERT INTO #Weeks (WeekStart, WeekEnd)
SELECT WeekStart,
DATEADD(ss,-1,DATEADD(ww,1,WeekStart))
FROM dbo.[GetWeekStart](#RunDate, -5, 'MON')
SET #RowCount = (SELECT COUNT(*) FROM #Weeks)
SET #Index = 0
WHILE #Index < #RowCount
BEGIN
SET #WeekStart = (SELECT WeekStart FROM #Weeks WHERE WeekNum = #Idx)
SET #WeekEnd = (SELECT WeekEnd FROM #Weeks WHERE WeekNum = #Idx)
INSERT INTO #Output (WeekStart, OpenContractCount)
SELECT #WeekStart,
COUNT(*)
FROM Contracts c
WHERE c.StartDate <= #WeekEnd
AND ISNULL(c.EndDate, GETDATE()) >= #WeekStart
SET #Index = #Index + 1
END
SELECT * FROM #Output
I see no reason why this wouldn't work:
DECLARE #RunDate DATETIME = GETDATE()
SELECT WeekStart, COUNT(*)
FROM Contracts c
INNER JOIN dbo.[GetWeekStart](#RunDate, -5, 'MON')
ON c.StartDate < DATEADD(WEEK, 1, WeekStart)
AND (c.EndDate IS NULL OR c.EndDate >= #WeekStart)
GROUP BY WeekStart
I am not sure how you are generating your dates within your function, just in case you are using a loop/recursive CTE I'll include a query that doesn't use loops/cursors etc.
DECLARE #RunDate DATETIME = GETDATE()
-- SET DATEFIRST AS 1 TO ENSURE MONDAY IS THE FIRST DAY OF THE WEEK
-- CHANGE THIS TO SIMULATE CHANGING YOUR WEEKDAY INPUT TO db
SET DATEFIRST 1
-- SET RUN DATE TO BE THE START OF THE WEEK
SET #RunDate = CAST(DATEADD(DAY, 1 - DATEPART(WEEKDAY, #RunDate), #RunDate) AS DATE)
;WITH Weeks AS
( SELECT TOP 5 -- CHANGE THIS TO CHANGE THE WEEKS TO RUN
DATEADD(WEEK, 1 - ROW_NUMBER() OVER(ORDER BY Object_ID), #RunDate) [WeekStart]
FROM sys.All_Objects
)
SELECT WeekStart, COUNT(*)
FROM Contracts c
INNER JOIN Weeks
ON c.StartDate < DATEADD(WEEK, 1, WeekStart)
AND (c.EndDate IS NULL OR c.EndDate >= #WeekStart)
GROUP BY WeekStart
Did this quick but it should work
/*CTE generates Start & End Dates for 5 weeks
Start Date = Sunday of week # midnight
End Date = Sunday of next week # midnight
*/
WITH weeks
AS ( SELECT DATEADD(ww, -4,
CAST(FLOOR(CAST(GETDATE() - ( DATEPART(dw,
GETDATE()) - 1 ) AS FLOAT)) AS DATETIME)) AS StartDate
UNION ALL
SELECT DATEADD(wk, 1, StartDate)
FROM weeks
WHERE DATEADD(wk, 1, StartDate) <= GETDATE()
)
SELECT w.StartDate ,
COUNT(*) AS OpenContracts
FROM dbo.Contracts c
LEFT JOIN weeks w ON c.StartDate < DATEADD(d, 7, w.StartDate)
AND ISNULL(c.EndDate, GETDATE()) >= w.StartDate
GROUP BY w.StartDate

How to get Saturday's Date (Or any other weekday's Date)- SQL Server

How to get Saturday's Date. I have today's date with me.
GETDATE()
How to do this.
For eg. TODAY is 08-08-2011
I want output as 08-13-2011
This is a function that will return the next Saturday if you call it like this:
SELECT dbo.fn_Get_NextWeekDay('2011-08-08', 6)
The "6" comes from the list of possible values you can set for DATEFIRST.
You can get any other day of the week by changing the second parameter accordingly.
This is the function:
IF OBJECT_ID('dbo.fn_Get_NextWeekDay') IS NOT NULL
DROP FUNCTION dbo.fn_Get_NextWeekDay
GO
CREATE FUNCTION dbo.fn_Get_NextWeekDay(
#aDate DATETIME
, #dayofweek INT
/*
#dw - day of the week
1 - Monday
2 - Tuesday
3 - Wednesday
4 - Thursday
5 - Friday
6 - Saturday
7 - Sunday
*/
)
RETURNS DATETIME
AS
/*
SELECT dbo.fn_Get_NextWeekDay('2011-08-08', 6)
SELECT dbo.fn_Get_NextWeekDay('2011-08-08', 1)
*/
BEGIN
RETURN
DATEADD(day
, ( #dayofweek + 8 - DATEPART(dw, #aDate) - ##DATEFIRST ) % 7
, #aDate
)
END
GO
[EDIT]
This might be another solution. This should work in any language:
IF OBJECT_ID('dbo.fn_NextWeekDay') IS NOT NULL
DROP FUNCTION dbo.fn_NextWeekDay
GO
CREATE FUNCTION dbo.fn_NextWeekDay(
#aDate DATE
, #dayofweek NVARCHAR(30)
)
RETURNS DATE
AS
/*
SELECT dbo.fn_NextWeekDay('2016-12-14', 'fri')
SELECT dbo.fn_NextWeekDay('2016-03-15', 'mon')
*/
BEGIN
DECLARE #dx INT = 6
WHILE UPPER(DATENAME(weekday,#aDate)) NOT LIKE UPPER(#dayofweek) + '%'
BEGIN
SET #aDate = DATEADD(day,1,#aDate)
SET #dx=#dx-1
if #dx < 0
BEGIN
SET #aDate = NULL
BREAK
END
END
RETURN #aDate
END
GO
Use DATEPART to get the day of week of today and add the difference to the desired day of week to todays date.
DECLARE #Today date = 'TODAYS-DATE';
DECLARE #TodayNumber int = DATEPART(dw, #Today) -- Get the day number
DECLARE #Saturday date = DATEADD(DAY, (6-#TodayNumber)%7, #Today)
-- Add the number of days between today and saturday (the 6th day), modulus 7 to stop you adding negative days
Hope that helps!
Use a Calendar table (table with one row per date):
SELECT MIN(DateValue) DateValue
FROM Calendar
WHERE DateValue >= CURRENT_TIMESTAMP
AND DayOfWeek = 'Saturday';
Another approach to this takes two steps, but might be more readable (look ma, no modulus):
Go back to last saturday: DATEADD(DAY, -1 * datepart(weekday, GETDATE()), getdate())
Then, add on a week: DATEADD(WEEK, 1, #lastSaturday, getdate()))
The whole thing:
declare #today DATETIME = GETDATE()
declare #lastSaturday DATETIME = DATEADD(DAY, -1 * datepart(weekday, #today), #today)
declare #nextSaturday DATETIME = DATEADD(WEEK, 1, #lastSaturday)
Or, if you're ok with #today being GETDATE(), you can do the calculation all at once:
SELECT DATEADD(WEEK, 1, DATEADD(DAY, -1 * datepart(weekday, GETDATE()), getdate()))
Checkout the SQL DATEADD function.
DATEADD (Transact-SQL)
Which you can use this along with DATEPART function to return the correct date.
DATEPART (Transact-SQL)
Try this :
SET DATEFIRST 7
DECLARE #d DATETIME
SET #d = '2011-08-08' --GETDATE()
SELECT NEXT_SAT = DATEADD(day, (7 + ##DATEFIRST - DATEPART(dw, #d)) % 7, #d )
declare #Curdate date=( SELECT SWITCHOFFSET(SYSDATETIMEOFFSET(),'+05:30') )
declare #nextsaturdaydate date=(select dateadd(d, 7-datepart(WEEKDAY, #CurDate),#Curdate))
select #nextsaturdaydate

How to determine the number of days in a month in SQL Server?

I need to determine the number of days in a month for a given date in SQL Server.
Is there a built-in function? If not, what should I use as the user-defined function?
In SQL Server 2012 you can use EOMONTH (Transact-SQL) to get the last day of the month and then you can use DAY (Transact-SQL) to get the number of days in the month.
DECLARE #ADate DATETIME
SET #ADate = GETDATE()
SELECT DAY(EOMONTH(#ADate)) AS DaysInMonth
You can use the following with the first day of the specified month:
datediff(day, #date, dateadd(month, 1, #date))
To make it work for every date:
datediff(day, dateadd(day, 1-day(#date), #date),
dateadd(month, 1, dateadd(day, 1-day(#date), #date)))
Most elegant solution: works for any #DATE
DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,#DATE),0)))
Throw it in a function or just use it inline. This answers the original question without all the extra junk in the other answers.
examples for dates from other answers:
SELECT DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,'1/31/2009'),0))) Returns 31
SELECT DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,'2404-feb-15'),0))) Returns 29
SELECT DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,'2011-12-22'),0))) Returns 31
--Last Day of Previous Month
SELECT DATEPART(day, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0)))
--Last Day of Current Month
SELECT DATEPART(day, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0)))
--Last Day of Next Month
SELECT DATEPART(day, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+2,0)))
Personally though, I would make a UDF for it if there is not a built in function...
I would suggest:
SELECT DAY(EOMONTH(GETDATE()))
This code gets you the number of days in current month:
SELECT datediff(dd,getdate(),dateadd(mm,1,getdate())) as datas
Change getdate() to the date you need to count days for.
--- sql server below 2012---
select day( dateadd(day,-1,dateadd(month, 1, convert(date,'2019-03-01'))))
-- this for sql server 2012--
select day(EOMONTH(getdate()))
Solution 1: Find the number of days in whatever month we're currently in
DECLARE #dt datetime
SET #dt = getdate()
SELECT #dt AS [DateTime],
DAY(DATEADD(mm, DATEDIFF(mm, -1, #dt), -1)) AS [Days in Month]
Solution 2: Find the number of days in a given month-year combo
DECLARE #y int, #m int
SET #y = 2012
SET #m = 2
SELECT #y AS [Year],
#m AS [Month],
DATEDIFF(DAY,
DATEADD(DAY, 0, DATEADD(m, ((#y - 1900) * 12) + #m - 1, 0)),
DATEADD(DAY, 0, DATEADD(m, ((#y - 1900) * 12) + #m, 0))
) AS [Days in Month]
You do need to add a function, but it's a simple one. I use this:
CREATE FUNCTION [dbo].[ufn_GetDaysInMonth] ( #pDate DATETIME )
RETURNS INT
AS
BEGIN
SET #pDate = CONVERT(VARCHAR(10), #pDate, 101)
SET #pDate = #pDate - DAY(#pDate) + 1
RETURN DATEDIFF(DD, #pDate, DATEADD(MM, 1, #pDate))
END
GO
SELECT Datediff(day,
(Convert(DateTime,Convert(varchar(2),Month(getdate()))+'/01/'+Convert(varchar(4),Year(getdate())))),
(Convert(DateTime,Convert(varchar(2),Month(getdate())+1)+'/01/'+Convert(varchar(4),Year(getdate()))))) as [No.of Days in a Month]
select datediff(day,
dateadd(day, 0, dateadd(month, ((2013 - 1900) * 12) + 3 - 1, 0)),
dateadd(day, 0, dateadd(month, ((2013 - 1900) * 12) + 3, 0))
)
Nice Simple and does not require creating any functions Work Fine
You need to create a function, but it is for your own convenience. It works perfect and I never encountered any faulty computations using this function.
CREATE FUNCTION [dbo].[get_days](#date datetime)
RETURNS int
AS
BEGIN
SET #date = DATEADD(MONTH, 1, #date)
DECLARE #result int = (select DAY(DATEADD(DAY, -DAY(#date), #date)))
RETURN #result
END
How it works: subtracting the date's day number from the date itself gives you the last day of previous month. So, you need to add one month to the given date, subtract the day number and get the day component of the result.
select add_months(trunc(sysdate,'MM'),1) - trunc(sysdate,'MM') from dual;
I upvoted Mehrdad, but this works as well. :)
CREATE function dbo.IsLeapYear
(
#TestYear int
)
RETURNS bit
AS
BEGIN
declare #Result bit
set #Result =
cast(
case when ((#TestYear % 4 = 0) and (#testYear % 100 != 0)) or (#TestYear % 400 = 0)
then 1
else 0
end
as bit )
return #Result
END
GO
CREATE FUNCTION dbo.GetDaysInMonth
(
#TestDT datetime
)
RETURNS INT
AS
BEGIN
DECLARE #Result int
DECLARE #MonthNo int
Set #MonthNo = datepart(m,#TestDT)
Set #Result =
case #MonthNo
when 1 then 31
when 2 then
case
when dbo.IsLeapYear(datepart(yyyy,#TestDT)) = 0
then 28
else 29
end
when 3 then 31
when 4 then 30
when 5 then 31
when 6 then 30
when 7 then 31
when 8 then 31
when 9 then 30
when 10 then 31
when 11 then 30
when 12 then 31
end
RETURN #Result
END
GO
To Test
declare #testDT datetime;
set #testDT = '2404-feb-15';
select dbo.GetDaysInMonth(#testDT)
here's another one...
Select Day(DateAdd(day, -Day(DateAdd(month, 1, getdate())),
DateAdd(month, 1, getdate())))
I know this question is old but I thought I would share what I'm using.
DECLARE #date date = '2011-12-22'
/* FindFirstDayOfMonth - Find the first date of any month */
-- Replace the day part with -01
DECLARE #firstDayOfMonth date = CAST( CAST(YEAR(#date) AS varchar(4)) + '-' +
CAST(MONTH(#date) AS varchar(2)) + '-01' AS date)
SELECT #firstDayOfMonth
and
DECLARE #date date = '2011-12-22'
/* FindLastDayOfMonth - Find what is the last day of a month - Leap year is handled by DATEADD */
-- Get the first day of next month and remove a day from it using DATEADD
DECLARE #lastDayOfMonth date = CAST( DATEADD(dd, -1, DATEADD(mm, 1, FindFirstDayOfMonth(#date))) AS date)
SELECT #lastDayOfMonth
Those could be combine to create a single function to retrieve the number of days in a month if needed.
SELECT DAY(SUBDATE(ADDDATE(CONCAT(YEAR(NOW()), '-', MONTH(NOW()), '-1'), INTERVAL 1 MONTH), INTERVAL 1 DAY))
Nice 'n' Simple and does not require creating any functions
Mehrdad Afshari reply is most accurate one, apart from usual this answer is based on formal mathematical approach given by Curtis McEnroe in his blog https://cmcenroe.me/2014/12/05/days-in-month-formula.html
DECLARE #date DATE= '2015-02-01'
DECLARE #monthNumber TINYINT
DECLARE #dayCount TINYINT
SET #monthNumber = DATEPART(MONTH,#date )
SET #dayCount = 28 + (#monthNumber + floor(#monthNumber/8)) % 2 + 2 % #monthNumber + 2 * floor(1/#monthNumber)
SELECT #dayCount + CASE WHEN #dayCount = 28 AND DATEPART(YEAR,#date)%4 =0 THEN 1 ELSE 0 END -- leap year adjustment
To get the no. of days in a month we can directly use Day() available in SQL.
Follow the link posted at the end of my answer for SQL Server 2005 / 2008.
The following example and the result are from SQL 2012
alter function dbo.[daysinm]
(
#dates nvarchar(12)
)
returns int
as
begin
Declare #dates2 nvarchar(12)
Declare #days int
begin
select #dates2 = (select DAY(EOMONTH(convert(datetime,#dates,103))))
set #days = convert(int,#dates2)
end
return #days
end
--select dbo.daysinm('08/12/2016')
Result in SQL Server SSMS
(no column name)
1 31
Process:
When EOMONTH is used, whichever the date format we use it is converted into DateTime format of SQL-server. Then the date output of EOMONTH() will be 2016-12-31 having 2016 as Year, 12 as Month and 31 as Days.
This output when passed into Day() it gives you the total days count in the month.
If we want to get the instant result for checking we can directly run the below code,
select DAY(EOMONTH(convert(datetime,'08/12/2016',103)))
or
select DAY(EOMONTH(convert(datetime,getdate(),103)))
for reference to work in SQL Server 2005/2008/2012, please follow the following external link ...
Find No. of Days in a Month in SQL
DECLARE #date DATETIME = GETDATE(); --or '12/1/2018' (month/day/year)
SELECT DAY(EOMONTH ( #date )) AS 'This Month';
SELECT DAY(EOMONTH ( #date, 1 )) AS 'Next Month';
result:
This Month
31
Next Month
30
DECLARE #m int
SET #m = 2
SELECT
#m AS [Month],
DATEDIFF(DAY,
DATEADD(DAY, 0, DATEADD(m, +#m -1, 0)),
DATEADD(DAY, 0, DATEADD(m,+ #m, 0))
) AS [Days in Month]
RETURN day(dateadd(month, 12 * #year + #month - 22800, -1))
select day(dateadd(month, 12 * year(date) + month(date) - 22800, -1))
A cleaner way of implementing this is using the datefromparts function to construct the first day of the month, and calculate the days from there.
CREATE FUNCTION [dbo].[fn_DaysInMonth]
(
#year INT,
#month INT
)
RETURNS INT
AS
BEGIN
IF #month < 1 OR #month > 12 RETURN NULL;
IF #year < 1753 OR #year > 9998 RETURN NULL;
DECLARE #firstDay DATE = datefromparts(#year, #month, 1);
DECLARE #lastDay DATE = dateadd(month, 1, #firstDay);
RETURN datediff(day, #firstDay, #lastDay);
END
GO
Similarily, you can calculate the days in a year:
CREATE FUNCTION [dbo].[fn_DaysInYear]
(
#year INT
)
RETURNS INT
AS
BEGIN
IF #year < 1753 OR #year > 9998 RETURN NULL;
DECLARE #firstDay DATE = datefromparts(#year, 1, 1);
DECLARE #lastDay DATE = dateadd(year, 1, #firstDay);
RETURN datediff(day, #firstDay, #lastDay);
END
GO
use SQL Server EOMONTH Function nested with day to get last day of month
select Day(EOMONTH('2020-02-1')) -- Leap Year returns 29
select Day(EOMONTH('2021-02-1')) -- returns 28
select Day(EOMONTH('2021-03-1')) -- returns 31
For any date
select DateDiff(Day,#date,DateAdd(month,1,#date))
select first_day=dateadd(dd,-1*datepart(dd,getdate())+1,getdate()),
last_day=dateadd(dd,-1*datepart(dd,dateadd(mm,1,getdate())),dateadd(mm,1,getdate())),
no_of_days = 1+datediff(dd,dateadd(dd,-1*datepart(dd,getdate())+1,getdate()),dateadd(dd,-1*datepart(dd,dateadd(mm,1,getdate())),dateadd(mm,1,getdate())))
replace any date with getdate to get the no of months in that particular date
DECLARE #Month INT=2,
#Year INT=1989
DECLARE #date DateTime=null
SET #date=CAST(CAST(#Year AS nvarchar) + '-' + CAST(#Month AS nvarchar) + '-' + '1' AS DATETIME);
DECLARE #noofDays TINYINT
DECLARE #CountForDate TINYINT
SET #noofDays = DATEPART(MONTH,#date )
SET #CountForDate = 28 + (#noofDays + floor(#noofDays/8)) % 2 + 2 % #noofDays + 2 * floor(1/#noofDays)
SET #noofDays= #CountForDate + CASE WHEN #CountForDate = 28 AND DATEPART(YEAR,#date)%4 =0 THEN 1 ELSE 0 END
PRINT #noofDays
DECLARE #date nvarchar(20)
SET #date ='2012-02-09 00:00:00'
SELECT DATEDIFF(day,cast(replace(cast(YEAR(#date) as char)+'-'+cast(MONTH(#date) as char)+'-01',' ','')+' 00:00:00' as datetime),dateadd(month,1,cast(replace(cast(YEAR(#date) as char)+'-'+cast(MONTH(#date) as char)+'-01',' ','')+' 00:00:00' as datetime)))
simple query in SQLServer2012 :
select day(('20-05-1951 22:00:00'))
i tested for many dates and it return always a correct result