Bạn đang mất quá nhiều độ chính xác trong chuyển đổi của mình để có thể quay lại theo cách khác. Bạn có thể đến gần hơn bằng cách sử dụng dấu thời gian thay vì ngày.
Trước hết truy vấn ban đầu của bạn đã làm mất hoàn toàn thành phần thời gian:
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
... nhưng ngay cả với điều đó, việc chuyển đổi ngược lại đã bị mất quá nhiều:
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
Con số nào gần hơn con số 1432549301782839296 mà bạn nhận được, nhưng vẫn còn khá xa.
Một phần của vấn đề là độ chính xác của DATE
, chỉ là thứ hai. Nếu bạn sử dụng TIMESTAMP
thay vào đó bạn có thể đến khá gần; bạn có thể thấy rằng giá trị cần có được cho là rất chính xác:
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
Việc chuyển đổi trở lại đó rất phức tạp bởi số học dấu thời gian đưa ra kết quả khoảng thời gian, sau đó bạn phải thao tác để quay lại một số, trước tiên là số ngày ban đầu:
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
... và sau đó với thao tác quyền lực của bạn:
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
Đó là khá gần gũi. Bạn có thể cắt bớt hoặc làm tròn số đó đến số nguyên gần nhất.
Chỉ cần nhìn vào các con số của bạn và thao tác quyền lực theo từng cách cho thấy dường như nó nằm trong độ chính xác mà Oracle có thể đối phó:
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...
Ngay cả với dấu thời gian, bạn sẽ mất một số giá trị đó, vì giá trị đầu tiên đó đang vượt qua giới hạn phân số thứ hai gồm 9 chữ số. Phần đại diện cho số giây phân số - khi bạn đã tính đến 15895 giờ, v.v. - là .0000089776673785814232865555418862
trong một ngày, là .77567046150943497195839881896768
giây; dấu thời gian làm tròn thành .775670462
. Vì vậy, nó sẽ không bao giờ là hoàn hảo.
Điều đó cũng khiến người ta tự hỏi làm thế nào số gốc được tạo ra; có vẻ như nó không thực sự đại diện cho thời gian xuống đến độ chính xác cực cao, vì nó dưới yoctoseconds . Không thực sự rõ ràng liệu 'độ chính xác' có thực sự là một đồ tạo tác của việc nó được điều khiển dựa trên sức mạnh của 2 hay không, nhưng dù sao thì nó trông không hữu ích cho lắm. Thông thường hơn là sử dụng ngày kỷ nguyên kiểu Unix, đếm giây hoặc đôi khi mili giây kể từ ngày kỷ nguyên bạn đang sử dụng, nếu nó phải được lưu trữ dưới dạng số. Thiết kế này ... thú vị.