Je verliest te veel precisie in je conversie om de andere kant op terug te kunnen gaan. Je kunt dichterbij komen door tijdstempels te gebruiken in plaats van datums.
Ten eerste verloor uw eerste vraag de tijdcomponent volledig:
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
... maar zelfs daarmee heeft het terug converteren veel te veel verloren:
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
Dat is dichterbij dan de 1432549301782839296 die je hebt, maar nog steeds een heel eind weg.
Een deel van het probleem is de precisie van DATE
, die slechts aan de tweede is. Als u TIMESTAMP
. gebruikt in plaats daarvan kun je heel dichtbij komen; je kunt zien dat de waarde die je moet hebben erg precies is:
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
Dat terug converteren wordt gecompliceerd door tijdstempelberekeningen die intervalresultaten opleveren, die u vervolgens moet manipuleren om terug te keren naar een getal, eerst als het oorspronkelijke aantal dagen:
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
... en dan met je machtsmanipulatie:
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
Wat verdomd dichtbij is. Je zou dat kunnen afkappen of afronden naar het dichtstbijzijnde gehele getal.
Alleen al kijken naar je cijfers en de machtsmanipulatie in beide richtingen laat zien dat het lijkt te vallen binnen de precisie die Oracle aankan:
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...
Zelfs met een tijdstempel verlies je een deel daarvan, omdat die eerste waarde voorbij de 9-cijferige fractionele tweede limiet gaat. Het deel dat de fractionele seconden vertegenwoordigt - als je eenmaal de 15895 uur enz. hebt berekend - is .0000089776673785814232865555418862
van een dag, dat is .77567046150943497195839881896768
seconden; het tijdstempel rondt dat af op .775670462
. Het zal dus nooit perfect zijn.
Dat leidt er ook toe dat je je afvraagt hoe het oorspronkelijke aantal wordt gegenereerd; het lijkt onwaarschijnlijk dat het een tijd vertegenwoordigt die tot die uiterste precisie reikt, aangezien het lager is dan yoctoseconden . Het is niet echt duidelijk of de 'precisie' eigenlijk een artefact is van het manipuleren ervan op basis van machten van 2, maar het ziet er toch niet erg handig uit. Het is gebruikelijker om de epochedatum in Unix-stijl te gebruiken, waarbij seconden of soms milliseconden worden geteld sinds de epochedatum die je toch gebruikt, als het al als een getal moet worden opgeslagen. Dit ontwerp is... interessant.