Conversión de cadena a fecha de servidor SQL

186

Quiero convertir una cadena como esta:

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

en el valor DATETIME equivalente en SQL Server.

En Oracle, diría esto:

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

Esta pregunta implica que debo analizar la cadena en uno de los formatos estándar y luego convertir usando uno de esos códigos. Eso parece ridículo para una operación tan mundana. hay una manera mas facil?

JosephStyons
fuente

Respuestas:

28

SQL Server (2005, 2000, 7.0) no tiene ninguna forma flexible, o incluso no flexible, de tomar una fecha y hora arbitrariamente estructurada en formato de cadena y convertirla al tipo de datos de fecha y hora.

Por "arbitrariamente", me refiero a "una forma que la persona que la escribió, aunque tal vez no usted o yo o alguien del otro lado del planeta, consideraría intuitiva y completamente obvia". Francamente, no estoy seguro de que exista tal algoritmo.

Philip Kelley
fuente
32
existe dicho algoritmo, Oracle ya lo implementó y la falta de un equivalente en SQL Server es un problema constante.
matao
19
@matao así que, por favor, ilumínenos, ¿cómo determina Oracle mágicamente si un usuario que escribió 9/6/12significaba el 6 de septiembre de 2012, el 9 de junio de 2012, el 6 de diciembre de 2009, o algo más?
Aaron Bertrand
13
no se preocupe, aquí: techonthenet.com/oracle/functions/to_date.php Obviamente tiene que ser un formato consistente que especifique el desarrollador, pero mucho más flexible que el puñado de máscaras de formato que MS le da, lo que resulta en un análisis personalizado doloroso .
matao
3
@JosphStyons estaba al tanto de la función TO_DATE de Oracle, como se muestra en su muestra. Quería saber si había una forma de convertir fechas como cadenas sin tener que conocer el formato / estructura de la cadena. SQL no hace eso, y ciertamente parece que el TO_DATE de Oracle tampoco lo hace.
Philip Kelley el
23
@PhilipKelley No veo donde el OP quiere saber cómo hacerlo sin tener que conocer el formato. Dice explícitamente que conoce el formato y pregunta si SQL Server tiene algo equivalente a TO_DATE, es decir, algo que le permite al desarrollador ingresar una cadena de formato arbitrario.
neverfox
306

Prueba esto

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

y

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

Ver CAST y CONVERT (Transact-SQL) para más detalles.

gauravg
fuente
14
Esta es la forma correcta de hacerlo, y debe marcarse como la respuesta correcta. Tenga en cuenta que Cast('2011-07-07' as datetime)también funciona y elimina la ambigüedad sobre el orden de mes y día.
Joe DeRose
Esto no funciona cuando el mes es> 12. El formato espera formato mm / dd / aaaa
Chakri
Use Convertir (varchar (30), '7/7/2011', 103) al convertir de dd / mm / aaaa
Matias Masso
2
@Chakri si sus fechas están en dd / mm / aaaa, use SET DATEFORMAT dmyantes de su consulta
Nathan Griffiths
49

Ejecute esto a través de su procesador de consultas. Formatea fechas y / o horarios de esta manera y uno de estos debería darle lo que está buscando. No será difícil adaptarse:

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
fuente
47

En SQL Server Denali, podrá hacer algo que se acerque a lo que está buscando. Pero aún no puede pasar ninguna cadena de fecha loca arbitrariamente definida y esperar que SQL Server se adapte. Aquí hay un ejemplo usando algo que publicaste en tu propia respuesta. La función FORMAT () y también puede aceptar configuraciones regionales como argumento opcional: se basa en el formato de .Net, por lo que la mayoría, si no todos, los formatos de token que esperaría ver estarán allí.

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

Le recomiendo encarecidamente que tome más control y desinfecte sus entradas de fecha. Los días de permitir que las personas escriban fechas usando el formato que quieran en un campo de formulario de texto libre ya deberían estar atrás. Si alguien ingresa el 8/9/2011, ¿es ese el 9 de agosto o el 8 de septiembre? Si los hace elegir una fecha en un control de calendario, la aplicación puede controlar el formato. No importa cuánto intente predecir el comportamiento de sus usuarios, siempre encontrarán una manera más tonta de ingresar una fecha que no planeó.

Sin embargo, hasta Denali, creo que @Ovidiu tiene el mejor consejo hasta ahora ... esto puede hacerse bastante trivial implementando su propia función CLR. Luego puede escribir un caso / interruptor para tantos formatos extraños no estándar como desee.


ACTUALIZACIÓN 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

Todavía necesita tener esa otra información crucial primero. No puede usar T-SQL nativo para determinar si 6/9/2012es el 9 de junio o el 6 de septiembre.

Aaron Bertrand
fuente
1
Creo que la pregunta era cómo convertir una cadena en una fecha y hora, no una fecha y hora en una cadena.
David Hergert
1
TRY_PARSE fue perfecto. Tuvimos un problema al analizar una fecha 'jue 22 sep 2016', ¡gracias por compartir!
Simon
11

Para este problema, la mejor solución que uso es tener una función CLR en SQL Server 2005 que use una de las funciones DateTime.Parse o ParseExact para devolver el valor DateTime con un formato especificado.

Ovidiu Pacurar
fuente
11

Utilizar este:

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

Y consulte la tabla en la documentación oficial para los códigos de conversión.

Simone
fuente
8

porque no intentarlo

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

los formatos de fecha se pueden encontrar en Ayudante de SQL Server> Formatos de fecha de SQL Server

