Tracisz zbyt dużo precyzji w konwersji, aby móc cofnąć się w drugą stronę. Możesz się zbliżyć, używając znaczników czasu zamiast dat.
Po pierwsze, początkowe zapytanie całkowicie straciło składnik czasu:
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 nawet przy tym konwersja powrotna straciła zbyt wiele:
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 jest bliżej niż 1432549301782839296, które masz, ale wciąż dość daleko.
Częścią problemu jest precyzja DATE
, który jest tylko do drugiego. Jeśli używasz TIMESTAMP
zamiast tego możesz podejść całkiem blisko; widać, że wartość, którą należy mieć, jest podobno bardzo precyzyjna:
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
Konwersja tego wstecz jest skomplikowana przez arytmetykę znacznika czasu dającą wyniki interwału, które następnie trzeba manipulować, aby powrócić do liczby, najpierw jako oryginalnej liczby dni:
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 potem z manipulacją 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 jest cholernie bliskie. Możesz to skrócić lub zaokrąglić do najbliższej liczby całkowitej.
Wystarczy spojrzeć na swoje liczby i manipulację mocą w każdą stronę, aby pokazać, że wydaje się, że mieści się to w precyzji, z jaką może sobie poradzić Oracle:
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...
Nawet ze znacznikiem czasu tracisz część tego, ponieważ ta pierwsza wartość przekracza 9-cyfrowy limit drugiego ułamka. Część reprezentująca ułamki sekund — po uwzględnieniu 15895 godzin itd. — to .0000089776673785814232865555418862
dnia, czyli .77567046150943497195839881896768
sekundy; znacznik czasu zaokrągla to do .775670462
. Więc nigdy nie będzie idealnie.
To również prowadzi do zastanowienia się, w jaki sposób generowana jest oryginalna liczba; wydaje się mało prawdopodobne, że w rzeczywistości reprezentuje czas do tej ekstremalnej precyzji, ponieważ wynosi on poniżej joktosekund . Nie jest jasne, czy „precyzja” jest w rzeczywistości artefaktem manipulacji w oparciu o moc 2, ale i tak nie wygląda to zbyt użytecznie. Częściej używa się daty epoki w stylu Uniksa, licząc sekundy, a czasem milisekundy od daty epoki, której i tak używasz, jeśli w ogóle ma być przechowywana jako liczba. Ten projekt jest... interesujący.