当前位置: 代码迷 >> SQL >> SQL Server时间粒度系列-第7节台历数据表详解
  详细解决方案

SQL Server时间粒度系列-第7节台历数据表详解

热度:136   发布时间:2016-05-05 09:40:49.0
SQL Server时间粒度系列----第7节日历数据表详解
 
将该系列涉及到的时间粒度以及分钟以下的粒度做个总结,如以下表格:
时间粒度
 
 
  
 
 
 
 
纳秒
 
 
 
 
 
 
 
 
微妙
 
 
 
 
 
 
 
 
毫秒
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
分钟
日期分钟数(整数)*
日期分钟*
日内分钟数
 
 
 
 
 
小时
日期小时数(整数)
日期小时
日内小时数
 
 
 
 
 
日期天数(整数)
日期天
周内日索引
旬内日索引
月内日索引
季内日索引
年内日索引日期内日索引
日期周数(整数)
日期周
旬内周索引
月内周索引
季内周索引
年内周索引
日期内周索引
 
日期旬数(整数)
日期旬
月内旬索引季内旬索引
年内旬索引
日期内旬索引
 
 
日期月数(整数)
日期月
季内月索引
年内月索引
日期内月索引
 
 
 
日期季数(整数)
日期季
年内季索引
日期内季索引
 
 
 
 
日期年数(整数)
日期年
日期内年索引
 
 
 
 
 
注意:
1、最左边第一列表示时间粒度,其左边列的空格表示没有相应的参数,有文字表示有相对应的功能函数。
2、带有数的描述从0开始计数,带有索引则是从1开始计数。
3、日期天和日期天数(整数)是一对一映射的,一个日期对应一个整数。日期周、日期旬、日期月、日期季、日期年都是其时间粒度的基准日期的。
4、日期内相关的索引这个日期内是个范围区间[0001-01-01,9999-12-31],时间粒度日、周、旬、月、季、年的有关日期内的相关索引都是基于这个范围区间计算的。
5、带有*符号的表示谨慎使用。
 
时间维度有关功能函数
    
    根据时间粒度有关表述中总结的表格,将提供的时间粒度有关功能函数分为:日期时间通用有关函数、分钟时间粒度有关函数、 小时时间粒度有关函数、周以上时间粒度基准日期有关函数、天时间粒度有关函数、周时间粒度有关函数、旬时间粒度有关函数、月时间粒度有关函数、季时间粒度有关函数、年时间粒度有关函数。日期时间通用函数主要包括获取最小日期时间、获取最大日期时间、获取默认基准日期以及获取有效日期时间和有效日期时间数的函数。周以上时间粒度基准日期就是获取周、旬、月、季、年和日期的相关基准日期,都是其时间刻度的第一天所对应的日期范围。
 
    日期时间通用有关函数,T-SQL代码如下:
