[转载]SQL Server时间算法总结 – Face Code,Brain bloom – 博客园.
1: DECLARE @Date DATETIME
2: SET @Date=GETDATE()
3: --前一天,给定日期的前一天
4: SELECT DATEADD(DAY,-1,@Date) AS '前一天'
5: --后一天,给定日期的后一天
6: SELECT DATEADD(DAY,1,@Date) AS '后一天'
7: GO
8:
9:
10: --月初,计算给定日期所在月的第一天
11: --这个计算的技巧是先计算当前日期到“1900-01-01”的时间间隔数,然后把它加到“1900-01-01”上来获得特殊的日期,这个技巧可以用---来计算很多不同的日期。
12: DECLARE @Date DATETIME
13: SET @Date=GETDATE()
14: SELECT DATEADD(MONTH,DATEDIFF(MONTH,'1900-01-01',@Date),'1900-01-01') AS '所在月的第一天'
15: --精简算法,根据SQL Server的时间表示方式可知,'1900-01-01' 可以用0代替
16: SELECT DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0) AS '所在月的第一天'
17: --上面两种算法精确到天 时分秒均为00:00:00.000
18: --下面算法课以保留时分秒
19: --思路:用给定日期减去月第一天与给定日期差的天数
20: SELECT DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)
21: GO
22:
23: --月末,计算给定日期所在月的最后一天
24: DECLARE @Date DATETIME
25: SET @Date=GETDATE()
26: --思路:当前月的下一月1号在减1天
27: SELECT DATEADD(DAY,-1,DATEADD(MONTH,1+DATEDIFF(MONTH,'1900-01-01',@Date),'1900-01-01')) AS '所在月的最一天'
28: SELECT DATEADD(MONTH,1+DATEDIFF(MONTH,'1900-01-01',@Date),'1900-01-01')-1 AS '所在月的最一天'
29: --1900-01-01 用0代替
30: SELECT DATEADD(DAY,-1,DATEADD(MONTH,1+DATEDIFF(MONTH,0,@Date),0)) AS '所在月的最一天'
31: SELECT DATEADD(MONTH,1+DATEDIFF(MONTH,0,@Date),0)-1 AS '所在月的最一天'
32: --思路:与月初计算思路相同
33: SELECT DATEADD(MONTH,DATEDIFF(MONTH,'1989-12-31',@Date),'1989-12-31') AS '所在月的最一天'
34: --精简算法,'1989-12-31' 用-1代替
35: SELECT DATEADD(MONTH,DATEDIFF(MONTH,-1,@Date),-1) AS '所在月的最一天'
36: --保留时分秒的算法
37: SELECT DATEADD(DAY,-1,DATEADD(MONTH,1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)))
38: GO
39:
40: --其他月计算
41:
42: --计算给定日期所在月的上月第一天
43: DECLARE @Date DATETIME
44: SET @Date=GETDATE()
45: --当前月第一天减去一个月
46: SELECT DATEADD(MONTH,-1,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0)) AS '上月第一天'
47: --简化
48: SELECT DATEADD(MONTH,DATEDIFF(MONTH,0,@Date)-1,0) AS '上月第一天'
49: --另一种当前月第一天算法
50: SELECT DATEADD(MONTH,-1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)) '上月第一天'
51: GO
52:
53: --计算给定日期所在月的上月最后一天
54: DECLARE @Date DATETIME
55: SET @Date=GETDATE()
56: --当前月第一天减去一天
57: SELECT DATEADD(DAY,-1,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0)) AS '上月最后一天'
58: --另一种当前月第一天算法
59: SELECT DATEADD(DAY,-1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)) '上月最后一天'
60: SELECT DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)-1 '上月最后一天'
61: --另一种算法,不能用当前月的最后一天加一个月,因为当前月可能是30天。
62: --例如 SELECT DATEADD(MONTH,1,'2010-06-30') --结果是2010-07-30而不是2010-07-31,
63: --这也是月末算法采用下月第一天减1天计算的原因
64: --但是如果计算月是31天择无此问题
65: --例如 SELECT DATEADD(MONTH,1,'2010-05-31') --结果是2010-06-30
66: --因此下面算法是正确的,-1 表示'1899-12-31 00:00:00.000'-- SELECT CONVERT(DATETIME,-1)
67: SELECT DATEADD(MONTH,DATEDIFF(MONTH,-1,@Date)-1,-1)
68: --另一种当前月算法
69: SELECT DATEADD(DAY,-1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)) '上月最后一天'
70: --简化
71: SELECT DATEADD(DAY,0-DATEPART(DAY,@Date),@Date) '上月最后一天'
72: GO
73:
74: --计算给定日期所在月的下月第一天
75: DECLARE @Date DATETIME
76: SET @Date=GETDATE()
77: --当前月第一天加一个月
78: SELECT DATEADD(MONTH,1,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0)) AS '下月第一天'
79: --简化
80: SELECT DATEADD(MONTH,DATEDIFF(MONTH,0,@Date)+1,0) AS '下月第一天'
81: --另一种当前月第一天算法
82: SELECT DATEADD(MONTH,1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)) '下月第一天'
83: GO
84:
85: --计算给定日期所在月的下月最后一天
86: DECLARE @Date DATETIME
87: SET @Date=GETDATE()
88: --当前月第一天加2个月再减去1天
89: SELECT DATEADD(DAY,-1,DATEADD(MONTH,2,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0))) AS '下月最后一天'
90: --简化
91: SELECT DATEADD(DAY,-1,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date)+2,0)) AS '下月最后一天'
92: SELECT DATEADD(MONTH,DATEDIFF(MONTH,0,@Date)+2,0)-1 AS '下月最后一天'
93: --另一种算法
94: SELECT DATEADD(MONTH,DATEDIFF(MONTH,-1,@Date)+1,-1) '下月最后一天'
95: --另一种当前月第一天算法
96: SELECT DATEADD(DAY,-1,DATEADD(MONTH,2,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date))) '下月最后一天'
97: GO
98:
99: --所在星期的第一天,计算给定日期所在星期的第1天(星期日为第一天)
100: DECLARE @Date DATETIME
101: SET @Date= GETDATE()
102: --与SQL Server语言版本相关的算法
103: --思路:当前日期+星期日(每周的第1天)与当前日期的差的天数
104: --DATEPART(WEEKDAY,DATE)的返回值与@@DATEFIRST相关
105: SET DATEFIRST 7 -- 或者设置为美国英语SET LANGUAGE us_english; (星期日为第一天)
106: SELECT DATEADD(WEEKDAY,1-DATEPART(WEEKDAY,@Date),@Date) AS '所在星期的第一天,星期日'
107: --星期日,与SQL Server语言版本或@@DATEFIRST无关
108: --'1989-12-31' 是星期日,'1989-12-31' 再加上(当前日期与1989-12-31差的星期数)个星期
109: SELECT DATEADD(WEEK,DATEDIFF(WEEK,-1,@Date),-1) AS '所在星期的星期日'
110: --或者
111: SELECT DATEADD(WEEK,DATEDIFF(WEEK,6,@Date),6) AS '所在星期的星期日'
112: GO
113:
114:
115: --所在星期的第二天,计算给定日期所在星期的第2天(星期日为第一天)
116: DECLARE @Date DATETIME
117: SET @Date= GETDATE()
118: --思路:当前日期+星期一(每周的第2天)与当前日期的差的天数
119: --DATEPART(WEEKDAY,DATE)的返回值与@@DATEFIRST相关
120: SET DATEFIRST 7 -- 或者设置为美国英语SET LANGUAGE us_english; (星期日为第一天)
121: SELECT DATEADD(DAY,2-DATEPART(WEEKDAY,@Date),@Date) AS '所在星期的第二天,星期一'
122: --星期一,与SQL Server语言版本或@@DATEFIRST无关
123: --'1900-01-01' 是星期一,'1900-01-01' 再加上(当前日期与1900-01-01差的星期数)个星期
124: SELECT DATEADD(WEEK,DATEDIFF(WEEK,0,@Date),0) AS '所在星期的星期一'
125: GO
126:
127: --上个星期第一天,计算给定日期所在星期的上一个星期日(星期日为第一天)
128: DECLARE @Date DATETIME
129: SET @Date= GETDATE()
130: --思路:当前日志所在星期的星期日再减1周
131: --DATEPART(WEEKDAY,DATE)的返回值与@@DATEFIRST相关
132: SET DATEFIRST 7 -- 或者设置为美国英语SET LANGUAGE us_english; (星期日为第一天)
133: SELECT DATEADD(WEEK,-1,DATEADD(DAY,1-DATEPART(WEEKDAY,@Date),@Date)) AS '上个星期第一天,星期日'
134: --一周等于7天
135: SELECT DATEADD(DAY,-7,DATEADD(DAY,1-DATEPART(WEEKDAY,@Date),@Date)) AS '上个星期第一天,星期日'
136: --简化
137: SELECT DATEADD(DAY,-6-DATEPART(WEEKDAY,@Date),@Date) AS '上个星期第一天,星期日'
138: --上个星期日,与SQL Server语言版本或@@DATEFIRST无关
139: SELECT DATEADD(WEEK,-1+DATEDIFF(WEEK,-1,@Date),-1) AS '上个星期日'
140: --或者
141: SELECT DATEADD(WEEK,DATEDIFF(WEEK,6,@Date),-1) AS '上个星期日'
142: GO
143:
144:
145: --下个星期第一天,计算给定日期所在星期的下一个星期日(星期日为第一天)
146: DECLARE @Date DATETIME
147: SET @Date= GETDATE()
148: --思路:当前日志所在星期的星期日再加1周
149: --DATEPART(WEEKDAY,DATE)的返回值与@@DATEFIRST相关
150: SET DATEFIRST 7 -- 或者设置为美国英语SET LANGUAGE us_english; (星期日为第一天)
151: SELECT DATEADD(WEEK,1,DATEADD(DAY,1-DATEPART(WEEKDAY,@Date),@Date)) AS '下个星期第一天,星期日'
152: --一周等于7天
153: SELECT DATEADD(DAY,7,DATEADD(DAY,1-DATEPART(WEEKDAY,@Date),@Date)) AS '下个星期第一天,星期日'
154: --简化
155: SELECT DATEADD(DAY,8-DATEPART(WEEKDAY,@Date),@Date) AS '下个星期第一天,星期日'
156: --下个星期日,与SQL Server语言版本或@@DATEFIRST无关
157: SELECT DATEADD(WEEK,1+DATEDIFF(WEEK,-1,@Date),-1) AS '下个星期日'
158: --或者
159: SELECT DATEADD(WEEK,DATEDIFF(WEEK,-1,@Date),6) AS '下个星期日'
160: GO
161:
162: --判断给定日期是星期几
163: DECLARE @Date DATETIME
164: SET @Date= GETDATE()
165: --DATEPART(WEEKDAY,DATE)的返回值与@@DATEFIRST相关
166: SET DATEFIRST 7 -- 或者设置为美国英语SET LANGUAGE us_english; (星期日为第一天)
167: SELECT DATEPART(WEEKDAY,@Date) --返回值 1-星期日,2-星期一,3-星期二......7-星期六
168: --上面算法与SQL 语言版本或 @@DATEFIRST 相关
169: --下面算法与SQL Server语言版本或@@DATEFIRST无关
170: SELECT DATENAME(WEEKDAY,@Date) '星期'
171: GO
172:
173:
174: --年度计算
175: DECLARE @Date DATETIME
176: SET @Date=GETDATE()
177: --年初,计算给定日期所在年的第一天
178: SELECT DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),0) AS '所在年的第一天'
179: --年末,计算给定日期所在年的最后一天
180: SELECT DATEADD(YEAR,DATEDIFF(YEAR,-1,@Date),-1) AS '所在年的最后一天'
181: --上一年年初,计算给定日期所在年的上一年的第一天
182: SELECT DATEADD(YEAR,DATEDIFF(YEAR,-0,@Date)-1,0) AS '所在年的上一年的第一天'
183: --上一年年末,计算给定日期所在年的上一年的最后一天
184: SELECT DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),-1) AS '所在年的上一年的最后一天'
185: --下一年年初,计算给定日期所在年的下一年的第一天
186: SELECT DATEADD(YEAR,1+DATEDIFF(YEAR,0,@Date),0) AS '所在年的下一年的第一天'
187: --下一年年末,计算给定日期所在年的下一年的最后一天
188: SELECT DATEADD(YEAR,1+DATEDIFF(YEAR,-1,@Date),-1) AS '所在年的下一年的最后一天'
189: GO
190:
191: --季度计算
192: DECLARE @Date DATETIME
193: SET @Date=GETDATE()
194: --季度初,计算给定日期所在季度的第一天
195: SELECT DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date),0) AS '当前季度的第一天'
196: --季度末,计算给定日期所在季度的最后一天
197: SELECT DATEADD(QUARTER,1+DATEDIFF(QUARTER,0,@Date),-1) AS '当前季度的最后一天'
198: --上个季度初
199: SELECT DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date)-1,0) AS '当前季度的上个季度初'
200: --上个季度末
201: SELECT DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date),-1) AS '当前季度的上个季度末'
202: --下个季度初
203: SELECT DATEADD(QUARTER,1+DATEDIFF(QUARTER,0,@Date),0) AS '当前季度的下个季度初'
204: --下个季度末
205: SELECT DATEADD(QUARTER,2+DATEDIFF(QUARTER,0,@Date),-1) AS '当前季度的下个季度末'
206: GO
207:
208: --计算给定日期所在月的天数
209: DECLARE @Date DATETIME;
210: SET @Date = GETDATE()
211: --本月度第一天与下月度第一天所差的天数
212: SELECT DATEDIFF(DAY,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0),DATEADD(MONTH,1+DATEDIFF(MONTH,0,@Date),0))
213: --借助变量简化
214: SELECT @Date = DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0) --本月度第一天
215: SELECT DATEDIFF(DAY,@Date,DATEADD(MONTH,1,@Date))
216: --另一种思路:给定月最后一天的日期,记为本月天数
217: SELECT DAY(DATEADD(MONTH,DATEDIFF(MONTH,-1,@Date),-1))
218: GO
219:
220: --计算给定日期所在季度的天数
221: DECLARE @Date DATETIME;
222: SET @Date = GETDATE()
223: --本季度第一天与下季度第一天所差的天数
224: SELECT DATEDIFF(DAY,DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date),0),DATEADD(QUARTER,1+DATEDIFF(QUARTER,0,@Date),0))
225: --借助变量简化
226: SELECT @Date = DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date),0) --本季度第一天
227: SELECT DATEDIFF(DAY,@Date,DATEADD(QUARTER,1,@Date))
228: GO
229:
230: --计算给定日期所在年度的天数
231: DECLARE @Date DATETIME;
232: SET @Date = GETDATE()
233: --本年度第一天与下年度第一天所差的天数
234: SELECT DATEDIFF(DAY,DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),0),DATEADD(YEAR,1+DATEDIFF(YEAR,0,@Date),0))
235: --借助变量简化
236: SELECT @Date = DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),0) --本年度第一天
237: SELECT DATEDIFF(DAY,@Date,DATEADD(YEAR,1,@Date))
238: GO
239:
240: --判断给定日期所在年是否闰年
241: --根据全年总天数判断
242: DECLARE @Date DATETIME;
243: SET @Date = GETDATE()
244: SELECT CASE DATEDIFF(DAY,DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),0),DATEADD(YEAR,1+DATEDIFF(YEAR,0,@Date),0))
245: WHEN 365 THEN '平年' ELSE '闰年' END
246: --根据二月天数判断
247: --给日期的上一年最后一天加2个月,即为当年2月最后一天
248: SELECT CASE DAY(DATEADD(MONTH,2,DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),-1))) WHEN 28 THEN '平年' ELSE '闰年' END
249: GO
250:
251: --计算给定日期是当年的第几天
252: DECLARE @Date DATETIME;
253: SET @Date = GETDATE()
254: SELECT DATEPART(DAYOFYEAR,@Date) [DayOfYear];
255: SELECT DATENAME(DAYOFYEAR,@Date) [DayOfYear];
256: --另一种思路:当前日期与上年最后一天差的天数
257: SELECT DATEDIFF(DAY,DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),-1),@Date)[DayOfYear]
258: GO
259:
260: --计算给定日期是当年的第几周
261: DECLARE @Date DATETIME;
262: SET @Date = GETDATE()
263: SELECT DATEPART(WEEK,@Date) [WeekOfYear]; --返回int型
264: SELECT DATENAME(WEEK,@Date) [WeekOfYear]; --返回varchar型
265: GO
266:
267: --计算给定日期是当年的第几月
268: DECLARE @Date DATETIME;
269: SET @Date = GETDATE()
270: SELECT DATEPART(MONTH,@Date) [MonthOfYear]; --返回int型
271: SELECT DATENAME(MONTH,@Date) [MonthOfYear]; --返回varchar型
272: SELECT MONTH(@Date) [MonthOfYear];--返回int型
273: GO
274:
275: --计算给定日期是当年的第几季度
276: DECLARE @Date DATETIME;
277: SET @Date = GETDATE()
278: SELECT DATEPART(QUARTER,@Date) [QuarterOfYear]; --返回int型
279: SELECT DATENAME(QUARTER,@Date) [QuarterOfYear]; --返回varchar型
280: GO
281:
282: --计算给定日期是当月的第几周
283: DECLARE @Date DATETIME;
284: SET @Date = GETDATE()
285: --思路,给定日期是当年的第几周-给定日期所在月第一天是当年的第几周
286: SELECT DATEPART(WEEK,@Date)-DATEPART(WEEK,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0))+1 [WeekOfMonth]
287: SELECT DATEPART(WEEK,@Date)-DATEPART(WEEK,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date))+1 [WeekOfMonth]
288: GO
289:
290: --计算给定日期所在月的第一个星期一是哪天
291: DECLARE @Date DATETIME;
292: SET @Date = GETDATE()
293: --思路,1900-01-01(星期一)加上(给定日志所在月的月6号与1900-01-01差的周数)个周
294: --为什么不选7号?如果是7号,那么7好恰好是星期日的话,第一个周一就会算到8号。
295: --为什么不选5号?如果5号是星期六,那么周一就跑到上月了。小于5号与这个道理一样。
296: SELECT DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(DAY,6-DATEPART(DAY,@Date),@Date)),0) '所在月的第一个星期一'
297: SELECT DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(DAY,6-DATEPART(DAY,@Date),@Date)),7) '所在月的第二个星期一'
298: SELECT DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(DAY,6-DATEPART(DAY,@Date),@Date)),1) '所在月的第一个星期二'
299: SELECT DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(DAY,6-DATEPART(DAY,@Date),@Date)),8) '所在月的第二个星期二'
300: GO