sql >> Databáze >  >> RDS >> Oracle

Oracle SQL Date to Long a naopak

Při konverzi ztrácíte příliš mnoho přesnosti, než abyste se mohli vrátit opačným směrem. Můžete se přiblížit pomocí časových razítek namísto dat.

Za prvé, váš původní dotaz úplně ztratil časovou složku:

select to_char(date '1970-01-01'
  + (1432550197431912935 - power(2, 60))/power(2, 44), 'YYYY-MM-DD HH24:MI:SS')
from dual;

2013-07-09 01:13:19

... ale i s tím převod zpět ztratil příliš mnoho:

select ((to_date('2013-07-09 01:13:19','YYYY-MM-DD HH24:MI:SS')
  - date '1970-01-01') * power(2, 44)) + power(2, 60) from dual;

1432550197477589405

Což je blíž než 1432549301782839296, které máte, ale stále je to docela daleko.

Součástí problému je přesnost DATE , což je teprve do druhého. Pokud používáte TIMESTAMP místo toho se můžete dostat docela blízko; můžete vidět, že hodnota, kterou chcete mít, je údajně velmi přesná:

select timestamp '1970-01-01 00:00:00'
  + numtodsinterval((1432550197431912935 - power(2, 60))/power(2, 44), 'DAY')
from dual;

2013-07-09 01:13:18.775670462

Převod tohoto zpět je komplikovaný aritmetikou časových razítek poskytujících intervalové výsledky, se kterými pak musíte manipulovat, abyste se dostali zpět na číslo, nejprve jako původní počet dní:

select extract(day from int_val)
  + extract(hour from int_val) / 24
  + extract(minute from int_val) / (24 * 60)
  + extract(second from int_val) / (24 * 60 * 60)
from (
select to_timestamp('2013-07-09 01.13.18.775670462', 'YYYY-MM-DD HH24:MI:SS.FF9')
  - timestamp '1970-01-01 00:00:00' as int_val from dual);

15895.0509117554451620370370370370370371

... a pak s vaší manipulací s mocí:

select ((extract(day from int_val)
    + extract(hour from int_val) / 24
    + extract(minute from int_val) / (24 * 60)
    + extract(second from int_val) / (24 * 60 * 60))
  * power(2, 44)) + power(2, 60)
as x
from (
select to_timestamp('2013-07-09 01.13.18.775670462', 'YYYY-MM-DD HH24:MI:SS.FF9')
  - timestamp '1970-01-01 00:00:00' as int_val from dual);

1432550197431912935.09988554676148148148

Což je zatraceně blízko. Můžete to zkrátit nebo zaokrouhlit na nejbližší celé číslo.

Pouhý pohled na vaše čísla a manipulaci s mocí v každém směru ukazuje, že se zdá být v rámci přesnosti, se kterou se Oracle dokáže vyrovnat:

select (1432550197431912935 - power(2, 60)) / power(2, 44)
from dual;

15895.050911755445156359201064333319664

select (15895.050911755445156359201064333319664 * power(2, 44)) + power(2, 60)
from dual;

1432550197431912935.000...

I s časovým razítkem něco z toho ztratíte, protože první hodnota překračuje limit 9-ti místný zlomek sekund. Část, která představuje zlomkové sekundy – jakmile započítáte 15 895 hodin atd. – je .0000089776673785814232865555418862 dne, což je .77567046150943497195839881896768 sekundy; časové razítko je zaokrouhluje na .775670462 . Takže to nikdy nebude dokonalé.

To také vede k zamyšlení nad tím, jak se generuje původní číslo; zdá se nepravděpodobné, že ve skutečnosti představuje čas až do této extrémní přesnosti, protože je pod yoktosekundy . Není skutečně jasné, zda je „přesnost“ skutečně artefaktem manipulace na základě mocnin 2, ale každopádně to nevypadá příliš užitečně. Je běžnější používat datum epochy ve stylu Unixu, počítající sekundy nebo někdy milisekundy od data epochy, které stejně používáte, pokud vůbec musí být uloženo jako číslo. Tento design je... zajímavý.



  1. Funkce pro získání počtu dnů v týdnu mezi dvěma daty kromě svátků

  2. Problém s porovnáním data MySQL?

  3. přiřazení hodnoty mysql proměnné inline

  4. Tvůrce dotazů nevkládá časová razítka