23

I thought it was really simple but it isn't.

SELECT TO_TIMESTAMP('10/08/2012','DD/MM/YYYY') 
          - 1/(24*50*60*1000) data 
FROM dual;

It simply doesn't work.


Other details:

SELECT TO_TIMESTAMP('10/08/2012','DD/MM/YYYY') -
           NUMTODSINTERVAL(1/(24*50*60*1000),'HOUR') data 
FROM dual;

doesn't work..

The right seems to be

SELECT TO_TIMESTAMP('10/08/2012','DD/MM/YYYY') -
           NUMTODSINTERVAL(1/(24*25*60*1000),'HOUR') data 
FROM dual;

Why? How does it work?

3
  • I did not get your point. What do you want to do?
    – Thinhbk
    Commented Aug 10, 2012 at 11:21
  • 2
    @Thinhbk:He wanted millisecond to be subtracted from that timestamp,if you look to the query above ,this will output you only 10/AUG/12,and actually he wanted 09/AUG/12 11:59:59.999950000 PM as output .Gik25 correct me if i am wrong . Commented Aug 10, 2012 at 11:27
  • Subtract one millisecond from the date
    – Revious
    Commented Aug 10, 2012 at 11:27

5 Answers 5

32
+25

For adding or subtracting an amount of time expressed as a literal you can use INTERVAL.

SELECT TO_TIMESTAMP('10/08/2012','DD/MM/YYYY')
     - INTERVAL '0.001' SECOND 
FROM dual;

As well there are now standard ways to express date and time literals and avoid the use of various database specific conversion functions.

SELECT TIMESTAMP '2012-10-08 00:00:00' 
   - INTERVAL '0.001' SECOND DATA
FROM dual;

For your original question the time part of a day is stored in fractional days. So one second is:

1 / (hours in day * minutes in hour * seconds in a minute)

Divide by 1000 to get milliseconds.

1 / (24 * 60 * 60 * 1000)
1
  • 2
    +1 Interval literals are definitely the way to go. Format models and date multiplication are just bugs waiting to happen.
    – Jon Heller
    Commented Sep 7, 2012 at 4:10
11
SELECT TO_TIMESTAMP('10/08/2012','DD/MM/YYYY') - NUMTODSINTERVAL(1/(24*50*60*1000),'HOUR') data 
FROM dual;

OUTPUT

DATA                             
---------------------------------
09/AUG/12 11:59:59.999950000 PM  

1 row selected.
4
  • How do you simulate the OUTPUT?
    – Revious
    Commented Aug 10, 2012 at 11:27
  • It didn't work.. Correct seems to be: SELECT TO_TIMESTAMP('10/08/2012','DD/MM/YYYY') - NUMTODSINTERVAL(1/(24*25*60*1000),'HOUR') data FROM dual; Why? I don't understand..
    – Revious
    Commented Sep 6, 2012 at 11:05
  • Not working. SELECT TO_TIMESTAMP('10/08/2012','DD/MM/YYYY') - NUMTODSINTERVAL(1/(24*50*60*1000),'HOUR') data FROM dual; gives the error: FROM keyword not found where expected Commented Jan 28, 2015 at 14:34
  • 1
    @AlikElzin-kilaka:It works for me ,try to align the text in one line ,its strange but this is how it is working :) Commented Feb 2, 2015 at 6:28
9

The answer posted above subtracts a tenth of a millisecond from the date. I think what you want is the following:

SELECT TO_TIMESTAMP('10/08/2012','DD/MM/YYYY')-NUMTODSINTERVAL(1/1000,'SECOND')
  FROM dual;

Output:

DATA
---------------------------------------------------------------------------
09-AUG-12 11.59.59.999000000 PM
                   ^^^
                   |||
              tenths|thousandths
                    |
                hundredths

The following NUMTODSINTERVAL(1/(24*25*60*1000),'HOUR') seems to work only because 24*25 = 600. But that number is wrong because 1/(600*60*1000) of an hour is a tenth of a millisecond, not a millisecond. If you want to use 'HOUR' in NUMTODSINTERVAL() you should use 1/(60*60*1000) (sixty minutes in an hour, sixty seconds in a minute, 1000 ms in a second).

7

This is correct (with a millisecond being 1000th of a second):-

SELECT TO_TIMESTAMP('10/08/2012','DD/MM/YYYY') - NUMTODSINTERVAL(1/1000,'SECOND') data FROM dual;


DATA
-----------------------------
09-AUG-12 23.59.59.999000000

As to why the other code isn't working it's because you aren't calculating a millisecond correctly. An hour must be divided by 60 to give minutes and again by 60 to given seconds then by 1000 to give a millisecond, thus if you must use HOUR as the interval then it is:-

SELECT TO_TIMESTAMP('10/08/2012','DD/MM/YYYY') - NUMTODSINTERVAL(1/(60*60*1000),'HOUR') as data FROM dual;

DATA
---------------------------------------------------------------------------
09-AUG-12 23.59.59.999000000
3
select TO_CHAR(TO_TIMESTAMP('10.05.2012', 'DD.MM.YYYY') - 
       NUMTODSINTERVAL(1/1000, 'SECOND'), 'DD.MM.YYYY HH24:MI:SS:FF3')  Res 
  from dual;

RES
-----------------------------
09.05.2012 23:59:59.999

Not the answer you're looking for? Browse other questions tagged or ask your own question.