编写SQL中经常可以遇到日期的格式化与日期相关函数,这篇文章中我们将整理一下相关函数并给出一些实例供参考

获取时间函数

getdate()函数

getdate()函数获取当前的日期与时间。返回的为datetime类型

select GETDATE()

返回2020-09-21 10:07:38.170

SYSDATETIME()函数

SYSDATETIME()函数获取当前的日期与时间,但是返回的数据类型是DATETIME2,会更加精准,使用频率较少

SELECT SYSDATETIME()

格式化函数

CONVERT()函数

CONVERT() 函数是一个数据类型转化的通用函数,例如将数字类型转化为文本等。我们可以使用此函数把日期转换为新数据类型
语法为:

        CONVERT(data_type(length),expression,style)

其中data_type(length) 规定目标数据类型(带有可选的长度)。expression指需要转换的值。style 规定日期/时间的输出格式。

其中常用的style代码及显示格式如下:

        101: mm/dd/yyyy
        110: mm-dd-yyyy
        111: yyyy/mm/dd
        112: yyyymmdd
        120: yyyy-mm-dd hh:mm:ss
        121: yyyy-mm-dd hh:mm:sssssss

全部的style代码可以参考:https://www.cnblogs.com/rainman/p/6558261.html

例如;

    SELECT CONVERT(varchar(100), GETDATE(), 111)

通过查看转化后的数据类型,可以看到新的数据类型已变成varchar(100)类型。

--查看数据类型
DECLARE @query nvarchar(max) = 'SELECT CONVERT(varchar(100), GETDATE(), 111) AS [Column1]';
EXEC sp_describe_first_result_set @query, null, 0;

FORMAT()函数

Format函数用于指定显示的格式。
语法:

FORMAT(value,format[,culture])

参数format用于指定显示的格式,给予用户对格式更自由地控制,culture参数是可选的,用于指定显示的语言,该函数返回值的数据类型是NVARCHAR,如果格式转换失败,该函数返回NULL

参数format使用#表示一个数值,参数 format 使用以下占位符来表示日期/时间的格式:

1. yyyy、MM、dd:表示年、月、日
2. hh:mm:ss fffffff:表示时、分、秒、毫秒
3. 使用“/”,“-”等作为连接各个部分(part)的分割符号

例如要将当前日期转化为20200921,则SQL语句为:

SELECT Format(GETDATE(), 'yyyyMMdd')

同时format()函数还可以转变数值类型,使用特定的格式展示等

select FORMAT(123456789,'###-##-####') AS 'Custom Number Result'

对应返回结果为123-45-6789

日期的拆分

YEAR(date),MONTH(date),DAY(date)

YEAR(date),MONTH(date),DAY(date)等函数返回给定date的年,月,日
实例:

select year('2020-9-21'),month('2020-9-21'),day('2020-9-21')

DATEPART() 函数

DATEPART() 函数用于返回日期/时间的单独部分,比如年、月、日、小时、分钟等等

语法:

DATEPART(datepart,date)

其中date 参数是合法的日期表达式。datepart为需要取出的数据缩写代码。常用的datepart参数可以是下列的值:

    quarter:季度,取值范围是 1、2、3、4
    week:周在年中的序数,取值范围是 1 - 53
    dayofyear:天在年中的序数,取值范围是 1 - 366
    weekday:天在一周中的序数,取值范围是 1 - 7

全部参数可参阅:https://www.w3school.com.cn/sql/func_datepart.asp

具体实例代码:

--返回年,月份,季度,当前天数统计
SELECT DATEPART(yyyy,GETDATE()) AS Year,
DATEPART(m,GETDATE()) AS Month,
DATEPART(quarter,GETDATE()) AS Quarter,
DATEPART(dayofyear,GETDATE()) AS daynumber

DATENAME()函数,

与DATEPART不同的地方在于返回字符类型,比如Jan,一月等
语法:

DATENAME(datepart,date)

实例:

SELECT DATENAME(month, getdate()) AS 'Month'

对于中英文切换,使用如下语句:

set LANGUAGE 'Simplified Chinese'
select  DATENAME(WEEKDAY,getutcdate())

set LANGUAGE 'us_english'
select  DATENAME(WEEKDAY,getutcdate())

日期计算函数

EOMonth()函数

