简体   繁体   中英

How to grab the previous hour of a timestamp(4) with TIMEZONE column?

so I have a table called Value. I am trying to derive the Value for the last hour ( HR --> Timestamp(4) with TIME ZONE ) so that I can use it in a conditional statement in this Stored Procedure that I'm building. However, when i try the following, Oracle only returns a Date ( 01-Jan-19 ) rather than the previous hour ( 01-Jan-19 01.00.00.00000000 AM UTC ). What am I doing wrong?

select hr
     , hr - (1/24) as Converted
 from value;

If I try the following, I return ' 31-DEC-16 12.00.00.000000000 AM ' as the value for 'Converted' (no matter what the value for HR is):

select hr
     , to_timestamp(hr - (1/24)) as converted
   from value;

Which ultimately will be used as the definition of a variable in my stored procedure:

 select max(value) 
   into v_Previous_hour
   from value
  where hr = hr - (1/24);

Am I missing something here? Thanks in advance.

Try this:

select hr
     , cast( hr - (1/24) as timestamp) as Converted
 from value;

Also, the query below is not going to do what you think it is.

 select max(value) 
   into v_Previous_hour
   from value
  where hr = hr - (1/24);

Or you could use INTERVAL :

SELECT TO_CHAR(HR) AS HR,
       TO_CHAR(CAST(HR - INTERVAL '1' HOUR - INTERVAL '0.233' SECOND AS TIMESTAMP(4) WITH TIME ZONE)) AS HR_MINUS_ONE_HOUR
  FROM VAL;

(Here I subtracted an additional 0.233 seconds just to make sure we were dealing with timestamps, per @AlexPoole's comment on @OldProgrammer's answer).

SQLFiddle here

Oracle only returns a Date (01-Jan-19)

A date still has a time, your client just isn't showing it to you. You can use to_char() to display it explicitly:

select to_char(hr - (1/24), 'YYYY-MM-DD HH24:MI:SS') from ...

It is a date because [that's the result of timestamp - number] arithmetic, and the timestamp is implicitly converted to a date before the subtraction. But you are losing both the fractional seconds and the time zone from your original value. Even if you cast back to a plain timestamp that information isn't recovered, and if you cast back to a timestamp with time zone it imolicitly picks up the current session's time zone, so won't necessarily match.

To keep both you can do what you suggested in your answer, or

select hr - interval '1' hour from ...

In your procedure, declare a variable of the same data type, eg (as an nonymous block):

declare
  l_hr value.hr%type;
begin
  select hr - interval '1' hour
  into l_hr
  from value
  where ... ;

  ...
end;

Don't be tempted to store or manipulate the value as a string, keep it as its origial data type. It will be easieer to work with, safer and more efficient.

Have a look at this table Matrix of Datetime Arithmetic

When you perform {TIMESTAMP WITH TIME ZONE} - {NUMERIC} then you get DATE value, ie you loose the time zone information.

Better use INTERVAL, eg hr - INTERVAL '1' HOUR or hr - NUMTODSINTERVAL(1, 'HOUR')

Anyway, I don't understand your question. If you ask " How to grab the previous hour of a timestamp(4) with TIMEZONE column? " then my answer would be

SELECT
    EXTRACT(HOUR FROM hr - INTERVAL '1' HOUR) AS Solution_1
    TO_CHAR(hr - INTERVAL '1' HOUR, 'HH24')  AS Solution_2
FROM ...

Note, solution EXTRACT(HOUR FROM hr - INTERVAL '1' HOUR) always returns the hour of UTC time, whereas TO_CHAR(hr - INTERVAL '1' HOUR, 'HH24') returns hour from the stored time zone.

After 2 hours of hairpulling (and ironically after OldProgrammer was nice enough to provide me with an answer), I found a workaround:

 select hr
      , hr - numtodsinterval(1, 'hour') as converted
   from value;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM