418

How can one select the first day of the month of a given DateTime variable?


I know it's quite easy to do using this kind of code:

select CAST(CAST(YEAR(@mydate) AS VARCHAR(4)) 
+ '/' + CAST(MONTH(@mydate) AS VARCHAR(2)) + '/01' AS DATETIME)

This is not very elegant, and not very fast either.

Is there a better way to do this?

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
Brann
  • 31,689
  • 32
  • 113
  • 162

34 Answers34

748
SELECT DATEADD(month, DATEDIFF(month, 0, @mydate), 0) AS StartOfMonth
LukeH
  • 263,068
  • 57
  • 365
  • 409
  • 24
    [There is a cardinality estimation bug to be aware of if using this approach](http://stackoverflow.com/a/18242413/73226) – Martin Smith Aug 15 '13 at 14:01
  • 86
    It should be noted the bug mentioned by Martin Smith can "only" affect performance, not correctness. – Olson.dev Mar 05 '14 at 21:19
  • 15
    Here is an [explanation on why and how this works](http://www.jasonstrate.com/2010/03/grouping-and-rounding-dates/). – RubberDuck Oct 15 '14 at 19:24
  • Discovered this does not work with out of range datetime2 values. `select DATEADD(month, DATEDIFF(month, 0, cast('0002-01-01 00:00:00.0000000' as datetime2)), 0) ` will throw an error. – David Oct 01 '15 at 16:58
  • 64
    In case anyone is wondering `SELECT EOMONTH(@mydate) AS EndOfMonth` will give you the last day of the month. – hallizh Nov 03 '15 at 13:47
  • 1
    The noted cardinality estimation bug just caused 40 queries to pile up and a system to have an outage, so I'd strongly consider finding another method if performance / availability is important to you. – Sam Jul 28 '16 at 15:58
  • 3
    How can I determine if the noted cardinality estimation bug will affect me? It is marked as fixed in 2010. Does that mean that only SQL Server 2012 and newer are safe, or is it possible that a 2008 server may have been patched? – Jon May 05 '17 at 18:05
208

In addition to all the above answer, a way based on a function introduced in sql 2012

SELECT DATEFROMPARTS(YEAR(@mydate),MONTH(@mydate),1)
Jithin Shaji
  • 5,893
  • 5
  • 25
  • 47
139

Starting with SQL Server 2012:

SELECT DATEADD(DAY,1,EOMONTH(@mydate,-1))
ChrisG
  • 1,230
  • 4
  • 17
  • 35
Marcos Krucken
  • 1,391
  • 1
  • 8
  • 2
17

Simple Query:

SELECT DATEADD(m, DATEDIFF(m, 0, GETDATE()), 0) 
-- Instead of GetDate you can put any date.
Abhishek Gupta
  • 583
  • 5
  • 6
  • I like this.....select DATEFROMPARTS(year(getdate()),month(getdate()),'01') ,convert(date,dateadd(day,1-day(getdate()),getdate())) ,DATEADD(m, DATEDIFF(m, 0, GETDATE()), 0) ,DATEADD(d, DATEDIFF(d, 0, GETDATE()), 0) – JWBG Mar 22 '23 at 17:18
15

The casting of a string (i.e. "5/1/2009") to datetime is certainly more legible but we found code a while back that would return the first of the month...

DECLARE @Date DATETIME
//...
SELECT DATEADD(mm, DATEDIFF(mm,0,@Date), 0)
Mayo
  • 10,544
  • 6
  • 45
  • 90
13

From SQL Server 2022 you can use DATETRUNC

SELECT DATETRUNC(month, @mydate)

for this need

Martin Smith
  • 438,706
  • 87
  • 741
  • 845
8

This might be a new function, but you can also use old functions :

select DATEFROMPARTS(year(@mydate),month(@mydate),'01')

If the date in the variable was for example '2017-10-29' it would return a date of '2017-10-01'

https://learn.microsoft.com/en-us/sql/t-sql/functions/datefromparts-transact-sql?view=sql-server-ver15

Standin.Wolf
  • 1,224
  • 1
  • 10
  • 32
Luc
  • 81
  • 1
  • 1
7
SELECT @myDate - DAY(@myDate) + 1
PoloSoares
  • 215
  • 2
  • 6
  • Really simple and elegant solution but keep in mind that this also returns the time portion of the date if specified in the variable. – kuklei Oct 17 '14 at 15:52
  • I couldn't get this to work. Besides the extra closing bracket, I get this error: `Operand type clash: date is incompatible with int`. I guess it's because you're trying to use the `-` operator on a date? – Sam Dec 10 '14 at 03:26
  • I don't know how good it is in terms of performance, but it certainly does the job. – salcoin Oct 20 '15 at 15:39
  • @Sam, you've got a clash because simple arithmetic (+, -) works on datetimes, not on dates. – darlove Dec 11 '19 at 17:43
6

If you would like to go for SQL Server 2012+ you can try solution I used:

SELECT DATEADD(DAY, 1, EOMONTH(DATEADD(MONTH, -1, GETDATE())))
Dale K
  • 25,246
  • 15
  • 42
  • 71
dariuszewski
  • 86
  • 1
  • 3
5

It is probably quite fast. Why not create it as a sql function.

CREATE FUNCTION [dbo].[GetFirstDayOfMonth] ( @InputDate    DATETIME )
RETURNS DATETIME
BEGIN

    RETURN CAST(CAST(YEAR(@InputDate) AS VARCHAR(4)) + '/' + 
                CAST(MONTH(@InputDate) AS VARCHAR(2)) + '/01' AS DATETIME)

END
GO
dove
  • 20,469
  • 14
  • 82
  • 108
4

First and last day of the current month:

select dateadd(mm, -1,dateadd(dd, +1, eomonth(getdate()))) as FirstDay, 
eomonth(getdate()) as LastDay
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
stecyk
  • 59
  • 1
  • 4
3

This works too:

    SELECT DATEADD(DAY,(DATEPART(DAY,@mydate)-1)*(-1),@mydate) AS FirstOfMonth
Alan Burstein
  • 7,770
  • 1
  • 15
  • 18
3

Please use this

  1. For Server 2012

    DATEFROMPARTS(year('2015-06-30'),month('2015-06-30'),1)
    
  2. Before Server 2012

    select  cast(cast(year('2015-06-30') as varchar(4))+'-'+ cast(month('2015-06-30') as varchar(2))+'-01' as smalldatetime)
    
cuongle
  • 74,024
  • 28
  • 151
  • 206
adnan umar
  • 127
  • 1
  • 5
2

I used GETDATE() as a date to work with, you can replace it with the date which you need.
Here's how this works: First we format the date in YYYYMMDD... format truncating to keep just the 6 leftmost characters in order to keep just the YYYYMM portion, and then append '01' as the month - and voila! you have the first day of the current month.

SELECT CAST(CONVERT(VARCHAR(6),GETDATE(),112) +'01' AS DATETIME) AS StartOfMonth

BTW, performance is great on this!

Eli
  • 2,538
  • 1
  • 25
  • 36
2
DECLARE @startofmonth date
SET @startofmonth = DATEADD(dd,1,EOMONTH(Getdate(),-2))

The -2 will get you the first day of last month. ie, getdate() is 10/15/18. Your results would be 9/1/18. Change to -1 and your results would be 10/1/18. 0 would be the start of next month, 11/1/2018.. etc etc.

or

DECLARE @startofmonth date
SET @startofmonth = DATEADD(dd,1,EOMONTH(@mydate,-1))
1
SELECT DATEADD (DAY, -1 * (DAY(GETDATE()) - 1), GETDATE())

.....................................................................

If you dont want the time, then convert it to DATE or if want to make to time to 0:00:00, Convert to DATE and then back to DATETIME.

SELECT CONVERT (DATETIME,  
CONVERT (DATE, DATEADD (DAY, -1 * (DAY(GETDATE()) - 1),
GETDATE())))

Change GETDATE() to the date you want

Abdul Saleem
  • 10,098
  • 5
  • 45
  • 45
1

If you are looking at this today, and using SQL server 2012 or newer you have the EOMONTH function which makes things easier:

SELECT DATEADD(day, 1, EOMONTH(DATEADD(month, -1, GETDATE()))) as firstdateofmonth

You can change GETDATE() with whatever date variable you want.

Ang Li
  • 11
  • 1
1

Here we can use below query to the first date of the month and last date of the month.

SELECT DATEADD(DAY,1,EOMONTH(Getdate(),-1)) as 'FD',Cast(Getdate()-1 as Date)
as 'LD'
Jérémie B
  • 10,611
  • 1
  • 26
  • 43
1

If using SQL Server 2012 or above;

SELECT DATEADD(MONTH, -1, DATEADD(DAY, 1, EOMONTH(GETDATE())))
user692942
  • 16,398
  • 7
  • 76
  • 175
1
----Last Day of Previous Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))
LastDay_PreviousMonth
----Last Day of Current Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))
LastDay_CurrentMonth
----Last Day of Next Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+2,0))
LastDay_NextMonth
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
r-magalhaes
  • 427
  • 2
  • 9
  • 18
  • But the OP is looking for the first day of the month. For last day, you could just use EOMONTH() - has been this way since 2012. – deutschZuid Feb 14 '19 at 21:51
