【问题标题】:Dealing with out of range value on varchar date conversion处理 varchar 日期转换的超出范围值
【发布时间】:2023-03-26 16:10:01
【问题描述】:

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

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

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

并抛出超出范围的值错误。

我该如何克服这个问题,以便将其转换为正确的值,在本例中为30/09/2016

【问题讨论】:

    标签: sql-server tsql sql-server-2005 types date-conversion


    【解决方案1】:

    适应@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',并在 2 月提供常量 '28'。

    【讨论】:

    • EOMONTH 功能在 2005 年不可用。可能会在我的答案中阅读更新...(无论如何,我这边 +1)
    【解决方案2】:

    你可以试试这样的:

    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 的技术了 :-)

    由于 SQL Server 2005 没有 EOMONTH 函数,但最好让 SQL Server 进行计算(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,这将首先跳转到 下个月的第一天的午夜而不是回去一天...

    更新 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;
    

    【讨论】:

    • 抱歉,我的原始问题应该更清楚。在该字段中,我也有真正的有效日期,我不想移动/更改。
    • @GavinP 请查看我的更新 2
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-15
    • 2020-01-05
    • 1970-01-01
    相关资源
    最近更新 更多