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?

JosephStyons
fonte

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.

Philip Kelley
fonte
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.

gauravg
fonte
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)'
Taptronic
fonte
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.

Aaron Bertrand
fonte
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.

Ovidiu Pacurar
fonte
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.

Simone
fonte
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

Scott Gollaglee
fonte
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
Jared
fonte
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.

tvanfosson
fonte
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.

SyWill
fonte
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.

Jeff Moden
fonte
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.

Will Rickards
fonte
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


user12913610
fonte
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')
Yaroslav
fonte
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