Лучший способ конвертировать и проверять строку даты

У меня есть одна переменная char (8), отформатированная как ddmmyyyy в хранимой процедуре (качество и достоверность этого значения неизвестны и находятся за пределами моего контроля). Каков наилучший наиболее эффективный способ перемещения значения в переменную 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 @[email protected]

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

Ответ 1

Прежде всего, поскольку вы используете SQL Server 2005, вы должны поместить свой код в блок BEGIN TRY.....END TRY BEGIN CATCH....END CATCH - блоки try/catch для T-SQL!

Во-вторых, для всех манипуляций с датами я бы всегда использовал формат ISO-8601, который будет работать независимо от того, что текущий формат даты установлен в 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" - это несильная > та же самая настройка на всей планете.

К сожалению, SQL Server - это довольно слабые даты обработки - возможно, это может быть точкой расширения, где использование сборки CLR внутри SQL Server имеет смысл, использовать гораздо более богатые функции обработки даты в .NET.

Марк

PS: кажется, что формат ISO-8601, который я знал, YYYY-MM-DD не всегда работает в SQL Server - вопреки тому, что, по-видимому, проповедует Books Online. Используйте YYYYMMDD или YYYY-MM-DDTHH: MM: SS вместо.
Спасибо, gbn!

Ответ 2

Вы можете гарантировать дату-месяц-год, используя SET DATEFORMAT. Это означает, что ISDATE будет анализировать "15 -07-2009" с 15 июля 2009 года.

В противном случае ваш подход достаточно хорош с учетом внешних ограничений... но вы также можете переупорядочить в ANSI/ISO.

После ответа marc_s: "SET DATEFORMAT dmy" работает для большинства европейских настроек...

OK:

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