2

I am working with dates relative to the database server.

In Oracle, to get the full timezone offset you would use something like the following:

select tz_offset(SESSIONTIMEZONE) from dual;

or

select tz_offset(DBTIMEZONE) from dual;

These would return, in my case (importantly it includes the sign)

-04:00

I was wondering what functionality exists in Postgres to get a result of the exact same format as the Oracle version above? I need to know the timezone offset of the server inclusive of the sign indicating it being behind or ahead of GMT/UTC.

xingyu
  • 312
  • 1
  • 3
  • 13

2 Answers2

4

For the time zone you can:

SHOW timezone;

or the equivalent:

SELECT current_setting('TIMEZONE');

but this can be in any format accepted by the server, so it may return UTC, 08:00, Australia/Victoria, or similar.

Frustratingly, there appears to be no built-in function to report the time offset from UTC the client is using in hours and minutes, which seems kind of insane to me. You can get the offset by comparing the current time in UTC to the current time locally:

SELECT age(current_timestamp AT TIME ZONE 'UTC', current_timestamp)`

... but IMO it's cleaner to extract the tz offset in seconds from the current_timestamp and convert to an interval:

SELECT to_char(extract(timezone from current_timestamp) * INTERVAL '1' second, 'FMHH24:MM');

That'll match the desired result except that it doesn't produce a leading zero, so -05:00 is just -5:00. Annoyingly it seems to be impossible to get to_char to produce a leading zero for hours, leaving me with the following ugly manual formatting:

CREATE OR REPLACE FUNCTION oracle_style_tz() RETURNS text AS $$
SELECT to_char(extract(timezone_hour FROM current_timestamp),'FM00')||':'||
       to_char(extract(timezone_minute FROM current_timestamp),'FM00');
$$ LANGUAGE 'SQL' STABLE;

Credit to Glenn for timezone_hour and timezone_minute instead of the hack I used earlier with extract(timezone from current_timestamp) * INTERVAL '1' second) and a CTE.

If you don't need the leading zero you can instead use:

CREATE OR REPLACE FUNCTION oracle_style_tz() RETURNS text AS $$
SELECT to_char(extract(timezone from current_timestamp) * INTERVAL '1' second, 'FMHH24:MM');
$$ LANGUAGE 'SQL' STABLE;

See also:

Community
  • 1
  • 1
Craig Ringer
  • 307,061
  • 76
  • 688
  • 778
1

The "to_char" formats the components, the trim gets rid of the "sign" character which is just a space for positive numbers.

select trim(to_char(extract(timezone_hour from now()), '00')) ||
       ':' ||
       trim(to_char(extract(timezone_minute from now()), '00')) AS tz

Take a look at the documentation for time functions.

Glenn
  • 8,932
  • 2
  • 41
  • 54