Anda kehilangan terlalu banyak presisi dalam konversi Anda untuk dapat kembali ke arah lain. Anda bisa lebih dekat dengan menggunakan stempel waktu alih-alih tanggal.
Pertama, kueri awal Anda kehilangan komponen waktu sepenuhnya:
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
... tetapi bahkan dengan itu, mengubah kembali telah kehilangan terlalu banyak:
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
Mana yang lebih dekat dari 1432549301782839296 yang Anda dapatkan, tapi masih jauh.
Sebagian dari masalahnya adalah ketepatan DATE
, yang hanya untuk yang kedua. Jika Anda menggunakan TIMESTAMP
sebaliknya Anda bisa cukup dekat; Anda dapat melihat bahwa nilai yang dimiliki seharusnya sangat tepat:
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
Mengonversi kembali itu diperumit oleh aritmatika stempel waktu yang memberikan hasil interval, yang kemudian harus Anda manipulasi untuk kembali ke angka, pertama sebagai jumlah hari asli:
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
... dan kemudian dengan manipulasi kekuatan Anda:
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
Yang sangat sangat dekat. Anda dapat memotong atau membulatkannya ke bilangan bulat terdekat.
Hanya dengan melihat angka-angka Anda dan manipulasi kekuatan setiap cara menunjukkan bahwa itu tampaknya berada dalam ketepatan yang dapat diatasi 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...
Bahkan dengan stempel waktu, Anda kehilangan sebagian dari itu, karena nilai pertama melewati batas pecahan 9 digit kedua. Bagian yang mewakili pecahan detik - setelah Anda menghitung 15895 jam, dll. - adalah .0000089776673785814232865555418862
hari, yaitu .77567046150943497195839881896768
detik; stempel waktu membulatkannya menjadi .775670462
. Jadi tidak akan pernah sempurna.
Itu juga membuat orang bertanya-tanya bagaimana nomor asli dihasilkan; sepertinya tidak mungkin itu benar-benar mewakili waktu hingga presisi ekstrem itu, karena di bawah yoctoseconds . Tidak terlalu jelas apakah 'presisi' sebenarnya adalah artefak yang dimanipulasi berdasarkan kekuatan 2, tetapi tetap tidak terlihat sangat berguna. Lebih umum menggunakan tanggal epoch gaya Unix, menghitung detik atau terkadang milidetik sejak tanggal epoch yang Anda gunakan, jika harus disimpan sebagai angka sama sekali. Desain ini... menarik.