NUMTODSINTERVAL in Redshift. Convert a number to hours - sql

My goal is to offset timestamps in table Date_times to reflect local timezones. I have a Timezone_lookup table that I use for that, which has a column utc_convert and its values are (2, -1, 5, etc.) depending on the timezone.
I used to use NUMTODSINTERVAL in Oracle to be able to convert the utc_convert values to hours so I can add/subtract from the datetimes in the Date_times table.
For Redshift I found INTERVAL, but that's only hardcoding the offset with a specific number.
I also tried:
SELECT CAST(utc as TIME)
FROM(
SELECT *
,to_char(cast(utc_convert as int)||':00:00', 'HH24') as utc
from Timezon_lookup
)
But this doesn't work as some number in the utc_convert column have negative values. Any ideas?

Have you tried multiplying the offset by an interval:
select current_timestamp + utc_convert * interval '1 hour'

In Oracle, you can use the time zone of the user's session (which means you do not need to maintain a table of time zone look-ups or compensate for daylight savings time).
SELECT FROM_TZ( your_timestamp_column, 'UTC' ) AT LOCAL
FROM Date_times
SQLFIDDLE
In RedShift you should be able to use the CONVERT_TIMEZONE( ['source_timezone',] 'target_timezone', 'timestamp') function rather adding a number of intervals. This would allow you to specify the target_timezone as a numeric offset from UTC or as a time zone name (which would automatically compensate for DST).

Related

Update only the time from a CURRENT_TIMESTAMP

How can I update and change only the time-section of a CURRENT_TIMESTAMP in postgres SQL?
I have to INSERT INTO a TABLE a new VALUE with the CURRENT_TIMESTAMP to get the correct year, month and day. The Time needs always to be 10 PM.
I tried to find a function where I eventually just get a TIMESTAMP with the current Year,month, day and the default time of 00:00:00. Later I tried to DATEADD 22:00:00 Into it. Doesn't seem to work.
If the time part is the same for all rows without exception, I would not store it at all. Use a date column then turn that into a timestamp when selecting from the table:
select the_column + time '22:00:00' as the_column_adjusted
from the_table
Another alternative is to define a default value with a fixed time:
the_column timestamp default current_date + time '22:00:00'
This approach can also be used during an INSERT:
insert into the_table (the_column)
values (current_date + time '22:00:00');
To change existing rows, you can convert the timestamp to a date, then add the desired time back:
update the_table
set the_column = the_column::date + time '22:00:00'
where ...
You can convert current_timestamp, which is of type "timestamptz" (short for "timestamp with time zone"), to a "date", then back to "timestamp with time zone", which will make it 00:00 at current timezone used by connection, and then add 22h:
=> select current_timestamp::date::timestamptz+'22h'::interval;
2022-11-05 22:00:00+01
You can simplify this with just using current_date:
=> select current_date::timestamptz+'22h'::interval;
2022-11-05 22:00:00+01
If you want to make it independent from current connection timezone, and just use UTC date (or any other time zone you need), you can use:
=> select ((current_timestamp at time zone 'UTC')::date::timestamp+'22h'::interval)::timestamptz;
2022-11-05 22:00:00+01
But, if hour is not important, then "date" type would be better and more efficient to store than "timestamp with time zone".
And never ever use "timestamp" type (short for "timestamp without timezone") for anything.

Group by day from nanosecond timestamp

I have a table column transaction_timestamp storing timestamps as epochs with nanosecond resolution.
How do I group and/or count by day? I guess I have to convert the nanosecond timestamp to milliseconds first. How can I do that?
I tried:
SELECT DATE_TRUNC('day', CAST((transaction_timestamp /pow(10,6))as bigint)), COUNT(*)
FROM transaction
GROUP BY DATE_TRUNC('day', transaction_timestamp)
which is does not work:
error: function date_trunc(unknown, bigint) does not exist
I also tried this:
SELECT DATE_TRUNC('day', to_timestamp(transaction_timestamp / 1000000000.0)),
COUNT(*)
FROM transaction
GROUP BY DATE_TRUNC('day', transaction_timestamp)
Basic conversion as instructed here:
What kind of datestyle can this be?
Repeat the same expression in GROUP BY, or use a simple positional reference, like:
SELECT date_trunc('day', to_timestamp(transaction_timestamp / 1000000000.0))
, count(*)
FROM transaction
GROUP BY 1;
Be aware that to_timestamp() assumes UTC time zone for the given epoch to produce a timestamp with time zone (timestamptz). The following date_trunc() then uses the timezone setting of your current session to determine where to truncate "days". You may want to define a certain time zone explicitly ...
Basics:
Ignoring time zones altogether in Rails and PostgreSQL
Typically, it's best to work with a proper timestamptz to begin with. Unfortunately, Postgres timestamps only offer microsecond resolution. Since you need nanoseconds, your approach seems justified.

Substraction with decimal in ORACLE SQL