1

Try executing the following query:

SELECT DATE_ADD(DATE_ADD(LAST_DAY(CURRENT_DATE-INTERVAL 1 DAY),INTERVAL 1 DAY),INTERVAL -1 MONTH)

Harshith Rai
  • 3,018
  • 7
  • 22
  • 35
divya
  • 11
  • 1
1

You can use below function for getting 1st day of current month:

DECLARE @mydate date
set @mydate=GETDATE()
SELECT DATEFROMPARTS(YEAR(@mydate),MONTH(@mydate),1)
BoP
  • 2,310
  • 1
  • 15
  • 24
0

Future googlers, on MySQL, try this:

select date_sub(ref_date, interval day(ref_date)-1 day) as day1;
Ariel T
  • 2,879
  • 1
  • 21
  • 21
0

select CONVERT(date,DATEADD(dd,-(DATEPART(dd,getdate())-1),getdate()),120)

This function will provide you date part of start date of the month

Tushar
  • 1
0

This query should work very well on MySQL:

SELECT concat(left(curdate(),7),'-01') 
Uladz Kha
  • 2,154
  • 4
  • 40
  • 61
0

What about something different! Use Format.

DECLARE @Date Date =GetDate();
SELECT CONVERT(Date,Format(@Date,'yyyyMM01'));

