如何在SQL Server中使用整数创建日期

102

举个例子,如果我有:

DECLARE @Day int = 25
DECLARE @Month int  = 10 
DECLARE @Year int = 2016

我想要返回

2016-10-25

作为日期或日期时间

9个回答

185

在SQL Server 2012+中,您可以使用datefromparts()函数:

select datefromparts(@year, @month, @day)

在早期版本中,您可以将字符串转换。以下是一种方法:

select cast(cast(@year*10000 + @month*100 + @day as varchar(255)) as date)

字符串/日期时间转换是不确定的,除非使用CONVERT指定一个样式(而不是使用CAST)。https://msdn.microsoft.com/zh-cn/library/ms178091(SQL.90).aspx - Riley Major
3
@RileyMajor . . . 如果确定性很重要,那么确实需要一个格式。然而,格式为YYYYMMDD的字符串始终可以正确转换,无论任何国际化格式。 - Gordon Linoff
我经常听到这样的说法,我的实验也证明了这一点,但我没有看到微软官方文件证实这一点。你有看到吗? - Riley Major
此外,这种方法在1000年之前的年份上会失败:select cast(cast(900*10000 + 1*100 + 1 as varchar(255)) as date) - Riley Major
3
@RileyMajor . . . 文档位于 https://learn.microsoft.com/en-us/sql/t-sql/data-types/date-transact-sql#ansi-and-iso-8601-compliance,具体来说,“六位或八位数字字符串始终被解释为ymd。” - Gordon Linoff

18
在SQL Server 2012及以上版本中,您可以使用DATEFROMPARTS()函数:
DECLARE @Year int = 2016, @Month int = 10, @Day int = 25;
SELECT DATEFROMPARTS (@Year, @Month, @Day);

在早期版本中,一种方法是创建并转换字符串。

有一些字符串日期格式,SQL Server可以可靠地解释,而不管日期、语言或国际化设置如何。

六位或八位字符串始终被解释为ymd。月份和日期必须始终为两位数。

https://learn.microsoft.com/en-us/sql/t-sql/data-types/datetime-transact-sql

因此,格式为“yyyymmdd”的字符串将始终被正确解释。

(ISO 8601-- YYYY-MM-DDThh:mm:ss--也可以使用,但您必须指定时间,因此比您需要的更复杂。)

虽然您可以将此字符串简单地CAST为日期,但您必须使用CONVERT才能指定样式,而且必须指定样式才能确定(如果这对您很重要)。

“yyyymmdd”格式是样式112,因此您的转换如下:

DECLARE @Year int = 2016, @Month int = 10, @Day int = 25;
SELECT CONVERT(date,CONVERT(varchar(50),(@Year*10000 + @Month*100 + @Day)),112);

这将得到以下结果:

2016年10月25日

从技术上讲,即使指定了其他样式,ISO/112/yyyymmdd格式仍然有效。例如,使用样式104(德国,dd.mm.yyyy)的文本格式:

DECLARE @Year int = 2016, @Month int = 10, @Day int = 25;
SELECT CONVERT(date,CONVERT(varchar(50),(@Year*10000 + @Month*100 + @Day)),104);

还会导致以下结果:

2016年10月25日

其他格式不够稳健。例如:

SELECT CASE WHEN CONVERT(date,'01-02-1900',110) = CONVERT(date,'01-02-1900',105) THEN 1 ELSE 0 END;

结果为:

0

作为一个旁注,使用这种方法时,要注意无意义的输入可能会产生有效但不正确的日期:
DECLARE @Year int = 2016, @Month int = 0, @Day int = 1025;
SELECT CONVERT(date,CONVERT(varchar(50),(@Year*10000 + @Month*100 + @Day)),112);

同时也会产生:

2016-10-25

DATEFROMPARTS 可以防止无效的输入。下面这个示例:

DECLARE @Year int = 2016, @Month int = 10, @Day int = 32;
SELECT DATEFROMPARTS (@Year, @Month, @Day);

产生:

消息 289,级别 16,状态 1,行 2 无法构造数据类型日期,一些参数具有无效值。

还要注意,此方法不适用于早于1000-01-01的日期。例如:

DECLARE @Year int = 900, @Month int = 1, @Day int = 1;
SELECT CONVERT(date,CONVERT(varchar(50),(@Year*10000 + @Month*100 + @Day)),112);

产生的字符串 '9000101' 不符合 'yyyymmdd' 格式,因此出现了这个错误。为确保正确格式化,您需要在前面填充零,但这会牺牲一些性能。例如:

Msg 241,级别 16,状态 1,第 2 行 转换字符时转换日期和/或时间失败。

DECLARE @Year int = 900, @Month int = 1, @Day int = 1;
SELECT CONVERT(date,RIGHT('000' + CONVERT(varchar(50),(@Year*10000 + @Month*100 + @Day)),8),112);

结果为:

0900-01-01

除了字符串转换之外,还有其他方法。有几种方法在 "使用 T-SQL 创建日期" 的答案中提供。 一个值得注意的例子 是通过将年、月和日添加到“零日期”来创建日期。

(这个答案受Gordon Linoff回答启发,我进行了扩展并提供了额外的文档和注释。)


5

旧版 Microsoft Sql Server (< 2012)

RETURN dateadd(month, 12 * @year + @month - 22801, @day - 1)  

2

我相信以下代码应该在所有版本的SQL Server上都有效:

SELECT CAST(CONCAT(CAST(@Year AS VARCHAR(4)), '-',CAST(@Month AS VARCHAR(2)), '-',CAST(@Day AS VARCHAR(2))) AS DATE)

这将根据本地设置而表现不同。除非使用CONVERT指定style,否则字符串/日期转换是不确定的。https://msdn.microsoft.com/en-us/library/ms178091(SQL.90).aspx - Riley Major
@RileyMajor 请求您仔细阅读整个文档,https://learn.microsoft.com/en-us/sql/t-sql/data-types/date-transact-sql#ansi-and-iso-8601-compliance - Shubham Pandey
但是你没有填充年、月或日。所以它不会是"yyyy-mm-dd",而是"y-m-d"。它可能在1000年以外的年份上表现正确,但并不符合规范。 - Riley Major

2

简单且最灵活的解决方案

使用FORMAT函数制作任何你喜欢的格式。 以下是可复制粘贴的工作示例:

DECLARE @year int = 2021, @month int = 12, @day int = 16
DECLARE @date varchar(20)
SET @date = cast((format(@year,'####') +'-'+format(@month,'##')+'-'+format(@day,'##')) as date)
SELECT @date

它还会显示日期和月份前导零。

1
对于SQL Server 2008用户,我创建了一个自定义函数:
CREATE FUNCTION sql2012_datefromparts
(   
    @Year int, @Month int, @Day int
)
RETURNS DATETIME
AS
BEGIN
    RETURN convert(datetime,convert(varchar,@year)+right('0'+convert(varchar,@month),2)+right('0'+convert(varchar,@day),2)) 
END
GO

使用它:

DECLARE @day int=29, @month int=10, @year int=1971
SELECT dbo.sql2012_datefromparts(@year,@month,@day)

0

选择 convert(varchar(11), transfer_date, 106)

让我得到了我想要的日期格式,即 2018年3月7日

我的列 'transfer_date' 是 datetime 类型的列,我正在使用 Azure 上的 SQL Server 2017


0

所以,你可以尝试这个解决方案:

DECLARE @DAY INT = 25
DECLARE @MONTH INT  = 10 
DECLARE @YEAR INT = 2016
DECLARE @DATE AS DATETIME

SET @DATE = CAST(RTRIM(@YEAR * 10000 + @MONTH * 100 + @DAY) AS DATETIME) 

SELECT REPLACE(CONVERT(VARCHAR(10), @DATE, 102), '.', '-') AS EXPECTDATE

你可以尝试下面这几行代码:
DECLARE @DAY INT = 25
DECLARE @MONTH INT  = 10 
DECLARE @YEAR INT = 2016

SELECT CAST(RTRIM(@YEAR * 10000 +'-' +  @MONTH * 100+ '-' + @DAY) AS DATE) AS EXPECTDATE

这些操作根据本地设置表现不同。除非使用CONVERT指定style,否则字符串/日期转换是不确定的。Gordon或我所提供的ISO格式(yyyymmdd)更加可靠。 - Riley Major

0

使用 SQL 创建月份年份的日期:

DECLARE @FromMonth int=NULL,
@ToMonth int=NULL,
@FromYear int=NULL,
@ToYear int=NULL

/**Region For Create Date**/
        DECLARE @FromDate DATE=NULL
        DECLARE @ToDate DATE=NULL

    SET @FromDate=DateAdd(day,0, DateAdd(month, @FromMonth - 1,DateAdd(Year, @FromYear-1900, 0)))
    SET @ToDate=DateAdd(day,-1, DateAdd(month, @ToMonth - 0,DateAdd(Year, @ToYear-1900, 0)))
/**Region For Create Date**/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接