views:

3628

answers:

7

Specifically MSSQL 2005.

+3  A: 

DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0,CURRENT_TIMESTAMP) + 1, 0)

sebastian
I've often found that people don't follow the logic of this. So, although it seems to be correct (where the answer accepted appears to Not be correct) , I'm not going to give +1. Any chance you can edit the answer to give the explanation?
Dems
+7  A: 

Here's a solution that gives you the last second of the current month. You can extract the date part or modify it to return just the day. I tested this on SQL Server 2005.

select dateadd( s, -1, dateadd( mm, datediff( m, 0, getdate() ) + 1, 0 ) );

To understand how it works we have to look at the dateadd() and datediff() functions.

DATEADD(datepart, number, date)  
DATEDIFF(datepart, startdate, enddate)

If you run just the most inner call to datediff(), you get the current month number since timestamp 0.

select datediff(m, 0, getdate() );  
1327

The next part adds that number of months plus 1 to the 0 timestamp, giving you the starting point of the next calendar month.

select dateadd( mm, datediff( m, 0, getdate() ) + 1, 0 );
2010-09-01 00:00:00.000

Finally, the outer dateadd() just subtracts one second from the beginning timestamp of next month, giving you the last second of the current month.

select dateadd( s, -1, dateadd( mm, datediff( m, 0, getdate() ) + 1, 0 ) );
2010-08-31 23:59:59.000


This old answer (below) has a bug where it doesn't work on the last day of a month that has more days than the next month. I'm leaving it here as a warning to others.

Add one month to the current date, and then subtract the value returned by the DAY function applied to the current date using the functions DAY and DATEADD.

dateadd(day, -day(getdate()), dateadd(month, 1, getdate()))
Bill the Lizard
What if the two getdate calls give answers in different dates?
David B
I suppose that's possible. You'd have to declare a variable to hold today's date beforehand.
Bill the Lizard
They won't. We create reports that generate year, quarter, month and rundate (GetDate()) columns that take 30 seconds and the value never changes.
Jeff O
Try: Select GetDate() Select GetDate() and compare to:Select GetDate() GO Select GetDate()The first gives the same time, the second does not.
Jeff O
They can't come back differently. Scalar functions are executed once and then their result substituted in. That's why if you do [SELECT RAND(), * FROM myTable] ever row has the same value for rand. Even if the query took a day to execute, the value at the Start of the exceution is what is used.
Dems
Has this been tested for dates like "30th Jan"? My understanding is that "dateadd(month, 1, getdate())" would give "28th Feb" and then "-day(getdate())" would give "-30". The final result being the "28th Jan", which is wrong...
Dems
Maybe it's just because I'm using SQL 2000, but when I use this query for today's date, the query returns '2010-08-30', when I would have expected '2010-08-31'.
LittleBobbyTables
@LittleBobbyTables: There was a bug in my old answer. Thanks for commenting on it, as I was unaware of the bug (I guess the other comments were left before we had the notification envelope here on SO). See my update for a better solution.
Bill the Lizard
A: 
DECLARE
  @Now datetime,
  @Today datetime,
  @ThisMonth datetime,
  @NextMonth datetime,
  @LastDayThisMonth datetime

SET @Now = getdate()
SET @Today = DateAdd(dd, DateDiff(dd, 0, @Now), 0)
SET @ThisMonth = DateAdd(mm, DateDiff(mm, 0, @Now), 0)
SET @NextMonth = DateAdd(mm, 1, @ThisMonth)
SET @LastDayThisMonth = DateAdd(dd, -1, @NextMonth)

Sometimes you really do need the last day of this month, but frequently what you really want is to describe the time interval of this month. This is the best way to describe the time interval of this month:

WHERE @ThisMonth <= someDate and someDate < @NextMonth
David B
+2  A: 
SELECT DATEADD(M, DATEDIFF(M, '1990-01-01T00:00:00.000', CURRENT_TIMESTAMP), '1990-01-31T00:00:00.000')

Explanation:

General approach: use temporal functionality.

SELECT '1990-01-01T00:00:00.000', '1990-01-31T00:00:00.000'

These are DATETIME literals, being the first time granule on the first day and last day respectively of the same 31-day month. Which month is chosen is entirely arbitrary.

SELECT DATEDIFF(M, '1990-01-01T00:00:00.000', CURRENT_TIMESTAMP)

This is the difference in whole months between the first day of the reference month and the current timestamp. Let's call this @calc.

SELECT DATEADD(M, @calc, '1990-01-31T00:00:00.000')

This adds @calc month granules to the last day of the reference month, the result of which is the current timestamp 'rounded' to the last day of its month. Q.E. D.

onedaywhen
+1 for included an explanation :)
Dems
A: 

For completeness, in Oracle you'd do something like ...

select add_months(trunc(sysdate,'MM'),1) ...

or

select last_day(sysdate)+1 ...
David Aldridge
A: 
DATEADD(dd, -1, DATEADD(mm, +1, DATEADD(dd, 1 - DATEPART(dd, @myDate), @myDate)))
van