有關日期

SET LANGUAGE對日期處理的影響示例

 

--以下示例演示了在不同的語言環境(SET LANGUAGE)下,DATENAME與CONVERT函數的不同結果。
USE master

--設置會話的語言環境爲: English
SET LANGUAGE N'English'
SELECT
   
DATENAME(Month,GETDATE()) AS [Month],
   
DATENAME(Weekday,GETDATE()) AS [Weekday],
   
CONVERT(varchar,GETDATE(),109) AS [CONVERT]
/*--結果:
Month    Weekday   CONVERT
------------- -------------- -------------------------------
March    Tuesday   Mar 15 2005  8:59PM
--
*/

--設置會話的語言環境爲: 簡體中文
SET LANGUAGE N'簡體中文'
SELECT
   
DATENAME(Month,GETDATE()) AS [Month],
   
DATENAME(Weekday,GETDATE()) AS [Weekday],
   
CONVERT(varchar,GETDATE(),109) AS [CONVERT]
/*--結果
Month    Weekday    CONVERT
------------- --------------- -----------------------------------------
05       星期四     05 19 2005  2:49:20:607PM
--
*/

 

日期格式化處理

 

DECLARE @dt datetime
SET @dt=GETDATE()

--1.短日期格式:yyyy-m-d
SELECT REPLACE(CONVERT(varchar(10),@dt,120),N'-0','-')

--2.長日期格式:yyyy年mm月dd日
--
A. 方法1
SELECT STUFF(STUFF(CONVERT(char(8),@dt,112),5,0,N''),8,0,N'')+N''
--B. 方法2
SELECT DATENAME(Year,@dt)+N''+DATENAME(Month,@dt)+N''+DATENAME(Day,@dt)+N''

--3.長日期格式:yyyy年m月d日
SELECT DATENAME(Year,@dt)+N''+CAST(DATEPART(Month,@dt) AS varchar)+N''+DATENAME(Day,@dt)+N''

--4.完整日期+時間格式:yyyy-mm-dd hh:mi:ss:mmm
SELECT CONVERT(char(11),@dt,120)+CONVERT(char(12),@dt,114)

 

日期推算處理

 

DECLARE @dt datetime
SET @dt=GETDATE()

DECLARE @number int
SET @number=3

--1.指定日期該年的第一天或最後一天
--
A. 年的第一天
SELECT CONVERT(char(5),@dt,120)+'1-1'

--B. 年的最後一天
SELECT CONVERT(char(5),@dt,120)+'12-31'


--2.指定日期所在季度的第一天或最後一天
--
A. 季度的第一天
SELECT CONVERT(datetime,
   
CONVERT(char(8),
       
DATEADD(Month,
           
DATEPART(Quarter,@dt)*3-Month(@dt)-2,
           
@dt),
       
120)+'1')

--B. 季度的最後一天(CASE判斷法)
SELECT CONVERT(datetime,
   
CONVERT(char(8),
       
DATEADD(Month,
           
DATEPART(Quarter,@dt)*3-Month(@dt),
           
@dt),
       
120)
   
+CASE WHEN DATEPART(Quarter,@dt) in(1,4)
       
THEN '31'ELSE '30' END)

--C. 季度的最後一天(直接推算法)
SELECT DATEADD(Day,-1,
   
CONVERT(char(8),
       
DATEADD(Month,
           
1+DATEPART(Quarter,@dt)*3-Month(@dt),
           
@dt),
       
120)+'1')


--3.指定日期所在月份的第一天或最後一天
--
A. 月的第一天
SELECT CONVERT(datetime,CONVERT(char(8),@dt,120)+'1')

--B. 月的最後一天
SELECT DATEADD(Day,-1,CONVERT(char(8),DATEADD(Month,1,@dt),120)+'1')

--C. 月的最後一天(容易使用的錯誤方法)
SELECT DATEADD(Month,1,DATEADD(Day,-DAY(@dt),@dt))