EOMonth()函数可以返回月份的最后一天。因此我们可以利用这个函数求某个月的最后一天与第一天。
语法:

EOMONTH(start_date [,month_to_add])

其中start_date: 有两种输入方式,能够转换为Date的字符串类型 和 date 数据类型
month_to_add: 是int 类型,能够为正整数,负整数和0,默认值是0,如果省略,那么使用默认值0,表示月份的偏移量。

--查看当前月的最后一天、下一个月的最后一天、上一个月的最后一天
declare @date date
set @date=getdate()

select EOMONTH(@date) as CurrentMonth_EndDay,
    EOMONTH(@date,1) as NextMonth_EndDay,
    EOMONTH(@date,-1) as LastMonth_EndDay

dateadd()函数

DATEADD() 函数在日期中添加或减去指定的时间间隔。
语法:

DATEADD(datepart,number,date)

其中datepart是單位(年,月,天等),number是指定的數值,date是原始日期
如下例的結果是当前时间的两个月后的日期,类型为datetime类型

    SELECT DATEADD(MONTH,2,getdate())

根据上述两个函数我们还可以通过上个月的最后一天+1来获取每个月第一天

select dateadd(day,1,EOMONTH(getdate(),-1)) as CurrentMonth_startDay

同时也可以通过前面所说的日期拼接函数与format函数实现

declare @date date
set @date=getdate()

select DATEFROMPARTS(year(@date),month(@date),1) 

--or

select FORMAT(GETDATE(),'yyyy-MM-01')

DATEDIFF()函数

DATEDIFF()函数计算两个日期之间的间隔,传回带正负符号的整数

语法:

DATEDIFF(datepart,startdate,enddate)

datepart为间隔的单位,可以选择天,周,月等。startdate跟enddate为起始时间

实例:

SELECT DATEDIFF(DAY, '2010-10-03','2010-10-04'  )

结果返回1

构造日期的函数

构造日期的函数有以下几个:
语法:

    DATEFROMPARTS ( year, month, day )
    DATETIME2FROMPARTS ( year, month, day, hour, minute, seconds, fractions, precision ) 
    DATETIMEOFFSETFROMPARTS ( year, month, day, hour, minute, seconds, fractions, hour_offset, minute_offset, precision )
    TIMEFROMPARTS ( hour, minute, seconds, fractions, precision )

传入对应参数后即可
其中参数precision 是指小数秒的精度,指的是DateTime2(n)、DateTimeOffset(n),Time(n)中的n值,表示以多少位小数表示1s,一般比较少使用

select DATEFROMPARTS ( 2020, 1, 2 )

练习实例

现有一列日期,请根据日期输出对应的每周开始与每周结束日期并格式化。
例如原始数据time_test表:

| date      | 
|-----------|
| 2020-8-4  | 
| 2020-8-5  | 
| 2020-8-6  | 
| 2020-8-12 | 
| 2020-8-8  | 
| 2020-8-12 | 
| 2020-9-15 |

期望的输出结果:

| date      | period  |
|-----------|---------|
| 2020-8-4  |0803-0809|
| 2020-8-5  |0803-0809|
| 2020-8-6  |0803-0809|
| 2020-8-12 |0810-0816|
| 2020-8-8  |0803-0809|
| 2020-8-12 |0803-0809|
| 2020-9-15 |0810-0816|

其中period的开始为每周周一,结束日期为每周周日

解答:
先给出代码

select [date],
format(DATEADD(wk, DATEDIFF(wk,0,DATEADD(dd,-1,[date])), 0),'MMdd')+'-'+format(DATEADD(dd,-1,DATEADD(wk, DATEDIFF(wk,0,DATEADD(dd,6,[date])), 0)),'MMdd') as period
from time_test

从内到外解析这一段代码,我们首先利用datediif(wk,0,date)计算从1900-01-01 到指定日期的周数(0代表日期对应的数字形式,即1900-01-01)。之后利用DateAdd函数在1900-01-01 的基础上加上刚刚我们计算出的周数,从而得到每周的开始时间。最后通过forma函数对日期格式化即可得出结果。

其中在最内层有一个DATEADD(dd,-1,[date]),这个是由于我使用的是英文版的SQL server,所以每周是周日开始与周六结束,如果使用中文版SQL server,应该就可以直接使[date]列