【问题标题】:best way to convert and validate a date string转换和验证日期字符串的最佳方法
【发布时间】:2010-11-11 09:48:52
【问题描述】:

我在存储过程中有一个格式化为 ddmmyyyy 的 char(8) 变量(该值的质量和有效性未知且超出我的控制范围)。将值移动到 datetime 变量中的最佳最有效方法是什么,如果它不是有效的 datetime 则抛出错误。

DECLARE @Source       char(8)
DECLARE @Destination  datetime

SET @Source='07152009'

--your solution here


SELECT @Destination

这是我能想到的最好方法:

DECLARE @Source             char(8)
DECLARE @Temp               varchar(10)
DECLARE @Destination        datetime

set @Source='07152009'
SET @Temp=LEFT(@Source,2)+'/'+SUBSTRING(@Source,3,2)+'/'+RIGHT(@Source,4)

IF ISDATE(@Temp)!=1
BEGIN
    RAISERROR('ERROR, invalid date',16,1)
END
SET @Destination=@Temp

SELECT @Source AS Source, @Temp AS  Temp, @Destination AS Destination

编辑这就是我要使用的...

DECLARE @Source             char(8)
DECLARE @Destination        datetime

set @Source='07152009'
BEGIN TRY
    SET @Destination=CONVERT(datetime,RIGHT(@Source,4)        -- YYYY
                                      +LEFT(@Source,2)        -- MM
                                      +SUBSTRING(@Source,3,2) -- DD
                             )
END TRY
BEGIN CATCH
    PRINT 'ERROR!!!' --I'll add a little more logic here and abort processing
END CATCH

SELECT @Source AS Source, @Destination AS Destination

【问题讨论】:

  • 对我来说似乎不错,这也是我会写的。我很想知道是否有更好的。

标签: sql-server sql-server-2005 tsql


【解决方案1】:

首先,由于您使用的是 SQL Server 2005,您应该将 可能 失败的代码放入 BEGIN TRY.....END TRY BEGIN CATCH....END CATCH 块 - 用于 T-SQL 的 try/catch 块!

其次,对于所有日期操作,我会始终使用ISO-8601 format,无论在 SQL Server 中设置什么当前日期格式,它都可以工作。

ISO-8601 格式为 YYYYMMDD 仅用于日期,或 YYYY-MM-DDTHH:MM:SS 用于日期与时间 - 所以我将您的代码编写为:

BEGIN TRY
  SET @Source='07152009'
  SET @Temp = RIGHT(@Source, 4) +             -- YYYY
              LEFT(@Source, 2) +              -- MM
              SUBSTRING(@Source, 3, 2)        -- DD

  IF ISDATE(@Temp)!=1
  BEGIN
      RAISERROR('ERROR, invalid date',16,1)
  END

  SET @Destination = CAST(@Temp AS DATETIME)
END TRY
BEGIN CATCH
      -- handle error if something bombs out
END CATCH

不要依赖任何特定的日期格式设置!!把你的代码发给我,我会在瑞士-德国系统上试一试——我几乎保证如果你盲目地假设“en-US”并因此假设“mm/dd/yyyy”它会崩溃——它不是 strong> 这个星球上到处都是相同的设置。

不幸的是,SQL Server 处理日期的能力相当弱——也许这可能是一个扩展点,在 SQL Server 中使用 CLR 程序集是有意义的,以利用 .NET 中更丰富的日期处理功能??

马克

PS:似乎我知道 YYYY-MM-DD 的 ISO-8601 格式在 SQL Server 中并不总是有效 - 与 Books Online 似乎宣扬的相反。请改用 YYYYMMDD 或 YYYY-MM-DDTHH:MM:SS。
谢谢,gbn!

【讨论】:

  • 这是 ANSI 而不是 ISO。 ISO 将是 '1998-02-23T14:23:05'
  • ...没有“T”和时间,yyyy-mm-dd 默认为 ANSI
  • 我的系统处于受控环境中,不会出现瑞士-德国日期转换问题。我确实喜欢尝试捕捉的想法。我可能会删除 IF ISDATE() 和 @Temp,然后在执行 SET @Destination=LEFT(@Source,2)+'/'+SUBSTRING(@Source,3,2) 时捕获转换错误(如果有) +'/'+RIGHT(@Source,4)
  • 您上面编码的版本在我的系统上不起作用,RAISERROR() 被命中有效日期。 @Temp='20091507' 和 ISDATE('20091507')!=1
  • 哎呀抱歉 - 混淆了 DAY 和 MONTH - 修复了我的代码块 - 现在对我有用
【解决方案2】:

您可以使用 SET DATEFORMAT 保证日期-月份-年份的顺序。 这意味着 ISDATE 会将“15-07-2009”解析为 2009 年 7 月 15 日

否则,考虑到外部限制,您的方法已经足够好......但您也可以重新排序为 ANSI/ISO。

marc_s 回答后:“SET DATEFORMAT dmy”适用于大多数欧洲设置...

好的:

SET LANGUAGE british
SELECT ISDATE('2009-07-15') --this is ansi says marc_s. It gives "zero"
SELECT ISDATE('2009-07-15T11:22:33') --this really is ANSI and gives true


SET LANGUAGE german
SELECT ISDATE('2009-07-15') --false
SELECT ISDATE('2009-07-15T11:22:33') --true

【讨论】:

  • 同意 - 对于大多数人来说 - 但为什么不使用适用于 SET DATEFORMAT 的所有设置的 ISO-8601 格式?安全起见.....
  • ISO-8601 确实适用于所有设置,但它不是 ISO:它是您指定的 ANSI stackoverflow.com/questions/1135746/…
  • 确实如此。但是 yyyy-mm-dd 不是 ISO。正如您的链接所述,yyyy-mm-ddThh:mm:ss[.mmm] 是 ISO。没有时间,默认为ANSI。
  • 有趣 - SQL 联机丛书和 SQL Server 中的实际实现不匹配.....嗯....我第一次看到!
猜你喜欢
  • 2016-11-23
  • 1970-01-01
  • 2017-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-21
  • 1970-01-01
相关资源
最近更新 更多