We can remove the convert if we are casting to Date Column or variable

DECLARE @Date Date =GetDate();
SELECT @Date =Format(@Date,'yyyyMM01');
SELECT [Date]=@Date

Have Fun :)

Waleed A.K.
  • 1,596
  • 13
  • 13
-1

I personal recommended that the sql below because when i try use date function in the condition clause, its slow down my query speed very much.

anyway feel free to try this.

select CONCAT(DATEPART(YYYY,@mydate),'-',DATEPART(MM,@mydate),'-01')
Jelly
  • 31
  • 11
-1

Not to compete with any of the great minds here, but a simple suggestion slightly different that the accepted answer above.

select dateadd(day, -(datepart(day,@date)+1,@date)
-1

I like to use FORMAT, you can even specify a time

SELECT FORMAT(@myDate,'yyyy-MM-01 06:00') first_of_a_month
michal
  • 327
  • 4
  • 15
-1

In Sql Server 2012,

 select getdate()-DATEPART(day, getdate())+1

 select DATEADD(Month,1,getdate())-DATEPART(day, getdate())
BornToCode
  • 207
  • 2
  • 7
-1

For anyone still looking for an answer, this works like a charm and does away with any dateadds. The timestamp is optional, in case it needs specifying, but works without as well.

SELECT left(convert(varchar, getdate(),23),7)+'-01 00:00:00'
-1

Get First Date and Last Date in the Date we pass as parameter in SQL

     @date DATETIME
    SELECT @date = GETDATE()
    SELECT CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(@date)-1),@date),105) AS value,
    'First Day of Current Month' AS name
    UNION
    SELECT CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(DATEADD(mm,1,@date))),
    DATEADD(mm,1,@date)),105),
    'Last Day of Current Month'
    GO


      **OutPut**

12/01/2019  First Day of Current Month
12/31/2019  Last Day of Current Month
Rinku Choudhary
  • 1,529
  • 1
  • 13
  • 22
-4

Try the following:

select trunc(sysdate,'MM') 
from dual;
AirlineDog
  • 520
  • 8
  • 21
manoj
  • 1
  • 1
    The question is about SQL Server, which does not have a `trunc` function. Always make sure you check the question tags. – Connor Low Apr 21 '21 at 15:47
-4

Try the following:

select trunc(to_date('23-03-2021','DD-MM-YYYY'),'MM') from dual;
Michal Levý
  • 33,064
  • 4
  • 68
  • 86
manoj
  • 1