Convert To Another Timezone in Postgresql - sql

How do I convert the below code to another timezone using postgresql?
SELECT date_trunc('month', CURRENT_DATE);
The above code returns this output:
'2020-05-01 00:00:00'
I want to convert from the default timezone to 'PST'.

Is this what you are looking for?
select date_trunc('month', current_date) at time zone 'utc' at time zone 'pst'
Yields:
2020-05-01 08:00:00+01

The following is not specific to this question.
While Postgres supports timezone abbreviations (pst, ...) be cautious using them. They establish fixed offsets from UTC. That offset remains the same all time; they are not aware of day light saving changes. In most cases much better to use full timezone name, i.e 'America/Los_Angeles' instead. From Postgres Documentation
A time zone abbreviation, for example PST. Such a specification merely
defines a particular offset from UTC, in contrast to full time zone
names which can imply a set of daylight savings transition-date rules
as well. The recognized abbreviations are listed in the
pg_timezone_abbrevs view (see Section 51.91). You cannot set the
configuration parameters TimeZone or log_timezone to a time zone
abbreviation, but you can use abbreviations in date/time input values
and with the AT TIME ZONE operator.

Related

Add offset value to time in SQL Server

I felt like this should be easy but I'm not finding answer. The query below will give me the current date/time in California and represent it as UTC with a timezone offset (currently -08:00):
select getdate() at time zone 'Pacific Standard Time'
I simply want to apply the offset and get a timestamp showing the current local time and then drop the offset. I feel like there should be a way to achieve this without having to pick through it with string and date functions. For example, I want to go from
2021-11-24 18:03:41.190 -08:00
to
2021-11-24 10:03:41.190
Is there a succinct way to do this?
When you use AT TIME ZONE on a value that isn't a datetimeoffset it's assumed that the value is at the time zone you are converting it to.
Instead, therefore, you could nest the AT TIME ZONE clauses. If you did do this though, I would also suggest using SYSUTCDATE rather than GETDATE (which returns the local time to the host, which could be any timezone).
SELECT SYSUTCDATETIME() AT TIME ZONE 'UTC' AT TIME ZONE 'Pacific Standard Time';
Though really, just use SYSDATETIMEOFFSET to start with; then you just need one AT TIME ZONE as the RDBMS already knows what timezone the value is for.
SELECT SYSDATETIMEOFFSET() AT TIME ZONE 'Pacific Standard Time';
db<>fiddle
Declare #myDateTime datetime = '2021-11-24 21:35:25.984'; --UTC time
Select cast(#myDateTime At Time Zone 'UTC' At Time Zone 'Pacific Standard Time' As datetime);
Or - you can just apply the desired offset and convert back to datetime
Select cast(switchoffset(#myDateTime, '-08:00') As datetime)
The problem with using switchoffset is that it isn't DST aware and would need to be changed to use a different offset value. If you change the date above to October - the PST time would be 14:35:25.983 but the second calculation still returns 13:35:25.983

Postgres function to return datetime with time zone offset

Instead of always writing:
select my_column at time zone 'UTC' at time zone 'Europe/Paris' from my_table;
I would prefer doing:
select dtz(my_column, 'Europe/Paris') from my_table;
UTC is system-wide (server time zone), and could even be hardcoded in dtz().
Can someone share an efficient implementation of such a function?
Edit
select my_column at time zone 'UTC' at time zone 'Europe/Paris' from my_table;
Can be shortened a very very little bit like this:
select timezone('UTC', my_column) at time zone 'Europe/Paris' from my_table;
Its really dificult to see what you are having trouble with on this.
I don't believe the server timezone helps you here. As I understand it, it's the SQL client timezone than affects this.
You're not going to get a function more efficient than (IMMUTABLE):
RETURN arg1 AT TIME ZONE 'UTC' AT TIME ZONE arg2;
But this will always be less efficient than writing it inline in your SQL.
Ideally your timestamp should be TIMESTAMP WITH TIMEZONE instead of TIMESTAMP WITHOUT TIMEZONE since it's being used to store absolute timestamps not local timestamps. This would prevent the need for two conversions (into UTC and out of it). But that does mean you would need to add the AT TIME ZONE 'UTC' into your INSERT and UPDATE statements.

converting timestamp with time zone to localtime postgres

I having trouble figuring out how to convert the stored timestamp to whatever the local time zone so for example i have this query
SELECT INTO result string_agg(concat_ws(' - '
,sampleid
,starttime
,stoptime)
,'|')
FROM (
Select "ID" as sampleid,
to_char("StartTimestamp",'YYYY/MM/DD HH24:MI:SS') as starttime,
to_char("EndTimestamp",'YYYY/MM/DD HH24:MI:SS') as stoptime from "Samples" ORDER BY starttime DESC) res;
even though the "StartTimestamp" is of type timestamp with time zone I don't know how to convert it to local time zone that the system is in.
Use the AT TIME ZONE operator - or just set the TimeZone system variable.
thetimestamptz AT TIME ZONE 'Australia/Perth'
This works with UTC offsets too, but be aware that PostgreSQL uses the ISO-8601 standard for UTC offsets.
See Timezones in the PostgreSQL docs. Note in particular the paragraphs about timezone formats, and the paragraph:
Another issue to keep in mind is that in POSIX time zone names, positive offsets are used for locations west of Greenwich. Everywhere else, PostgreSQL follows the ISO-8601 convention that positive timezone offsets are east of Greenwich.

Insert time with timezone daylight savings

I would like to insert time data type in postgresql that includes the timezone and is aware of daylight savings time. This is what I have done:
CREATE TABLE mytable(
...
start_time time(0) with time zone,
end_time time(0) with time zone
)
INSERT INTO mytable(start_time, end_time)
VALUES(TIME '08:00:00 MST7MDT', TIME '18:00:00 MST7MDT')
I get the following error:
invalid input syntax for type time: "08:00:00 MST7MDT"
It works if I use 'MST' instead of 'MST7MDT', but I need it to be aware of DST. I also tried using 'America/Edmonton' as the timezone, but I got the same error.
What is the proper way to insert a time value (not timestamp) with timezone and DST?
EDIT:
I would actually like to use the 'America/Edmonton' syntax
The proper way is not to use time with time zone (note the space between time and zone) at all, since it is broken by design. It is in the SQL standard, so Postgres supports the type - but advises not to use it. More in this related answer:
Accounting for DST in Postgres, when selecting scheduled items
Since you are having problems with DST, timetz (short name) is a particularly bad choice. It is ill-equipped to deal with DST. It's impossible to tell whether 8:00:00 is in winter or summer time.
Use timestamp with time zone (timstamptz) instead. You can always discard the date part. Simply use start_time::time to get the local time from a timestamptz. Or use AT TIME ZONE to transpose to your time zone.
Generally, to take DST into account automatically, use a time zone name instead of a time zone abbreviation. More explanation in this related question & answer:
Time zone names with identical properties yield different result when applied to timestamp
In your particular case, you could probably use America/Los_Angeles (example with timestamptz):
INSERT INTO mytable(start_time, end_time)
VALUES
('1970-01-01 08:00:00 America/Los_Angeles'
, '1970-01-01 18:00:00 America/Los_Angeles')
I found this by checking:
SELECT * FROM pg_timezone_names
WHERE utc_offset = '-07:00'
AND is_dst;
Basics about time zone handling:
Ignoring time zones altogether in Rails and PostgreSQL
How about this?
INSERT INTO mytable(start_time, end_time)
VALUES('08:00:00'::time at time zone 'MST7MDT', '18:00:00'::time at time zone 'MST7MDT')

How to format "time with time zone" in Postgres?

I have a database field of type time with time zone. How can I query this field in EST5EDT time zone with the output format hh:mm:ss?
All I can find is using multiple calls to EXTRACT:
SELECT EXTRACT(HOUR FROM TIME WITH TIME ZONE '20:38:40-07' AT TIME ZONE 'EST5EDT');
[Edit:]
To be clear, this query:
SELECT TIME WITH TIME ZONE '20:38:40.001-07' AT TIME ZONE 'EST5EDT';
Returns "22:38:40.001" but I just want "22:38:40" as the output.
Use the TO_CHAR() function:
SELECT TO_CHAR(date '2001-09-28' +time, 'HH24:MI:SS')
Seeing that TO_CHAR only accepts the timestamp datatype, you need to concatentate an arbitrary date value to your time value.
"time with time zone" is basically a bogus datatype, and as such isn't really supported in a lot of cases.
How do you define "time with time zone"? Time zones are dependent on dates, which aren't included in the datatype, and thus it's not fully defined. (yes, it's mandatory by the SQL standard, but that doesn't make it sane)
You're probably best off first fixing what datatype you're using. Either use timestamp with time zone, or use time (without time zone).
You can simply use CAST and CAST to the time type:
SELECT CAST(now() AS TIME)
(Of course, the result will have a different data type)