Conversione da stringa a data server SQL


186

Voglio convertire una stringa come questa:

'10/15/2008 10:06:32 PM'

nel valore DATETIME equivalente in SQL Server.

In Oracle, direi questo:

TO_DATE('10/15/2008 10:06:32 PM','MM/DD/YYYY HH:MI:SS AM')

Questa domanda implica che devo analizzare la stringa in uno dei formati standard e quindi convertire utilizzando uno di quei codici. Sembra ridicolo per un'operazione così banale. C'è un modo più semplice?


Risposte:


28

SQL Server (2005, 2000, 7.0) non ha alcun modo flessibile, o anche non flessibile, per prendere un datetime arbitrariamente strutturato in formato stringa e convertirlo nel tipo di dati datetime.

Con "arbitrariamente", intendo "una forma che la persona che l'ha scritta, sebbene forse tu o io o qualcuno dall'altra parte del pianeta, considererebbe intuitiva e completamente ovvia". Francamente, non sono sicuro che esista un tale algoritmo.


32
esiste un tale algoritmo, Oracle lo ha già implementato e la mancanza di un equivalente di SQL Server è un dolore costante.
matao,

19
@matao quindi, per favore, illuminaci, in che modo Oracle determina magicamente se un utente che ha digitato 9/6/12significava 6 settembre 2012, 9 giugno 2012, 6 dicembre 2009 o qualcos'altro?
Aaron Bertrand,

13
non preoccuparti, qui: techonthenet.com/oracle/functions/to_date.php Ovviamente deve essere un formato coerente specificato dallo sviluppatore, ma enormemente più flessibile della manciata di maschere di formato che MS ti offre, il che si traduce in un doloroso analisi personalizzata .
matao,

3
@JosphStyons era a conoscenza della funzione TO_DATE di Oracle, come mostrato nel suo esempio. Voleva sapere se c'era un modo per convertire le date come stringhe senza dover conoscere il formato / struttura della stringa. SQL non lo fa e sembra che anche il TO_DATE di Oracle non lo faccia.
Philip Kelley,

23
@PhilipKelley Non vedo dove l'OP vuole sapere come farlo senza dover conoscere il formato. Dice esplicitamente di conoscere il formato e chiede se SQL Server ha qualcosa di equivalente a TO_DATE, ovvero qualcosa che consente allo sviluppatore di inserire una stringa di formato arbitraria.
Neverfox,

306

Prova questo

Cast('7/7/2011' as datetime)

e

Convert(varchar(30),'7/7/2011',102)

Vedi CAST e CONVERT (Transact-SQL) per maggiori dettagli.


14
Questo è il modo giusto per farlo e dovrebbe essere contrassegnato come la risposta corretta. Si noti che Cast('2011-07-07' as datetime)funziona anche ed elimina l'ambiguità nell'ordine del mese e del giorno.
Joe DeRose,

Questo non funziona quando il mese è> 12. La formattazione prevede il formato mm / gg / aaaa
Chakri,

Usa Convert (varchar (30), '7/7/2011', 103) durante la conversione da gg / mm / aaaa
Matias Masso,

2
@Chakri se le date sono in gg / mm / aaaa utilizzate SET DATEFORMAT dmyprima della query
Nathan Griffiths,

49

Esegui questo attraverso il tuo Query Processor. Formatta date e / o orari in questo modo e uno di questi dovrebbe darti quello che stai cercando. Non sarà difficile adattarsi:

Declare @d datetime
select @d = getdate()