--4.指定日期所在周的任意一天
SELECT DATEADD(Day,@number-DATEPART(Weekday,@dt),@dt)


--5.指定日期所在周的任意星期幾
--
A.  星期天做爲一週的第1天
SELECT DATEADD(Day,@number-(DATEPART(Weekday,@dt)+@@DATEFIRST-1)%7,@dt)

--B.  星期一做爲一週的第1天
SELECT DATEADD(Day,@number-(DATEPART(Weekday,@dt)+@@DATEFIRST-2)%7-1,@dt)


特殊日期加減函數

 

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_DateADD]') and xtype in (N'FN', N'IF', N'TF'))
   
drop function [dbo].[f_DateADD]
GO

/*--特殊日期加減函數

    對於日期指定部分的加減,使用DATEADD函數就可以輕鬆實現。
    在實際的處理中,還有一種比較另類的日期加減處理
    就是在指定的日期中,加上(或者減去)多個日期部分
    比如將2005年3月11日,加上1年3個月11天2小時。
    對於這種日期的加減處理,DATEADD函數的力量就顯得有點不夠。

    本函數實現這樣格式的日期字符串加減處理:
    y-m-d h:m:s.m | -y-m-d h:m:s.m
    說明:
    要加減的日期字符輸入方式與日期字符串相同。日期與時間部分用空格分隔
    最前面一個字符如果是減號(-)的話,表示做減法處理,否則做加法處理。
    如果日期字符只包含數字,則視爲日期字符中,僅包含天的信息。
--
*/

/*--調用示例

    SELECT dbo.f_DateADD(GETDATE(),'11:10')
--
*/

CREATE FUNCTION dbo.f_DateADD(
@Date     datetime,
@DateStr   varchar(23)
)
RETURNS datetime
AS
BEGIN
   
DECLARE @bz int,@s varchar(12),@i int

   
IF @DateStr IS NULL OR @Date IS NULL
       
OR(CHARINDEX('.',@DateStr)>0
           
AND @DateStr NOT LIKE '%[:]%[:]%.%')
       
RETURN(NULL)
   
IF @DateStr='' RETURN(@Date)

   
SELECT @bz=CASE
           
WHEN LEFT(@DateStr,1)='-' THEN -1
           
ELSE 1 END,
       
@DateStr=CASE
           
WHEN LEFT(@Date,1)='-'
           
THEN STUFF(RTRIM(LTRIM(@DateStr)),1,1,'')
           
ELSE RTRIM(LTRIM(@DateStr)) END

   
IF CHARINDEX(' ',@DateStr)>1
       
OR CHARINDEX('-',@DateStr)>1
       
OR(CHARINDEX('.',@DateStr)=0
           
AND CHARINDEX(':',@DateStr)=0)
   
BEGIN
       
SELECT @i=CHARINDEX(' ',@DateStr+' ')
            ,
@s=REVERSE(LEFT(@DateStr,@i-1))+'-'
            ,
@DateStr=STUFF(@DateStr,1,@i,'')
            ,
@i=0
       
WHILE @s>'' and @i<3
           
SELECT @Date=CASE @i
                   
WHEN 0 THEN DATEADD(Day,@bz*REVERSE(LEFT(@s,CHARINDEX('-',@s)-1)),@Date)
                   
WHEN 1 THEN DATEADD(Month,@bz*REVERSE(LEFT(@s,CHARINDEX('-',@s)-1)),@Date)
                   
WHEN 2 THEN DATEADD(Year,@bz*REVERSE(LEFT(@s,CHARINDEX('-',@s)-1)),@Date)
               
END,
               
@s=STUFF(@s,1,CHARINDEX('-',@s),''),
               
@i=@i+1               
   
END
   
IF @DateStr>''
   
BEGIN
       
IF CHARINDEX('.',@DateStr)>0
           
