11 Stimmen

beste Methode zur Konvertierung und Validierung einer Datumszeichenfolge

Ich habe eine einzelne char(8)-Variable, die als ddmmyyyy in einer gespeicherten Prozedur formatiert ist (Qualität und Gültigkeit dieses Werts sind unbekannt und liegen außerhalb meiner Kontrolle). Was ist der beste und effizienteste Weg, um den Wert in eine Datetime-Variable zu verschieben und einen Fehler auszugeben, wenn er nicht gültig ist.

DECLARE @Source       char(8)
DECLARE @Destination  datetime

SET @Source='07152009'

--your solution here

SELECT @Destination

Das ist der beste Weg, den ich mir vorstellen kann:

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

EDIT Ich werde mich für Folgendes entscheiden...

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

0 Stimmen

Das scheint mir gut zu sein, das hätte ich auch geschrieben. Ich bin neugierig, ob es etwas Besseres gibt.

13voto

marc_s Punkte 701497

Zunächst einmal sollten Sie, da Sie SQL Server 2005 verwenden, Ihren Code so platzieren, dass pourrait in die Hose gehen BEGIN TRY.....END TRY BEGIN CATCH....END CATCH Blöcke - try/catch-Blöcke für T-SQL!

Zweitens würde ich bei allen Datumsmanipulationen immer verwenden. ISO-8601-Format die unabhängig von dem in SQL Server eingestellten Datumsformat funktioniert.

Das ISO-8601-Format ist YYYYMMDD nur für Daten, oder YYYY-MM-DDTHH:MM:SS für Datum mit Uhrzeit - also würde ich Ihren Code so schreiben:

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

Verlassen Sie sich nicht darauf, dass ein bestimmtes Datumsformat eingestellt ist! Schicken Sie mir Ihren Code und ich werde ihn auf einem schweizerisch-deutschen System ausprobieren - ich garantiere fast, dass er kaputt geht, wenn Sie blindlings "en-US" und damit "mm/dd/yyyy" annehmen - es ist no überall auf diesem Planeten die gleiche Einstellung.

Leider ist SQL Server eher schwach Umgang mit Daten - vielleicht, dass ein Erweiterungspunkt sein könnte, wo mit einer CLR-Assembly innerhalb von SQL Server sinnvoll wäre, um in die viel reicher Datumsverarbeitung Funktionen in .NET?

マルク

PS: Das mir bekannte ISO-8601-Format JJJJ-MM-TT scheint in SQL Server nicht immer zu funktionieren - im Gegensatz zu dem, was Books Online zu predigen scheint. Verwenden Sie stattdessen JJJJMMTT oder JJJJ-MM-TTTHH:MM:SS.
Danke, gbn!

0 Stimmen

Dies ist ANSI und nicht ISO. Bei ISO wäre es "1998-02-23T14:23:05".

0 Stimmen

...ohne "T" und Zeit, yyyy-mm-dd ist standardmäßig ANSI

0 Stimmen

Mein System befindet sich in einer kontrollierten Umgebung, so dass es keine Probleme mit der Umrechnung des schweizerisch-deutschen Datums geben wird. Mir gefällt die Idee von try-catch. Wahrscheinlich werde ich die IF ISDATE() und @Temp entfernen und dann nur den Konvertierungsfehler abfangen, wenn ich SET @Destination=LEFT(@Source,2)+'/'+SUBSTRING(@Source,3,2)+'/'+RIGHT(@Source,4) mache.

7voto

gbn Punkte 407102

Mit SET DATEFORMAT können Sie die Reihenfolge von Datum, Monat und Jahr garantieren. Das bedeutet, dass ISDATE "15-07-2009" als 15. Juli 2009 interpretiert.

Ansonsten ist Ihr Ansatz in Anbetracht der externen Beschränkungen gut genug... aber Sie könnten auch nach ANSI/ISO umstellen.

Nach der Antwort von marc_s: "SET DATEFORMAT dmy" funktioniert für die meisten europäischen Einstellungen...

GUT:

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

0 Stimmen

Einverstanden - für die meisten - aber warum nicht das ISO-8601-Format verwenden, das für ALLE Einstellungen von SET DATEFORMAT? funktioniert? Gehen Sie auf Nummer sicher.....

0 Stimmen

ISO-8601 funktioniert zwar für alle Einstellungen, aber es ist nicht ISO: Sie haben ANSI angegeben. stackoverflow.com/questions/1135746/

0 Stimmen

MS Books Online scheint da anderer Meinung zu sein: msdn.microsoft.com/de-us/library/ms190977%28SQL.90%29.aspx

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X