Scott Gollaglee
fuente
Su código de ejemplo no funciona. "La conversión falló al convertir la fecha y / o la hora de la cadena de caracteres".
César León
55
Debe ser select convert(date,'10/15/2011 00:00:00',101). Más detalles sobre el formato y por qué 101, en docs.microsoft.com/en-us/sql/t-sql/functions/…
anotherUser
1
Ocho personas votaron esta respuesta y ni siquiera funciona ...
David Klempfner
4

Me tomó un minuto resolver esto, así que aquí está en caso de que pueda ayudar a alguien:

En SQL Server 2012 y superior, puede usar esta función:

SELECT DATEFROMPARTS(2013, 8, 19);

Así es como terminé extrayendo las partes de la fecha para ponerlas en esta función:

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

Esta página tiene algunas referencias para todas las conversiones de fecha y hora disponibles para la función CONVERTIR. Si sus valores no caen dentro de uno de los patrones aceptables, entonces creo que lo mejor es seguir la ruta ParseExact.

tvanfosson
fuente
El enlace está roto.
Michael Potter
3

Personalmente, si está tratando con formatos arbitrarios o totalmente fuera de la pared, siempre que sepa cuáles son antes de lo que serán, simplemente use regexp para extraer las secciones de la fecha que desee y formar un componente válido de fecha / fecha y hora.

SyWill
fuente
1

Sé que esta es una publicación antigua malvada con muchas respuestas, pero muchas personas piensan que NECESITAN separar las cosas y volver a armarlas o insisten en que no hay forma de hacer implícitamente la conversión que solicitó el original de OP. .

Para revisar y, con suerte, proporcionar una respuesta fácil a otros con la misma pregunta, el OP preguntó cómo convertir '10 / 15/2008 10:06:32 PM 'a un DATETIME. Ahora, SQL Server tiene algunas dependencias de idioma para las conversiones temporales, pero si el idioma es inglés o algo similar, esto se convierte en un problema simple ... solo haga la conversión y no se preocupe por el formato. Por ejemplo (y puedes usar 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)
;

... y eso produce las siguientes respuestas, las cuales son correctas.

ingrese la descripción de la imagen aquí

Como dicen en los comerciales de televisión, "¡Pero espera! ¡No hagas el pedido todavía! ¡Sin costo adicional, puede hacer MUCHO más!"

Veamos el poder real de las conversiones temporales con DATETIME y examinemos parcialmente el error conocido como DATETIME2. Echa un vistazo a los formatos extravagantes que DATETIME puede manejar automáticamente y DATETIME2 no puede. Ejecute el siguiente código y vea ...

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

Entonces, sí ... SQL Server realmente tiene un método bastante flexible para manejar todo tipo de formatos temporales extraños y no se requiere un manejo especial. Ni siquiera tuvimos que eliminar los "PM" que se agregaron a las 24 horas. Es "PFM" (Pure Freakin 'Magic).

Las cosas variarán un poco dependiendo del IDIOMA que haya seleccionado para su servidor, pero gran parte de esto se manejará de cualquier manera.

Y estas conversiones "auto-mágicas" no son algo nuevo. Recorren un largo camino de regreso.

Jeff Moden
fuente
Una nueva respuesta perversa para una vieja pregunta perversa. ¡Gracias!
JosephStyons
Gracias por los comentarios, @JosephStyons.
Jeff Moden
0

Si desea que SQL Server intente resolverlo, simplemente use CAST CAST ('cualquiera' como fecha y hora) Sin embargo, esa es una mala idea en general. Hay problemas con las fechas internacionales que aparecerían. Entonces, como ha encontrado, para evitar esos problemas, desea utilizar el formato canónico ODBC de la fecha. Ese es el formato número 120, 20 es el formato para años de solo dos dígitos. No creo que SQL Server tenga una función incorporada que le permita proporcionar un formato dado por el usuario. Puede escribir el suyo e incluso puede encontrar uno si busca en línea.

Will Rickards
fuente
Si tiene fechas internacionales en una sola columna, estoy totalmente de acuerdo en que usar un número de formato es una buena idea. Si tiene fechas internacionales y fechas de EE. UU. Todas mezcladas en una sola columna, no hay forma de determinar la diferencia entre algo así como 7/6/2000 y 6/7/2000 a menos que tenga una columna hermana que explique el formato. Es por eso que la calidad de los datos en la fuente simplemente DEBE ser una cosa. Si SABES que tienes, por ejemplo, todas las fechas de EE. UU., Deja que las conversiones implícitas hagan lo suyo. Si fallan, entonces sabes con seguridad que algo en la columna necesita ser reparado.
Jeff Moden
0

convertir cadena a fecha y hora en MSSQL implícitamente

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


usuario12913610
fuente
Hola y bienvenido a stackoverflow, y gracias por responder. Si bien este código puede responder la pregunta, ¿puede considerar agregar alguna explicación sobre cuál fue el problema que resolvió y cómo lo resolvió? Esto ayudará a los futuros lectores a comprender mejor su respuesta y aprender de ella.
Plutian
-4
dateadd(day,0,'10/15/2008 10:06:32 PM')
Yaroslav
fuente
3
¡Bienvenido a StackOverflow! Por favor, editar su respuesta para agregar una explicación de su código. Esta pregunta tiene casi once años y ya tiene muchas respuestas bien explicadas y votadas. Sin una explicación en su respuesta, es de una calidad mucho menor en comparación con estos otros y lo más probable es que sea rechazado o rechazado. Agregar esa explicación ayudará a justificar la existencia de su respuesta aquí.
Das_Geek
Sí, pero las publicaciones "bien explicadas", incluso las votadas, son demasiado complejas. El publicado aquí es en realidad uno de los mejores, con o sin explicación,
Jeff Moden