Can't extract date from milliseconds epoch postgresql - amazon-redshift

I'm querying the database (RedShift) and I have a piece of information stored in epoch MS format. Envision a table along the lines of:
Purchase, date
1, 1620140227019
2, 1620140227045
3, 1620140226573
I need to convert the timestamp to a readable date but I can't make it work with to_timestamp() or extract(). The problem is first with the size of the value (13 digits are not supported).
The closest solution I have is
select to_timestamp(1620140226573/1000, 'SS')
But the result is 0051-05-04 14:57:06. In other words month, date and seconds are correct but the year is wrong.

You can run this query
select to_timestamp(round(1620140227254/1000))

The solution was in the documentation: https://docs.aws.amazon.com/redshift/latest/dg/r_Dateparts_for_datetime_functions.html
SELECT timestamp with time zone 'epoch' + 1620140227019/1000 * interval '1 second' AS converted_timestamp
or
select '1970-01-01'::date + 1620140227019/1000 * interval '1 second'

Related

how to add 1 minute to a given year, month, day hour minute seconds in postgresql?

I have this given date and time
2020-11-05 09:30:00
I wanted to add 1 minute to it. so I tried
select '2020-11-05 09:30:00' + INTERVAL '1 Minute'; -- result is invalid syntax
I tried
select DATEADD(minute, 1, '2020-11-05 09:30:00'); -- result ERROR: column "minute" doesn't exist
so how to add 1 minute to that given date and time in my example ?
There are several possible operators named + that PostgreSQL considers here:
interval + interval
date + interval
timestamp without time zone + interval
timestamp with time zone + interval
time without time zone + interval
time with time zone + interval
Since it does not know which data type the first argument has, it follows its data type resolution rules and ends up with the first one (because the arguments are of the same type). That explains the error message.
So you must be explicit about the data type of the first argument:
select TIMESTAMP '2020-11-05 09:30:00' + INTERVAL '1 Minute';

Datatype of Hour in oracle

When we use the query like this in oracle to get the the total number of hours in round figure,
hours= select round(out_time-in_time)*24 from table_name;
what is the datatype of hours here?
out_time and in_time are column names
You can take NUMBER as the datatype in your case.
EDIT:- This will return you an integer
select 24 * round((to_date('2013-07-07 22:00', 'YYYY-MM-DD hh24:mi')
- to_date('2013-07-07 19:30', 'YYYY-MM-DD hh24:mi'))) diff_hours
from table_name;
Maybe a datatype called "INTERVAL" will suit you. It's called:
INTERVAL DAY [(day_precision)] TO SECOND
Stores a period of time in days, hours, minutes, and seconds
Interval is something that can we added (or substrated) to a DATE or TIMESTAMP.
see: http://docs.oracle.com/cd/E11882_01/server.112/e26088/sql_elements001.htm

PostgreSQL: exists robust third party date-math functions to augment the built-in date operators?

I'm porting some T-SQL stored procs to PL/pgSql and, being very new to PostgreSQL, don't know what helpful utility functions might be available in the pg community. Is there a set of robust date-math functions that "nearly everybody uses" out there somewhere? I don't want to quickly cobble together some date-math functions if there's already a great package out there.
The PostgreSQL date math operators with "natural language" string literal arguments are user-friendly if you're typing a query and you happen to know the interval:
select now() - interval '1 day'
but if the interval 1 is the result of a calculation involving nested date-math function calls, these string literals are actually not very user-friendly at all, and it would easier to work with a date_add function:
select dateadd(d, {calculation that returns the interval}, now() )
Thanks
Let me give you an example. I want to subtract from an arbitrary date the number of months that have elapsed since 1/1/1970, and then add that number of months to 1/1/1970 to return the first day of the month in which the arbitrary date falls
select (date_trunc('month', '2013-01-30'::date))::date
Or add a month to the first day of this month to get the first day of the next month, then subtract one day to get the last day of this month
select date_trunc('month', '2013-01-30'::date + 1 * interval '1 month')::date - 1
Notice in the above example you can add any number of months by multiplying the interval '1 month' by an integer. You can do that with any interval without manipulating the string '1 month'. So to add or subtract any interval you just:
select current_date + 5 * interval '1 month'
No need for messy string manipulations. You can multiply by fractions also:
select current_timestamp + 3.5 * interval '1 minute'
To add or subtract days to a date type you use an integer:
select current_date + 10
The "natural language" strings you're talking about are interval literals. Intervals can also be obtained by using date arithmetic.
Surely dateadd can be quite simply emulated in Postgresql as follows:
select d + ({calculation the returns the interval}::text || ' day')::interval
Substitute "month" or "hours" etc as appropriate.
In PostgreSQL, you simply add and subtract interval values to datetime
values:
'2001-06-27 14:43:21'::TIMESTAMP - '00:10:00'::INTERVAL = '2001-06-27 14:33:21'::TIMESTAMP
'2001-06-27 14:43:21'::TIMESTAMP- '2001-06-27 14:33:21'::TIMESTAMP = '00:10:00'::INTERVAL
For more information, see "Functions and Operators" in the PostgreSQL
online docs.
To compute the first day of the month of a date: date_trunc('month', date)
First day of the next month: date_trunc('month', date) + '1 month'::INTERVAL
Add three months to the first day of the month of this date: date_trunc('month', date) + 3*('1 month'::INTERVAL)
The interval is a data type, not a string, and you can do computations with its values.