SELECT @Date=DATEADD(Millisecond
                    ,
@bz*STUFF(@DateStr,1,CHARINDEX('.',@DateStr),''),
                   
@Date),
               
@DateStr=LEFT(@DateStr,CHARINDEX('.',@DateStr)-1)+':',
               
@i=0
       
ELSE
           
SELECT @DateStr=@DateStr+':',@i=0
       
WHILE @DateStr>'' and @i<3
           
SELECT @Date=CASE @i
                   
WHEN 0 THEN DATEADD(Hour,@bz*LEFT(@DateStr,CHARINDEX(':',@DateStr)-1),@Date)
                   
WHEN 1 THEN DATEADD(Minute,@bz*LEFT(@DateStr,CHARINDEX(':',@DateStr)-1),@Date)
                   
WHEN 2 THEN DATEADD(Second,@bz*LEFT(@DateStr,CHARINDEX(':',@DateStr)-1),@Date)
               
END,
               
@DateStr=STUFF(@DateStr,1,CHARINDEX(':',@DateStr),''),
               
@i=@i+1
   
END

   
RETURN(@Date)
END
GO

查詢指定日期段內過生日的人員

 

--測試數據
DECLARE @t TABLE(ID int,Name varchar(10),Birthday datetime)
INSERT @t SELECT 1,'aa','1999-01-01'
UNION ALL SELECT 2,'bb','1996-02-29'
UNION ALL SELECT 3,'bb','1934-03-01'
UNION ALL SELECT 4,'bb','1966-04-01'
UNION ALL SELECT 5,'bb','1997-05-01'
UNION ALL SELECT 6,'bb','1922-11-21'
UNION ALL SELECT 7,'bb','1989-12-11'

DECLARE @dt1 datetime,@dt2 datetime

--查詢 2003-12-05 至 2004-02-28 生日的記錄
SELECT @dt1='2003-12-05',@dt2='2004-02-28'
SELECT * FROM @t
WHERE DATEADD(Year,DATEDIFF(Year,Birthday,@dt1),Birthday)
       
BETWEEN @dt1 AND @dt2
   
OR DATEADD(Year,DATEDIFF(Year,Birthday,@dt2),Birthday)
       
BETWEEN @dt1 AND @dt2
/*--結果
ID         Name       Birthday
---------------- ---------------- --------------------------
1           aa         1999-01-01 00:00:00.000
7           bb         1989-12-11 00:00:00.000
--
*/

--查詢 2003-12-05 至 2006-02-28 生日的記錄
SET @dt2='2006-02-28'
SELECT * FROM @t
WHERE DATEADD(Year,DATEDIFF(Year,Birthday,@dt1),Birthday)
       
BETWEEN @dt1 AND @dt2
   
OR DATEADD(Year,DATEDIFF(Year,Birthday,@dt2),Birthday)
       
BETWEEN @dt1 AND @dt2
/*--查詢結果
ID         Name       Birthday
---------------- ----------------- --------------------------
1           aa         1999-01-01 00:00:00.000
2           bb         1996-02-29 00:00:00.000
7           bb         1989-12-11 00:00:00.000
--
*/

 

生成日期列表的函數


if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_getdate]') and xtype in (N'FN', N'IF', N'TF'))
drop function [dbo].[f_getdate]
GO

/*--生成日期列表
   
    生成指定年份的工作日/休息日列表

--鄒建 2003.12(引用請保留此信息)--
*/

/*--調用示例

    --查詢 2003 年的工作日列表
    SELECT * FROM dbo.f_getdate(2003,0)
   
    --查詢 2003 年的休息日列表
    SELECT * FROM dbo.f_getdate(2003,1)

    --查詢 2003 年全部日期列表
    SELECT * FROM dbo.f_getdate(2003,NULL)
--
*/
CREATE FUNCTION dbo.f_getdate(
@year int,    --要查詢的年份
@bz bit       --@bz=0 查詢工作日,@bz=1 查詢休息日,@bz IS NULL 查詢全部日期
)RETURNS @re TABLE(id int identity(1,1),Date datetime,Weekday nvarchar(3))
AS
BEGIN
   
