PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Mengonversi Antara Zona Waktu di Postgres

Mari saya jelaskan dua contoh:

Di keduanya, kami mengasumsikan zona waktu UTC (yaitu SET timezone TO UTC ).

db=# SELECT timezone('US/Pacific', '2016-01-01 00:00');
      timezone
---------------------
 2015-12-31 16:00:00
(1 row)

Ini setara dengan SELECT timezone('US/Pacific', '2016-01-01 00:00'::timestamptz) , yaitu Postgres secara implisit mengonversi string menjadi timestamptz .

Kita tahu bahwa timezone fungsi mengkonversi bolak-balik antara timestamp dan timestamptz :

Karena kami memberikannya timestamptz sebagai input, itu akan menampilkan timestamp . Dengan kata lain, ini mengubah titik waktu absolut 2016-01-01 00:00Z ke waktu dinding di US/Pacific , yaitu apa yang ditunjukkan jam di Los Angeles pada titik waktu absolut tersebut.

Pada contoh 2 kita melakukan kebalikannya, yaitu mengambil timestamp dan mengubahnya menjadi timestamptz . Dengan kata lain, kami bertanya:di mana titik waktu absolut ketika jam di Los Angeles menunjukkan 2016-01-01 00:00 ?

Anda menyebutkan:

'2016-01-01 00:00'::timestamp adalah timestamp , yaitu waktu dinding. Itu tidak memiliki gagasan tentang zona waktu.

Saya pikir Anda mungkin belum sepenuhnya memahami perbedaan antara timestamp dan timestamptz , yang merupakan kunci di sini. Anggap saja mereka sebagai waktu dinding , yaitu waktu yang ditunjukkan di suatu tempat di dunia pada jam yang tergantung di dinding, dan waktu absolut , yaitu waktu absolut di alam semesta kita.

Contoh yang Anda buat dalam jawaban Anda sendiri tidak cukup akurat.

SELECT ts FROM  (VALUES
(timestamptz '2012-03-05 17:00:00+0') -- outputs 2012-03-05 17:00:00+00 --1
,(timestamptz '2012-03-05 18:00:00+1') -- outputs 2012-03-05 17:00:00+00 --2
,(timestamp   '2012-03-05 18:00:00+1') -- outputs 2012-03-05 18:00:00+00 --3
,(timestamp   '2012-03-05 11:00:00'  AT TIME ZONE '+6') -- outputs 2012-03-05 17:00:00+00 --4
,(timestamp   '2012-03-05 17:00:00'  AT TIME ZONE 'UTC') -- outputs 2012-03-05 17:00:00+00 --5
,(timestamp   '2012-03-05 17:00:00'::timestamp) -- outputs 2012-03-05 17:00:00+00 --6
,(timestamp   '2012-03-05 17:00:00'::timestamptz) -- outputs 2012-03-05 17:00:00+00 --7
    ) t(ts);

Masalah dengan contoh Anda adalah Anda sedang membangun satu kumpulan data dengan satu kolom. Karena kolom hanya dapat memiliki satu jenis, setiap baris (atau nilai tunggal dalam hal ini) dikonversi ke jenis yang sama, yaitu timestamptz , meskipun beberapa nilai dihitung sebagai timestamp (misalnya nilai 3). Dengan demikian, Anda memiliki konversi implisit tambahan di sini.

Mari kita pisahkan contoh menjadi kueri terpisah dan lihat apa yang terjadi:

Contoh 1

db=# SELECT timestamptz '2012-03-05 17:00:00+0';
      timestamptz
------------------------
 2012-03-05 17:00:00+00

Seperti yang mungkin sudah Anda ketahui, timestamptz '2012-03-05 17:00:00+0' dan '2012-03-05 17:00:00+0'::timestamptz setara (saya lebih suka yang terakhir). Jadi, hanya untuk menggunakan sintaks yang sama seperti di artikel, saya akan menulis ulang:

db=# SELECT '2012-03-05 17:00:00+0'::timestamptz;
      timestamptz
------------------------
 2012-03-05 17:00:00+00

Sekarang, apa yang terjadi di sini? Nah, kurang dari penjelasan awal Anda. String hanya diuraikan sebagai timestamptz . Ketika hasilnya dicetak, ia menggunakan timezone yang ditetapkan saat ini config untuk mengubahnya kembali menjadi representasi yang dapat dibaca manusia dari struktur data yang mendasarinya, yaitu 2012-03-05 17:00:00+00 .

