Select items where local time is ~8AM - postgresql

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'

Related

How to extract data from DWH on a certain date? Is there the special pattern for this case in Postgres SQL?

Usually we use EXTRACT (FROM YEAR date_column) = 2000 (let it be 2000 year). Also we can add EXTRACT (MONTH FROM date_column) = 1 (let it be January). Also we can extract a day - EXTRACT (DAY FROM date_column) = 5 (let it 5). But is it possible to use the pattern for this data? How does it look like in Postgres SQL
Say we have the table Shipment, the columns - date_payment, quantity, sum.
I'd like to get the table that content all shipments for 01.01.2020
How to query this table with data format 'YYYY-MM-DD', not using EXTRACT-function?
If the date column is a date type then:
SELECT * FROM some_table WHERE date_col = '2020-01-01';
If the column is timestamp or timestamptz then:
SELECT * FROM some_table WHERE date_trunc('day', date_col) = '2020-01-01'
Beware that with timestamptz time zones come into play when doing the date_trunc. From here date_trunc:
When the input value is of type timestamp with time zone, the truncation is performed with respect to a particular time zone; for example, truncation to day produces a value that is midnight in that zone. By default, truncation is done with respect to the current TimeZone setting, but the optional time_zone argument can be provided to specify a different time zone. The time zone name can be specified in any of the ways described in Section 8.5.3.
For a timestamp value per the above link:
A time zone cannot be specified when processing timestamp without time zone or interval inputs. These are always taken at face value.

Can't extract date from milliseconds epoch postgresql

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'

Column of type "timestamp(6) with timezone" and "current time" difference in minutes

I have Oracle 12c DB table and one of it's column utc_timestamp is of type
UTC_TIMESTAMP TIMESTAMP(6) WITH TIME ZONE
It stores timestamp in UTC while current_timestamp and systimestamp both gives timestamp in different timezones.
How can I get time difference in MAX(utc_timestamp) and current_timestamp in minutes ignoring time difference due to different time zones.
For example:
select current_timestamp from dual;
Gives=> 23-AUG-17 04.43.16.253931000 PM AMERICA/CHICAGO
select systimestamp from dual;
Gives=> 23-AUG-17 05.43.16.253925000 PM -04:00
select max(UTC_TIMESTAMP) from table_name;
Gives=> 23-AUG-17 09.40.02.000000000 PM +00:00
For above condition when I run SQL to check time difference between in MAX(utc_timestamp) and current_timestamp I should get number 3.
I think I need something like:
select (extract(minute from current_timestamp) - extract(minute from max(UTC_TIMESTAMP)) * 1440) AS minutesBetween from table_name;
But different timezones are messing it up and I get negative number like -4317. This might be correct as current_timestamp will be higher than max(utc_timestamp) being in CST. So I tried:
select (extract(minute from CAST(current_timestamp as TIMESTAMP(6) WITH TIME ZONE)) - extract(minute from max(UTC_TIMESTAMP)) * 1440) AS minutesBetween from table_name;
This SQL runs without error but producing a big negative number like -83461. Please help me find what am I doing wrong.
You really have two problems here.
One is to convert CURRENT_TIMESTAMP to UTC. That is trivial:
select CURRENT_TIMESTAMP AT TIME ZONE 'UTC' from dual [.....]
(use the AT TIME ZONE clause https://docs.oracle.com/cd/B19306_01/server.102/b14225/ch4datetime.htm#i1007699)
The other is that the difference between two timestamps is an interval, not a number.
select current_timestamp at time zone 'UTC'
- to_timestamp_tz('24-AUG-17 04.00.00.000 AM UTC', 'dd-MON-yy hh.mi.ss.ff AM TZR')
from dual;
produces something like
+00 00:02:39.366000
which means + (positive difference) 00 days, 00 hours, 02 minutes, 39.366 seconds.
If you just want the minutes (always rounded down), you may wrap this whole expression within extract( minute from < ...... > ). Be aware though that the answer will still be 2 (minutes) even if the difference is five hours and two minutes. It is probably best to leave the result in interval data type, unless you are 100% sure (or more) that the result is always less than 1 hour.

Return rows based on timestamp respective to their time zone

I have a table in which every row represents a user. I am also storing the user's time zone as text such as 'America/Denver', 'America/New_York' etc.
Is it possible to write a query that would return users for whom their current time of day is between 1 PM to 11 PM respective to their time zone?
Given this table:
CREATE TABLE usr (
usr_id serial PRIMARY KEY
, usr text NOT NULL
, tz text -- time zone names
);
Use the AT TIME ZONE construct:
SELECT *, (now() AT TIME ZONE tz)::time AS local_time
FROM usr
WHERE (now() AT TIME ZONE tz)::time BETWEEN '13:00'::time AND '23:00'::time;
Including upper and lower bounds 1 PM and 11 PM.
SQL Fiddle.
Details for AT TIME ZONE:
Ignoring timezones altogether in Rails and PostgreSQL
SELECT CONVERT_TZ(FROM_UNIXTIME(1196440219),'GMT','America/Denver');
SELECT * FROM table WHERE
DATE_FORMAT(CONVERT_TZ(FROM_UNIXTIME(timestamp_column),'GMT','America/Denver'),'%H') between 13 and 23

Postgresql timestamp and future default values in HSQLDB

I'm working with a legacy postgres db that uses column definitions as follows:
timestamp without time zone default (CURRENT_TIMESTAMP
AT TIME ZONE 'UTC')
and
timestamp without time zone default (CURRENT_TIMESTAMP
AT TIME ZONE 'UTC' + 30 * interval '1 day')
Unfortunately these cannot be changed.
The goal of the latter one is that the default value is 30 days in the future.
I'm trying to add a modern day junit test framework using hsqldb on top of it.
To bring this in line with hsqldb, the first definition needed to be changed to:
timestamp without time zone default CURRENT_TIMESTAMP
AT TIME ZONE INTERVAL '0:00' HOUR TO MINUTE
However, try as I may, I cannot figure out a way to replicate the column with the addition of the 30 days
You can use a TRIGGER for this kind of default value:
CREATE TRIGGER t BEFORE INSERT ON the_table
REFERENCING NEW AS newrow FOR EACH ROW
BEGIN ATOMIC
SET newrow.the_column = CURRENT_TIMESTAMP AT TIME ZONE INTERVAL '0:00' HOUR TO MINUTE + INTERVAL '30' DAY;
END
Update: PostgreSQL compatibility has been extended to accept values in the future. Example
timestamp without time zone default (CURRENT_TIMESTAMP AT TIME ZONE INTERVAL '0:00' HOUR TO MINUTE + INTERVAL 30 DAY))