Conversão de cadeia de caracteres do SQL Server para data


186

Eu quero converter uma string como esta:

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

no valor DATETIME equivalente no Sql Server.

No Oracle, eu diria o seguinte:

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

Esta pergunta implica que eu devo analisar a string em um dos formatos padrão e depois converter usando um desses códigos. Isso parece ridículo para uma operação tão mundana. Existe uma maneira mais fácil?


Respostas:


28

O SQL Server (2005, 2000, 7.0) não possui nenhuma maneira flexível, ou mesmo não flexível, de obter um horário datado arbitrariamente estruturado no formato de string e convertê-lo no tipo de dados datetime.

Por "arbitrariamente", quero dizer "uma forma que a pessoa que a escreveu, embora talvez você, eu ou alguém do outro lado do planeta, considere intuitiva e completamente óbvia". Francamente, não tenho certeza se existe algum algoritmo desse tipo.


32
existe esse algoritmo, a Oracle já o implementou e a falta de um equivalente do SQL Server é uma dor constante.
matao 9/10/12

19
@matao então, por favor, esclareça-nos, como a Oracle determina magicamente se um usuário digitou 9/6/12significava 6 de setembro de 2012, 9 de junho de 2012, 6 de dezembro de 2009 ou outra coisa?
Aaron Bertrand

13
não se preocupe, aqui: techonthenet.com/oracle/functions/to_date.php Obviamente, deve ser um formato consistente que você especifique pelo desenvolvedor, mas muito mais flexível do que o punhado de máscaras de formato que a MS fornece, o que resulta em uma análise personalizada dolorosa .
matao 23/01

3
@JosphStyons estava ciente da função TO_DATE do Oracle, como mostrado em seu exemplo. Ele queria saber se havia uma maneira de converter datas como seqüências de caracteres sem precisar conhecer o formato / estrutura da sequência. O SQL não faz isso e certamente parece que o TO_DATE da Oracle também não.
Philip Kelley

23
@PhilipKelley Não vejo onde o OP quer saber como fazê-lo sem precisar saber o formato. Ele diz explicitamente que conhece o formato e está perguntando se o SQL Server tem algo equivalente a TO_DATE, ou seja, algo que permite ao desenvolvedor inserir uma seqüência de formato arbitrária.
neverfox

306

Tente isto

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

e

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

Consulte CAST e CONVERT (Transact-SQL) para obter mais detalhes.


14
Esta é a maneira correta de fazer isso e deve ser marcada como a resposta correta. Observe que Cast('2011-07-07' as datetime)também funciona e elimina a ambiguidade em relação ao pedido mensal e diário.
precisa

Isso não funciona quando o mês é> 12. O formato espera mm / dd / aaaa formatação
Chakri

Use Convert (varchar (30), '07/07/2011', 103) ao converter de dd / mm / aaaa
Matias Masso

2
@Chakri se suas datas estiverem em dd / mm / aaaa SET DATEFORMAT dmyantes da sua consulta #
Nathan Griffiths

49

Execute isso no seu processador de consultas. Ele formata datas e / ou horários como esse e um deles deve fornecer o que você está procurando. Não será difícil se adaptar:

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

No SQL Server Denali, você poderá fazer algo que se aproxima do que está procurando. Mas você ainda não pode simplesmente passar nenhuma sequência de datas maluca definida arbitrariamente e esperar que o SQL Server se adapte. Aqui está um exemplo usando algo que você postou em sua própria resposta. A função FORMAT () e também pode aceitar localidades como argumento opcional - é baseada no formato .Net, portanto, a maioria, se não todos, os formatos de token que você espera ver estarão 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);

É altamente recomendável que você assuma mais controle e desinfete suas entradas de data. Os dias em que as pessoas digitam datas usando o formato que desejam em um campo de formulário de texto livre devem estar muito atrasados ​​agora. Se alguém entrar em 9/8/2011 é 9 de agosto ou 8 de setembro? Se você escolher uma data em um controle de calendário, o aplicativo poderá controlar o formato. Não importa o quanto você tente prever o comportamento de seus usuários, eles sempre descobrirão uma maneira mais burra de inserir uma data para a qual você não planejou.

Até Denali, no entanto, acho que o @Ovidiu tem os melhores conselhos até agora ... isso pode ser feito de maneira bastante trivial, implementando sua própria função CLR. Em seguida, você pode escrever um caso / alternar para os formatos malucos não-padrão que desejar.


ATUALIZAÇÃO para @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');

Resultados:

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

Você ainda precisa ter essa outra informação crucial primeiro. Você não pode usar o T-SQL nativo para determinar se 6/9/2012é 9 de junho ou 6 de setembro.


1
Eu acho que a pergunta era como converter uma string em um datetime, não um datetime em uma string.
David Hergert

1
TRY_PARSE foi perfeito. Ocorreu um problema ao analisar uma data 'Qui, 22 de setembro de 2016', obrigado por compartilhar!
Simon

11

Para esse problema, a melhor solução que eu uso é ter uma função CLR no Sql Server 2005 que use uma das funções DateTime.Parse ou ParseExact para retornar o valor DateTime com um formato especificado.


11

Usa isto:

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

E consulte a tabela na documentação oficial para os códigos de conversão.


8

por que nao tentar

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

formatos de data podem ser encontrados em Auxiliar do SQL Server> Formatos de data do SQL Server


