10

We are having a debate about the best way to store a timestamp in postgres. Currently all time stamps are stored as +00 and we have a timezone associated with each client. We look up the timezone and convert the time that something happened which increases complexity as we need to do more joins and a more complex query.

Another method is connecting to Postgres and setting the timezone of the connection and it changes all the times to be that timezone.

My problem with this is that in ANZ there are 4-5 timezones. When we try and do our invoices we need to know what day certain transactions happened, and across three timezones there is no perfect solution.

I was thinking of including the timezone in the timestamp to make it easier - TIMESTAMP '1999-01-15 8:00:00 -8:00'

I was under the impression that this was best practice, but some people say this is a bad idea. We will have customers across ANZ that we need to do accurate invoices for, what is the best solution and most elegant?

Cheers Scott

4

2 に答える 2

16

ここには防弾ソリューションはありません。

私の最初のアドバイスは、サーバーのデフォルトのタイムゾーンに決して依存しないことです。

私の 2 番目のアドバイス:データの (主要な) セマンティクスに従って、次timestampのいずれかを選択してください。timestamptz

詳細: PostgresSQL には、紛らわしい名前TIMESTAMP WITHOUT TIMEZONE (timestamp)の との 2 つのタイムスタンプ バリアントがありTIMESTAMP WITH TIMEZONE (timestamptz)ます。実際には、タイムゾーンもオフセットも保存しませんどちらのデータ型も同じ幅 (4 バイト) を占めており、その違いは微妙です。さらに悪いことに、それらを完全に理解していないと、サーバーがタイムゾーンを変更する可能性があります。私の正気のルールセットは次のとおりです。

  • 主に「物理的な」時間TIMESTAMP WITH TIMEZONE (timestamptz)に関連するイベントを保存するために使用します。これは主に、(タイムゾーンに関係なく)以前であったかどうかを照会したり、時間間隔を計算したりすることに関心があります (「物理的な単位」、たとえば秒ではなく、「市民」の単位は日月など)。典型的な例は、レコードの作成/変更時間です。これは通常、「タイムスタンプ」という言葉で意味されます。event 1event 2

  • 関連情報が「常用時間」 (つまり、フィールド全体) であり、クエリにカレンダーの計算が含まれるTIMESTAMP WITHOUT TIMEZONE (timestamp)イベントを格納するために使用します。この場合、ここには「現地時間」のみを保存します。つまり、特定されていない (無関係、暗示的、または別の場所に保存されている) タイムゾーンに関連する日時です。{year-month-day hour-min-sec}

2 番目のオプションを使用すると、たとえば、「'2013-01-20' に発生したすべてのイベント」(対応する地域/国/タイムゾーンごと) のクエリが容易になりますが、「そのすべてのイベント」のクエリが難しくなります。参照イベントの前に(物理的に)発生しました」(同じタイムゾーンにあることがわかっている場合を除く). 選んで。

完全なものが必要な場合は、どちらも十分ではありません。追加のフィールドにタイムゾーンまたはオフセットを保存する必要があります。数バイトを浪費しますが、クエリではより効率的な別のオプションは、両方のフィールドを格納することです。

この回答も参照してください。

于 2013-01-31T00:46:31.780 に答える
12

入力フィールドに使用timestamptz(またはtimestamp with time zone標準 SQL 構文) すると、タイムゾーンまたは時間オフセットを使用して、好みに合わせてすべての挿入にカスタムの時間オフセットを設定できます。

例…</p>

CREATE TABLE "timetest"
(
"timestamp" timestamptz
);

INSERT INTO "timetest" ("timestamp") VALUES ('2013-01-01 08:45:00 PST');
INSERT INTO "timetest" ("timestamp") VALUES ('2013-01-01 08:45:00 Europe/Madrid');
INSERT INTO "timetest" ("timestamp") VALUES ('2013-01-01 08:45:00 Europe/Athens');
INSERT INTO "timetest" ("timestamp") VALUES ('2013-01-01 08:45:00 GMT+11');
INSERT INTO "timetest" ("timestamp") VALUES ('2013-01-01 08:45:00 GMT-11');
INSERT INTO "timetest" ("timestamp") VALUES ('2013-01-01 08:45:00 UTC');

...それに応じて時間は調整されます

SELECT * FROM "timetest"; -- note this may default to your timezone
------------------------
[timestamp]
------------------------
2013-01-01 16:45:00+00
2013-01-01 07:45:00+00
2013-01-01 06:45:00+00
2012-12-31 21:45:00+00
2013-01-01 19:45:00+00
2013-01-01 08:45:00+00
2013-01-01 08:45:00+00

またはさらに良い場合は、次のことを試してください...

SELECT 
"timestamp" AT TIME ZONE 'Australia/Sydney' AS "Sydney", 
"timestamp" AT TIME ZONE 'Australia/Perth' AS "Perth" 
FROM "timetest";
--------------------------------------------
[Sydney]..............[Perth]
--------------------------------------------
2013-01-02 03:45:00 - 2013-01-02 00:45:00
2013-01-01 18:45:00 - 2013-01-01 15:45:00
2013-01-01 17:45:00 - 2013-01-01 14:45:00
2013-01-01 08:45:00 - 2013-01-01 05:45:00
2013-01-02 06:45:00 - 2013-01-02 03:45:00
2013-01-01 19:45:00 - 2013-01-01 16:45:00

最後に、データベースで利用可能なタイムゾーンのリストを把握するには、次を試してください。

SELECT * FROM pg_timezone_names ORDER BY utc_offset DESC; 
于 2013-01-30T23:12:29.427 に答える