select @d as OriginalDate,
convert(varchar,@d,100) as ConvertedDate,
100 as FormatValue,
'mon dd yyyy hh:miAM (or PM)' as OutputFormat
union all
select @d,convert(varchar,@d,101),101,'mm/dd/yy'
union all
select @d,convert(varchar,@d,102),102,'yy.mm.dd'
union all
select @d,convert(varchar,@d,103),103,'dd/mm/yy'
union all
select @d,convert(varchar,@d,104),104,'dd.mm.yy'
union all
select @d,convert(varchar,@d,105),105,'dd-mm-yy'
union all
select @d,convert(varchar,@d,106),106,'dd mon yy'
union all
select @d,convert(varchar,@d,107),107,'Mon dd, yy'
union all
select @d,convert(varchar,@d,108),108,'hh:mm:ss'
union all
select @d,convert(varchar,@d,109),109,'mon dd yyyy hh:mi:ss:mmmAM (or PM)'
union all
select @d,convert(varchar,@d,110),110,'mm-dd-yy'
union all
select @d,convert(varchar,@d,111),111,'yy/mm/dd'
union all
select @d,convert(varchar,@d,12),12,'yymmdd'
union all
select @d,convert(varchar,@d,112),112,'yyyymmdd'
union all
select @d,convert(varchar,@d,113),113,'dd mon yyyy hh:mm:ss:mmm(24h)'
union all
select @d,convert(varchar,@d,114),114,'hh:mi:ss:mmm(24h)'
union all
select @d,convert(varchar,@d,120),120,'yyyy-mm-dd hh:mi:ss(24h)'
union all
select @d,convert(varchar,@d,121),121,'yyyy-mm-dd hh:mi:ss.mmm(24h)'
union all
select @d,convert(varchar,@d,126),126,'yyyy-mm-dd Thh:mm:ss:mmm(no spaces)'

47

In SQL Server Denali, sarai in grado di fare qualcosa che si avvicina a ciò che stai cercando. Ma non puoi ancora passare qualsiasi stringa di data stravagante definita arbitrariamente e aspettarti che SQL Server accolga. Ecco un esempio usando qualcosa che hai pubblicato nella tua risposta. La funzione FORMAT () e può anche accettare le localizzazioni come argomento facoltativo - si basa sul formato .Net, quindi la maggior parte, se non tutti i formati di token che ti aspetteresti di vedere, saranno lì.

DECLARE @d DATETIME = '2008-10-13 18:45:19';

-- returns Oct-13/2008 18:45:19:
SELECT FORMAT(@d, N'MMM-dd/yyyy HH:mm:ss');

-- returns NULL if the conversion fails:
SELECT TRY_PARSE(FORMAT(@d, N'MMM-dd/yyyy HH:mm:ss') AS DATETIME);

-- returns an error if the conversion fails:
SELECT PARSE(FORMAT(@d, N'MMM-dd/yyyy HH:mm:ss') AS DATETIME);

Ti incoraggio vivamente a prendere più controllo e a disinfettare i tuoi input di data. I giorni in cui lasciare che le persone digitino le date usando qualunque formato desiderino in un campo di forma a testo libero dovrebbero essere ormai alle nostre spalle. Se qualcuno entra l'8 / 9/2011 è quel 9 agosto o l'8 settembre? Se li fai scegliere una data su un controllo calendario, l'app può controllare il formato. Indipendentemente da quanto cerchi di prevedere il comportamento dei tuoi utenti, questi troveranno sempre un modo più stupido per inserire una data che non hai pianificato.

Fino a Denali, però, penso che @Ovidiu abbia i migliori consigli finora ... questo può essere reso abbastanza banale implementando la tua funzione CLR. Quindi puoi scrivere un caso / interruttore per tutti i formati stravaganti non standard che desideri.


AGGIORNAMENTO per @dhergert :

SELECT TRY_PARSE('10/15/2008 10:06:32 PM' AS DATETIME USING 'en-us');
SELECT TRY_PARSE('15/10/2008 10:06:32 PM' AS DATETIME USING 'en-gb');

risultati:

2008-10-15 22:06:32.000
2008-10-15 22:06:32.000

Devi comunque avere prima quell'altra informazione cruciale. Non è possibile utilizzare T-SQL nativo per determinare se 6/9/2012è il 9 giugno o il 6 settembre.


1
Penso che la domanda fosse come convertire una stringa in un datetime, non un datetime in una stringa.
David Hergert,

