How to declare interval infinity in postgres? - postgresql

It seems that we can't currently case infinity as an interval.
While trying:
SELECT 'infinity'::interval;`
we get
SQL Error [22007]: ERROR: invalid input syntax for type interval: "infinity"
How could I specify a max value for an interval?
I tried comparing 2 infinity timestamps
SELECT ('-infinity'::timestamp + '1 day'::INTERVAL)::timestamp without time zone at time zone 'UTC'
- 'infinity'::timestamp without time zone at time zone 'UTC';
but now getting
SQL Error [22008]: ERROR: cannot subtract infinite timestamps
Any idea?

Yes, that is true. You cannot represent infinite intervals with the interval data type.

Related

discarding milliseconds from the average time calculated

Here is my code:
SELECT cluster_id, AVG(min_per_imei_cluster::TIME) as avg_time
FROM arrival
group by cluster_id
The avg_time column gives values with milliseconds and beyond. How do I truncate or round to the nearest second?
I tried using
AVG(min_per_imei_cluster::TIME)::timestamp(0)
but got the following error:
SQL Error [42846]: ERROR: cannot cast type interval to timestamp without time zone
It looks like you can use the date_trunc function to specify the level of precision that you want. So in this instance, you would do date_trunc('second',min_per_imei_cluster).

PostgreSQL "date at time zone" unexpected behaviour

The behavior of the at time zone operator on the date type is not as expected in PostgreSQL.
set time zone 'UTC';
select
'2021-01-03'::date at time zone 'America/Chicago' as "value",
pg_typeof('2021-01-03'::date at time zone 'America/Chicago') as "type";
x
value
type
Expected
2021-01-03 06:00:00+00
timestamp with time zone
Actual
2021-01-02 18:00:00
timestamp without time zone
DB Fiddle
Tested on PostgreSQL server versions 10, 11, 12, and 13.
This behavior is very strange to me, and I have not been able to find anywhere it is described or discussed. It seems PSQL is implicitly casting date to timestamptz (using the system time zone) and then applying the at time zone operator. I know that the at time zone operator is only defined (in the docs) for the timestamp(tz) and time(tz) types. However, I would have assumed PSQL would implicitly cast date to timestamp and not timestamptz because:
It is a "safe" conversion (no need to assume a time zone). Simply append 00:00:00.
It results in a timestamptz which one would expect when using the at time zone operator on a type that does not have a time zone.
The current behavior simply doesn't make sense to me and I can't think of a use case that would benefit from it. You are asking for the timestamp with time zone for a date at a particular time zone and instead you get a timestamp of the date at the system time zone localized to the given time zone.
Of course, a simple workaround is to cast to timestamp first:
set time zone 'UTC';
select '2021-01-03'::date::timestamp at time zone 'America/Chicago';
I was hoping someone could shed some light on this. What am I missing? Perhaps some overarching rule about how date is implicitly cast to timestamp(tz)? Is this behavior documented somewhere?
Thanks!
Mike
You ask "why". The reason is that AT TIME ZONE does not operate on date, so PostgreSQL invokes an implicit type cast to convert it to a different data type. Lacking an explicit directive, PostgreSQL opts for the preferred data type for datetime, which happens to be timestamp with time zone.
The data type resolution rules for operators are documented here, and the preferred type for a type category can be found in the typispreferred and typcategory columns of the pg_type system catalog.
As per the Postgresql documentation:
The AT TIME ZONE converts time stamp without time zone to/from time stamp with time zone, and time values to different time zones
Here in first query, you are trying to apply at time zone to date type, not to time stamp
set time zone 'UTC';
select
'2021-01-03'::date at time zone 'America/Chicago' as "value",
pg_typeof('2021-01-03'::date at time zone 'America/Chicago') as "type";
which is eventually gets ignored, and you will get a timestamp without timezone
But in second query,
set time zone 'UTC';
select '2021-01-03'::date::timestamp at time zone 'America/Chicago';
You are casting the date to time stamp first and then converting it to desired time zone,
which gives you the expected result of time stamp with time zone.
Hope this clears your doubt.

Postgres timestamp with time zone saving with hour shift

I am trying to process input data putting timestamp when save it
tsSrc timestamp with time zone;
...
tsSrc := strTelegram.rte_data[ iPos ];-- this input data datetime
-- string e.g.'2015/12/13 21:35:26.000'
...
insert into telegram(
tld_id,
ddt_num, tld_src_timestamp,
tld_dst_timestamp, tld_year, tld_month,
tld_day, tld_hour, tld_min,
tld_sec, tld_data
) values(
uuId,
strTelegram.rte_type,
tsSrc,
strTelegram.rte_dst_timestamp,
extract(year from tsSrc), extract(month from tsSrc),
extract(day from tsSrc), extract(hour from tsSrc),
extract(minute from tsSrc), extract(second from tsSrc),
strTelegram.rte_data
);
But I have got unexpected result, tsSrc saved as 2015-12-13 20:35:26+03 i.e. has hour -1 shift, at the same time extract(hour from tsSrc) returns right value and saved as 21. What I am doing wrong?
Timezone is set as 'MSK-3' in postgresql.conf, select now() returns right datetime, postgresql 9.3.
You need to understand handling of timestamp (timestamp without time zone) and timestamptz (timestamp with time zone) and how each interacts with the timezone setting of your current session.
To explain the "difference" you observe we would need to know the exact table definition and the timezone setting of the session saving the row, as well as the timezone setting of the session displaying the row.
For example, if you take the timestamp literal '2015-12-13 21:35:26' (use ISO format to avoid additional complication with the input format!) and save it to a timestamptz column in a session with time zone offset +2 and later select the same row in a session with with time zone offset +3, then you get what you see:
SELECT '2015-12-13 21:35:26'::timestamp AT TIME ZONE '+2' AT TIME ZONE '+3';
Result:
'2015-12-13 20:35:26'
In other words: the timestamptz value '2015-12-13 20:35:26+03' is exactly the same (same point in time) as '2015-12-13 21:35:26+02', only the display has been adapted to your time zone setting. When you treat the timestamptz value according to the clock on the wall in your corner of the world (like you do with extract(hour from tsSrc)), you get different results depending where you are currently (the timezone setting of your session).
Detailed explanation:
Ignoring timezones altogether in Rails and PostgreSQL

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))

Now() without timezone

I have a column added_at of type timestamp without time zone. I want it's default value to be the current date-time but without time zone. The function now() returns a timezone as well.
How do I solve that problem?
SELECT now()::timestamp;
The cast converts the timestamptz returned by now() to the corresponding timestamp in your time zone - defined by the timezone setting of the session. That's also how the standard SQL function LOCALTIMESTAMP is implemented in Postgres.
If you don't operate in multiple time zones, that works just fine. Else switch to timestamptz for added_at. The difference?
Ignoring time zones altogether in Rails and PostgreSQL
BTW, this does exactly the same, just more noisy and expensive:
SELECT now() AT TIME ZONE current_setting('timezone');
Well you can do something like:
SELECT now() AT TIME ZONE current_setting('TimeZone');
SELECT now() AT TIME ZONE 'Europe/Paris';
SELECT now() AT TIME ZONE 'UTC';
Not sure how that makes any sense for a column "added_at". You almost always want an absolute timestamp (timestamp with time zone) not a floating one.
Edit responding to points below:
Yes, should use timestamp with time zone (absolute time) unless you have a good reason not to.
The client timezone is given by SHOW TimeZone or current_setting(...) as shown above.
Do take some time to skim the manuals - they cover all this quite well.
"Current Date/Time":
CURRENT_TIME and CURRENT_TIMESTAMP deliver values with time zone; LOCALTIME and LOCALTIMESTAMP deliver values without time zone.
New, and Native Answer in 2020
In PostgreSQL, If you only want the current date-time by calling CURRENT_TIMESTAMP() without time zone, and fractional digits in the seconds field which come after the decimal point of the seconds field?
(Tested on PostgreSQL v12.4)
Then use this:
SELECT CURRENT_TIMESTAMP(0)::TIMESTAMP WITHOUT TIME ZONE;
If you define your column's data type as timestamp (not as timestamptz), then you can store the timestamp without time zone, in that case you don't neet to add TIMESTAMP WITHOUT TIME ZONE
Like this:
CREATE TABLE foo (created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP(0))
In the above function, 0 is passed to get rid of the fractional digits in the seconds field.
If your application doesn't care about timezone, you can use SELECT LOCALTIMESTAMP for it.
Ex:
SELECT LOCALTIMESTAMP
-- Result: 2023-01-30 17:43:33.628952