Select Data over time period

I'm a bit of newbie when it comes to postgres, so bear with me a wee bit and i'll see if i can put up enough information.
i insert weather data into a table every 10 mins, i have a time column that is stamped with an epoch date.
I Have a column of the last hrs rain fall, and every hr that number changes of course with the running total (for that hour).
What i would like to do is skim through the rows to the end of each hour, and get that row, but do it over the last 4 hours, so i would only be returning 4 rows say.
Is this possible in 1 query? Or should i do multiple queries?
I would like to do this in 1 query but not fussed...
Thanks
Thanks guys for your answers, i was/am a bit confused by yours gavin - sorry:) comes from not knowing this terribly well.
I'm still a bit unsure about this, so i'll try and explain it a bit better..
I have a c program that inserts data into the database every 10 mins, it reads the data fom a device that keeps the last hrs rain fall, so every 10 mins it could go up by x amount.
So i guess i have 6 rows / hr of data.
My plan was to go back (in my php page) every 7, which would be the last entry for every hour, and just grab that value. Hence why i would only ever need 4 rows.. just spaced out a bit!
My table (readings) has data like this
index | time (text) | last hrs rain fall (text)
1 | 1316069402 | 1.2
All ears to better ways of storing it too :) I very much appreciate your help too guys thanks.
You should be able to do it in one query...
Would something along the lines of:
SELECT various_columns,
the_hour,
SUM ( column_to_be_summed )
FROM ( SELECT various_columns,
column_to_be_summed,
extract ( hour FROM TIME ) AS the_hour
FROM readings
WHERE TIME > ( NOW() - INTERVAL '4 hour' ) ) a
GROUP BY various_columns,
the_hour ;
do what you need?
SELECT SUM(rainfall) FROM weatherdata WHERE time > (NOW() - INTERVAL '4 hour' );
I don't know column names but that should do it the ones in caps are pgsql types. Is that what you are after?
I am not sure if this is exactly what you are looking for but perhaps it may serve as a basis for adaptation.
I often have a requirment for producing summary data over time periods though I don't use epoch time so there may be better ways of manipulating the values than I have come up with.
create and populate test table
create table epoch_t(etime numeric);
insert into epoch_t
select extract(epoch from generate_series(now(),now() - interval '6 hours',interval '-10 minutes'));
To divide up time into period buckets:
select generate_series(to_char(now(),'yyyy-mm-dd hh24:00:00')::timestamptz,
to_char(now(),'yyyy-mm-dd hh24:00:00')::timestamptz - interval '4 hours',
interval '-1 hour');
Convert epoch time to postgres timestamp:
select timestamptz 'epoch' + etime * '1 second'::interval from epoch_t;
then truncate to hour :
select to_char(timestamptz 'epoch' + etime * '1 second'::interval,
'yyyy-mm-dd hh24:00:00')::timestamptz from epoch_t
To provide summary information by hour :
select to_char(timestamptz 'epoch' + etime * '1 second'::interval,
'yyyy-mm-dd hh24:00:00')::timestamptz,
count(*)
from epoch_t
group by 1
order by 1 desc;
If you might have gaps in the data but need to report zero results use a generate_series to create period buckets and left join to data table.
In this case I create sample hour buckets back prior to the data population above - 9 hours instead of 6 and join on the conversion of epoch time to timestamp truncated to hour.
select per.sample_hour,
sum(case etime is null when true then 0 else 1 end) as etcount
from (select generate_series(to_char(now(),
'yyyy-mm-dd hh24:00:00')::timestamptz,
to_char(now(),'yyyy-mm-dd hh24:00:00')::timestamptz - interval '9 hours',
interval '-1 hour') as sample_hour) as per
left join epoch_t on to_char(timestamptz 'epoch' + etime * '1 second'::interval,
'yyyy-mm-dd hh24:00:00')::timestamptz = per.sample_hour
group by per.sample_hour
order by per.sample_hour desc;

Select items where local time is ~8AM

I have a table called items. It contains a column tz with timezone identifiers (like America/New_York, Europe/London, etc).
I want to select all the items where the current time is 8AM +/- 5 minutes.
So if I run the query at 8AM EST it will return rows where tz = 'America/New_York'.
If I run the query at 9AM EST it will return rows where tz = 'America/Chicago'.
SELECT *
FROM items
WHERE CAST(current_timestamp at time zone tz AS time) BETWEEN '07:55' AND '08:05'
You should be storing the offset for each timezone. Then the query is as simple as
select * from items where GETDATE() between
DATEADD(minute,5,DATEADD(HOUR,offset,GETUTCDATE())) and
DATEADD(minute,-5,DATEADD(HOUR,offset,GETUTCDATE()))
I'm using SqlServer GETUTCDATE and DATEADD functions, but you can easily make them work in postgresql if you lookup the correct function names.
EDIT
If you can't add a offset to the table, create a timezone table with the string timezone and numeric offset. Join and run the above query.
Your tz field is valid if it respects this: http://www.postgresql.org/docs/8.0/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE
If so, I think this should work (no tested):
SELECT *
FROM items
WHERE LOCALTIMESTAMP BETWEEN
(LOCALTIMESTAMP AT TIME ZONE tz) - interval '5 minutes' AND
(LOCALTIMESTAMP AT TIME ZONE tz) + interval '5 minutes'