1
TRY_PARSE è stato perfetto. Abbiamo riscontrato un problema con l'analisi della data "Gio 22 set 2016", grazie per averlo condiviso!
Simone,

11

Per questo problema, la soluzione migliore che utilizzo è quella di disporre di una funzione CLR in SQL Server 2005 che utilizza una delle funzioni DateTime.Parse o ParseExact per restituire il valore DateTime con un formato specificato.


11

Usa questo:

SELECT convert(datetime, '2018-10-25 20:44:11.500', 121) -- yyyy-mm-dd hh:mm:ss.mmm

E fare riferimento alla tabella nella documentazione ufficiale per i codici di conversione.


8

perché non provarci

select convert(date,'10/15/2011 00:00:00',104) as [MM/dd/YYYY]

i formati di data sono disponibili in Helper di SQL Server> Formati di data di SQL Server


Il tuo esempio di codice non funziona. "Conversione non riuscita durante la conversione di data e / o ora dalla stringa di caratteri."
César León,

5
Dovrebbe essere select convert(date,'10/15/2011 00:00:00',101). Maggiori dettagli sul formato e perché 101, su docs.microsoft.com/en-us/sql/t-sql/functions/…
Utente

1
Otto persone hanno votato questa risposta e non funziona nemmeno ...
David Klempfner il

4

Mi ci è voluto un minuto per capirlo, quindi eccolo nel caso in cui potesse aiutare qualcuno:

In SQL Server 2012 e versioni successive è possibile utilizzare questa funzione:

SELECT DATEFROMPARTS(2013, 8, 19);

Ecco come ho finito per estrarre le parti della data da inserire in questa funzione:

select
DATEFROMPARTS(right(cms.projectedInstallDate,4),left(cms.ProjectedInstallDate,2),right( left(cms.ProjectedInstallDate,5),2)) as 'dateFromParts'
from MyTable

3

Questa pagina contiene alcuni riferimenti per tutte le conversioni datetime specificate disponibili per la funzione CONVERT. Se i tuoi valori non rientrano in uno dei modelli accettabili, penso che la cosa migliore sia seguire il percorso ParseExact.


il collegamento è interrotto.
Michael Potter,

3

Personalmente, se hai a che fare con formati arbitrari o totalmente fuori dal comune, a condizione che tu sappia cosa sono in anticipo o che saranno, allora semplicemente usa regexp per estrarre le sezioni della data desiderata e formare un componente data / datetime valido.


1

So che questo è un vecchio post malvagio con un sacco di risposte, ma molte persone pensano che NECESSITANO di rompere le cose e rimetterle insieme o insistono sul fatto che non c'è modo di fare implicitamente la conversione richiesta dall'originale OP .

Per riesaminare e, si spera, fornire agli altri una risposta semplice con la stessa domanda, il PO ha chiesto come convertire "10/10/2008 2008 22:06:32 PM" in un DATETIME. Ora, SQL Server ha alcune dipendenze linguistiche per le conversioni temporali ma se la lingua è inglese o qualcosa di simile, questo diventa un semplice problema ... basta fare la conversione e non preoccuparti del formato. Ad esempio (e puoi usare CONVERT o CAST) ...

 SELECT UsingCONVERT = CONVERT(DATETIME,'10/15/2008 10:06:32 PM')
        ,UsingCAST   = CAST('10/15/2008 10:06:32 PM' AS DATETIME)
;

... e questo produce le seguenti risposte, entrambe corrette.

inserisci qui la descrizione dell'immagine

Come dicono gli spot televisivi, "Ma aspetta! Non ordinare ancora! Senza costi aggiuntivi, può fare molto di più!"

Vediamo il vero potere delle conversioni temporali con il DATETIME ed esaminiamo parzialmente l'errore noto come DATETIME2. Scopri i formati bizzarri che DATETIME può gestire in modo automatico e che DATETIME2 non può. Esegui il codice seguente e vedi ...

--===== Set the language for this example.
    SET LANGUAGE ENGLISH --Same a US-English