DECLARE @tb TABLE(ID int IDENTITY(0,1),Date datetime)
   
INSERT INTO @tb(Date) SELECT TOP 366 DATEADD(Year,@YEAR-1900,'1900-1-1')
   
FROM sysobjects a ,sysobjects b
   
UPDATE @tb SET Date=DATEADD(DAY,id,Date)
   
DELETE FROM @tb WHERE Date>DATEADD(Year,@YEAR-1900,'1900-12-31')
   
   
IF @bz=0
       
INSERT INTO @re(Date,Weekday)
       
SELECT Date,DATENAME(Weekday,Date)
       
FROM @tb
       
WHERE (DATEPART(Weekday,Date)+@@DATEFIRST-1)%7 BETWEEN 1 AND 5
   
ELSE IF @bz=1
       
INSERT INTO @re(Date,Weekday)
       
SELECT Date,DATENAME(Weekday,Date)
       
FROM @tb
       
WHERE (DATEPART(Weekday,Date)+@@DATEFIRST-1)%7 IN (0,6)
   
ELSE
       
INSERT INTO @re(Date,Weekday)
       
SELECT Date,DATENAME(Weekday,Date)
       
FROM @tb
       
   
RETURN
END
GO


/*====================================================================*/

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_getdate]') and xtype in (N'FN', N'IF', N'TF'))
drop function [dbo].[f_getdate]
GO

/*--生成列表

    生成指定日期段的日期列表

--鄒建 2005.03(引用請保留此信息)--
*/

/*--調用示例

    --查詢工作日
    SELECT * FROM dbo.f_getdate('2005-1-3','2005-4-5',0)
   
    --查詢休息日
    SELECT * FROM dbo.f_getdate('2005-1-3','2005-4-5',1)
   
    --查詢全部日期
    SELECT * FROM dbo.f_getdate('2005-1-3','2005-4-5',NULL)
--
*/

CREATE FUNCTION dbo.f_getdate(
@begin_date Datetime--要查詢的開始日期
@end_date Datetime,    --要查詢的結束日期
@bz bit                --@bz=0 查詢工作日,@bz=1 查詢休息日,@bz IS NULL 查詢全部日期
)RETURNS @re TABLE(id int identity(1,1),Date datetime,Weekday nvarchar(3))
AS
BEGIN
   
DECLARE @tb TABLE(ID int IDENTITY(0,1),a bit)
   
INSERT INTO @tb(a) SELECT TOP 366 0
   
FROM sysobjects a ,sysobjects b
   
   
IF @bz=0
       
WHILE @begin_date<=@end_date
       
BEGIN
           
INSERT INTO @re(Date,Weekday)
           
SELECT Date,DATENAME(Weekday,Date)
           
FROM(
               
SELECT Date=DATEADD(Day,ID,@begin_date)
               
FROM @tb               
            )a
WHERE Date<=@end_date
               
AND (DATEPART(Weekday,Date)+@@DATEFIRST-1)%7 BETWEEN 1 AND 5
           
SET @begin_date=DATEADD(Day,366,@begin_date)
       
END
   
ELSE IF @bz=1
       
WHILE @begin_date<=@end_date
       
BEGIN
           
INSERT INTO @re(Date,Weekday)
           
SELECT Date,DATENAME(Weekday,Date)
           
FROM(
               
SELECT Date=DATEADD(Day,ID,@begin_date)
               
FROM @tb               
            )a
WHERE Date<=@end_date
               
AND (DATEPART(Weekday,Date)+@@DATEFIRST-1)%7 in(0,6)
           
SET @begin_date=DATEADD(Day,366,@begin_date)
       
END
   
