I want to get the current timezone name.
What I already achieved is to get the utc_offset / the timezone abbreviation via:
SELECT * FROM pg_timezone_names WHERE abbrev = current_setting('TIMEZONE')
This gives me all Continent / Capital combinations for this timezone but not the exact timezone. For example I get:
Europe/Amsterdam
Europe/Berlin
The server is in Berlin and I want to get the timezone name of the server.
The problem I have with CET that it is always UTC+01:00 and does not account for DST iirc.
I don't think this is possible using PostgreSQL alone in the most general case. When you install PostgreSQL, you pick a time zone. I'm pretty sure the default is to use the operating system's timezone. That will usually be reflected in postgresql.conf as the value of the parameter "timezone". But the value ends up as "localtime". You can see this setting with the SQL statement.
show timezone;
But if you change the timezone in postgresql.conf to something like "Europe/Berlin", then show timezone; will return that value instead of "localtime".
So I think your solution will involve setting "timezone" in postgresql.conf to an explicit value rather than the default "localtime".
It seems to work fine in Postgresql 9.5:
SELECT current_setting('TIMEZONE');
This may or may not help you address your problem, OP, but to get the timezone of the current server relative to UTC (UT1, technically), do:
SELECT EXTRACT(TIMEZONE FROM now())/3600.0;
The above works by extracting the UT1-relative offset in minutes, and then converting it to hours using the factor of 3600 secs/hour.
Example:
SET SESSION timezone TO 'Asia/Kabul';
SELECT EXTRACT(TIMEZONE FROM now())/3600.0;
-- output: 4.5 (as of the writing of this post)
(docs).
You can access the timezone by the following script:
SELECT * FROM pg_timezone_names WHERE name = current_setting('TIMEZONE');
current_setting('TIMEZONE') will give you Continent / Capital information of settings
pg_timezone_names The view pg_timezone_names provides a list of time zone names that are
recognized by SET TIMEZONE, along with their associated abbreviations, UTC offsets, and
daylight-savings status.
name column in a view (pg_timezone_names) is time zone name.
output will be :
name- Europe/Berlin,
abbrev - CET,
utc_offset- 01:00:00,
is_dst- false
See this answer: Source
If timezone is not specified in postgresql.conf or as a server command-line option, the server attempts to use the value of the TZ environment variable as the default time zone. If TZ is not defined or is not any of the time zone names known to PostgreSQL, the server attempts to determine the operating system's default time zone by checking the behavior of the C library function localtime(). The default time zone is selected as the closest match among PostgreSQL's known time zones. (These rules are also used to choose the default value of log_timezone, if not specified.) source
This means that if you do not define a timezone, the server attempts to determine the operating system's default time zone by checking the behavior of the C library function localtime().
If timezone is not specified in postgresql.conf or as a server command-line option, the server attempts to use the value of the TZ environment variable as the default time zone.
It seems to have the System's timezone to be set is possible indeed.
Get the OS local time zone from the shell. In psql:
=> \! date +%Z
Related
Does anyone know what this actually does?
There appears to be two different timezones, a Session timezone and a Database time zone. The former is clear, it causes timezones with timestamp to be converted from a text representation in psql to UTC.
But what does the Database time zone do?
It can be changed with
ALTER DATABASE database_name SET TIMEZONE='zone';
Is Database Timezone just some sort of default for the Session Timezone? Or does it affect how timestamps are stored? My understanding is that the psql session timezone defaults to the client computer timezone.
There is also the question of the 99.9% of usages that do not use psql. Say JDBC. When and how are offsets added. But that is not this question.
Timezones are tricky, and never well documented.
This is covered in the documentation. In particular:
For timestamp with time zone, the internally stored value is
always in UTC […].
Admittedly mentioning UTC is a bit misleading, I'd prefer to say that a timestamptz represents an instant, an exact fixed point in time, without regard to calendar or location (timezone). It's just an offset since an epoch. Very much like a Date in Java or JavaScript, or better: like an Instant (Java, JavaScript).
[For literal timestamptz values, if] no time zone is stated in the
input string, then it is assumed to be in the time zone indicated by
the system's TimeZone
parameter,
and is converted to UTC using the offset for the timezone zone.
When a timestamp with time zone value is output, it is always
converted from UTC to the current timezone zone, and displayed as
local time in that zone.
The TimeZone configuration
parameter
can be set in the file postgresql.conf, or in any of the other
standard ways described in Chapter
20.
TimeZone (string):
Sets the time zone for displaying and interpreting time stamps. The
built-in default is GMT, but that is typically overridden in
postgresql.conf; initdb will install a setting there corresponding
to its system environment.
So the timezone setting affects conversions of timestamps from and to text, both via casting and the via to_char/to_timestamp function calls, in SQL execution.
It does not affect storage.
Looking at chapter 20, in particular Setting Parameters, shows that there are many more than just two places to set the timezone configuration variable.
The most fundamental way to set these parameters is to edit the file postgresql.conf. […]
Parameters set in this way provide default values for the cluster. The
settings seen by active sessions will be these values unless they are
overridden. The following sections describe ways in which the
administrator or user can override these defaults.
[The file postgresql.auto.conf] is intended to be edited
automatically, not manually. This file holds settings provided through
the ALTER SYSTEM
command.
[…] Settings in postgresql.auto.conf override those in
postgresql.conf.
[T]here are two commands that allow setting of defaults on a
per-database or per-role basis:
The ALTER DATABASE command
allows global settings to be overridden on a per-database basis.
The ALTER ROLE command
allows both global and per-database settings to be overridden with
user-specific values.
Values set with ALTER DATABASE and ALTER ROLE are applied only when
starting a fresh database session. They override values obtained from
the configuration files or server command line, and constitute
defaults for the rest of the session.
Once a client is connected to the database, PostgreSQL provides […]
SQL commands […] to interact with session-local configuration
settings:
The SET command allows
modification of the current value of those parameters that can be set
locally to a session; it has no effect on other sessions.
The documentation of the SET command details how this may be limited to the current session, the current transaction, or the currently executing function.
A client would have to explicitly set this to use the client computer's system timezone for the session. JDBC does this, for example.
(another post answering exactly the questions from the OP, taken from the comments of my other answer)
What does the Database time zone do?
It's a configuration setting that is applied when starting a fresh session (connection), overrides the server defaults, and constitutes the default for the rest of the session.
Is Database Timezone just some sort of default for the Session Timezone?"
Yes.
Or does it affect how timestamps are stored?
No. timestamp with timezone represents an instant, a fixed point in time, without regard to calendar or location (timezone). It's just an offset since an epoch.
My understanding is that the psql session timezone defaults to the client computer timezone.
No: only when your client explicitly sets it - like JDBC does.
What happens for JDBC, for cols timestamptz, values Date vs String?
I've not used it myself and don't know how it does conversion of raw serialisation to java objects. But I would presume that when you query timestamptz as a Date, the timezone setting doesn't matter. When you query timestamptz as a String, the timezone would apply ("When a timestamp with time zone value is output, it is always converted from UTC to the current timezone zone, and displayed as local time in that zone.").
When you query timestamp as a String, it would not apply. And you shouldn't query a timestamp as a Date (JDBC might assume UTC? Postgres does not!)
How do you show the current Database Timezone?
See How do you view the configuration settings of a PostgreSQL database? or Query for all the Postgres configuration parameters‘ current values?
Manual ALTER DATABASE part.
The remaining forms change the session default for a run-time
configuration variable for a PostgreSQL database. Whenever a new
session is subsequently started in that database, the specified value
becomes the session default value. The database-specific default
overrides whatever setting is present in postgresql.conf or has been
received from the postgres command line. Only the database owner or a
superuser can change the session defaults for a database. Certain
variables cannot be set this way, or can only be set by a superuser.
meaning if the new connection not explicitly override the value, then the new value will become session default.
Like ALTER DATABASE test15 SET TIMEZONE='Singapore'; if you are still in session, you will still have the previous timezone value, if you quit the session, reenter agagin, then the new TIMEZONE is Singapore.
SELECT
name,
category,
short_desc,
extra_desc,
context
FROM
pg_settings
WHERE
name = 'TimeZone' gx
return.
-[ RECORD 1 ]---------------------------------------------------------------
name | TimeZone
category | Client Connection Defaults / Locale and Formatting
short_desc | Sets the time zone for displaying and interpreting time stamps.
extra_desc |
context | user
The context is user level, which means any connection can use set command change it.
So when query the interval value like timestamptz column > now(). the return values will become different for connections in differenent timezone.
psql session timezone defaults to the client computer timezone.
if you not explicitly set it, the default will be database level timezone parameter value.
There is also the question of the 99.9% of usages that do not use
psql. Say JDBC. When and how are offsets added. But that is not this
question.
psql is same as JDBC, both are client. they can change timezone use set command, if the connection is superuser or owner, then they can change database default, which means other connection will follow the new default.
However each connection can still use set command to change the timezone paramter.
does it affect how timestamps are stored?
If your timestamp from string literal,then no. if your timezone from timestamptz then yes. First query result is the same, second is not.
begin;
set time zone 'Singapore';
select '2022-01-01 11:30'::timestamp;
reset time zone;
select '2022-01-01 11:30'::timestamp;
commit;
begin;
set time zone 'Singapore';
select now()::timestamp;
reset time zone; --default not 'Singapore'
select now()::timestamp;
commit;
Why
Select timestamptz '2022-03-19T00:00Z' as test1
give result : 2022-03-19 03:00:00+03 ??
You're indicating Postgresql a timestamptz at UTC time.
There, it's returning a strictly equivalent time, except it is displayed in a different time zone (UTC-03).
Why does Postgresql not return the exact same thing you indicated ?
When parsing a timestamp with time zone, Postgresql internally stores it in UTC time, using the provided TZ info (here 'Z, understood as Z00, which means UTC time) to determine the offset to apply to convert it (here, you're giving a perfectly fine UTC timestamp).
When displaying data however, Postgresql relies on the internal TimeZone info defined in the postgresql.conf file to choose the time zone to use.
In your case, the local time zone info might be set to the place you live (or where your server lies), which is in UTC-03. Just type show time zone to be sure of that.
If you want to retrieve the data at timezone UTC, you have two or three options:
the simplest one is to precise the timezone info you want in the select statement:
select timestamptz '2022-03-19T00:00Z' at time zone 'UTC' as test1;
which gives you a timestamp without timezone though;
or you can set the time zone info for your local session:
set timezone='UTC';
or if you want to set the time zone info to UTC permanently, the timezone field of the postgresql.conf file has to be changed.
This file is for instance in /opt/homebrew/var/postgres if you're running a local instance of postgresql on Mac (like me), installed from brew. On Linux, I believe it might be in /etc/postgresql.
You need to restart your postgresql instance after the change:
brew services restart postgresql on Mac for example.
PostgreSQL 9.3 / postgresql-9.3-1100-jdbc41.jar
I have a table with a column of type timestamp without time zone, this generates my Object with the applicable java.util.Timestamp property.
What I'm seeing, during insert, is jOOQ's binding process converting a java.util.Timestamp into a date with local timezone offset.
eg for a unix timestamp 1421109419 (13 Jan 2015 00:36:59 GMT) the property is set with new Timestamp(1421109419 * 1000).
from the jOOQ logger I see:
2015-01-13 14:14:31,482 DEBUG [http-bio-8002-exec-4] org.jooq.tools.LoggerListener#debug:255 - -> with bind values : insert into "foo"."bar" ("start_date") values (timestamp '2015-01-13 13:36:59.0') returning "foo"."bar"."id"
2015-01-13 14:14:31,483 TRACE [http-bio-8002-exec-4] org.jooq.impl.DefaultBinding#trace:179 - Binding variable 3 : 2015-01-13 13:36:59.0 (class java.sql.Timestamp)
and sure enough in the record is the value "2015-01-13 13:36:59".
The software is running on a machine in NZDT which explains the +13 offset.
Given the time is being supplied in a TimeZone agnostic container (Timestamp) I would have expected that to be honoured when creating the insert statement.
How can I have jOOQ create timestamps NOT in local time?
Unfortunately you have a few things working against you:
The PostgreSQL JDBC driver sets the timezone to your JVM timezone in the Postgres session. So even if your Database Server is running in UTC a TIMESTAMP field will be inserted using the time zone of your JVM. When you insert or query data the database server will always use the JVM time zone.
You are using TIMESTAMP instead of TIMESTAMPTZ. The description of these types do not reflect their actually usage. TIMESTAMPTZ actually means time zone agnostic. Whatever value you insert it will be adjusted to UTC using the session timezone.
Because of these two issues, if you have two different JVMs -- one using Los Angeles time and the other using New York time -- whenever you write a TIMESTAMP with one JVM it will be a different "UTC time" in the other JVM. TIMESTAMP takes the adjusted value and just uses it as given. If you change your TIMESTAMP columns to be TIMESTAMPTZ then the same time in both JVMs will always be the same UTC time.
If you look at the Postgres JDBC Driver's ConnectionFactoryImpl#openConnectionImp you can see where it sets your local JVM's time zone as the time zone for the database server's session zone.
So the only sane way to deal with this is to only ever use TIMESTAMPTZ instead of TIMESTAMP. Here's some more information on this:
PostgreSQL/JDBC and TIMESTAMP vs. TIMESTAMPTZ
http://justatheory.com/computers/databases/postgresql/use-timestamptz.html
The following (very nasty) code works for me:
eventsRecord.setCreatedOn(new Timestamp(System.currentTimeMillis()
- TimeZone.getDefault().getOffset(new Date().getTime())));
Alas jOOQ simply uses the local timezone when saving into PostgreSQL "timestamp without timezone" or MySQL "datetime" fields. The source code evidence for this travesty is here, it does not specify the timezone nor have any facility for the user to override this functionality and specify a timezone. This renders usage of this very basic datatype from jOOQ completely useless, with a multitude of clients all with different timezones writing data to the same field without recording their timezone nor normalizing the data to UTC.
JDBC provides an extra three-argument setTimestamp where the user can specify what timezone is desired (UTC is basically the only value that makes sense). However jOOQ "abstracts" away from JDBC and does not offer this facility.
I have two data base in two differents machines with the same schemas, tables and data. I launch this query:
select mydate from mytable where date = '2013-10-03 14:25:00-07'::timestamp::date
the first machine return the correct rows and the second one doesn´t, both machines has the same prostgres version (9.2)
the only different between the machines is that first one works on windows and the second one on Linux (Centos)
Any suggestion?
'2013-10-03' can be interpreted as Oct, 3rd or March, 10th, depending on your datestyle setting. #Chris has more on that.
In addition to that, your query is generally incorrect. This expression is misleading:
'2013-10-03 14:25:00-07'::timestamp
timestamp in Postgres defaults to timestamp without time zone, which doesn't recognize time zone offsets. Therefore, the time zone offset -07 is discarded.
Use instead:
'2013-10-03 14:25:00-07'::timestamptz
Match the point in time:
SELECT * FROM mytable
WHERE mydate = '2013-10-03 14:25:00-07'::timestamptz
Does not depend on your local time zone setting, since the data type of the column is timestamp with time zone as you clarified in a later comment.
Match the day:
...
WHERE mydate::date = '2013-10-03 14:25:00-07'::timestamptz::date
Depends on your local time zone setting, which defines lower and upper borders of the "day".
Detailed explanation in this related answer:
Ignoring timezones altogether in Rails and PostgreSQL
The cleanest solution would be to, at the beginning of the session, just issue the following command:
SET datestyle = "ISO, YMD";
This will ensure properly handling the timestamp according to your input format.
I think one of the two scourges of IT are timestamps and time zones (the other being character encoding) where one keeps stumbling upon again and again...
In that regard I currently have a problem related to different timestamps within a Java application storing into a PostgreSQL database.
For keeping things simple, assume having the following table:
CREATE TABLE ts_test
(
id integer NOT NULL,
utc timestamp without time zone,
local timestamp with time zone,
CONSTRAINT pk PRIMARY KEY (id)
)
So, I have to store a UTC time stamp and a local one, which in my case is central Europe summer time, so currently UTC+2.
Further assume having 2 entries in the table, which output on the psql console as follows (the database runs in UTC):
# select id, utc, local, local-utc as diff from ts_test;
id | utc | local | diff
----+---------------------+------------------------+----------
1 | 2012-06-27 12:00:00 | 2012-06-27 12:00:00+00 | 00:00:00
2 | 2012-06-27 12:00:00 | 2012-06-27 14:00:00+00 | 02:00:00
(2 rows)
Now, several questions arise:
What exactly does the output in the local column mean?
How does the system know the timezone, I inserted the value in?
How can I see the real raw value (e.g. milliseconds) stored?
I would have assumed, that the first line's local "12:00:00+00" means, that it's 12:00 in UTC, which again is 14:00 in CEST. But it seems (and so I was told by our database admin), that the 2nd line's local "14:00:00+00" is the correct value for 14:00 CEST - which is supported by the diff of 2 hours.
But to produce the 2nd line via sql insert, I have to write
insert into ts_test (id, utc, local) values (2, '2012-06-27 12:00:00', '2012-06-27 16:00:00+02');
which again does not support the predication.
So, to sum up this long question - can anyone enlighten me on how this whole thing works in detail, what the output is supposed to mean and how one should write local time stamps correctly into the database?
According to the output of the local column, the time zone of your SQL session is set to UTC or GMT and not the time zone where you live in. Presumably this is what you mean by: the database runs in UTC. This is the root of the problem, but let's try to elaborate.
The db itself, as a data repository, doesn't have a timezone, but each SQL session has its own timezone.
When they're requested by a SQL session, the values of timestamp without time zone are not rotated to the session's time zone and not presented with a time offset, whereas the values for timestamp with time zone are rotated to the session's timezone and presented with the time offset for this time zone. That's the difference between both.
The time zone is never stored in any of the datatypes, because when reading the value, all that matters is the time zone of the SQL session that is requesting this value.
Setting your SQL time zone to UTC is not a good idea because it contradicts this other part of your question:
So, I have to store a UTC time stamp and a local one, which in my case
is central Europe summer time, so currently UTC+2
Let the SQL session know your real time zone, and it will start to work as intended. If you don't, timestamp with time zone is essentially useless.
Also note that storing the same time in utc timestamp without time zone and local timestamp with time zone doesn't make sense, because you could always get the utc with:
SELECT local AT TIME ZONE 'UTC' FROM ts_test WHERE...
EDIT: answers to questions in the comments:
Q: you are saying that if my timezone is set to my local time in the
session, then I should see for example ...14:00:00+02 in local for a
utc value of ...12:00:00
Yes.
Q: And when writing something into the local field from my application,
it matters which timezone is set there?
Exactly.
Q: How does one set this in JDBS-session?
I don't know JDBC but at the SQL level, that would be for example:
SET timezone='Europe/Berlin';
Normally it's automatically set from the environment but it can be forced at various levels including postgresql.conf. Setting it explicitly in the session will override anything else.
Q: can I see the raw value of the timestamp somehow, to make sure it's
not just a representation problem when displaying
I'm not aware of how to do that except with pageinspect which operates at the lower level.