;
--===== Use a table constructor as if it were a table for this example.
 SELECT *
        ,DateTimeCONVERT  = TRY_CONVERT(DATETIME,StringDT)
        ,DateTimeCAST     = TRY_CAST(StringDT AS DATETIME)
        ,DateTime2CONVERT = TRY_CONVERT(DATETIME2,StringDT)
        ,DateTime2CAST    = TRY_CAST(StringDT AS DATETIME2)
   FROM (
         VALUES
         ('Same Format As In The OP'    ,'12/16/2001 01:51:01 PM')
        ,('Almost Normal'               ,'16 December, 2001 1:51:01 PM')
        ,('More Normal'                 ,'December 16, 2001 01:51:01 PM')
        ,('Time Up Front + Spaces'      ,'   13:51:01  16 December   2001')
        ,('Totally Whacky Format #01'   ,'  16  13:51:01  December   2001')
        ,('Totally Whacky Format #02'   ,'  16    December 13:51:01  2001  ')
        ,('Totally Whacky Format #03'   ,'  16    December 01:51:01  PM 2001  ')
        ,('Totally Whacky Format #04'   ,' 2001 16    December 01:51:01  PM ')
        ,('Totally Whacky Format #05'   ,' 2001    December 01:51:01  PM  16  ')
        ,('Totally Whacky Format #06'   ,' 2001 16    December  01:51:01 PM  ')
        ,('Totally Whacky Format #07'   ,' 2001 16    December  13:51:01 PM  ')
        ,('Totally Whacky Format #08'   ,' 2001 16  13:51:01 PM  December    ')
        ,('Totally Whacky Format #09'   ,'   13:51:01   PM  2001.12/16 ')
        ,('Totally Whacky Format #10'   ,'   13:51:01   PM  2001.December/16 ')
        ,('Totally Whacky Format #11'   ,'   13:51:01   PM  2001.Dec/16 ')
        ,('Totally Whacky Format #12'   ,'   13:51:01   PM  2001.Dec.16 ')
        ,('Totally Whacky Format #13'   ,'   13:51:01   PM  2001/Dec.16')
        ,('Totally Whacky Format #14'   ,'   13:51:01   PM  2001 . 12/16 ')
        ,('Totally Whacky Format #15'   ,'   13:51:01   PM  2001 . December / 16 ')
        ,('Totally Whacky Format #16'   ,'   13:51:01   PM  2001 . Dec /   16 ')
        ,('Totally Whacky Format #17'   ,'   13:51:01   PM  2001 . Dec .   16 ')
        ,('Totally Whacky Format #18'   ,'   13:51:01   PM  2001 / Dec .   16')
        ,('Totally Whacky Format #19'   ,'   13:51:01   PM  2001 . Dec -   16 ')
        ,('Totally Whacky Format #20'   ,'   13:51:01   PM  2001 - Dec -   16 ')
        ,('Totally Whacky Format #21'   ,'   13:51:01   PM  2001 - Dec .   16')
        ,('Totally Whacky Format #22'   ,'   13:51:01   PM  2001 - Dec /   16 ')
        ,('Totally Whacky Format #23'   ,'   13:51:01   PM  2001 / Dec -   16')
        ,('Just the year'               ,' 2001      ')
        ,('YYYYMM'                      ,' 200112      ')
        ,('YYYY MMM'                    ,'2001 Dec')
        ,('YYYY-MMM'                    ,'2001-Dec')
        ,('YYYY    .     MMM'           ,'2001    .     Dec')
        ,('YYYY    /     MMM'           ,'2001    /     Dec')
        ,('YYYY    -     MMM'           ,'2001    /     Dec')
        ,('Forgot The Spaces #1'        ,'2001December26')
        ,('Forgot The Spaces #2'        ,'2001Dec26')
        ,('Forgot The Spaces #3'        ,'26December2001')
        ,('Forgot The Spaces #4'        ,'26Dec2001')
        ,('Forgot The Spaces #5'        ,'26Dec2001 13:51:01')
        ,('Forgot The Spaces #6'        ,'26Dec2001 13:51:01PM')
        ,('Oddly, this doesn''t work'   ,'2001-12')
        ,('Oddly, this doesn''t work'   ,'12-2001')
        ) v (Description,StringDT)