ELSE
       
WHILE @begin_date<=@end_date
       
BEGIN
           
INSERT INTO @re(Date,Weekday)
           
SELECT Date,DATENAME(Weekday,Date)
           
FROM(
               
SELECT Date=DATEADD(Day,ID,@begin_date)
               
FROM @tb               
            )a
WHERE Date<=@end_date
           
SET @begin_date=DATEADD(Day,366,@begin_date)
       
END

   
RETURN
END
GO

 

工作日處理函數(標準節假日)

 

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_WorkDay]') and xtype in (N'FN', N'IF', N'TF'))
drop function [dbo].[f_WorkDay]
GO

--計算兩個日期相差的工作天數
CREATE FUNCTION f_WorkDay(
@dt_begin datetime--計算的開始日期
@dt_end  datetime    --計算的結束日期
)RETURNS int
AS
BEGIN
   
DECLARE @workday int,@i int,@bz bit,@dt datetime
   
IF @dt_begin>@dt_end
       
SELECT @bz=1,@dt=@dt_begin,@dt_begin=@dt_end,@dt_end=@dt
   
ELSE
       
SET @bz=0
   
SELECT @i=DATEDIFF(Day,@dt_begin,@dt_end)+1,
       
@workday=@i/7*5,
       
@dt_begin=DATEADD(Day,@i/7*7,@dt_begin)
   
WHILE @dt_begin<=@dt_end
   
BEGIN
       
SELECT @workday=CASE
           
WHEN (@@DATEFIRST+DATEPART(Weekday,@dt_begin)-1)%7 BETWEEN 1 AND 5
           
THEN @workday+1 ELSE @workday END,
           
@dt_begin=@dt_begin+1
   
END
   
RETURN(CASE WHEN @bz=1 THEN -@workday ELSE @workday END)
END
GO



/*=================================================================*/

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_WorkDayADD]') and xtype in (N'FN', N'IF', N'TF'))
drop function [dbo].[f_WorkDayADD]
GO

--在指定日期上,增加指定工作天數後的日期
CREATE FUNCTION f_WorkDayADD(
@date    datetime--基礎日期
@workday int       --要增加的工作日數
)RETURNS datetime
AS
BEGIN
   
DECLARE @bz int
   
--增加整週的天數
    SELECT @bz=CASE WHEN @workday<0 THEN -1 ELSE 1 END
        ,
@date=DATEADD(Week,@workday/5,@date)
        ,
@workday=@workday%5
   
--增加不是整週的工作天數
    WHILE @workday<>0
       
SELECT @date=DATEADD(Day,@bz,@date),
           
@workday=CASE WHEN (@@DATEFIRST+DATEPART(Weekday,@date)-1)%7 BETWEEN 1 AND 5
               
THEN @workday-@bz ELSE @workday END
   
--避免處理後的日期停留在非工作日上
    WHILE (@@DATEFIRST+DATEPART(Weekday,@date)-1)%7 in(0,6)
       
SET @date=DATEADD(Day,@bz,@date)
   
RETURN(@date)
END

工作日處理函數(自定義節假日)

if exists (select * from dbo.sysobjects where id = object_id(N'[tb_Holiday]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [tb_Holiday]
GO

--定義節假日表
CREATE TABLE tb_Holiday(
HDate
smalldatetime primary key clustered, --節假日期
Name nvarchar(50) not null)             --假日名稱
GO

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_WorkDay]') and xtype in (N'FN', N'IF', N'TF'))
drop function [dbo].[f_WorkDay]
GO

--計算兩個日期之間的工作天數
CREATE FUNCTION f_WorkDay(
@dt_begin datetime--計算的開始日期
@dt_end  datetime   --計算的結束日期
)RETURNS int
AS
BEGIN
   
IF @dt_begin>@dt_end
       
RETURN(DATEDIFF(Day,@dt_begin,@dt_end)
           
+1-(
               
SELECT COUNT(*) FROM tb_Holiday
               
WHERE HDate BETWEEN @dt_begin AND @dt_end))
   
RETURN(-(DATEDIFF(Day,@dt_end,@dt_begin)
       
+1-(
           
SELECT COUNT(*) FROM tb_Holiday
           
WHERE HDate BETWEEN @dt_end AND @dt_begin)))
END
GO

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_WorkDayADD]') and xtype in (N'FN', N'IF', N'TF'))
drop function [dbo].[f_WorkDayADD]
GO

