Ok, normalmente non rispondo alle mie domande ma dopo un po' di armeggiare, ho capito definitivamente come Oracle memorizza il risultato di una sottrazione DATE.
Quando si sottraggono 2 date, il valore non è un tipo di dati NUMBER (come farebbe credere il manuale di riferimento SQL di Oracle 11.2). Il numero del tipo di dati interno di una sottrazione DATE è 14, che è un tipo di dati interno non documentato (NUMERO è il tipo di dati interno numero 2). Tuttavia, viene effettivamente memorizzato come 2 numeri separati con segno in complemento a due, con i primi 4 byte utilizzati per rappresentare il numero di giorni e gli ultimi 4 byte utilizzati per rappresentare il numero di secondi.
Un esempio di sottrazione DATE risultante in una differenza intera positiva:
select date '2009-08-07' - date '2008-08-08' from dual;
Risultati in:
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
Ricordiamo che il risultato è rappresentato come un complemento a due separato di 2 con numeri di 4 byte con segno. Poiché in questo caso non ci sono decimali (esattamente 364 giorni e 0 ore), gli ultimi 4 byte sono tutti 0 e possono essere ignorati. Per i primi 4 byte, poiché la mia CPU ha un'architettura little-endian, i byte vengono invertiti e dovrebbero essere letti come 1.108 o 0x16c, che è decimale 364.
Un esempio di sottrazione DATE risultante in una differenza intera negativa:
select date '1000-08-07' - date '2008-08-08' from dual;
Risultati in:
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
Ancora una volta, poiché sto usando una macchina little-endian, i byte sono invertiti e dovrebbero essere letti come 255,250,97,224 che corrisponde a 11111111 11111010 01100001 11011111. Ora, poiché questo è nella codifica numerica binaria con segno in complemento a due, sappiamo che il numero è negativo perché la cifra binaria più a sinistra è un 1. Per convertirlo in un numero decimale dovremmo invertire il complemento a 2 (sottrai 1 quindi esegui il complemento a uno) risultando in:00000000 00000101 10011110 00100000 che equivale a -368160 come sospettato.
Un esempio di sottrazione DATE risultante in una differenza decimale:
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 differenza tra queste 2 date è di 0,25 giorni o 6 ore.
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
Ora questa volta, poiché la differenza è 0 giorni e 6 ore, ci si aspetta che i primi 4 byte siano 0. Per gli ultimi 4 byte, possiamo invertirli (perché la CPU è little-endian) e ottenere 84,96 =01010100 01100000 base 2 =21600 in decimale. La conversione di 21600 secondi in ore ti dà 6 ore, che è la differenza che ci aspettavamo.
Spero che questo aiuti chiunque si chiedesse come viene effettivamente memorizzata una sottrazione DATE.