Bueno, normalmente no respondo a mis propias preguntas, pero después de un poco de retoque, he descubierto definitivamente cómo Oracle almacena el resultado de una resta DATE.
Al restar 2 fechas, el valor no es un tipo de datos NUMBER (como lo haría creer Oracle 11.2 SQL Reference manual). El número de tipo de datos interno de una resta DATE es 14, que es un tipo de datos interno no documentado (NUMBER es internal datatype number 2). Sin embargo, en realidad se almacena como 2 números de complemento del complemento de dos separados, con los primeros 4 bytes utilizados para representar el número de días y los últimos 4 bytes utilizados para representar el número de segundos.
Un ejemplo de una resta FECHA que resulta en una diferencia de número entero positivo:
select date '2009-08-07' - date '2008-08-08' from dual;
Resultados en:
DATE'2009-08-07'-DATE'2008-08-08'
---------------------------------
364
select dump(date '2009-08-07' - date '2008-08-08') from dual;
DUMP(DATE'2009-08-07'-DATE'2008
-------------------------------
Typ=14 Len=8: 108,1,0,0,0,0,0,0
Recordemos que el resultado se representa como una particular complemento 2 de dos firmaron 4 números de bytes . Como no hay decimales en este caso (364 días y 0 horas exactamente), los últimos 4 bytes son todos ceros y se pueden ignorar. Para los primeros 4 bytes, dado que mi CPU tiene una arquitectura little-endian, los bytes se invierten y deben leerse como 1,108 o 0x16c, que es el decimal 364.
Un ejemplo de una resta DATE que da como resultado una diferencia entera negativa :
select date '1000-08-07' - date '2008-08-08' from dual;
resultados en:
DATE'1000-08-07'-DATE'2008-08-08'
---------------------------------
-368160
select dump(date '1000-08-07' - date '2008-08-08') from dual;
DUMP(DATE'1000-08-07'-DATE'2008-08-0
------------------------------------
Typ=14 Len=8: 224,97,250,255,0,0,0,0
vez más, ya que estoy usando una máquina ascendente hacia la izquierda, los bytes se invierten y deben ser leídas como 255,250,97,224 que corresponde a 11111111 11111010 01100001 11011111. Ahora que esto está en el complemento de dos código numérico binario con signo, sabemos que el número es negativo porque el dígito binario más a la izquierda es 1. Para convertir esto en un número decimal, tendríamos que invertir el complemento de 2 (restar 1 luego hacer el complemento) resultando en: 00000000 00000101 10011110 00100000 que es igual a -368160 como se sospecha.
Un ejemplo de una resta FECHA resultando en una diferencia decimal:
select to_date('08/AUG/2004 14:00:00', 'DD/MON/YYYY HH24:MI:SS'
- to_date('08/AUG/2004 8:00:00', 'DD/MON/YYYY HH24:MI:SS') from dual;
TO_DATE('08/AUG/200414:00:00','DD/MON/YYYYHH24:MI:SS')-TO_DATE('08/AUG/20048:00:
--------------------------------------------------------------------------------
.25
La diferencia entre esos 2 fechas es de 0,25 días o 6 horas.
select dump(to_date('08/AUG/2004 14:00:00', 'DD/MON/YYYY HH24:MI:SS')
- to_date('08/AUG/2004 8:00:00', 'DD/MON/YYYY HH24:MI:SS')) from dual;
DUMP(TO_DATE('08/AUG/200414:00:
-------------------------------
Typ=14 Len=8: 0,0,0,0,96,84,0,0
Ahora esta vez, ya que la diferencia es de 0 días y 6 horas, se espera que los primeros 4 bytes son 0. Durante los últimos 4 bytes, que ellos pueden invertir (porque la CPU es ascendente hacia la izquierda) y obtenga 84,96 = 01010100 01100000 base 2 = 21600 en decimal. La conversión de 21600 segundos a horas te da 6 horas, que es la diferencia que esperábamos.
Espero que esto ayude a cualquiera que se pregunte cómo se almacena realmente una resta DATE.
¿Esto sucede cuando pones en lugar de sysdate algo como to_date (' 20120216 ',' aaaammdd ')? –
Hola, lo siento, no he visto su comentario hasta ahora: S ... Primero, para responder a su pregunta, sí lo hace incluso si utiliza 'to_date()' en lugar de SYSDATE. Sin embargo, en otra nota, logré averiguar cómo se almacena la resta DATE, así que la publiqué como mi respuesta: D ... ya que nadie más en Internet parece haber escrito sobre esto todavía, pensé que escribiría lo que descubierto. – BYS2
@ BYS2 - ¿Por qué debería poner un número en() y luego tratar de restar días de un número y convertirlo a segundos: SELECCIONAR (1242.12423) DÍA (5) A SEGUNDO de la prueba? Esto es lo que debes preguntar. – Art