1

I have an api that is returning timezones like "Pacific Standard Time".

I want to use that format in AT TIME ZONE. When I try

SELECT '2020-11-01T18:46:00'::timestamptz AT TIME ZONE 'Pacific Standard Time'

I get ERROR: time zone "Pacific Standard Time" not recognized

I need "Pacific Standard Time" to look like "US/Pacific" or "America/Los_Angeles"

I have seen the pg_timezone_names table built into Postgres but I cannot find 'Pacific Stanard Time' in them. Any advice on converting this into a type that can be used with Postgres?

BigBoy1337
  • 4,735
  • 16
  • 70
  • 138
  • What environment are you calling postgres from? – Matt Johnson-Pint Dec 04 '20 at 17:15
  • Its installed on ubuntu. Im not sure what you mean exactly @MattJohnson-Pint – BigBoy1337 Dec 04 '20 at 17:16
  • In many cases a database is called from an application layer, such as .NET or Python or Node.js, etc. – Matt Johnson-Pint Dec 04 '20 at 17:17
  • This is me just running sql directly on pgAdmin4 – BigBoy1337 Dec 04 '20 at 17:18
  • Where do your input values originate from then? Is "Pacific Standard Time" example you gave coming from somewhere else, such as a Windows time zone identifier? Or is it just a display value for an end user, or ad-hoc anything? – Matt Johnson-Pint Dec 04 '20 at 17:19
  • @MattJohnson-Pint It comes from an api listing invoices. For each invoice, there a field returned from the api that looks like "TimeZone": { "Id": "Pacific Standard Time", "DaylightSavingTimeEnabled": true }. I convert that in sql to "Pacific Standard Time" and then am using that now to convert the timestamp – BigBoy1337 Dec 04 '20 at 17:21
  • Hmmm... It would help to know more about the API. Can you be more specific? Is it public, and if so is there documentation you can point at? If not public, can you check with the author to see how they generate those values? If they are indeed Windows time zones, then you can refer to my answer [here](https://stackoverflow.com/questions/17348807/how-to-translate-between-windows-and-iana-time-zones), but that assumes you are either able to use .NET or consume the CLDR translation XML file manually. – Matt Johnson-Pint Dec 04 '20 at 17:23
  • Its not public. I checked with the author and they said thats just the way those values are returned. I was hoping to convert them in the database - the information is there but its just not the right format. – BigBoy1337 Dec 04 '20 at 17:24
  • 1
    Can you edit your question to provide a few more example? Or better yet, compare them to the [CLDR `windowsZones.xml` translation file](https://github.com/unicode-org/cldr/blob/master/common/supplemental/windowsZones.xml). Are all of your values exact strings as in the "other" field in that file? Do any deviate? – Matt Johnson-Pint Dec 04 '20 at 17:29
  • @MattJohnson-Pint None deviate right now. I think they might in the future. In that file, I would say its . Are you suggesting I import this file somehow into Postgres? – BigBoy1337 Dec 04 '20 at 17:35
  • Yes. I will add an answer below shortly. Thanks. – Matt Johnson-Pint Dec 04 '20 at 17:38
  • What version of Postgres are you using? – Matt Johnson-Pint Dec 04 '20 at 17:41
  • version 11 I believe – BigBoy1337 Dec 04 '20 at 17:50

2 Answers2

3

Per our discussion in the question chat, let's assume your input values are all Windows time zone identifiers.

The source of truth for conversion between Windows and IANA identifiers is the windowsZones.xml file, part of the Unicode CLDR project.

You can parse the necessary data from this file using the xml features of Postgres, such as xmlparse and xmltable.

CREATE TABLE zone_mapping AS
SELECT xmltable.*
FROM XMLPARSE (DOCUMENT '...put xml here...')
AS data,
xmltable('//mapZone[@territory = ''001'']'
  PASSING data
  COLUMNS
    windows_zone varchar PATH '@other' not null,
    iana_zone varchar PATH '@type' not null
);

You can then query it, or join to it in your own queries, etc.

select * from zone_mapping;

Results will include the value you're looking for:

windows_zone              iana_zone
-----------------------------------------------
...
Pacific Standard Time     America/Los_Angeles
...

Working fiddle here (click Run at top).

Note that by filtering to the "001" territory (called the "Golden Zone"), the mapping table will work in the Windows to IANA direction only. If you need to go the other direction, then it's much more complex because not only do you have to take the other entries into consideration, but you also have to expand to all IANA aliases (links) using other data sources.

Also note when you paste your xml in, you'll need to replace any ' characters with '' for the query. There is only one in the file presently.

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
1

To help in cases like this I have written a Postgresql function that uses windowsZones.xml as a source of data as advised by Matt Johnson-Pint above. It converts between Windows and IANA time zone names and has this function prototype:

FUNCTION timezone_names(windows_tz text DEFAULT NULL, iana_tz text DEFAULT NULL, territory text DEFAULT NULL)
RETURNS TABLE(windows_timezone text, liana_timezone text, territory_abbrev text)

Examples:

-- List of all Windows and IANA time zones and territory codes (as to store in a table)
select * from timezone_names();

-- Data for Bulgaria by IANA time zone name
select * from timezone_names(iana_tz => 'Europe/Sofia');

-- Data for Bulgaria by Windows time zone name and territory
select * from timezone_names(windows_tz => 'FLE Standard Time', territory => 'BG');

In order to force a single-line result for a Windows or IANA time zone name supply
territory => '001' as an argument.

  • The function is a bit too long to be put in the answer. It can be found here.
  • In case when time zones change (the EU is about to make such a change sometime soon) the XML document must be extracted again, single quotes doubled and then replaced in the function body (lines 6 - 800).
Stefanov.sm
  • 11,215
  • 2
  • 21
  • 21
  • 1
    Hi. Unfortunately you are conflating a time zone with an offset. They are two different things. A time zone can have *multiple* offsets. The offset that appears next to a Windows display name (from `tzutil`) is the standard offset - which is not necessarily the offset in effect at a particular time. Please read "Time Zone != Offset" in [the timezone tag wiki](https://stackoverflow.com/tags/timezone/info). Thanks. – Matt Johnson-Pint Dec 04 '20 at 21:54
  • 1
    As a clear example, Pacific Time is represented by the Windows time zone ID `"Pacific Standard Time"` which in English has a display name of `"(UTC-08:00) Pacific Time (US & Canada)"`. That time zone is UTC-8 when standard time is in effect, and UTC-7 when daylight time is in effect. Despite the word "standard" in the name, the entry represents the entirety of the time zone. The same goes for the IANA time zone `America/Los_Angeles`, which is the form that Postgres expects with its `AT TIME ZONE` functionality. – Matt Johnson-Pint Dec 04 '20 at 21:57
  • Thanks, Matt. I am curious could it be that Windows' `tzutil` will list different offset values in he summer? – Stefanov.sm Dec 04 '20 at 23:07
  • Nope, the offset is part of the display name string. The string always shows the *standard time* offset, not necessarily the one that is in effect. They only change if Microsoft issues an update in response to changes made by a government. – Matt Johnson-Pint Dec 05 '20 at 00:16
  • @MattJohnsonPint, this was an eye opener. If you find [this](https://github.com/stefanov-sm/Time-zone-names) of use then I will be glad. – Stefanov.sm Dec 06 '20 at 18:40
  • Yes! That's great! You should edit your question to describe and link to that one instead, and I will upvote. :) – Matt Johnson-Pint Dec 07 '20 at 17:33