;

Quindi, sì ... SQL Server ha effettivamente un metodo abbastanza flessibile per gestire tutti i tipi di formati temporali strani e non è richiesta alcuna gestione speciale. Non abbiamo nemmeno bisogno di rimuovere i "PM" che sono stati aggiunti alle 24 ore. È "PFM" (Pure Freakin 'Magic).

Le cose varieranno un po 'a seconda della LINGUA che hai selezionato per il tuo server, ma gran parte verrà gestita in entrambi i modi.

E queste conversioni "auto-magiche" non sono qualcosa di nuovo. Vanno molto indietro nel tempo.


Una nuova malvagia risposta a una vecchia malvagia domanda. Grazie!
JosephStyons,

Grazie per il feedback, @JosephStyons.
Jeff Moden,

0

Se vuoi che SQL Server provi a capirlo, usa semplicemente CAST CAST ("qualunque" datetime AS). Tuttavia, questa è una cattiva idea in generale. Ci sono problemi con le date internazionali che potrebbero sorgere. Quindi, come hai scoperto, per evitare questi problemi, vuoi usare il formato canonico ODBC della data. Questo è il formato numero 120, 20 è il formato per soli anni a due cifre. Non credo che SQL Server abbia una funzione integrata che ti permetta di fornire un formato specifico per l'utente. Puoi scriverne uno tuo e potresti persino trovarne uno se cerchi online.


Se hai date internazionali in una singola colonna, sono assolutamente d'accordo che usare un numero di formato sia una buona idea. Se hai date internazionali e statunitensi tutte mescolate in una singola colonna, non c'è modo di determinare la differenza tra qualcosa come 7/6/2000 e 6/7/2000 a meno che tu non abbia una colonna gemella che spieghi il formato. Ecco perché la qualità dei dati alla fonte DEVE semplicemente essere una cosa. Se sai di avere, diciamo, tutte le date degli Stati Uniti, lascia che le conversioni implicite facciano le loro cose. Se falliscono, allora sai per certo che qualcosa nella colonna deve essere riparato.
Jeff Moden,

0

convertire implicitamente la stringa in datetime in MSSQL

create table tmp 
(
  ENTRYDATETIME datetime
);

insert into tmp (ENTRYDATETIME) values (getdate());
insert into tmp (ENTRYDATETIME) values ('20190101');  --convert string 'yyyymmdd' to datetime


select * from tmp where ENTRYDATETIME > '20190925'  --yyyymmdd 
select * from tmp where ENTRYDATETIME > '20190925 12:11:09.555'--yyyymmdd HH:MIN:SS:MS



Ciao e benvenuto su StackOverflow, e grazie per aver risposto. Mentre questo codice potrebbe rispondere alla domanda, puoi prendere in considerazione l'aggiunta di alcune spiegazioni per quale problema hai risolto e come lo hai risolto? Questo aiuterà i futuri lettori a capire meglio la tua risposta e ad imparare da essa.
Plutian il

-4
dateadd(day,0,'10/15/2008 10:06:32 PM')

3
Benvenuto in StackOverflow! Si prega di modificare la risposta di aggiungere una spiegazione per il codice. Questa domanda ha quasi undici anni e ha già molte risposte ben spiegate e votate. Senza una spiegazione nella tua risposta, è di qualità molto inferiore rispetto a questi altri e molto probabilmente verrà ridimensionato o rimosso. L'aggiunta di tale spiegazione aiuterà a giustificare l'esistenza della tua risposta qui.
Das_Geek,

Sì, ma i post "ben spiegati", anche quelli votati, sono troppo complessi. Quello pubblicato qui è in realtà uno dei migliori, con o senza una spiegazione,
Jeff Moden il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.