I need to substract 2 timestamps in the given format:
16/01/17 07:01:06,165000000
16/01/17 07:01:06,244000000
I want to express the result with 2 decimal values but somewhere in the CAST process I am loosing precision. My atempt by now goes this way:
select
id,
trunc((CAST(MAX(T.TIMESTAMP) AS DATE) - CAST(MIN(T.TIMESTAMP) AS DATE))*24*60*60,2) as result
from table T
group by id;
But I get id_1 '0' as a result for the two timestamps above even after I set the truncate decimals at 2.
Is there a way that I can obtain the 0.XX aa a result of the substraction?
It's because you are casting the timestamp to date.
Use to_timestamp to convert your string into timestamp.
Try this:
with your_table(tstamp) as (
select '16/01/17 07:01:06,165000000' from dual union all
select '16/01/17 07:01:06,244000000' from dual
),
your_table_casted as (
select to_timestamp(tstamp,'dd/mm/yy hh24:mi:ss,ff') tstamp from your_table
)
select trunc(sysdate + (max(tstamp) - min(tstamp)) * 86400 - sysdate, 2) diff
from your_table_casted;
The difference between two timestamps is INTERVAL DAY TO SECOND.
To convert it into seconds, use the above trick.
DATE—This datatype stores a date and a time, resolved to the second. It does not include the time zone. DATE is the oldest and most commonly used datatype for working with dates in Oracle applications.
TIMESTAMP—Time stamps are similar to dates, but with these two key distinctions: you can store and manipulate times resolved to the nearest billionth of a second (9 decimal places of precision), and you can associate a time zone with a time stamp, and Oracle Database will take that time zone into account when manipulating the time stamp.
The result of a substraction of two timestamps is an INTERVAL:
INTERVAL—Whereas DATE and TIMESTAMP record a specific point in time, INTERVAL records and computes a time duration. You can specify an interval in terms of years and months, or days and seconds.
You can find more information here

Compare date + time with timestamp

I have a table with two temporal columns. First (name is DATE) is storing the date (not including the time part) and therefor the datatype is DATE. Second column (name is TIME) is for storing the time in seconds and therefor the datatype is NUMBER.
I need to compare this two dates with a timestamp from another table. How can I calculate the date of the two columns (DATE and TIME) and compare to the timestamp of the other table?
I have tried to calculate the hours out of the time column and add it to the date column, but the output seems not correct:
SELECT to_date(date + (time/3600), 'dd-mm-yy hh24:mi:ss') FROM mytable;
The output is just the date, but not the time component.
You can use the INTERVAL DAY TO SECOND type:
SELECT your_date + NUMTODSINTERVAL(your_time_in_seconds, 'SECOND') FROM dual;
Example:
SELECT TRUNC(SYSDATE) + NUMTODSINTERVAL(39687, 'SECOND') FROM dual;
The calculated date with time is: 10-11-2013 11:01:27
This is a better idea than dividing your value by 3600 in my opinion, as you have an interval in seconds, so it feels natural to use an interval to represent your time, which can then be easily added to a column of DATE datatype.
Oracle Interval in Documentation
NUMTODSINTERVAL Function in documentation
date + (time/3600) is already a DATE, so you don't need to do to_date(). It does have the time part you added though, you just aren't displaying it. If you want to output that as a string in the format you've shown, use to_char() instead:
SELECT to_char(date + (time/3600), 'dd-mm-yy hh24:mi:ss') FROM mytable;
... except that if time is actually in seconds, you need to divide by 86400 (24x60x60), not 3600. At the moment you're relying on your client's default date format, probably NLS_DATE_FORMAT, which doesn't include the time portion from what you've said. That doesn't mean the time isn't there, it just isn't displayed.
But that is just for display. Leave it as a date, by just adding the two values, when comparing against you timestamp, e.g.
WHERE date + (time/86400) < systimestamp
Try like this,
SELECT TO_DATE('11/11/2013','dd/mm/yyyy') + 3600/60/60/24 FROM DUAL;
Your query,
SELECT date + time/60/60/24 FROM mytable;
try using to_timestamp instead of to_date

How to get the date and time from timestamp in PostgreSQL select query?

How to get the date and time only up to minutes, not seconds, from timestamp in PostgreSQL. I need date as well as time.
For example:
2000-12-16 12:21:13-05
From this I need
2000-12-16 12:21 (no seconds and milliseconds only date and time in hours and minutes)
From a timestamp with time zone field, say update_time, how do I get date as well as time like above using PostgreSQL select query.
Please help me.
There are plenty of date-time functions available with postgresql:
See the list here
http://www.postgresql.org/docs/9.1/static/functions-datetime.html
e.g.
SELECT EXTRACT(DAY FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 16
For formatting you can use these:
http://www.postgresql.org/docs/9.1/static/functions-formatting.html
e.g.
select to_char(current_timestamp, 'YYYY-MM-DD HH24:MI') ...
To get the date from a timestamp (or timestamptz) a simple cast is fastest:
SELECT now()::date
You get the date according to your local time zone either way.
If you want text in a certain format, go with to_char() like #davek provided.
If you want to truncate (round down) the value of a timestamp to a unit of time, use date_trunc():
SELECT date_trunc('minute', now());
This should be enough:
select now()::date, now()::time
, pg_typeof(now()), pg_typeof(now()::date), pg_typeof(now()::time)