Postgresql Create Table Fieldname Timestamp with Time Zone UTC - postgresql

What is the syntax for creating a table with a field with the UTC time zone?
I have for the fields:
(id INT PRIMARY KEY NOT NULL,
bravo timestamp without time zone DEFAULT now(),
charlie timestamp with time zone UTC DEFAULT now()
)
This last field named charlie is not taking for some reason. I was hoping it was easy as just telling it had a time zone, then shoving UTC in there, and having the db figure out now() during input.

I think you want this:
charlie timestamp without time zone NOT NULL
DEFAULT (current_timestamp AT TIME ZONE 'UTC')

Related

Postgres: grouping by date for a specific time zone

Let us say we have a Postgres table:
CREATE TABLE public.observations (
id integer NOT NULL,
utc_created_at timestamp without time zone NOT NULL
)
If we are interested in counting the observations made at a specific UTC date, we could:
SELECT COUNT(observations.id),
DATE(utc_created_at) AS date_utc_created_at
GROUP BY DATE(date_utc_created_at);
But now let us say that I would like to group observations by Pacific Standard Time dates. Is there a way without altering the schema ?
If there is no way and I have now instead:
CREATE TABLE public.observations (
id integer NOT NULL,
utc_created_at timestamp with time zone NOT NULL
)
can I make the described query ?
Would the given solution also work with EXTRACT to say group by Pacific Standard Time year/month ?
Since the timestamp is a timestamp without time zone in UTC, you need to:
Tell Postgres what time zone to interpret the time stamp in
Tell Postgres what time zone you want it in.
After having done that, you can reliably and reproducibly convert to a string in whatever format desired.
To see what I mean, try running:
select
utc_created_at as original_timestamp
--correct conversion to PST
, (utc_created_at at time zone'Z') at time zone 'PST' as timestamp_in_pst
, date( (utc_created_at at time zone'Z') at time zone 'PST' ) as date_from_pst
--will correctly convert it to a timestamp with timezone, but Postgres will consider your session timezone in conversions
, utc_created_at at time zone'Z' as timestamp_with_timezone_displayed_in_session_time_zone
, date(utc_created_at at time zone'Z') as date_depends_on_session
--incorrect, will interpret it as if the original timestamp is in PST
, utc_created_at at time zone'PST' as timestamp_considered_with_PST_incorrect
, date( utc_created_at at time zone 'PST') as incorrect_date
from public.observations
You know that, for example, if it's 00:01 on Jan 1 UTC, it should actually be December 31 of the previous year in PST, which you can see in this fiddle: http://sqlfiddle.com/#!17/e6d3c/10

postgresql `at time zone` incorrect behaviour?

I have a simple postgresql table with the following data:
create table ti (
l text,
t timestamp without time zone
);
insert into ti(l, t) values ('now', now());
I do a select using at time zone, I expect UTC + 5.30 hours
select now(), t, t at time zone 'Asia/Kolkata' from ti;
But this is what I get:
now| t| timezone
2019-06-06T12:11:42.576388Z| 2019-06-06T11:50:48.178689Z| 2019-06-06T06:20:48.178689Z
It subtracted 5.30 hours instead of adding them.
Sqlfiddle here
now() returns a timestamp with time zone. The time zone info will be stripped off when it is cast to a timestamp without time zone when it is saved in your table, but the actual value saved in there will depend on the session time zone.
You can see this behavior pretty easily:
postgres=# begin;
BEGIN
postgres=# set time zone utc;
SET
postgres=# insert into test select now();
INSERT 0 1
postgres=# set time zone 'US/Eastern';
SET
postgres=# insert into test select now();
INSERT 0 1
postgres=# select * from test;
a
----------------------------
2019-06-06 12:46:10.475424
2019-06-06 08:46:10.475424
(2 rows)
A little more explanation after your comment. I think the issue you are having is with converting between timestamp and timestamptz. Timestamps are much less confusing if you stick with just timestamptz. Let's remove now() from the discussion, since that adds an additional layer of complexity because converting from the result of now() to a timestamp without time zone depends on the session time zone.
select '2019-06-06 12:00:00UTC'::timestamp with time zone,
('2019-06-06 12:00:00UTC'::timestamp with time zone) at time zone 'Asia/Kolkata';
timestamptz | timezone
------------------------+---------------------
2019-06-06 12:00:00+00 | 2019-06-06 17:30:00
I believe this is what you expect? We convert from a timestamp with time zone to a timestamp without time zone at a specific time zone.
What you are doing is similar to this, though:
select '2019-06-06 12:00:00UTC'::timestamp with time zone,
(('2019-06-06 12:00:00UTC'::timestamp with time zone)::timestamp without time zone) at time zone 'Asia/Kolkata';
timestamptz | timezone
------------------------+------------------------
2019-06-06 12:00:00+00 | 2019-06-06 06:30:00+00
(1 row)
I think you will find this much less confusing if you can store timestamp with time zone instead of timestamp without time zone.

Date and time as UTC timestamp in Postgres

I have date and time fields in my table. Both are set in local server time.
Is it possible to cast both fields as a single UTC ISO timestamp?
Just add the two:
SELECT date_col + time_col AS timestamp_col
The type timestamp [without time zone] is stored as UTC timestamp internally anyway. Only the display is adjusted to the time zone setting of your session. If you need to display the timestamp as UTC timestamp, use the AT TIME ZONE construct:
SELECT timestamp_col AT TIME ZONE 'UTC';
Note that this returns a timestamp with time zone when applied to a timestamp.
Ample details:
Ignoring timezones altogether in Rails and PostgreSQL
For example, to display the timestamp as timestamptz in Moscow:
SELECT (date_col + time_col) AT TIME ZONE 'Europe/Moscow' AS tstz_col

Using current time in UTC as default value in PostgreSQL

I have a column of the TIMESTAMP WITHOUT TIME ZONE type and would like to have that default to the current time in UTC. Getting the current time in UTC is easy:
postgres=# select now() at time zone 'utc';
timezone
----------------------------
2013-05-17 12:52:51.337466
(1 row)
As is using the current timestamp for a column:
postgres=# create temporary table test(id int, ts timestamp without time zone default current_timestamp);
CREATE TABLE
postgres=# insert into test values (1) returning ts;
ts
----------------------------
2013-05-17 14:54:33.072725
(1 row)
But that uses local time. Trying to force that to UTC results in a syntax error:
postgres=# create temporary table test(id int, ts timestamp without time zone default now() at time zone 'utc');
ERROR: syntax error at or near "at"
LINE 1: ...int, ts timestamp without time zone default now() at time zo...
A function is not even needed. Just put parentheses around the default expression:
create temporary table test(
id int,
ts timestamp without time zone default (now() at time zone 'utc')
);
Still another solution:
timezone('utc', now())
Wrap it in a function:
create function now_utc() returns timestamp as $$
select now() at time zone 'utc';
$$ language sql;
create temporary table test(
id int,
ts timestamp without time zone default now_utc()
);
What about
now()::timestamp
If your other timestamp are without time zone then this cast will yield the matching type "timestamp without time zone" for the current time.
I would like to read what others think about that option, though. I still don't trust in my understanding of this "with/without" time zone stuff.
EDIT:
Adding Michael Ekoka's comment here because it clarifies an important point:
Caveat. The question is about generating default timestamp in UTC for
a timestamp column that happens to not store the time zone (perhaps
because there's no need to store the time zone if you know that all
your timestamps share the same). What your solution does is to
generate a local timestamp (which for most people will not necessarily
be set to UTC) and store it as a naive timestamp (one that does not
specify its time zone).
These are 2 equivalent solutions:
(in the following code, you should substitute 'UTC' for zone and now() for timestamp)
timestamp AT TIME ZONE zone - SQL-standard-conforming
timezone(zone, timestamp) - arguably more readable
The function timezone(zone, timestamp) is equivalent to the SQL-conforming construct timestamp AT TIME ZONE zone.
Explanation:
zone can be specified either as a text string (e.g., 'UTC') or as an interval (e.g., INTERVAL '-08:00') - here is a list of all available time zones
timestamp can be any value of type timestamp
now() returns a value of type timestamp (just what we need) with your database's default time zone attached (e.g. 2018-11-11T12:07:22.3+05:00).
timezone('UTC', now()) turns our current time (of type timestamp with time zone) into the timezonless equivalent in UTC.
E.g., SELECT timestamp with time zone '2020-03-16 15:00:00-05' AT TIME ZONE 'UTC' will return 2020-03-16T20:00:00Z.
Docs: timezone()
Function already exists:
timezone('UTC'::text, now())

PostgreSQL: Aliases for "timestamp with time zone" and "at time zone"

I happen to have tables with timestamp without time zone column in my database. Now I need to compare them with respect to time zone.
I can do it like:
select my_timestamp::timestamp with time zone at time zone 'EST5EDT'
from my_table
where
my_timestamp >= '2010-07-01'::timestamp at time zone 'EST5EDT'
and my_timestamp < '2010-08-01'::timestamp at time zone 'EST5EDT'
This is getting pretty ugly. Is there a shorter way that does not require me to type timestamp with time zone as type and at time zone as conversion?
timestamptz is an alias for timestamp with time zone, timestamp is an alias for timestamp without time zone.
I don't think at time zone has an alias.