Du mister for meget præcision i din konvertering til at kunne gå tilbage den anden vej. Du kan komme tættere på ved at bruge tidsstempler i stedet for datoer.
For det første mistede din første forespørgsel tidskomponenten fuldstændigt:
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
... men selv med det, har konvertering tilbage mistet alt for meget:
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
Hvilket er tættere på end de 1432549301782839296, du har, men stadig et stykke væk.
En del af problemet er præcisionen af DATE
, som kun er til den anden. Hvis du bruger TIMESTAMP
i stedet kan du komme helt tæt på; du kan se, at den værdi, der skal have, angiveligt er meget præcis:
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
Konvertering af denne tilbage er kompliceret af tidsstempel-aritmetik, der giver intervalresultater, som du derefter skal manipulere for at komme tilbage til et tal, først som det oprindelige antal dage:
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
... og så med din magtmanipulation:
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
Hvilket er ret tæt på. Du kan afkorte eller afrunde det til det nærmeste hele tal.
Bare at se på dine tal og magtmanipulationen hver vej viser, at det ser ud til at være inden for den præcision, Oracle kan klare:
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...
Selv med et tidsstempel mister du noget af det, da den første værdi går forbi den 9-cifrede brøksekundgrænse. Den del, der repræsenterer brøksekunderne - når du har taget højde for de 15895 timer osv. - er .0000089776673785814232865555418862
af en dag, som er .77567046150943497195839881896768
sekunder; tidsstemplet afrunder det til .775670462
. Så det bliver aldrig perfekt.
Det får også en til at undre sig over, hvordan det oprindelige nummer bliver genereret; det virker usandsynligt, at det faktisk repræsenterer en tid ned til den ekstreme præcision, da det er under yoktosekunder . Det er ikke rigtig klart, om 'præcisionen' faktisk er en artefakt af, at den bliver manipuleret baseret på 2-potenser, men den ser ikke særlig brugbar ud alligevel. Det er mere almindeligt at bruge epokedatoen i Unix-stil, der tæller sekunder eller nogle gange millisekunder siden den epokedato, du alligevel bruger, hvis den overhovedet skal gemmes som et tal. Dette design er... interessant.