Mari kita ubah timezone config dan lihat apa yang terjadi:

db=# SET timezone TO 'Europe/Berlin';
SET
db=# SELECT '2012-03-05 17:00:00+0'::timestamptz;
      timestamptz
------------------------
 2012-03-05 18:00:00+01

Satu-satunya hal yang berubah adalah bagaimana timestamptz dicetak di layar, yaitu menggunakan Eropa/Berlin zona waktu.

Contoh 2

db=# SELECT timestamptz '2012-03-05 18:00:00+1';
      timestamptz
------------------------
 2012-03-05 17:00:00+00
(1 row)

Sekali lagi, hanya menguraikan tanggal.

Contoh 3

db=# SELECT timestamp '2012-03-05 18:00:00+1';
      timestamp
---------------------
 2012-03-05 18:00:00
(1 row)

Ini sama dengan '2012-03-05 18:00:00+1'::timestamp . Apa yang terjadi di sini adalah offset zona waktu diabaikan begitu saja karena Anda meminta timestamp .

Contoh 4

db=# SELECT timestamp '2012-03-05 11:00:00' AT TIME ZONE '+6';
        timezone
------------------------
 2012-03-05 17:00:00+00
(1 row)

Mari kita menulis ulang menjadi lebih sederhana:

db=# SELECT timezone('+6', '2012-03-05 11:00:00'::timestamp);
        timezone
------------------------
 2012-03-05 17:00:00+00
(1 row)

Ini menanyakan:berapa waktu absolut ketika jam di dinding di zona waktu dengan offset +6 jam menunjukkan 2012-03-05 11:00:00 ?

Contoh 5

db=# SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC';
        timezone
------------------------
 2012-03-05 17:00:00+00
(1 row)

Mari kita menulis ulang:

db=# SELECT timezone('UTC', '2012-03-05 17:00:00'::timestamp);
        timezone
------------------------
 2012-03-05 17:00:00+00
(1 row)

Ini menanyakan:berapa waktu absolut ketika jam di dinding di zona waktu UTC menunjukkan 2012-03-05 17:00:00 ?

Contoh 6

db=# SELECT timestamp '2012-03-05 17:00:00'::timestamp;
      timestamp
---------------------
 2012-03-05 17:00:00
(1 row)

Di sini Anda melakukan casting dua kali ke timestamp , yang tidak ada bedanya. Mari kita sederhanakan:

db=# SELECT '2012-03-05 17:00:00'::timestamp;
      timestamp
---------------------
 2012-03-05 17:00:00
(1 row)

Itu jelas menurut saya.

Contoh 7

db=# SELECT timestamp '2012-03-05 17:00:00'::timestamptz;
      timestamptz
------------------------
 2012-03-05 17:00:00+00
(1 row)

Mari kita menulis ulang:

db=# SELECT ('2012-03-05 17:00:00'::timestamp)::timestamptz;
      timestamptz
------------------------
 2012-03-05 17:00:00+00
(1 row)

Anda pertama kali menguraikan string sebagai timestamp dan kemudian mengubahnya menjadi timestamptz menggunakan timezone yang ditetapkan saat ini . Jika kita mengubah timezone , kami mendapatkan sesuatu yang lain karena Postgres mengasumsikan zona waktu itu saat mengonversi timestamp (atau string yang tidak memiliki informasi zona waktu) ke timestamptz :

db=# SET timezone TO 'Europe/Berlin';
SET
db=# SELECT ('2012-03-05 17:00:00'::timestamp)::timestamptz;
      timestamptz
------------------------
 2012-03-05 17:00:00+01
(1 row)

Waktu absolut ini, dinyatakan dalam UTC, adalah 2012-03-05 16:00:00+00 , sehingga berbeda dari contoh aslinya.

Saya harap ini menjelaskan banyak hal. Sekali lagi, pahami perbedaan antara timestamp dan timestamptz adalah kunci. Pikirkan waktu dinding versus waktu absolut.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Hibernate, Postgresql:Kolom x bertipe oid tetapi ekspresi bertipe byte

  2. Mendapatkan kata terakhir dari string Postgres, secara deklaratif

  3. Log Heroku mengatakan Tidak ada modul bernama 'urlparse' saat saya menggunakan urlparse impor

  4. Menggunakan .pgpass dari Apache libphp5.so

  5. Dalam fungsi pemicu, cara mendapatkan bidang mana yang diperbarui