--在指定日期上增加工作天數
CREATE FUNCTION f_WorkDayADD(
@date    datetime--基礎日期
@workday int       --要增加的工作日數
)RETURNS datetime
AS
BEGIN
   
IF @workday>0
       
WHILE @workday>0
           
SELECT @date=@date+@workday,@workday=count(*)
           
FROM tb_Holiday
           
WHERE HDate BETWEEN @date AND @date+@workday
   
ELSE
       
WHILE @workday<0
           
SELECT @date=@date+@workday,@workday=-count(*)
           
FROM tb_Holiday
           
WHERE HDate BETWEEN @date AND @date+@workday
   
RETURN(@date)
END

計算工作時間的函數

if exists (select * from dbo.sysobjects where id = object_id(N'[tb_worktime]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [tb_worktime]
GO

--定義工作時間表
CREATE TABLE tb_worktime(
    ID      
int identity(1,1) PRIMARY KEY,            --序號
    time_start smalldatetime,                            --工作的開始時間
    time_end  smalldatetime,                           --工作的結束時間
    worktime  AS DATEDIFF(Minute,time_start,time_end) --工作時數(分鐘)
)
GO

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_WorkTime]') and xtype in (N'FN', N'IF', N'TF'))
drop function [dbo].[f_WorkTime]
GO

--計算兩個日期之間的工作時間
CREATE FUNCTION f_WorkTime(
@date_begin datetime--計算的開始時間
@date_end datetime     --計算的結束時間
)RETURNS int
AS
BEGIN
   
DECLARE @worktime int
   
IF DATEDIFF(Day,@date_begin,@date_end)=0
       
SELECT @worktime=SUM(DATEDIFF(Minute,
           
CASE WHEN CONVERT(VARCHAR,@date_begin,108)>time_start
               
THEN CONVERT(VARCHAR,@date_begin,108)
               
ELSE time_start END,
           
CASE WHEN CONVERT(VARCHAR,@date_end,108)<time_end
               
THEN CONVERT(VARCHAR,@date_end,108)
               
ELSE time_end END))
       
FROM tb_worktime
       
WHERE time_end>CONVERT(VARCHAR,@date_begin,108)
           
AND time_start<CONVERT(VARCHAR,@date_end,108)
   
ELSE
       
SET @worktime
           
=(SELECT SUM(CASE
                   
WHEN CONVERT(VARCHAR,@date_begin,108)>time_startTHEN DATEDIFF(Minute,CONVERT(VARCHAR,@date_begin,108),time_end) ELSE worktime END)
               
FROM tb_worktime
               
WHERE time_end>CONVERT(VARCHAR,@date_begin,108))
           
+(SELECT SUM(CASE
                   
WHEN CONVERT(VARCHAR,@date_end,108)<time_end
                   
THEN DATEDIFF(Minute,time_start,CONVERT(VARCHAR,@date_end,108))
                   
ELSE worktime END)
               
FROM tb_worktime
               
WHERE time_start<CONVERT(VARCHAR,@date_end,108))
           
+CASE
               
WHEN DATEDIFF(Day,@date_begin,@date_end)>1
               
THEN (DATEDIFF(Day,@date_begin,@date_end)-1)
                   
*(SELECT SUM(worktime) FROM tb_worktime)
               
ELSE 0 END
   
RETURN(@worktime)
END

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章