Seu exemplo de código não funciona. "Falha na conversão ao converter data e / ou hora da cadeia de caracteres."
César León

5
Deveria ser select convert(date,'10/15/2011 00:00:00',101). Mais detalhes sobre o formato e por 101, no docs.microsoft.com/en-us/sql/t-sql/functions/...
anotherUser

1
Oito pessoas votaram nessa resposta e ela nem funciona ...
David Klempfner 6/03

4

Levei um minuto para descobrir isso, então aqui está, caso isso possa ajudar alguém:

No SQL Server 2012 e melhor, você pode usar esta função:

SELECT DATEFROMPARTS(2013, 8, 19);

Aqui está como eu acabei extraindo as partes da data para colocar nessa função:

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

3

Esta página possui algumas referências para todas as conversões de data e hora especificadas disponíveis para a função CONVERT. Se seus valores não se enquadram em um dos padrões aceitáveis, acho que a melhor coisa é seguir a rota ParseExact.


link está quebrado.
Michael Potter

3

Pessoalmente, se você estiver lidando com formatos arbitrários ou totalmente fora do comum, desde que você saiba o que eles estão adiantados ou serão, basta usar o regexp para extrair as seções da data desejada e formar um componente válido de data / hora.


1

Sei que este é um post antigo e com muitas respostas, mas muitas pessoas pensam que precisam separar as coisas e juntá-las novamente ou insistem que não há como fazer implicitamente a conversão solicitada pelo original do OP .

Para revisar e, esperançosamente, fornecer uma resposta fácil para outras pessoas com a mesma pergunta, o OP perguntou como converter '15/10/2008 22:06:32' em DATETIME. Agora, o SQL Server possui algumas dependências de idioma para conversões temporais, mas se o idioma for inglês ou algo semelhante, isso se tornará um problema simples ... basta fazer a conversão e não se preocupar com o formato. Por exemplo (e você pode usar CONVERT ou CAST) ...

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

... e que produz as respostas a seguir, ambas corretas.

insira a descrição da imagem aqui

Como se costuma dizer nos comerciais de TV: "Mas espere! Não faça o pedido ainda! Sem nenhum custo extra, pode fazer MUITO mais!"

Vamos ver o verdadeiro poder das conversões temporais com o DATETIME e examinar parcialmente o erro conhecido como DATETIME2. Confira os formatos malucos que o DATETIME pode manipular automaticamente e o DATETIME2 não. Execute o código a seguir e veja ...

--===== 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)
;

Então, sim ... O SQL Server realmente tem um método bastante flexível de lidar com todos os tipos de formatos temporais esquisitos e nenhum tratamento especial é necessário. Nem precisamos remover os "PM" adicionados às 24 horas. É "PFM" (Pure Freakin 'Magic).

As coisas variam um pouco, dependendo do IDIOMA que você selecionou para o servidor, mas muito dele será tratado de qualquer maneira.

E essas conversões "auto-mágicas" não são algo novo. Eles percorrem um longo caminho de volta.


Uma nova resposta perversa para uma velha pergunta perversa. Obrigado!
JosephStyons

Obrigado pelo feedback, @ JosephStyons.
Jeff Moden

0

Se você deseja que o SQL Server tente descobrir, basta usar CAST CAST ('qualquer que seja' AS data / hora). No entanto, essa é uma má ideia em geral. Existem problemas com datas internacionais que surgiriam. Portanto, como você descobriu, para evitar esses problemas, você deseja usar o formato canônico ODBC da data. Esse é o formato número 120, 20 é o formato para apenas dois dígitos do ano. Não acho que o SQL Server tenha uma função interna que permita fornecer um formato determinado ao usuário. Você pode escrever o seu próprio e pode até encontrar um se pesquisar online.


Se você tiver datas internacionais em uma única coluna, concordo absolutamente que usar um número de formato é uma boa ideia. Se você tem datas internacionais e datas dos EUA misturadas em uma única coluna, não há como determinar a diferença entre algo como 7/6/2000 e 7/7/2000, a menos que você tenha uma coluna irmã que explique o formato. É por isso que a qualidade dos dados na fonte simplesmente DEVE ser uma coisa. Se você SABE que tem, digamos, todas as datas nos EUA, permita que as conversões implícitas façam o que precisam. Se eles falharem, você tem certeza de que algo na coluna precisa ser corrigido.
Jeff Moden

0

converter string para datetime no MSSQL implicitamente

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



Olá e bem-vindo ao stackoverflow, e obrigado por responder. Embora esse código possa responder à pergunta, considere adicionar algumas explicações sobre qual foi o problema que você resolveu e como o resolveu? Isso ajudará os futuros leitores a entender melhor sua resposta e aprender com ela.
Plutian

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

3
Bem-vindo ao StackOverflow! Por favor edite sua resposta para adicionar uma explicação para o seu código. Esta pergunta tem quase onze anos e já tem muitas respostas bem explicadas e votadas. Sem uma explicação na sua resposta, ela é de qualidade muito mais baixa em comparação com essas outras e provavelmente será votada ou removida. Adicionar essa explicação ajudará a justificar a existência da sua resposta aqui.
Das_Geek 20/11/19

Sim, mas as postagens "bem explicadas", mesmo as votadas, são muito complexas. O postado aqui é realmente um dos melhores, com ou sem uma explicação,
Jeff Moden
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.