IF OBJECT_ID(N'dbo.ufn_GetMinDateTime', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_GetMinDateTime
END
GO
 
--==================================
-- 功能: 获取最小日期时间
-- 说明: 运行在SQL Server 2008+。
--       结果值为date数据类型。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SELECT dbo.ufn_GetMinDateTime();
--==================================
CREATE FUNCTION dbo.ufn_GetMinDateTime
(
 
) RETURNS DATE
    --$Encode$--
AS 
BEGIN
    RETURN '0001-01-01';
END
GO
 
IF OBJECT_ID(N'dbo.ufn_GetMaxDateTime', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_GetMaxDateTime
END
GO
 
--==================================
-- 功能: 获取最最大日期时间
-- 说明: 运行在SQL Server 2005+。
--       结果值为datetime数据类型。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SELECT dbo.ufn_GetMaxDateTime();
--==================================
CREATE FUNCTION dbo.ufn_GetMaxDateTime
(
 
) RETURNS DATETIME
    --$Encode$--
AS 
BEGIN
    RETURN '9999-12-31 23:59:59';
END
GO
 
IF OBJECT_ID(N'dbo.ufn_GetDefaultBasedate', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_GetDefaultBasedate
END
GO
 
--==================================
-- 功能: 获取默认基准日期
-- 说明: 运行在SQL Server 2005+。
--       默认设置为"1900-01-01",调整范围区间为[1753-01-01,9999-12-31];可以调整为该区间任意一个日期,不能为该区间以外的。
--       结果值为datetime数据类型。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SELECT dbo.ufn_GetDefaultBasedate();
--==================================
CREATE FUNCTION dbo.ufn_GetDefaultBasedate
(
 
) RETURNS DATETIME
    --$Encode$--
AS 
BEGIN
    RETURN '1900-01-01';
END
GO
 
-- Test Code
SELECT dbo.ufn_GetMinDateTime() AS 'MinDateTime'
    ,dbo.ufn_GetMaxDateTime() AS 'MaxDateTime'
    ,dbo.ufn_GetDefaultBasedate() AS 'DefaultBasedate';
GO
 
IF OBJECT_ID(N'dbo.ufn_GetValidDate', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_GetValidDate;
END
GO
 
--==================================
-- 功能: 获取有效日期
-- 说明: 运行在SQL Server 2005+。
--         指定的日期如果为NULL或者小于默认基准日期时则直接返回默认基准日期。
--       结果值为datetime数据类型。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @dtmDate = dbo.ufn_GetValidDate('2008-01-14')
--==================================
CREATE FUNCTION dbo.ufn_GetValidDate
(
    @dtmDate DATETIME            -- 指定的日期时间
) RETURNS DATETIME
    --$Encode$--
BEGIN
    DECLARE @dtmDefaultBasedate AS DATETIME;
    SET @dtmDefaultBasedate = dbo.ufn_GetDefaultBasedate();
 
    IF @dtmDate IS NULL OR @dtmDate < @dtmDefaultBasedate
    BEGIN
        RETURN @dtmDefaultBasedate;
    END
 
    RETURN @dtmDate;
END
GO
 
IF OBJECT_ID(N'dbo.ufn_GetValidDateNum', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION ufn_GetValidDateNum;
END
GO
 
--==================================
-- 功能: 获取有效日期数
-- 说明: 运行在SQL Server 2005+。
--       指定的日期数如果为NULL或负数,则默认设置为0。
--       结果值为datetime数据类型。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @@intDateNum = dbo.ufn_GetValidDateNum(-1)
--==================================
CREATE FUNCTION dbo.ufn_GetValidDateNum
(
    @intDateNum INT            -- 指定的日期数
) RETURNS INT
    --$Encode$--
BEGIN
    IF @intDateNum IS NULL OR @intDateNum < 0
    BEGIN
        RETURN 0;
    END
 
    RETURN @intDateNum;
END
GO
 
-- Test Code
SELECT dbo.ufn_GetValidDate('1899-01-01') AS 'ValidDate'
    ,dbo.ufn_GetValidDateNum(0) AS 'ValidDateNum';
GO
 
以上5个通用函数的测试效果,如下图:
 
    分钟时间粒度有关函数,T-SQL代码如下:
 IF OBJECT_ID(N'dbo.ufn_Minutes', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Minutes;
END
GO
 
--==================================
-- 功能: 获得指定的日期时间基于默认基准日期的总小时数(一个整数值)
-- 说明: 运行在SQL Server 2005 +。
--       如果指定的日期时间为NULL或者小于默认基准日期时,则其值为默认基准日期。
--       结果值为非负整数,从0开始计数。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @intMinutes = dbo.ufn_Minutes('5983-01-24 02:07:00.000');
--==================================
CREATE FUNCTION dbo.ufn_Minutes
(
    @dtmDate DATETIME                    -- 指定的日期时间
) RETURNS INT
AS
BEGIN
    RETURN DATEDIFF(MINUTE, dbo.ufn_GetDefaultBasedate(), dbo.ufn_GetValidDate(@dtmDate));
END
GO
 
IF OBJECT_ID(N'dbo.ufn_Minutes2Date', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Minutes2Date;
END
GO
 
--==================================
-- 功能: 获得一个整数值基于默认基准日期对应的日期时间
-- 说明: 运行在SQL Server 2005+。
--       如果指定的整数值为NULL或为负整数时,则其值默认为0。
--       如果指定的整数值大于“5983-01-24 02:07:00”对应的整数值时,则其值默认设置为“5983-01-24 02:07:00”对应的整数值。
--       结果值为基于默认基准日期开始计数的日期。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @dtmDate = dbo.ufn_Minutes2Date(947033) -- '2008-01-14 17:00'
--==================================
CREATE FUNCTION dbo.ufn_Minutes2Date
(
    @intMinutes INT                -- 指定的整数值
) RETURNS DATETIME
AS
BEGIN
    SET @intMinutes = dbo.ufn_GetValidDateNum(@intMinutes);
 
    DECLARE @intMinutesMax AS INT;
    SET @intMinutesMax = dbo.ufn_Minutes('5983-01-24 02:07:00');
 
    IF @intMinutes >= @intMinutesMax
    BEGIN
        SET @intMinutes = @intMinutesMax;
    END
 
    RETURN DATEADD(MINUTE, @intMinutes, dbo.ufn_GetDefaultBasedate());
END
GO
 
IF OBJECT_ID(N'dbo.ufn_MinutesOfDay', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_MinutesOfDay;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间基于所在当前日午夜零时的分钟数
-- 功能: 运行在SQL Server 2005+。
--       结果值从0开始计数,包括0、1、2、3、1439。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @sintMinutesOfDay = dbo.fn_MinutesOfDay(GETDATE());
--==================================
CREATE FUNCTION dbo.ufn_MinutesOfDay
(
    @dtmDate DATETIME                    -- 指定的日期时间
) RETURNS SMALLINT
AS
BEGIN
    RETURN DATEPART(HOUR, @dtmDate) * 60 + DATEPART(MINUTE, @dtmDate);
END
GO
 
-- Test Code
DECLARE @dtmDate AS DATETIME;
SET @dtmDate = '2016-02-14 02:14:18';
 
SELECT
    @dtmDate AS 'The Current DateTime'
    ,dbo.ufn_Minutes(@dtmDate) AS 'Minutes'
    ,dbo.ufn_Minutes2Date(dbo.ufn_Minutes(@dtmDate)) AS 'DateTime Mapping Minutes'
    ,dbo.ufn_MinutesOfDay(@dtmDate) AS 'Minutes Of The Current Day';
 
SET @dtmDate = '2016-05-20 05:20:48';
 
SELECT 
    @dtmDate AS 'The Current DateTime'
    ,dbo.ufn_Minutes(@dtmDate) AS 'Minutes'
    ,dbo.ufn_Minutes2Date(dbo.ufn_Minutes(@dtmDate)) AS 'DateTime Mapping Minutes'
    ,dbo.ufn_MinutesOfDay(@dtmDate) AS 'Minutes Of The Current Day';
GO
 
以上3个函数的测试效果,如下图:
 
    小时时间粒度有关函数,T-SQL代码如下:
IF OBJECT_ID(N'dbo.ufn_Hours', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Hours;
END
GO
 
--==================================
-- 功能: 获得指定的日期时间基于基准日期的总小时数(一个整数值)
-- 说明: 运行在SQL Server 2005+。
--       如果指定的日期时间为NULL或者小于默认基准日期时,则其值为默认基准日期。
--       结果值为非负整数,从0开始计数。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @intHours = dbo.ufn_Hours('2008-01-14 17:45')  -- 947033
--==================================
CREATE FUNCTION dbo.ufn_Hours 
(
    @dtmDate DATETIME                    -- 指定的日期时间
) RETURNS INT
    --$Encode$--
AS
BEGIN
    RETURN DATEDIFF(HOUR, dbo.ufn_GetDefaultBasedate(), dbo.ufn_GetValidDate(@dtmDate));
END
GO
 
IF OBJECT_ID(N'dbo.ufn_Hours2Date', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Hours2Date;
END
GO
 
--==================================
-- 功能: 获得一个整数值基于基准日期对应的日期时间
-- 说明: 运行在SQL Server 2005+。
--       如果指定的整数值为NULL或为负整数时,则其值默认为0;
--       如果指定的整数值大于“9999-12-31 23:00:00”对应的整数值时,则其值默认设置为“9999-12-31 23:00:00”对应的整数值。
--       结果值为基于默认基准日期开始计数的日期。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @dtmDate = dbo.fn_Hours2Date(947033) -- '2008-01-14 17:00'
--==================================
CREATE FUNCTION dbo.ufn_Hours2Date 
(
    @intHours INT                        -- 指定的整数值
) RETURNS DATETIME
AS
BEGIN
    SET @intHours = dbo.ufn_GetValidDateNum(@intHours);
 
    DECLARE @intMaxHours AS INT;
    SET @intMaxHours = dbo.ufn_Hours(dbo.ufn_GetMaxDateTime());
 
    IF @intHours >= @intMaxHours
    BEGIN
        SET @intHours = @intMaxHours;
    END
 
    RETURN DATEADD(HOUR, @intHours, dbo.ufn_GetDefaultBasedate());
END
GO
 
 
IF OBJECT_ID(N'dbo.ufn_HoursOfDay', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_HoursOfDay;
END
GO
 
--==================================
-- 功能: 获取指定的日期日期基于所在当期日午夜零时的小时数
-- 说明: 运行在SQL Server 2005+。
--       结果值从0开始计数,包括0、1、2、……、23。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @tintHoursOfDay = dbo.ufn_HoursOfDay(GETDATE());
--==================================
CREATE FUNCTION dbo.ufn_HoursOfDay
(
    @dtmDate DATETIME            -- 指定的日期时间
)
RETURNS TINYINT
AS
BEGIN
    RETURN DATEPART(HOUR, @dtmDate);
END
GO
 
 
-- Test Code
DECLARE @dtmDate AS DATETIME;
SET @dtmDate = '2014-02-14 6:12:00'
 
SELECT 
    @dtmDate AS 'The Current DateTime'
    ,dbo.ufn_Hours(@dtmDate) AS 'Hours'
    ,dbo.ufn_Hours2Date(dbo.ufn_Hours(@dtmDate)) AS 'DateTime Mapping Hours'
    ,dbo.ufn_HoursOfDay(@dtmDate) AS 'Hours Of The Current Day';
 
SET @dtmDate = '2014-05-20 8:18:00'
 
SELECT
    @dtmDate AS 'The Current DateTime'
    ,dbo.ufn_Hours(@dtmDate) AS 'Hours'
    ,dbo.ufn_Hours2Date(dbo.ufn_Hours(@dtmDate)) AS 'DateTime Mapping Hours'
    ,dbo.ufn_HoursOfDay(@dtmDate) AS 'Hours Of The Current Day'
GO
 
以上3个函数的测试效果,如下图:
 
    周以上时间粒度基准日期有关函数,T-SQL代码如下:   
IF OBJECT_ID(N'dbo.ufn_FirstDayOfPeriodTable', 'IF') IS NOT NULL
BEGIN
    DROP FUNCTION ufn_FirstDayOfPeriodTable;
END
GO
 
--==================================
-- 功能: 旬首日索引表
-- 说明: 运行在SQL Server 2005+。
--       结果值为表数据,列名为FirstDayOfPeriod,其字段列(域)值包括1、11、21这3个数字,其字段列值对应每年每个旬的第一天。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SELECT * FROM dbo.ufn_FirstDayOfPeriodTable();
--==================================
CREATE FUNCTION dbo.ufn_FirstDayOfPeriodTable
(
 
) RETURNS TABLE
    --$Encode$--
    RETURN ( 
        SELECT 1 AS FirstDayOfPeriod
        UNION ALL SELECT 11
        UNION ALL SELECT 21
    );
GO
 
IF OBJECT_ID(N'dbo.ufn_FirstDayOfPeriod', N'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_FirstDayOfPeriod;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前旬的第一个日索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1开始计数,包括1、11、21。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SELECT @tintFirstDayOfPeriod = ufn_FirstDayOfPeriod(@dtmDate);
--==================================
CREATE FUNCTION dbo.ufn_FirstDayOfPeriod
(
    @dtmDate DATETIME                    -- 指定的日期时间
 
) RETURNS TINYINT
    --$Encode$--
BEGIN
    DECLARE @tintFirstDayOfPeriod AS TINYINT;
    SET @tintFirstDayOfPeriod = 1;
 
    SELECT TOP 1 @tintFirstDayOfPeriod = FirstDayOfPeriod
    FROM dbo.ufn_FirstDayOfPeriodTable()
    WHERE FirstDayOfPeriod <= DAY(@dtmDate)
    ORDER BY FirstDayOfPeriod DESC;
 
    RETURN @tintFirstDayOfPeriod;
END
GO
 
IF OBJECT_ID(N'dbo.ufn_BasedateOfPeriod', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_BasedateOfPeriod;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在旬的基准日期
-- 说明: 运行在SQL Server 2005+。
--       结果值为旬基准日,即每个旬第一天对应的日期。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @dtmBasedateOfPeriod = dbo.ufn_BasedateOfPeriod('2016-01-12');
--==================================
CREATE FUNCTION dbo.ufn_BasedateOfPeriod
(
    @dtmDate DATETIME                -- 指定的日期时间
) RETURNS DATETIME
    --$Encode$--
BEGIN
    RETURN CONVERT(DATETIME, CAST(YEAR(@dtmDate) AS CHAR(4)) + '-' + CAST(MONTH(@dtmDate) AS VARCHAR(2)) + '-' + CAST(dbo.ufn_FirstDayOfPeriod(@dtmDate) AS VARCHAR(2)), 120);
END
GO
 
IF OBJECT_ID(N'dbo.ufn_BasedateOfMonth', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_BasedateOfMonth;
END
GO
 
--==================================
-- 功能: 获取指定日期时间所在月的基准日期
-- 说明: 运行在SQL Server 2005+。
--       结果值为月基准日,即每个月第一天对应的日期。 
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @dtmBasedateOfMonth = dbo.ufn_BasedateOfMonth('2016-01-12');
--==================================
CREATE FUNCTION dbo.ufn_BasedateOfMonth
(
    @dtmDate DATETIME                -- 指定的日期时间
) RETURNS DATETIME
    --$Encode$--
BEGIN
    RETURN CONVERT(DATETIME, CAST(YEAR(@dtmDate) AS CHAR(4)) + '-' + CAST(MONTH(@dtmDate) AS VARCHAR(2)) + '-' + CAST(1 AS CHAR(1)), 120);
END
GO
 
IF OBJECT_ID(N'dbo.ufn_FirstMonthOfQuarterTable', 'IF') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_FirstMonthOfQuarterTable;
END
GO
 
--==================================
-- 功能: 季首月索引表
-- 说明: 运行在SQL Server 2005+。
--       结果值为表数据,列名为FirstMonthOfQuarter,其字段列(域)值包括1、4、7、10这4个数字,其字段列值对应每年每个季的第一个月份。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SELECT * FROM dbo.ufn_FirstMonthOfQuarterTable();
--==================================
CREATE FUNCTION dbo.ufn_FirstMonthOfQuarterTable
(
) RETURNS TABLE
    --$Encode$--
    RETURN ( 
        SELECT 1 AS FirstMonthOfQuarter
        UNION ALL SELECT 4
        UNION ALL SELECT 7
        UNION ALL SELECT 10
    );
GO
 
IF OBJECT_ID(N'dbo.ufn_FirstMonthOfQuarter', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_FirstMonthOfQuarter;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前季度的第一个月索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1开始计数,包括1、4、7、10。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SELECT @tintFirstMonthOfQuarter = ufn_FirstMonthOfQuarter(@dtmDate);
--==================================
CREATE FUNCTION dbo.ufn_FirstMonthOfQuarter
(
    @dtmDate DATETIME                    -- 指定的日期时间
 
) RETURNS TINYINT
    --$Encode$--
BEGIN
    DECLARE @tintFirstMonthOfQuarter AS TINYINT;
    SET @tintFirstMonthOfQuarter = 1;
 
    SELECT TOP 1 @tintFirstMonthOfQuarter = FirstMonthOfQuarter
    FROM dbo.ufn_FirstMonthOfQuarterTable() 
    WHERE FirstMonthOfQuarter <= MONTH(@dtmDate)
    ORDER BY FirstMonthOfQuarter DESC;
 
    RETURN @tintFirstMonthOfQuarter;
END
GO
 
IF OBJECT_ID(N'dbo.ufn_BasedateOfQuarter', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_BasedateOfQuarter;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前季的季基准日期
-- 说明: 运行在SQL Server 2005+。
--       结果值格式"XXXX-01-01",包括:"XXXX-01-01"、"XXXX-04-01"、"XXXX-07-01"、"XXXX-10-01"。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SELECT @tintFirstMonthOfQuarter = ufn_BasedateOfQuarter(@dtmDate);
--==================================
CREATE FUNCTION dbo.ufn_BasedateOfQuarter
(
    @dtmDate DATETIME                    -- 指定的日期时间
 
) RETURNS DATETIME
    --$Encode$--
BEGIN
    RETURN  CONVERT(DATETIME, CAST(YEAR(@dtmDate) AS CHAR(4)) + '-' + CAST(dbo.ufn_FirstMonthOfQuarter(@dtmDate) AS VARCHAR(2)) + '-' + CAST(1 AS CHAR(1)), 120);
END
GO
 
 
IF OBJECT_ID(N'dbo.ufn_BasedateOfYear', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_BasedateOfYear;
END
GO
--==================================
-- 功能: 获取指定日期时间所在年的基准日期
-- 说明: 结果值是每个年的基准日,每个年第一天对应的日期。 
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @dtmBasedateOfYear = dbo.ufn_BasedateOfYear('2016-01-12');
--==================================
CREATE FUNCTION dbo.ufn_BasedateOfYear
(
    @dtmDate DATETIME                -- 指定的日期时间
) RETURNS DATETIME
    --$Encode$--
BEGIN
    RETURN CONVERT(DATETIME, CAST(YEAR(@dtmDate) AS CHAR(4)) + '-' + CAST(1 AS CHAR(1)) +  '-' + CAST(1 AS char(1)), 120);
END
GO
 
-- Test Code
DECLARE @dtmDate AS DATETIME;
SET @dtmDate = '2016-01-14';
 
SELECT 
    @dtmDate AS 'The Current Date'
    ,dbo.ufn_BasedateOfPeriod(@dtmDate) AS 'Basedate Of The Current Period'
    ,dbo.ufn_BasedateOfMonth(@dtmDate) AS 'Basedate Of The Current Month'
    ,dbo.ufn_BasedateOfQuarter(@dtmDate) AS 'Basedate Of the Current Quarter'
    ,dbo.ufn_BasedateOfYear(@dtmDate) AS 'Basedate Of the Current Year'
    ,dbo.ufn_GetMinDateTime() AS 'Basedate Of the Current Date';
 
SET @dtmDate = '2016-4-30';
 
SELECT
    @dtmDate AS 'The Current Date'
    ,dbo.ufn_BasedateOfPeriod(@dtmDate) AS 'Basedate Of The Current Period'
    ,dbo.ufn_BasedateOfMonth(@dtmDate) AS 'Basedate Of The Current Month'
    ,dbo.ufn_BasedateOfQuarter(@dtmDate) AS 'Basedate Of the Current Quarter'
    ,dbo.ufn_BasedateOfYear(@dtmDate) AS 'Basedate Of the Current Year'
    ,dbo.ufn_GetMinDateTime() AS 'Basedate Of the Current Date';
GO
 
以上几个函数的测试效果,如下图:
    
    天时间粒度有关函数,T-SQL代码如下:
IF OBJECT_ID(N'dbo.ufn_Days', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Days;
END
GO
 
--==================================
-- 功能: 获得指定日期时间基于默认基准日期的总天数(一个整数值)
-- 说明: 运行在SQL Server 2005+。
--       如果指定的日期时间为NULL或者小于默认基准日期时,则其值为默认基准日期。
--       结果值为非负整数,从0开始计数。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @intDays = dbo.ufn_Days('2008-01-14')
--==================================
CREATE FUNCTION dbo.ufn_Days
(
    @dtmDate DATETIME                    -- 指定的日期时间
) RETURNS INT
    --$Encode$--
AS
BEGIN
    RETURN DATEDIFF(DAY, dbo.ufn_GetDefaultBasedate(), dbo.ufn_GetValidDate(@dtmDate));
END
GO
 
IF OBJECT_ID(N'dbo.ufn_Days2Date', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Days2Date;
END
GO
 
--==================================
-- 功能: 获得一个整数值基于默认基准日期对应的日期
-- 说明: 运行在SQL Server 2005+。
--       如果指定的整数值为NULL或为负整数时,则其值默认为0。
--       如果指定的整数值大于最大日期时间对应的整数值时,则其值默认设置为最大日期时间对应的整数值。
--       结果值为基于默认基准日期开始计数的日期。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @dtmDate = dbo.ufn_Days2Date(39459) --'2008-01-14'
--==================================
CREATE FUNCTION dbo.ufn_Days2Date 
(
    @intDays INT                -- 指定的整数值
) RETURNS DATETIME
    --$Encode$--
AS
BEGIN
    SET @intDays = dbo.ufn_GetValidDateNum(@intDays);
 
    DECLARE @intMaxDays AS INT;
    SET @intMaxDays = dbo.ufn_Days(dbo.ufn_GetMaxDateTime());
 
    IF @intDays >= @intMaxDays
    BEGIN
        SET @intDays = @intMaxDays;
    END
 
    RETURN DATEADD(DAY, @intDays, dbo.ufn_GetDefaultBasedate());
END
GO
 
IF OBJECT_ID(N'dbo.ufn_DayOfWeek', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_DayOfWeek;
END
GO
 
--==================================
-- 功能: 获取指定日期时间的所在当前周的日索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1到7,分别对应从周一到周日,该值与@@DATEFISRT配置函数值保持一致。
--       使用(@@datefirt + datepart(weekday, @dtmDate))%7的结果值从2、3、4、5、6、0、1
--       分别对应周一、周二、周三、周四、周五、周六、周日。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SELECT dbo.ufn_DayOfWeek('2017-01-07') -- 4(表示星期四)
--==================================
CREATE FUNCTION dbo.ufn_DayOfWeek
(
    @dtmDate DATETIME                -- 指定的日期时间
) RETURNS TINYINT
    --$Encode$--
BEGIN
    DECLARE    @tintRemainder AS TINYINT;
    SET @tintRemainder = (@@DATEFIRST + DATEPART(WEEKDAY, @dtmDate)) % 7;
    IF @tintRemainder <= 1
    BEGIN
        SET @tintRemainder = @tintRemainder + 6;
    END
    ELSE
    BEGIN
        SET @tintRemainder = @tintRemainder - 1;
    END
 
    RETURN @tintRemainder;
END
GO
 
IF OBJECT_ID(N'dbo.ufn_DayOfPeriod', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_DayOfPeriod;
END
GO
 
--==================================
-- 功能: 获得指定日期时间在当前旬的日索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1开始计数,包括1、2、3、……、8、9、10、11。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @intPeriods = dbo.ufn_DayOfPeriod('2008-01-14')
--==================================
CREATE FUNCTION dbo.ufn_DayOfPeriod
(
    @dtmDate DATETIME            -- 指定的日期时间
) RETURNS TINYINT
    --$Encode$--
AS
BEGIN
    --RETURN DAY(@dtmDate) - (dbo.ufn_PeriodOfMonth(@dtmDate) - 1) * 10;
    RETURN DATEDIFF(DAY, dbo.ufn_BasedateOfPeriod(@dtmDate), @dtmDate) + 1;
END
GO
 
IF OBJECT_ID(N'dbo.ufn_DayOfMonth', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_DayOfMonth;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前月的日索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1开始计数,包括1、2、3.……、28、29、30、31。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @sintDayOfYear = dbo.ufn_DayOfMonth('2016-01-11')
--==================================
CREATE FUNCTION dbo.ufn_DayOfMonth
(
    @dtmDate DATETIME            -- 指定的日期时间
) RETURNS TINYINT
    --$Encode$--
BEGIN
    RETURN DAY(@dtmDate);
END
GO
 
IF OBJECT_ID(N'dbo.ufn_DayOfQuarter', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_DayOfQuarter;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在季的日索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1开始计数,包括1、2、3.……、89、90、91、92。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
--==================================
CREATE FUNCTION dbo.ufn_DayOfQuarter
(
    @dtmDate DATETIME                -- 指定的日期时间
) RETURNS TINYINT
    --$Encode$--
BEGIN
    RETURN DATEDIFF(DAY, dbo.ufn_BasedateOfQuarter(@dtmDate), @dtmDate) + 1;
END
GO
 
IF OBJECT_ID(N'dbo.ufn_DayOfYear', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_DayOfYear;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前年的日索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1开始计数,包括1、2、3.……、364、365、366。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @sintDayOfYear = dbo.ufn_DayOfYear('2016-01-11')
--==================================
CREATE FUNCTION dbo.ufn_DayOfYear
(
    @dtmDate DATETIME                -- 指定的日期时间
) RETURNS SMALLINT
    --$Encode$--
BEGIN
    RETURN DATEPART(DAYOFYEAR, @dtmDate);
END
GO
 
 
IF OBJECT_ID(N'dbo.ufn_DayOfDate', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_DayOfDate;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前日期的日索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1开始计数,包括1、2、3.……、3652057、3652058、3652059。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @inntDayOfDate = dbo.ufn_DayOfDate('2016-01-11')
--==================================
CREATE FUNCTION dbo.ufn_DayOfDate
(
    @dtmDate DATETIME
) RETURNS INT
    --$Encode$--
BEGIN
    RETURN DATEDIFF(DAY, dbo.ufn_GetMinDateTime(), dbo.ufn_GetValidDate(@dtmDate)) + 1
END
GO
 
 
-- Test Code
DECLARE @dtmDate AS DATETIME;
SET @dtmDate = '2016-01-14';
 
SELECT
    @dtmDate AS 'The Current Date'
    ,dbo.ufn_Days(@dtmDate) AS 'Days'
    ,dbo.ufn_Days2Date(dbo.ufn_Days(@dtmDate)) AS 'Date Mapping Days'
    ,dbo.ufn_DayOfWeek(@dtmDate) AS 'Day Of The Current Week'
    ,dbo.ufn_DayOfPeriod(@dtmDate) AS 'Day Of The Current Period'
    ,dbo.ufn_DayOfMonth(@dtmDate) AS 'Day Of The Current Month'
    ,dbo.ufn_DayOfQuarter(@dtmDate) AS 'Day Of The Current Quarter'
    ,dbo.ufn_DayOfYear(@dtmDate) AS 'Day Of The Current Year'
    ,dbo.ufn_DayOfDate(@dtmDate) AS 'Day Of The Current Date';
 
SET @dtmDate = '2016-03-14';
 
SELECT
    @dtmDate AS 'The Current Date'
    ,dbo.ufn_Days(@dtmDate) AS 'Days'
    ,dbo.ufn_Days2Date(dbo.ufn_Days(@dtmDate)) AS 'Date Mapping Days'
    ,dbo.ufn_DayOfWeek(@dtmDate) AS 'Day Of The Current Week'
    ,dbo.ufn_DayOfPeriod(@dtmDate) AS 'Day Of The Current Period'
    ,dbo.ufn_DayOfMonth(@dtmDate) AS 'Day Of The Current Month'
    ,dbo.ufn_DayOfQuarter(@dtmDate) AS 'Day Of The Current Quarter'
    ,dbo.ufn_DayOfYear(@dtmDate) AS 'Day Of The Current Year'
    ,dbo.ufn_DayOfDate(@dtmDate) AS 'Day Of The Current Date';
GO
 
以上几个函数的测试效果,如下图:
 
    周时间粒度有关函数,T-SQL代码如下:
IF OBJECT_ID(N'dbo.ufn_Weeks', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Weeks;
END
GO
 
--==================================
-- 功能: 获得指定日期时间基于默认基准日期的总周数(一个整数值)
-- 说明: 运行在SQL Server 2005+。
--       如果指定的日期时间为NULL或者小于默认基准日期时,则其值为默认基准日期。
--       结果值为非负整数,从0开始计数。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @intDays = dbo.ufn_Weeks('2008-01-14')
--==================================
CREATE FUNCTION dbo.ufn_Weeks
(
    @dtmDate DATETIME                    -- 指定的日期时间
) RETURNS INT
    --$Encode$--
AS
BEGIN
    RETURN dbo.ufn_Days(@dtmDate) / 7;
END
GO
 
IF OBJECT_ID(N'dbo.ufn_Weeks2Date', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Weeks2Date;
END
GO
 
--==================================
-- 功能: 获得一个整数值基于默认基准日期对应的日期
-- 说明: 运行在SQL Server 2005+。
--       如果指定的整数值为NULL或为负整数时,则其值默认为0;
--       如果指定的整数值大于最大日期时间对应的整数值时,则其值默认设置为最大日期时间对应的整数值。
--       结果值为基于默认基准日期开始计数的周基准日期,也就是周一对应的日期。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @dtmDate = dbo.ufn_Weeks2Date(39459);
--==================================
CREATE FUNCTION dbo.ufn_Weeks2Date
(
    @intWeeks INT                    -- 指定的整数值
) RETURNS DATETIME
    --$Encode$--
AS
BEGIN
    SET @intWeeks = dbo.ufn_GetValidDateNum(@intWeeks);
 
    DECLARE @intMaxWeeks AS INT;
    SET @intMaxWeeks = dbo.ufn_Weeks(dbo.ufn_GetMaxDateTime());
 
    IF @intWeeks >= @intMaxWeeks
    BEGIN
        SET @intWeeks = @intMaxWeeks;
    END
 
    RETURN DATEADD(DAY, @intWeeks * 7, dbo.ufn_GetDefaultBasedate());
END
GO
 
IF OBJECT_ID(N'dbo.ufn_WeekOfPeriod', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_WeekOfPeriod;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前旬的周索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1开始计数,包括1、2、3。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @tintWeekOfPeriod = dbo.ufn_WeekOfPeriod('2016-01-11')
--==================================
CREATE FUNCTION dbo.ufn_WeekOfPeriod
(
    @dtmDate DATETIME                -- 指定的日期时间
) RETURNS TINYINT
    --$Encode$--
BEGIN
    DECLARE @tintWeekOffsetOfPeriod AS TINYINT;
    SET @tintWeekOffsetOfPeriod = DATEDIFF(WEEK, dbo.ufn_BasedateOfPeriod(@dtmDate), @dtmDate);
 
    IF dbo.ufn_DayOfWeek(@dtmDate) = 7 AND @tintWeekOffsetOfPeriod >= 1
    BEGIN
        SET @tintWeekOffsetOfPeriod = @tintWeekOffsetOfPeriod - 1;
    END
 
    RETURN @tintWeekOffsetOfPeriod + 1;
END
GO
 
IF OBJECT_ID(N'dbo.ufn_WeekOfMonth', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_WeekOfMonth;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前月的周索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1开始计数,包括1、2、3、4、5
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @tintWeekOfMonth = dbo.ufn_WeekOfMonth('2016-01-11')
--==================================
CREATE FUNCTION dbo.ufn_WeekOfMonth
(
    @dtmDate DATETIME
) RETURNS TINYINT
    --$Encode$--
BEGIN
    DECLARE @tintWeekOffsetOfMonth AS TINYINT;
    SET @tintWeekOffsetOfMonth = DATEDIFF(WEEK, dbo.ufn_BasedateOfMonth(@dtmDate), @dtmDate);
 
    IF dbo.ufn_DayOfWeek(@dtmDate) = 7 AND @tintWeekOffsetOfMonth >= 1
    BEGIN
        SET @tintWeekOffsetOfMonth = @tintWeekOffsetOfMonth - 1;
    END
 
    RETURN @tintWeekOffsetOfMonth + 1;
END
GO
 
IF OBJECT_ID(N'dbo.ufn_WeekOfQuarter', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_WeekOfQuarter;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前季的周索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1开始计数,包括1、2、3、4、5、6、7、7、……。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @tintWeekOfQuarter = dbo.ufn_WeekOfQuarter('2016-01-11')
--==================================
CREATE FUNCTION dbo.ufn_WeekOfQuarter
(
    @dtmDate DATETIME
) RETURNS TINYINT
    --$Encode$--
BEGIN
    DECLARE @tintWeekOffsetOfQuarter AS TINYINT;
    SET @tintWeekOffsetOfQuarter = DATEDIFF(WEEK, dbo.ufn_BasedateOfQuarter(@dtmDate), @dtmDate);
 
    IF dbo.ufn_DayOfWeek(@dtmDate) = 7 AND @tintWeekOffsetOfQuarter >= 1
    BEGIN
        SET @tintWeekOffsetOfQuarter = @tintWeekOffsetOfQuarter - 1;
    END
 
    RETURN @tintWeekOffsetOfQuarter + 1;
END
GO
 
IF OBJECT_ID(N'dbo.ufn_WeekOfYear', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_WeekOfYear;
END
GO
 
--==================================
-- 功能: 获取指定日期属于当前年的周索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1开始计数,一年最多1-53周。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SELECT dbo.ufn_WeekOfYear('2016-01-07');
--==================================
CREATE FUNCTION dbo.ufn_WeekOfYear
(
    @dtmDate DATETIME
) RETURNS TINYINT
    --$Encode$--
AS
BEGIN
    DECLARE @tintWeekOffsetOfYear AS TINYINT;
    SET @tintWeekOffsetOfYear = DATEDIFF(WEEK, dbo.ufn_BasedateOfYear(@dtmDate), @dtmDate);
 
    IF dbo.ufn_DayOfWeek(@dtmDate) = 7 AND @tintWeekOffsetOfYear >= 1
    BEGIN
        SET @tintWeekOffsetOfYear = @tintWeekOffsetOfYear - 1;
    END
 
    RETURN @tintWeekOffsetOfYear + 1;
END
GO
 
IF OBJECT_ID(N'dbo.ufn_WeekOfDate', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_WeekOfDate;
END
GO
 
--==================================
-- 功能: 获取指定日期属于当前日历的周索引
-- 说明: 运行在SQL Server 2008+。
--       结果值从1开始计数,包括1、2、3、4、……。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SELECT dbo.ufn_WeekOfDate('2016-01-07');
--==================================
CREATE FUNCTION dbo.ufn_WeekOfDate
(
    @dtmDate DATETIME
) RETURNS INT
    --$Encode$--
AS
BEGIN
    DECLARE @intWeekOffsetOfDate AS INT;
    SET @intWeekOffsetOfDate = DATEDIFF(WEEK, dbo.ufn_GetMinDateTime(), @dtmDate);
 
    IF (@@DATEFIRST + DATEPART(WEEKDAY, @dtmDate)) % 7 = 1 AND @intWeekOffsetOfDate >= 1
    BEGIN
        SET @intWeekOffsetOfDate = @intWeekOffsetOfDate - 1;
    END
 
    RETURN @intWeekOffsetOfDate + 1;
END
GO
 
-- Test Code
DECLARE @dtmDate AS DATETIME;
SET @dtmDate = '2016-01-15';
 
SELECT
    @dtmDate AS 'The Current Date'
    ,dbo.ufn_Weeks(@dtmDate) AS 'Weeks'
    ,dbo.ufn_Weeks2Date(dbo.ufn_Weeks(@dtmDate)) AS 'Date Mapping Weeks'
    ,dbo.ufn_WeekOfPeriod(@dtmDate) AS 'Week Of The Current Period'
    ,dbo.ufn_WeekOfMonth(@dtmDate) AS 'Week Of The Current Month'
    ,dbo.ufn_WeekOfQuarter(@dtmDate) AS 'Week Of The Current Quarter'
    ,dbo.ufn_WeekOfYear(@dtmDate) AS 'Week Of The Current Year'
    ,dbo.ufn_WeekOfDate(@dtmDate) AS 'Week Of The Current Date';
 
SET @dtmDate = '2016-01-31';
 
SELECT
    @dtmDate AS 'The Current Date'
    ,dbo.ufn_Weeks(@dtmDate) AS 'Weeks'
    ,dbo.ufn_Weeks2Date(dbo.ufn_Weeks(@dtmDate)) AS 'Date Mapping Weeks'
    ,dbo.ufn_WeekOfPeriod(@dtmDate) AS 'Week Of The Current Period'
    ,dbo.ufn_WeekOfMonth(@dtmDate) AS 'Week Of The Current Month'
    ,dbo.ufn_WeekOfQuarter(@dtmDate) AS 'Week Of The Current Quarter'
    ,dbo.ufn_WeekOfYear(@dtmDate) AS 'Week Of The Current Year'
    ,dbo.ufn_WeekOfDate(@dtmDate) AS 'Week Of The Current Date';
GO
 
测试以上函数的效果,如下图:
    旬时间粒度有关函数,T-SQL代码如下:
IF OBJECT_ID(N'dbo.ufn_PeriodOfMonth', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_PeriodOfMonth;
END
GO
 
--==================================
-- 功能: 获得指定日期时间在当前月的旬索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1开始计数,1、2、3分别对应上、中、下的旬索引。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @intPeriods = dbo.ufn_PeriodOfMonth('2008-01-14')
--==================================
CREATE FUNCTION [dbo].[ufn_PeriodOfMonth] 
(
    @dtmDate DATETIME            -- 指定的日期时间
) RETURNS TINYINT
    --$Encode$--
AS
BEGIN
    --当前月的日索引,从1开始计数,,包括1、2、3、……、28、29、30、31
    DECLARE @tintDayOfMonth AS TINYINT;
    SET @tintDayOfMonth = DAY(@dtmDate);
    -- 旬偏移索引,0:上旬,1:中旬,2:下旬
    DECLARE @tintPeriodOffsetIndexID AS INT;
    SET @tintPeriodOffsetIndexID = DAY(@dtmDate) / 10
 
    IF @tintDayOfMonth IN (10, 20, 30, 31)
    BEGIN
        SET @tintPeriodOffsetIndexID = @tintPeriodOffsetIndexID - 1;
    END
 
    RETURN @tintPeriodOffsetIndexID + 1;
END
GO
 
IF OBJECT_ID(N'dbo.ufn_Periods', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Periods;
END
GO
 
--==================================
-- 功能: 获得指定日期时间基于默认基准日期的总旬数(一个整数值)
-- 说明: 运行在SQL Server 2005+。
--       如果指定的日期时间为NULL或者小于默认基准日期时,则其值为默认基准日期。
--       结果值为非负整数,从0开始计数。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @intPeriods = dbo.ufn_Periods('2008-01-14')
--==================================
CREATE FUNCTION dbo.ufn_Periods
(
    @dtmDate DATETIME            -- 指定的日期时间
) RETURNS INT
    --$Encode$--
AS
BEGIN
    RETURN DATEDIFF(MONTH, dbo.ufn_GetDefaultBasedate(), dbo.ufn_GetValidDate(@dtmDate)) * 3 + (dbo.ufn_PeriodOfMonth(@dtmDate) - 1);
END
GO
 
IF OBJECT_ID(N'dbo.ufn_Periods2Date', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Periods2Date;
END
GO
 
--==================================
-- 功能: 获得一个整数值基于默认基准日期对应的旬基准日期
-- 说明: 运行在SQL Server 2005+。
--       如果指定的整数值为NULL或为负整数时,则其值默认为0;
--       如果指定的整数值大于“9999-12-31”对应的整数值时,则其值默认设置为“9999-12-31”对应的整数值;
--       结果值为基于默认基准日期开始计数的日期;
--       旬基准日期是指一个月份中第1天、第11天和第21天对应的日期,比如'2016-02'月份的3个旬基准日期分别为'2016-02-01','2016-02-11','2016-02-21'。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @dtmDate = dbo.ufn_Periods2Date(2705) --'1975-02-21'
--==================================
CREATE FUNCTION dbo.ufn_Periods2Date 
(
    @intPeriods INT        -- 指定的整数值
) RETURNS DATETIME
AS
BEGIN
    SET @intPeriods = dbo.ufn_GetValidDateNum(@intPeriods);
 
    DECLARE @intMaxPeriods AS INT;
    SET @intMaxPeriods = dbo.ufn_Periods(dbo.ufn_GetMaxDateTime());
 
    IF @intPeriods >= @intMaxPeriods
    BEGIN
        SET @intPeriods = @intMaxPeriods;
    END
 
    RETURN DATEADD(DAY, (@intPeriods - @intPeriods / 3 * 3) * 10, DATEADD(MONTH, @intPeriods / 3, dbo.ufn_GetDefaultBasedate()));
END
GO
 
IF OBJECT_ID(N'dbo.ufn_PeriodOfQuarter', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_PeriodOfQuarter;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前季的旬索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1开始计数,包括1、2、……、7、8、9。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @tintPeriodOfQuarter = dbo.ufn_PeriodOfQuarter('2016-01-11')
--==================================
CREATE FUNCTION dbo.ufn_PeriodOfQuarter
(
    @dtmDate DATETIME                -- 指定的日期时间
) RETURNS TINYINT
    --$Encode$--
BEGIN
    RETURN (MONTH(@dtmDate) - dbo.ufn_FirstMonthOfQuarter(@dtmDate)) * 3 + dbo.ufn_PeriodOfMonth(@dtmDate);
END
GO
 
IF OBJECT_ID(N'dbo.ufn_PeriodOfYear', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_PeriodOfYear;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前年的旬索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1开始计数,包括1、2、……、34、35、36。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @tintPeriodOfYear = dbo.ufn_PeriodOfYear('2016-01-11')
--==================================
CREATE FUNCTION dbo.ufn_PeriodOfYear
(
    @dtmDate DATETIME            -- 指定的日期时间
) RETURNS TINYINT
    --$Encode$--
BEGIN
    RETURN (MONTH(@dtmDate) - 1) * 3 + dbo.ufn_PeriodOfMonth(@dtmDate);
END
GO
 
IF OBJECT_ID(N'dbo.ufn_PeriodOfDate', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_PeriodOfDate;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前日期的旬索引
-- 说明: 运行在SQL Server 2008+。
--       结果值从1开始计数,包括1、2、3.……、359962、359963、359964。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @inntDayOfDate = dbo.ufn_DayOfDate('2016-01-11')
--==================================
CREATE FUNCTION dbo.ufn_PeriodOfDate
(
    @dtmDate DATETIME                -- 指定的日期时间
) RETURNS INT
    --$Encode$--
BEGIN
    SET @dtmDate = dbo.ufn_GetValidDate(@dtmDate);
 
    RETURN DATEDIFF(MONTH, dbo.ufn_GetMinDateTime(), @dtmDate) * 3 + dbo.ufn_PeriodOfMonth(@dtmDate);
END
GO
 
-- Test Code
DECLARE @dtmDate AS DATETIME;
SET @dtmDate = '2016-01-15';
 
SELECT
    @dtmDate AS 'The Current Date'
    ,dbo.ufn_Periods(@dtmDate) AS 'Periods'
    ,dbo.ufn_Periods2Date(dbo.ufn_Periods(@dtmDate)) AS 'Date Mapping Periods'
    ,dbo.ufn_PeriodOfMonth(@dtmDate) AS 'Period Of The Current Month'
    ,dbo.ufn_PeriodOfQuarter(@dtmDate) AS 'Period Of The Current Quarter'
    ,dbo.ufn_PeriodOfYear(@dtmDate) AS 'Period Of The Current Year'
    ,dbo.ufn_PeriodOfDate(@dtmDate) AS 'Period Of The Current Date';
 
SET @dtmDate = '2016-01-31';
 
SELECT
    @dtmDate AS 'The Current Date'
    ,dbo.ufn_Periods(@dtmDate) AS 'Periods'
    ,dbo.ufn_Periods2Date(dbo.ufn_Periods(@dtmDate)) AS 'Date Mapping Periods'
    ,dbo.ufn_PeriodOfMonth(@dtmDate) AS 'Period Of The Current Month'
    ,dbo.ufn_PeriodOfQuarter(@dtmDate) AS 'Period Of The Current Quarter'
    ,dbo.ufn_PeriodOfYear(@dtmDate) AS 'Period Of The Current Year'
    ,dbo.ufn_PeriodOfDate(@dtmDate) AS 'Period Of The Current Date';
GO
 
测试以上函数的效果,如下图:
 
    月时间粒度有关函数,T-SQL代码如下:
IF OBJECT_ID(N'dbo.ufn_Months', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Months;
END
GO
 
--==================================
-- 功能: 获得指定日期时间基于默认基准日期的总月数(一个整数值)
-- 说明: 运行在SQL Server 2005+。
--       如果指定的日期时间为NULL或者小于默认基准日期时,则其值为默认基准日期。
--       结果值为非负整数,从0开始计数。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @intMonths = dbo.ufn_Months('2008-01-14')
--==================================
CREATE FUNCTION dbo.ufn_Months 
(
    @dtmDate DATETIME                -- 指定的日期时间
) RETURNS INT
AS
BEGIN
    RETURN DATEDIFF(MONTH, dbo.ufn_GetDefaultBasedate(), dbo.ufn_GetValidDate(@dtmDate));
END
GO
 
IF OBJECT_ID(N'dbo.ufn_Months2Date', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Months2Date;
END
GO
 
--==================================
-- 功能: 获得一个整数值基于默认基准日期对应的月基准日期
-- 说明: 运行在SQL Server 2005+。
--       如果指定的整数值为NULL或为负整数时,则其值默认为0。
--       如果指定的整数值大于最大日期时间对应的整数值时,则其值默认设置为最大日期时间对应的整数值。
--       结果值为基于默认基准日期开始计数的日期。
--       月基准日期是指一个月份中第1天对应的日期,比如'2016-02'月份的月旬基准日期为'2016-02-01'。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @dtmDate = dbo.ufn_Months2Date(1296) --'2008-01-01'
--==================================
CREATE FUNCTION dbo.ufn_Months2Date 
(
    @intMonths INT                -- 指定的整数值
) RETURNS DATETIME
AS
BEGIN
    SET @intMonths = dbo.ufn_GetValidDateNum(@intMonths);
 
    DECLARE @intMaxMonths AS INT;
    SET @intMaxMonths = dbo.ufn_Months(dbo.ufn_GetMaxDateTime());
 
    IF @intMonths >= @intMaxMonths
    BEGIN
        SET @intMonths = @intMaxMonths;
    END
 
    RETURN DATEADD(MONTH, @intMonths, dbo.ufn_GetDefaultBasedate());
END
GO
 
IF OBJECT_ID(N'dbo.ufn_MonthOfQuarter', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_MonthOfQuarter;
END
GO
 
--==================================
-- 功能: 获得一个日期时间的月份在当前季度的月索引
-- 说明: 运行在SQL Server 2005+。
--       如果指定的整数值为NULL时,则其值默认设置为默认基准日期。
--       结果值从1开始计数,包括1、2、3。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @dtmDate = dbo.ufn_MonthOfQuarter(2008-01-01);
--==================================
CREATE FUNCTION dbo.ufn_MonthOfQuarter
(
    @dtmDate DATETIME            -- 指定的日期时间
) RETURNS TINYINT
AS
BEGIN
    SET @dtmDate = dbo.ufn_GetValidDate(@dtmDate);
    DECLARE @tintMonthOfQuarter AS TINYINT;
    SET @tintMonthOfQuarter = 1;
 
    SET @tintMonthOfQuarter =  MONTH(@dtmDate) % 3;
 
    IF @tintMonthOfQuarter = 0
    BEGIN
        SET @tintMonthOfQuarter = 3;
    END
 
    RETURN @tintMonthOfQuarter;
END
GO
 
IF OBJECT_ID(N'dbo.ufn_MonthOfYear', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_MonthOfYear;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前年的月索引
-- 说明: 运行在SQL Server 2005+。
--       结果值从1开始计数,包括1、2、……、9、10、11、12。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @tintMonthOfYear = dbo.ufn_MonthOfYear('2016-01-11')
--==================================
CREATE FUNCTION dbo.ufn_MonthOfYear
(
    @dtmDate DATETIME            -- 指定的日期时间
) RETURNS TINYINT
    --$Encode$--
BEGIN
    RETURN MONTH(@dtmDate);
END
GO
 
 
IF OBJECT_ID(N'dbo.ufn_MonthOfDate', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_MonthOfDate;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前日期的月索引
-- 说明: 运行在SQL Server 2008+。
--       结果值从1开始计数,包括1、2、3.……、119986、119987、119988。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @intMonthOfDate = dbo.ufn_MonthOfDate('2016-01-11')
--==================================
CREATE FUNCTION dbo.ufn_MonthOfDate
(
    @dtmDate DATETIME
) RETURNS INT
    --$Encode$--
BEGIN
    RETURN DATEDIFF(MONTH, dbo.ufn_GetMinDateTime(), dbo.ufn_GetValidDate(@dtmDate)) + 1;
END
GO
 
 
-- Test Code
DECLARE @dtmDate AS DATETIME;
SET @dtmDate = '2016-01-15';
 
SELECT
    @dtmDate AS 'The Current Date'
    ,dbo.ufn_Months(@dtmDate) AS 'Months'
    ,dbo.ufn_Months2Date(dbo.ufn_Months(@dtmDate)) AS 'Date Mapping Months'
    ,dbo.ufn_MonthOfQuarter(@dtmDate) AS 'Month Of The Current Quarter'
    ,dbo.ufn_MonthOfYear(@dtmDate) AS 'Month Of The Current Year'
    ,dbo.ufn_MonthOfDate(@dtmDate) AS 'Month Of The Current Date';
 
SET @dtmDate = '2016-09-30';
 
SELECT
    @dtmDate AS 'The Current Date'
    ,dbo.ufn_Months(@dtmDate) AS 'Months'
    ,dbo.ufn_Months2Date(dbo.ufn_Months(@dtmDate)) AS 'Date Mapping Months'
    ,dbo.ufn_MonthOfQuarter(@dtmDate) AS 'Month Of The Current Quarter'
    ,dbo.ufn_MonthOfYear(@dtmDate) AS 'Month Of The Current Year'
    ,dbo.ufn_MonthOfDate(@dtmDate) AS 'Month Of The Current Date';
GO
 
测试以上函数的效果,如下图:
 
    季时间粒度有关函数,T-SQL代码如下:
IF OBJECT_ID(N'dbo.ufn_Quarters', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Quarters;
END
GO
 
--==================================
-- 功能: 获得指定日期时间基于默认基准日期的总季数(一个整数值)
-- 说明: 运行在SQL Server 2005+。
--       如果指定的日期时间为NULL或者小于默认基准日期时,则其值为默认基准日期。
--       结果值为非负整数,从0开始计数。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @intQuarters = dbo.ufn_Quarters('2008-01-14')
--==================================
CREATE FUNCTION dbo.ufn_Quarters
(
    @dtmDate DATETIME                    -- 指定的日期时间
) RETURNS INT
    --$Encode$--
AS
BEGIN
    RETURN DATEDIFF(QUARTER, dbo.ufn_GetDefaultBasedate(), dbo.ufn_GetValidDate(@dtmDate));
END
GO
 
IF OBJECT_ID(N'dbo.ufn_Quarters2Date', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Quarters2Date;
END
GO
 
--==================================
-- 功能: 获得一个整数值基于默认基准日期对应的季基准日期
-- 说明: 运行在SQL Server 2005+。
--       如果指定的整数值为NULL或为负整数时,则其值默认为0。
--       如果指定的整数值大于最大日期时间对应的整数值时,则其值默认设置为最大日期时间对应的整数值。
--       结果值为基于默认基准日期开始计数的日期。
--       季基准日期是指所在季度的第一个月份中第1天对应的日期,比如'2016-06-08'月份的姐旬基准日期为'2016-04-01'。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @dtmDate = dbo.fn_Quarters2Date(300) --'1975-02-21'
--==================================
CREATE FUNCTION dbo.ufn_Quarters2Date 
(
    @intQuarters INT            -- 指定的整数值
) RETURNS DATETIME
    --$Encode$--
AS
BEGIN
    SET @intQuarters = dbo.ufn_GetValidDateNum(@intQuarters);
 
    DECLARE @intMaxQuarters AS INT;
    SET @intMaxQuarters = dbo.ufn_Quarters(dbo.ufn_GetMaxDateTime());
 
    IF @intQuarters >= @intMaxQuarters
    BEGIN
        SET @intQuarters = @intMaxQuarters;
    END
 
    RETURN DATEADD(QUARTER, @intQuarters, dbo.ufn_GetDefaultBasedate());
END
GO
 
IF OBJECT_ID(N'dbo.ufn_QuarterOfYear', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_QuarterOfYear;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前年内的旬索引
-- 说明: 运行在SQL Server 2005+。
--       结果从1开始计数,1、2、3、4分别表示第1季度、第2季度、第3季度、第4季度。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @tintQuarterOfYear = dbo.ufn_QuarterOfYear('2016-01-11');
--==================================
CREATE FUNCTION dbo.ufn_QuarterOfYear
(
    @dtmDate DATETIME                --指定的日期时间
) RETURNS TINYINT
    --$Encode$--
AS
BEGIN
    RETURN DATEPART(QUARTER, @dtmDate);
END
GO
 
IF OBJECT_ID(N'dbo.ufn_QuarterOfDate', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_QuarterOfDate;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在当前日期的季索引
-- 说明: 运行在SQL Server 2008+。
--       结果值从1开始计数,包括1、2、3.……、39994、39995、39996。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @intQuarterOfDate = dbo.ufn_QuarterOfDate('2016-01-11')
--==================================
CREATE FUNCTION dbo.ufn_QuarterOfDate
(
    @dtmDate DATETIME                --指定的日期时间
) RETURNS INT
    --$Encode$--
BEGIN
    RETURN DATEDIFF(QUARTER, dbo.ufn_GetMinDateTime(), dbo.ufn_GetValidDate(@dtmDate)) + 1;
END
GO
 
 
-- Test Code
DECLARE @dtmDate AS DATETIME;
SET @dtmDate = '2016-01-15';
 
SELECT
    @dtmDate AS 'The Current Date'
    ,dbo.ufn_Quarters(@dtmDate) AS 'Quarters'
    ,dbo.ufn_Quarters2Date(dbo.ufn_Quarters(@dtmDate)) AS 'Date Mapping Quarters'
    ,dbo.ufn_QuarterOfYear(@dtmDate) AS 'Quarter Of The Current Year'
    ,dbo.ufn_QuarterOfDate(@dtmDate) AS 'Quarter Of The Current Date';
 
SET @dtmDate = '2016-09-30';
 
SELECT
    @dtmDate AS 'The Current Date'
    ,dbo.ufn_Quarters(@dtmDate) AS 'Quarters'
    ,dbo.ufn_Quarters2Date(dbo.ufn_Quarters(@dtmDate)) AS 'Date Mapping Quarters'
    ,dbo.ufn_QuarterOfYear(@dtmDate) AS 'Quarter Of The Current Year'
    ,dbo.ufn_QuarterOfDate(@dtmDate) AS 'Quarter Of The Current Date';
GO
 
测试以上函数的效果,如下图:
 
    年时间粒度有关函数,T-SQL代码如下:
IF OBJECT_ID(N'dbo.ufn_Years', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Years;
END
GO
 
--==================================
-- 功能: 获得指定日期时间基于默认基准日期的总年数(一个整数值)
-- 说明: 运行在SQL Server 2005+。
--       如果指定的日期时间为NULL或者小于默认基准日期时,则其值为默认基准日期
--       结果值为非负整数,从0开始计数。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @sintYears = dbo.ufn_Years('2008-01-14')
--==================================
CREATE FUNCTION dbo.ufn_Years 
(
    @dtmDate DATETIME            -- 指定的日期时间
) RETURNS SMALLINT
    --$Encode$--
AS
BEGIN
    RETURN DATEDIFF(YEAR, dbo.ufn_GetDefaultBasedate(), dbo.ufn_GetValidDate(@dtmDate));
END
GO
 
IF OBJECT_ID(N'dbo.ufn_Years2Date', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_Years2Date;
END
GO
 
--==================================
-- 功能: 获得一个整数值基于默认基准日期对应的年基准日期
-- 说明: 运行在SQL Server 2005+。
--       如果指定的整数值为NULL或为负整数时,则其值默认为0;
--       如果指定的整数值大于最大日期时间对应的整数值时,则其值默认设置为最大日期时间对应的整数值;
--       结果值为基于默认基准日期开始计数的日期;
--       年基准日期是指所在年的第一个月份中第1天对应的日期,比如'2016-06-08'月份的姐旬基准日期为'2016-01-01'。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @dtmDate = dbo.ufn_Years2Date(300) --'1975-02-21'
--==================================
CREATE FUNCTION dbo.ufn_Years2Date
(
    @sintYears SMALLINT            -- 指定的整数值
) RETURNS DATETIME
    --$Encode$--
AS
BEGIN
    SET @sintYears = dbo.ufn_GetValidDateNum(@sintYears);
 
    DECLARE @sintMaxYears AS SMALLINT;
    SET @sintMaxYears = dbo.ufn_Years(dbo.ufn_GetMaxDateTime());
 
    IF @sintYears >= @sintMaxYears
    BEGIN
        SET @sintYears = @sintMaxYears;
    END
 
    RETURN DATEADD(YEAR, @sintYears, dbo.ufn_GetDefaultBasedate());
END
GO
 
IF OBJECT_ID(N'dbo.ufn_YearOfDate', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION dbo.ufn_YearOfDate;
END
GO
 
--==================================
-- 功能: 获取指定的日期时间所在日期内的年索引
-- 说明: 运行在SQL Server 2005+。
--       结果从1开始计数,1、2、3、……、9998、9999。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SET @sintYearOfDate = dbo.ufn_YearsOfDate('2016-01-11');
--==================================
CREATE FUNCTION dbo.ufn_YearOfDate
(
    @dtmDate DATETIME                --指定的日期时间
) RETURNS SMALLINT
    --$Encode$--
AS
BEGIN
    RETURN YEAR(@dtmDate);
END
GO
 
 
-- Test Code
DECLARE @dtmDate AS DATETIME;
SET @dtmDate = '2016-01-15';
 
SELECT
    @dtmDate AS 'The Current Date'
    ,dbo.ufn_Years(@dtmDate) AS 'Years'
    ,dbo.ufn_Years2Date(dbo.ufn_Years(@dtmDate)) AS 'Date Mapping Years'
    ,dbo.ufn_YearOfDate(@dtmDate) AS 'Year Of The Current Date';
 
SET @dtmDate = '2016-09-30';
 
SELECT
    @dtmDate AS 'The Current Date'
    ,dbo.ufn_Years(@dtmDate) AS 'Years'
    ,dbo.ufn_Years2Date(dbo.ufn_Years(@dtmDate)) AS 'Date Mapping Years'
    ,dbo.ufn_YearOfDate(@dtmDate) AS 'Year Of The Current Date';
GO
 
测试以上函数的效果,如下图:
 
日历数据表
 
    
根据以上各时间粒度有关的函数,汇总为一个日历数据表(Calendar),其表字段列如下表格:
序号字段列
字段列类型
字段列说明
1
CalendarDate
datetime日历日期[1900-01-01、1900-01-02、……、999-12-31]
2
Days
int
日期天数[0、1、2、……、最大值]
3
DayOfWeek
tinyint周内日索引[1、2、……、7]
4
WorkDayFlagbit
工作日标志,1:工作日,0:非工作日
5
DayOfPeriod
tinyint
旬内日索引[1、2、……、8、9、10、11]
6
DayOfMonth
tinyint
月内日索引[1、2、……、28、29、30、31]
7
DayOfQuarter
tinyint
季内日索引[1、2、……88、89、90、91、92]
8
DayOfYear
smallint
年内日索引[1、2、……、364、365、366]
9DayOfDate
int
日期内日索引[1、2、……、3652059]
10
Weeks
int
日期周数[0、1、2、……、最大值]
11WeekOfPeriod
tinyint
旬内周索引[1、2、3]
12
WeekOfMonth
tinyint
月内周索引[1、2、3、4、5]
13
WeekOfQuarter
tinyint
季内周索引[1、2、……、34、35、36、37]
14WeekOfYear
tinyint
年内周索引[1、2、……、51、52、53]
15
WeekOfDate
int
日期内周索引[1、2、……、521723]
16
Periods
int
日期旬数[0、1、2、……、最大值]
17PeriodOfMonth
tinyint
月内旬索引[1、2、3]
18
PeriodOfQuarter
tinyint
季内旬索引[1、2、3、4、5、6、7、8、9]
19
PeriodOfYear
tinyint
年内旬索引[1、2、……、35、36]
20
PeriodOfDate
int
日期内旬索引[1、2、……、359964]
21
Months
int
日期月数[0、1、2、……、最大值]
22
MonthOfQuarter
tinyint
季内月索引[1、2、3]
23
MonthOfYear
tinyint
年内月索引[1、2、……、11、12]
24
MonthOfDate
int
日期内月索引[1、2、……、119988]
25
Quarters
int
日期季数[0、1、2、……、最大值]
26
QuarterOfYear
tinyint
年内季索引[1、2、3、4]
27
QuarterOfDate
int
日期内季索引[1、2、……、39996]
28
Years
smallint
日期年数[0、1、2、……、最大值]
29
YearOfDatesmallint日期内年索引[1、2、……、9999]
日历数据表创建的T-SQL脚本如下:
IF OBJECT_ID(N'dbo.Calendar', 'U') IS NOT NULL
BEGIN    
    DROP TABLE dbo.Calendar;
END
GO
 
CREATE TABLE dbo.Calendar (
    CalendarDate DATETIME NOT NULL,
    [Days] INT NOT NULL,
    [DayOfWeek] TINYINT NOT NULL,
    WorkDayFlag BIT NOT NULL,
    DayOfPeriod TINYINT NOT NULL,
    [DayOfMonth] TINYINT NOT NULL,
    DayOfQuarter TINYINT NOT NULL,
    [DayOfYear] SMALLINT NOT NULL,
    DayOfDate INT NOT NULL,
    Weeks INT NOT NULL,
    WeekOfPeriod TINYINT NOT NULL,
    WeekOfMonth TINYINT NOT NULL,
    WeekOfQuarter TINYINT NOT NULL,
    WeekOfYear TINYINT NOT NULL,
    WeekOfDate INT NOT NULL,
    Periods INT NOT NULL,
    PeriodOfMonth TINYINT NOT NULL,
    PeriodOfQuarter TINYINT NOT NULL,
    PeriodOfYear TINYINT NOT NULL,
    PeriodOfDate INT NOT NULL,
    Months INT NOT NULL,
    MonthOfQuarter TINYINT NOT NULL,
    MonthOfYear TINYINT NOT NULL,
    MonthOfDate INT NOT NULL,
    Quarters INT NOT NULL,
    QuarterOfYear TINYINT NOT NULL,
    QuarterOfDate INT NOT NULL,
    Years SMALLINT NOT NULL,
    YearOfDate SMALLINT NOT NULL,
    TagID INT NOT NULL,
    FlagID INT NOT NULL    
);
 
IF OBJECT_ID(N'PK_U_CL_Calendar_Days', N'PK') IS NULL
BEGIN
    ALTER TABLE [dbo].[Calendar] ADD CONSTRAINT [PK_U_CL_Calendar_Days] PRIMARY KEY CLUSTERED 
    (
        [Days] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) 
    ON [PRIMARY];
END
GO
 
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[Calendar]', N'U') AND name = N'IX_U_NCL_Calendar_CalendarDate')
BEGIN
    CREATE NONCLUSTERED INDEX [IX_U_NCL_Calendar_CalendarDate] ON [dbo].[Calendar]
    (
        [CalendarDate] ASC
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90)
    ON [PRIMARY];
END
GO
 
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[Calendar]', N'U') AND name = N'IX_NU_NCL_Calendar_Weeks')
BEGIN
    CREATE NONCLUSTERED INDEX [IX_NU_NCL_Calendar_Weeks] ON [dbo].[Calendar]
    (
        [Weeks] ASC
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90)
    ON [PRIMARY];
END
GO
 
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[Calendar]', N'U') AND name = N'IX_NU_NCL_Calendar_Periods')
BEGIN
    CREATE NONCLUSTERED INDEX [IX_NU_NCL_Calendar_Periods] ON [dbo].[Calendar]
    (
        [Periods] ASC
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90)
    ON [PRIMARY];
END
GO
 
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[Calendar]', N'U') AND name = N'IX_NU_NCL_Calendar_Months')
BEGIN
    CREATE NONCLUSTERED INDEX [IX_NU_NCL_Calendar_Months] ON [dbo].[Calendar]
    (
        [Months] ASC
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90)
    ON [PRIMARY];
END
GO
 
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[Calendar]', N'U') AND name = N'IX_NU_NCL_Calendar_Quarters')
BEGIN
    CREATE NONCLUSTERED INDEX [IX_NU_NCL_Calendar_Quarters] ON [dbo].[Calendar]
    (
        [Quarters] ASC
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90)
    ON [PRIMARY];
END
GO
 
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[Calendar]', N'U') AND name = N'IX_NU_NCL_Calendar_Years')
BEGIN
    CREATE NONCLUSTERED INDEX [IX_NU_NCL_Calendar_Years] ON [dbo].[Calendar]
    (
        [Years] ASC
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90)
    ON [PRIMARY];
END
GO
 
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[Calendar]', N'U') AND name = N'IX_NU_NCL_Calendar_YearOfDate')
BEGIN
    CREATE NONCLUSTERED INDEX [IX_NU_NCL_Calendar_YearOfDate] ON [dbo].[Calendar]
    (
        [YearOfDate] ASC
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90)
    ON [PRIMARY];
END
GO
 
EXEC sp_addextendedproperty N'MS_Description', N'日历数据表', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', NULL, NULL;
GO
EXEC sp_addextendedproperty N'MS_Description', N'日历日期', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'CalendarDate';
GO
EXEC sp_addextendedproperty N'MS_Description', N'日期天数(从0开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'Days';
GO
EXEC sp_addextendedproperty N'MS_Description', N'周内日索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'DayOfWeek';
GO
EXEC sp_addextendedproperty N'MS_Description', N'工作日标志(1:工作日,0:非工作日)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'WorkDayFlag';
GO
EXEC sp_addextendedproperty N'MS_Description', N'旬内日索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'DayOfPeriod';
GO
EXEC sp_addextendedproperty N'MS_Description', N'月内日索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'DayOfMonth';
GO
EXEC sp_addextendedproperty N'MS_Description', N'季内日索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'DayOfQuarter';
GO
EXEC sp_addextendedproperty N'MS_Description', N'年内日索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'DayOfYear';
GO
EXEC sp_addextendedproperty N'MS_Description', N'日期内日索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'DayOfDate';
GO
EXEC sp_addextendedproperty N'MS_Description', N'日期周数(从0开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'Weeks';
GO
EXEC sp_addextendedproperty N'MS_Description', N'旬内周索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'WeekOfPeriod';
GO
EXEC sp_addextendedproperty N'MS_Description', N'月内周索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'WeekOfMonth';
GO
EXEC sp_addextendedproperty N'MS_Description', N'季内周索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'WeekOfQuarter';
GO
EXEC sp_addextendedproperty N'MS_Description', N'年内周索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'WeekOfYear';
GO
EXEC sp_addextendedproperty N'MS_Description', N'日期内周索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'WeekOfDate';
GO
EXEC sp_addextendedproperty N'MS_Description', N'日期旬数(从0开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'Periods';
GO
EXEC sp_addextendedproperty N'MS_Description', N'月内旬索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'PeriodOfMonth';
GO
EXEC sp_addextendedproperty N'MS_Description', N'季内旬索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'PeriodOfQuarter';
GO
EXEC sp_addextendedproperty N'MS_Description', N'年内旬索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'PeriodOfYear';
GO
EXEC sp_addextendedproperty N'MS_Description', N'日期内旬索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'PeriodOfDate';
GO
EXEC sp_addextendedproperty N'MS_Description', N'日期月数(从0开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'Months';
GO
EXEC sp_addextendedproperty N'MS_Description', N'季内月索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'MonthOfQuarter';
GO
EXEC sp_addextendedproperty N'MS_Description', N'年内月索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'MonthOfYear';
GO
EXEC sp_addextendedproperty N'MS_Description', N'日期内月索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'MonthOfDate';
GO
EXEC sp_addextendedproperty N'MS_Description', N'日期季数(从0开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'Quarters';
GO
EXEC sp_addextendedproperty N'MS_Description', N'年内季索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'QuarterOfYear';
GO
EXEC sp_addextendedproperty N'MS_Description', N'日期内季索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'QuarterOfDate';
GO
EXEC sp_addextendedproperty N'MS_Description', N'日期年数(从0开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'Years';
GO
EXEC sp_addextendedproperty N'MS_Description', N'日期内年索引(从1开始计数)', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'YearOfDate';
GO
EXEC sp_addextendedproperty N'MS_Description', N'标记ID,辅助扩展字段列', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'TagID';
GO
EXEC sp_addextendedproperty N'MS_Description', N'标志ID,辅助扩展字段列', 'SCHEMA', N'dbo', 'TABLE', N'Calendar', 'COLUMN', N'FlagID';
GO
 
日历数据表填充数据
    
初始化日历表数据的功能封装在一个存储过程中,T-SQL代码如下:
IF OBJECT_ID(N'dbo.usp_Calendar_Init', 'P') IS NOT NULL
BEGIN
    DROP PROCEDURE dbo.usp_Calendar_Init;
END
GO
 
--==================================
-- 功能: 初始化日历表中的数据
-- 说明: 具体实现阐述
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
--==================================
CREATE PROCEDURE dbo.usp_Calendar_Init
(
    @dtmEndDate DATETIME,                        -- 日历截止日期时间    
    @chvnErrMsg NVARCHAR(100) OUTPUT            -- 错误消息字符串
)     --$Encode$--
AS
BEGIN
    SET NOCOUNT ON;
 
    SET @chvnErrMsg = N'';
 
    DECLARE @tintReturnValue AS TINYINT;
    SET @tintReturnValue = 1;
 
    IF @dtmEndDate IS NULL
    BEGIN
        SET @chvnErrMsg = N'日历截止日期时间不能为NULL。';
 
        RETURN @tintReturnValue;
    END
 
    DECLARE    @dtmDefaultBasedate AS DATETIME;
    SET @dtmDefaultBasedate = dbo.ufn_GetDefaultBasedate();
 
    IF @dtmDefaultBasedate > @dtmEndDate
    BEGIN
        SET @chvnErrMsg = N'日历截止日期时间不能小于默认基准日期时间【' + CONVERT(VARCHAR(10), @dtmEndDate, 120) + N'】';
 
        RETURN @tintReturnValue;
    END
 
    -- 插入数据
    INSERT INTO dbo.Calendar (
        CalendarDate
        ,Days
        ,DayOfWeek
        ,WorkDayFlag
        ,DayOfPeriod
        ,DayOfMonth
        ,DayOfQuarter
        ,DayOfYear
        ,DayOfDate
        ,Weeks
        ,WeekOfPeriod
        ,WeekOfMonth
        ,WeekOfQuarter
        ,WeekOfYear
        ,WeekOfDate
        ,Periods
        ,PeriodOfMonth
        ,PeriodOfQuarter
        ,PeriodOfYear
        ,PeriodOfDate
        ,Months
        ,MonthOfQuarter
        ,MonthOfYear
        ,MonthOfDate
        ,Quarters
        ,QuarterOfYear
        ,QuarterOfDate
        ,Years
        ,YearOfDate
        ,TagID
        ,FlagID)
    SELECT 
        T.CalendarDate
        ,T.[Days]
        ,T.[DayOfWeek]
        ,CASE WHEN T.[DayOfWeek] >= 6 THEN 0 ELSE 1 END AS WorkDayFlag
        ,T.DayOfPeriod
        ,T.[DayOfMonth]
        ,T.DayOfQuarter
        ,T.[DayOfYear]
        ,T.DayOfDate
        ,T.Weeks
        ,T.WeekOfPeriod
        ,T.WeekOfMonth
        ,T.WeekOfQuarter
        ,T.WeekOfYear
        ,T.WeekOfDate
        ,T.Periods
        ,T.PeriodOfMonth
        ,T.PeriodOfQuarter
        ,T.PeriodOfYear
        ,T.PeriodOfDate
        ,T.Months
        ,T.MonthOfQuarter
        ,T.MonthOfYear
        ,T.MonthOfDate
        ,T.Quarters
        ,T.QuarterOfYear
        ,T.QuarterOfDate
        ,T.Years
        ,T.YearOfDate
        ,0 AS TagID
        ,0 AS FlagID
    FROM (
        SELECT T.CalendarDate
            ,dbo.ufn_Days(T.CalendarDate) AS [Days]
            ,dbo.ufn_DayOfWeek(T.CalendarDate) AS [DayOfWeek]
            ,dbo.ufn_DayOfPeriod(T.CalendarDate) AS DayOfPeriod
            ,dbo.ufn_DayOfMonth(T.CalendarDate) AS [DayOfMonth]
            ,dbo.ufn_DayOfQuarter(T.CalendarDate) AS DayOfQuarter
            ,dbo.ufn_DayOfYear(T.CalendarDate) AS [DayOfYear]
            ,dbo.ufn_DayOfDate(T.CalendarDate) AS DayOfDate
            ,dbo.ufn_Weeks(T.CalendarDate) AS Weeks
            ,dbo.ufn_WeekOfPeriod(T.CalendarDate) AS WeekOfPeriod
            ,dbo.ufn_WeekOfMonth(T.CalendarDate) AS WeekOfMonth
            ,dbo.ufn_WeekOfQuarter(T.CalendarDate) AS WeekOfQuarter
            ,dbo.ufn_WeekOfYear(T.CalendarDate) AS WeekOfYear
            ,dbo.ufn_WeekOfDate(T.CalendarDate) AS WeekOfDate
            ,dbo.ufn_Periods(T.CalendarDate) AS Periods
            ,dbo.ufn_PeriodOfMonth(T.CalendarDate) AS PeriodOfMonth
            ,dbo.ufn_PeriodOfQuarter(T.CalendarDate) AS PeriodOfQuarter
            ,dbo.ufn_PeriodOfYear(T.CalendarDate) AS PeriodOfYear
            ,dbo.ufn_PeriodOfDate(T.CalendarDate) AS PeriodOfDate
            ,dbo.ufn_Months(T.CalendarDate) AS Months
            ,dbo.ufn_MonthOfQuarter(T.CalendarDate) AS MonthOfQuarter
            ,dbo.ufn_MonthOfYear(T.CalendarDate) AS MonthOfYear
            ,dbo.ufn_MonthOfDate(T.CalendarDate) AS MonthOfDate
            ,dbo.ufn_Quarters(T.CalendarDate) AS Quarters
            ,dbo.ufn_QuarterOfYear(T.CalendarDate) AS QuarterOfYear
            ,dbo.ufn_QuarterOfDate(T.CalendarDate) AS QuarterOfDate
            ,dbo.ufn_Years(T.CalendarDate) AS Years
            ,dbo.ufn_YearOfDate(T.CalendarDate) AS YearOfDate
        FROM (
            SELECT DATEADD(DAY, Num, @dtmDefaultBasedate) AS CalendarDate
            FROM dbo.ufn_GetNums(0, DATEDIFF(DAY, @dtmDefaultBasedate, @dtmEndDate))
        ) AS T
    ) AS T
    WHERE NOT EXISTS (SELECT 1 FROM dbo.Calendar WHERE [Days] = T.[Days]);
 
    IF @@ERROR <> 0
    BEGIN
        SET @chvnErrMsg = N'向日历表初始化数据时发生错误。';
 
        RETURN RETURN @tintReturnValue;
    END
 
    SET @tintReturnValue = 0;
 
    RETURN @tintReturnValue;
END
GO
 
-- Test Code
DECLARE 
    @dtmEndDate AS DATETIME,
    @chvnErrMsg NVARCHAR(100),
    @tintReturnValue AS TINYINT;
SELECT
    @dtmEndDate = '1899-12-31',
    @chvnErrMsg = N'',
    @tintReturnValue = 0;
 
EXEC @tintReturnValue = dbo.usp_Calendar_Init
    @dtmEndDate = @dtmEndDate,            -- datetime
    @chvnErrMsg = @chvnErrMsg OUTPUT;    -- nvarchar(100)
 
SELECT
    @chvnErrMsg AS N'Error Message'
    ,@tintReturnValue AS 'Return Value(1:有错误,0:没有错误)';
 
SELECT
    @dtmEndDate = '2099-12-31',
    @chvnErrMsg = N'',
    @tintReturnValue = 0;
 
EXEC @tintReturnValue = dbo.usp_Calendar_Init
    @dtmEndDate = @dtmEndDate,            -- datetime
    @chvnErrMsg = @chvnErrMsg OUTPUT;    -- nvarchar(100)
 
SELECT
    @chvnErrMsg AS N'Error Message'
    ,@tintReturnValue AS 'Return Value(1:有错误,0:没有错误)';
GO
 
以上测试代码的效果,如下图:
 
查询日历数据表中2016年的数据,T-SQL代码如下:
SELECT *
FROM dbo.Calendar
WHERE DAYS BETWEEN dbo.ufn_Days('2016-01-01') AND dbo.ufn_Days('2016-12-31');
GO
 
执行后的查询结果如下图:
 
注意:usp_Calendar_Init存储使用到了数字辅助数字函数dbo.ufn_GetNums,该函数脚本请参考SQL Server数字辅助表的实现
 
总结语
    
    本文断断续续写了两天,才将本系列之前涉及到每个时间粒度有关的内容在本文做个总结。每个时间粒度有关的函数,以及将时间粒度有关的封装在了日历数据表中。
参考清单列表
  相关解决方案