2010-11-10 17 views
10

por qué el cabo de poner esta consulta:¿Cómo funciona la función de conversión de SQL al convertir la fecha y hora para flotar?

declare @currentDate as datetime 
    set @currentDate ='01/07/2010' 

select convert(float, @currentdate) 

... es 40183?

Entonces, para aquellos que se confunden con mi pregunta, mi pregunta es ¿Cómo saber el resultado de la consulta anterior sin ejecutarlo?

+0

¿qué más esperabas ??? –

+0

¿qué es exactamente lo que necesita hacer? – hgulyan

+0

esperaba el error, quiero saber cómo se convierte datetime para flotar, internamente cómo funciona. –

Respuesta

10

DateTime a menudo se representa como un recuento diario de una fecha predeterminada (generalmente conocida como la época) en la parte entera y el porcentaje del día transcurrido desde la mitad de la noche en la parte fraccionaria.

SQL Server no es la excepción a esto, por lo que la conversión a Float tiene mucho sentido. El día 0 es el 1 de enero de 1900 00:00:00 (AFAIK, en ninguna zona horaria en particular, por lo que debe considerarlo como "hora local").

Por lo tanto, se puede probar esto:

declare @ADate DateTime; 
set @ADate = '19000101 00:00:00'; 
select CONVERT(float, @ADate); --should print 0 
set @ADate = '19000101 12:00:00'; 
select CONVERT(float, @ADate); --should print 0.5 
set @ADate = '190:00:00'; 
select CONVERT(float, @ADate); --should print 364.25 

Así que, por sus resultados, 40183 días ha pasado desde 01/01/1900 00:00:00 01/07/2010 00:00 y: 00

Aclaración: los sistemas tipo Unix usan un enfoque diferente para almacenar las fechas: segundos desde la época de Unix (1 de enero de 1970 a las 00:00:00 UTC), que es más conocido como tiempo de época. [Editar] El formato de fecha en esta respuesta se cambió al formato YYYYMMDD en 20140416, después de algunos años de experiencia con SQL Server (y como dijo @Damien en su comentario) este es el único formato seguro.

+0

sobre su formato de fecha: la forma segura de especificar una fecha y hora es hacer AAAA-MM-DD, y usar una "T" en lugar de un espacio, para separar los componentes de fecha y hora (solo FYI realmente) –

+0

@ Damien_The_Unbeliever, solía trabajar con el formato de fecha YYYY-MM-DD en todos los principales motores de bases de datos ...pero (lo crea o no) MS-SQL Express 2008 en un Windows 7 Business 32bit en español, lo quiere en formato YYYY-DD-MM !! (solo para tu información): D – jachguate

+0

si solo es una fecha, entonces AAAAMMDD es el único formato seguro y sin ambigüedades (sin guiones). Por supuesto, si usa datetime2 u otros tipos más nuevos, entonces todas las reglas cambian una vez más :-) –

4

Los valores de DateTime se almacenan realmente como dos enteros de cuatro bytes debajo del capó. El primer entero de cuatro bytes representa el número de días desde 1900-01-01. El segundo entero de cuatro bytes almacena el número de milisegundos desde la medianoche. Cuando convierte una fecha y hora en un flotante, la porción decimal representa el porcentaje de los 24 días anteriores. Por lo tanto, 0.5 representa el mediodía.

3

Básicamente se está convirtiendo el datetime en una Fecha OLE. Hay una descripción decente del proceso en la documentación para System.DateTime.ToOADate():

http://msdn.microsoft.com/en-us/library/system.datetime.tooadate.aspx

La explicación rápida es que la parte entera es el número de días desde el 12/30/1899. La parte fraccionaria (cero en este caso) es el tiempo dividido por 24.

+0

Actualmente en TSQL es del 01/01/1900, todo lo demás es igual. – Vedran

0

Esto debería ayudar a entender la aplicación de TSQL (o implementar su propio):

DECLARE 
    @date DATETIME = '20180125 09:15:30.549', 
    @date_dec DECIMAL (26,10) = 43123.3857702546 

SELECT 
    CAST(@date_dec AS DATETIME) AS [TSQL cast to DATETIME], 
    CAST(@date AS DECIMAL (26,10)) AS [TSQL cast to DECIMAL] 

SELECT 
    DATEADD(DAY, FLOOR(@date_dec), 
     DATEADD(HOUR, FLOOR(@date_dec % 1 * 24), 
      DATEADD(MINUTE, FLOOR((@date_dec % 1 * 24) % 1 * 60), 
       DATEADD(SECOND, FLOOR(((@date_dec % 1 * 24) % 1 * 60) % 1 * 60), 
        DATEADD(MILLISECOND, FLOOR((((@date_dec % 1 * 24) % 1 * 60) % 1 * 60) % 1 * 1000), '19000101') 
       ) 
      ) 
     ) 
    ) AS [Manual cast to DATETIME], 
    DATEDIFF(DAY, '19000101', @date) 
    + (
     DATEPART(HOUR, @date) 
     + (
      DATEPART(MINUTE, @date) 
      + (
       DATEPART(SECOND, @date) 
       + DATEPART(MILLISECOND, @date)/CAST(1000 AS FLOAT) 
      )/CAST(60 AS FLOAT) 
     )/CAST(60 AS FLOAT) 
    )/CAST(24 AS DECIMAL (26,10)) AS [Manual cast to DECIMAL] 

Tenga en cuenta que el resultado no es siempre el lo mismo que TSQL pierde precisión en el último dígito milisegundo.

Cuestiones relacionadas