【问题标题】:How to determine the number of days in a month in SQL Server?SQL Server中如何确定一个月的天数?
【发布时间】:2010-10-16 00:23:40
【问题描述】:

我需要在 SQL Server 中确定给定日期一个月中的天数。

有内置函数吗?如果不是,我应该使用什么作为用户定义的函数?

【问题讨论】:

    标签: sql sql-server datetime date user-defined-functions


    【解决方案1】:

    在 SQL Server 2012 中,您可以使用 EOMONTH (Transact-SQL) 获取该月的最后一天,然后您可以使用 DAY (Transact-SQL) 获取该月的天数。

    DECLARE @ADate DATETIME
    
    SET @ADate = GETDATE()
    
    SELECT DAY(EOMONTH(@ADate)) AS DaysInMonth
    

    【讨论】:

    • 如果你需要给定的天数,你也可以使用 DATEFROMPARTS 方法。上面的代码将变为 SELECT DAY(EOMONTH(DATEFROMPARTS(@year, @month, 1))) AS DaysInMonth
    • 如果@ADate 是一个复杂的计算值,那么这个解决方案的美妙之处就会发挥作用! +1
    • 非常感谢!
    • 这应该是这个问题的实际答案。
    【解决方案2】:

    您可以在指定月份的第一天使用以下内容:

    datediff(day, @date, dateadd(month, 1, @date))
    

    使其适用于每个日期:

    datediff(day, dateadd(day, 1-day(@date), @date),
                  dateadd(month, 1, dateadd(day, 1-day(@date), @date)))
    

    【讨论】:

    • 就像 Stan 说的那样,这在某些情况下会给出不准确的结果
    • 你不是说: datediff ( day , dateadd ( day , 1-day(@date) , @date) , dateadd ( month , 1 , dateadd ( day , 1-day(@date ) , @date)))
    • 这是一个罕见的极端情况,但我只是偶然发现它:这将在 9999 年 12 月引发错误。
    • 这不适用于 9999 年 12 月的任何日期。日期类型会溢出。这在 SQL Server 2014 中对我有用:case when datediff(m, dateadd(day, 1-day(@date), @date), convert(date, convert(datetime, 2958463))) > 0 then datediff(day, dateadd(day, 1-day(@date), @date), dateadd(month, 1, dateadd(day, 1-day(@date), @date))) else 31 end
    • @Mikael Eriksson's answer 的优雅相比,这里提到的所有解决方案都显得苍白无力。只要提供了有效日期而没有针对小众案例的疯狂解决方法并且代码要简单得多 - 我强烈建议 T-SQL 上的任何人坚持获取eomonth 输出的day 组件。
    【解决方案3】:

    最优雅的解决方案:适用于任何 @DATE

    DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,@DATE),0)))
    

    将它扔到一个函数中或直接使用它。这回答了原始问题,没有其他答案中的所有额外垃圾。

    其他答案的日期示例:

    SELECT DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,'1/31/2009'),0))) 返回 31

    SELECT DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,'2404-feb-15'),0))) 返回 29

    SELECT DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,'2011-12-22'),0))) 返回 31

    【讨论】:

      【解决方案4】:

      简单得多...试试day(eomonth(@Date))

      【讨论】:

      • 我认为你的答案是最好的,就这么简单。谢谢!
      【解决方案5】:
      --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)))
      

      个人而言,如果没有内置函数,我会为它制作一个 UDF...

      【讨论】:

        【解决方案6】:

        我建议:

        SELECT DAY(EOMONTH(GETDATE()))
        

        【讨论】:

        • datepart 不返回天数,你的回答也是错误的
        • 为我工作,但肯定使用 day 函数会是一个更干净的答案
        • 这个答案与下面的几乎相同,票数为 75。
        【解决方案7】:

        此代码为您获取当月的天数:

        SELECT datediff(dd,getdate(),dateadd(mm,1,getdate())) as datas
        

        getdate() 更改为您需要计算天数的日期。

        【讨论】:

          【解决方案8】:
             --- 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()))
          

          【讨论】:

            【解决方案9】:

            解决方案 1:找出我们当前所在月份的天数

            DECLARE @dt datetime
            SET     @dt = getdate()
            
            SELECT @dt AS [DateTime],
                   DAY(DATEADD(mm, DATEDIFF(mm, -1, @dt), -1)) AS [Days in Month]
            

            解决方案 2:查找给定月-年组合中的天数

            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]
            

            【讨论】:

              【解决方案10】:

              您确实需要添加一个函数,但它是一个简单的函数。我用这个:

              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
              

              【讨论】:

              • 顺便说一下,DATEDIFF 和 DATEADD 的组合并不总是有效。如果您在其中输入 1/31/2009 的日期,则 DATEADD 将返回 2/28/2009,而 DATEDIFF 将返回 28,而不是 31。
              • 如何检查,我的意思是要执行什么来检查一个月的天数??
              【解决方案11】:
              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]
              

              【讨论】:

                【解决方案12】:
                select  datediff(day, 
                        dateadd(day, 0, dateadd(month, ((2013 - 1900) * 12) + 3 - 1, 0)),
                        dateadd(day, 0, dateadd(month, ((2013  - 1900) * 12) + 3, 0))
                        )
                

                非常简单,不需要创建任何功能工作正常

                【讨论】:

                  【解决方案13】:

                  您需要创建一个函数,但这是为了您自己的方便。它运行完美,我从未遇到过使用此函数的任何错误计算。

                  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
                  

                  它是如何工作的: 从日期本身中减去日期的天数会得到上个月的最后一天。所以,你需要给给定的日期加上一个月,减去天数,得到结果的天分量。

                  【讨论】:

                    【解决方案14】:
                    select add_months(trunc(sysdate,'MM'),1) -  trunc(sysdate,'MM') from dual;
                    

                    【讨论】:

                      【解决方案15】:

                      我赞成 Mehrdad,但这也有效。 :)

                      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
                      

                      测试

                      declare @testDT datetime;
                      
                      set @testDT = '2404-feb-15';
                      
                      select dbo.GetDaysInMonth(@testDT)
                      

                      【讨论】:

                        【解决方案16】:

                        还有一个……

                        Select Day(DateAdd(day, -Day(DateAdd(month, 1, getdate())), 
                                                 DateAdd(month, 1, getdate())))
                        

                        【讨论】:

                          【解决方案17】:

                          我知道这个问题很老,但我想我会分享我正在使用的内容。

                          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
                          

                          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
                          

                          如果需要,可以将这些组合起来创建一个函数来检索一个月中的天数。

                          【讨论】:

                            【解决方案18】:
                            SELECT DAY(SUBDATE(ADDDATE(CONCAT(YEAR(NOW()), '-', MONTH(NOW()), '-1'), INTERVAL 1 MONTH), INTERVAL 1 DAY))
                            

                            Nice 'n' 简单,不需要创建任何函数

                            【讨论】:

                            • 这是针对 SQL Server 的;我从未听说过 subdate 函数。
                            【解决方案19】:

                            Mehrdad Afshari 的回复是最准确的,除了通常这个答案是基于 Curtis McEnroe 在他的博客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
                            

                            【讨论】:

                              【解决方案20】:

                              要获得否。我们可以直接使用 SQL 中可用的 Day()。

                              按照我对 SQL Server 2005 / 2008 的回答末尾发布的链接进行操作。

                              以下示例和结果来自 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')
                              

                              SQL Server SSMS 中的结果

                                (no column name)
                              1 31
                              

                              流程:

                              当使用EOMONTH 时,无论我们使用哪种日期格式,都会将其转换为SQL-server 的DateTime 格式。那么 EOMONTH() 的日期输出将为 2016-12-31,其中 2016 为年,12 为月,31 为天。 此输出在传递给 Day() 时会为您提供当月的总天数。

                              如果我们想得到即时的检查结果,我们可以直接运行下面的代码,

                              select DAY(EOMONTH(convert(datetime,'08/12/2016',103)))
                              

                              select DAY(EOMONTH(convert(datetime,getdate(),103)))
                              

                              有关在 SQL Server 2005/2008/2012 中工作的参考,请点击以下外部链接...

                              Find No. of Days in a Month in SQL

                              【讨论】:

                                【解决方案21】:
                                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';
                                

                                结果: 这个月 31

                                下个月 30

                                【讨论】:

                                • 这不会返回当月的天数
                                • 是的。但仅适用于 SQL Server 2012 及更高版本
                                【解决方案22】:
                                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]
                                

                                【讨论】:

                                  【解决方案23】:
                                  RETURN day(dateadd(month, 12 * @year + @month - 22800, -1)) 
                                  select day(dateadd(month, 12 * year(date) + month(date) - 22800, -1)) 
                                  

                                  【讨论】:

                                    【解决方案24】:

                                    实现这一点的一种更简洁的方法是使用datefromparts 函数来构造每月的第一天,并从那里计算天数。

                                    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
                                    

                                    同样,你可以计算一年中的天数:

                                    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
                                    

                                    【讨论】:

                                      【解决方案25】:

                                      任何日期

                                      select DateDiff(Day,@date,DateAdd(month,1,@date))
                                      

                                      【讨论】:

                                        【解决方案26】:

                                        SQLServer2012 中的简单查询:

                                        选择日期(('20-05-1951 22:00:00'))

                                        我测试了很多日期,它总是返回正确的结果

                                        【讨论】:

                                        • SELECT DAY(CAST('1951-05-20' AS DATE)) 返回 20,这是日期的日期部分。它不返回 5 月份的天数。
                                        【解决方案27】:

                                        选择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())))

                                        用 getdate 替换任何日期以获得该特定日期的月份数

                                        【讨论】:

                                          【解决方案28】:
                                          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
                                          

                                          【讨论】:

                                          • 您好,欢迎来到 SO!尽管代码本身可能会说话,但提供一些细节将有助于提高您的答案质量!
                                          【解决方案29】:
                                          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)))
                                          

                                          【讨论】:

                                            猜你喜欢
                                            • 2019-01-16
                                            • 2020-01-12
                                            • 1970-01-01
                                            • 1970-01-01
                                            • 2013-08-16
                                            • 1970-01-01
                                            • 1970-01-01
                                            • 2022-08-16
                                            • 1970-01-01
                                            相关资源
                                            最近更新 更多