首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 日期計算完全指南:DATEADD/DATEDIFF 核心技巧與常用日期邊界公式

     編輯:關於SqlServer

核心函數回顧

  • DATEDIFF(datepart, start, end):回傳兩日期間的日期部件差值(整數)。
  • DATEADD(datepart, number, date):在日期上加減指定間隔,回傳新日期。

關鍵思維:**以「1900-01-01 00:00:00.000」為基準點,計算間隔數,再加減得到目標日期。**

常用日期邊界公式速查表

需求T-SQL 公式說明
本月第一天DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)間隔月數加到基準點
本週一(週一為週首)DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()), 0)依 @@DATEFIRST 決定週首,預設週日
今年第一天DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)
本季第一天DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE()), 0)
今天零點(去除時間)DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0)等同 CAST(GETDATE() AS DATE) (SQL 2008+)
上月最後一天DATEADD(MILLISECOND, -3, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))本月第一天 - 3ms(SQL Server 精度 3.33ms)
去年最後一天DATEADD(MILLISECOND, -3, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0))
本月最後一天DATEADD(MILLISECOND, -3, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())+1, 0))下月第一天 - 3ms
今年最後一天DATEADD(MILLISECOND, -3, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE())+1, 0))
本月第一個週一DATEADD(WEEK, DATEDIFF(WEEK, 0, DATEADD(DAY, 6-DATEPART(DAY, GETDATE()), GETDATE())), 0)以本月 6 號為基準推算

進階應用:動態日期範圍查詢


-- 最近 30 天
WHERE create_date >= DATEADD(DAY, -30, CAST(GETDATE() AS DATE))

-- 本月迄今
WHERE create_date >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)

-- 上月完整範圍
WHERE create_date >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0)
  AND create_date <  DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)

-- 本季度
WHERE create_date >= DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE()), 0)
  AND create_date <  DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE())+1, 0)

附錄:其他實用日期處理

1. 取得某月天數


-- 方法 A:下月第一天 - 本月第一天
DECLARE @m INT = 2; -- 二月
SELECT DATEDIFF(DAY, 
  DATEADD(MONTH, @m-1, DATEADD(YEAR, DATEDIFF(YEAR,0,GETDATE()),0)),
  DATEADD(MONTH, @m,   DATEADD(YEAR, DATEDIFF(YEAR,0,GETDATE()),0))
);

-- 方法 B:用本月最後一天的 DAY()
SELECT DAY(DATEADD(MILLISECOND, -3, 
  DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())+1, 0)));

2. 判斷閏年


-- 方法 A:二月天數
SELECT CASE DAY(DATEADD(MONTH, 2, 
  DATEADD(MILLISECOND, -3, DATEADD(YEAR, DATEDIFF(YEAR,0,GETDATE()),0)))) 
  WHEN 28 THEN '平年' ELSE '閏年' END;

-- 方法 B:直接計算二月天數
SELECT CASE DATEDIFF(DAY, 
  CAST(YEAR(GETDATE()) AS VARCHAR)+'-02-01',
  DATEADD(MONTH, 1, CAST(YEAR(GETDATE()) AS VARCHAR)+'-02-01'))
  WHEN 28 THEN '平年' ELSE '閏年' END;

3. 顯示星期幾


SELECT DATENAME(WEEKDAY, GETDATE()); -- 如 'Monday'

4. 季度天數


DECLARE @q_start SMALLDATETIME = DATEADD(QUARTER, DATEDIFF(QUARTER,0,GETDATE()),0);
SELECT DATEDIFF(DAY, @q_start, DATEADD(QUARTER, 1, @q_start));

版本差異提醒

  • SQL Server 2008+ 引入 DATE, TIME, DATETIME2, DATETIMEOFFSET 型別,CAST(GETDATE() AS DATE) 取代去除時間的技巧。
  • EOMONTH(start_date [, month_offset]) (2012+) 直接取得月份最後一天:EOMONTH(GETDATE())、EOMONTH(GETDATE(), -1) (上月)。
  • DATETRUNC(datepart, date) (2022+) 直接截斷至指定精度:DATETRUNC(MONTH, GETDATE()) 即本月第一天。

最佳實踐建議

  1. 優先使用新版內建函數(EOMONTH, DATETRUNC),可讀性高、效能佳。
  2. 日期範圍查詢用「半開區間」:WHERE dt >= @start AND dt < @end_next,避免時間精度邊界問題。
  3. 注意 @@DATEFIRST:影響 WEEK 計算,跨環境部署時明確 SET DATEFIRST 或用不依賴週首的邏輯。
  4. 統一時區處理:資料庫儲存 UTC,應用層轉換顯示時區,避免夏令時/跨時區混亂。

掌握 DATEADD/DATEDIFF 間隔思維,配合新版便利函數,能優雅解決所有日期邊界計算需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved