处理 varchar 日期转换时超出范围的值

Dealing with out of range value on varchar date conversion

我正在尝试将输入到我们系统中的日期作为 YYYYMMDD 格式的文本转换为日期。不幸的是,我们的系统允许使用任何一个月的 31 日来表示这是该月的最后一天,对于某些功能(如应计利息等)来说很重要。

我有一个显示为 20160931 的日期,显然无法通过

转换
CONVERT(DATETIME, CONVERT(CHAR(8), [FIELD]))

并抛出值超出范围错误。

如何克服这个问题,以便将其转换为正确的值,在这种情况下 30/09/2016?

您可以尝试这样的操作:

DECLARE @YourDate VARCHAR(100)='20160231';

SELECT CAST(y+m+dNew AS DATE)
FROM (VALUES(LEFT(@YourDate,4)
           ,SUBSTRING(@YourDate,5,2)
           ,SUBSTRING(@YourDate,7,2))) AS Parts(y,m,d)
CROSS APPLY
(
    SELECT CASE WHEN CAST(m AS INT) IN(4,6,9,11) AND CAST(d AS INT)>30 THEN '30' 
           ELSE CASE WHEN CAST(m AS INT)=2 AND CAST(d AS INT)>28 THEN '28' ELSE d END 
           END AS dNew
) AS NewDay

大约在 2 月 29 日,您还需要检查年份是否要除以 4:-)

更新

现在轮到我改进@Irawan 的技术了:-)

既然SQLServer 2005没有EOMONTH的功能,不过还是让SQLServer来计算比较好(2月29日隐式解决!),我建议这样做:

DECLARE @YourDate VARCHAR(100)='20160231';

SELECT DATEADD(SECOND,-1,DATEADD(MONTH,1,CAST(y+m+'01' AS DATETIME)))
FROM (VALUES(LEFT(@YourDate,4)
           ,SUBSTRING(@YourDate,5,2)
           ,SUBSTRING(@YourDate,7,2))) AS Parts(y,m,d)

无论如何,这将在本月的最后一秒交付...

如果你想要一个普通的 DATE(没有时间),你可以将 SECOND 更改为 DAY,这将首先跳到 DATE 第一天的午夜=35=]下一个 个月然后再往前一天...

更新 2 如果有效则使用现有日期

语法简单...

DECLARE @YourDate VARCHAR(100)='20160229';

SELECT CASE WHEN ISDATE(@YourDate)=1 THEN @YourDate 
            ELSE DATEADD(SECOND,-1,DATEADD(MONTH,1,CAST(LEFT(@YourDate,4) + SUBSTRING(@YourDate,5,2) +'01' AS DATETIME)))
            END AS CorrectDate;

适应@Shnugo 的技术,我觉得还是离开SQL 决定月底比较好。因此:

SELECT eomonth(CAST(y+m+'01' AS DATE))
FROM (VALUES(LEFT(@YourDate,4)
           ,SUBSTRING(@YourDate,5,2)
           ,SUBSTRING(@YourDate,7,2))) AS Parts(y,m,d)

将给出“2016-02-29”而不是“2016-02-28”,二月份的常数为“28”