PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Какъв тип клеймо за дата да избера в PostgreSQL база данни?

Първо, обработката на времето и аритметиката на PostgreSQL са фантастични и опция 3 е добра в общия случай. Това обаче е непълен изглед на времето и часовите зони и може да бъде допълнен:

  1. Съхранете името на часовата зона на потребителя като потребителско предпочитание (напр. America/Los_Angeles , а не -0700 ).
  2. Данните за потребителските събития/време да бъдат изпращани локално към тяхната референтна рамка (най-вероятно отместване от UTC, като -0700 ).
  3. В приложението преобразувайте времето в UTC и се съхранява с помощта на TIMESTAMP WITH TIME ZONE колона.
  4. Заявки за време за връщане локално към часовата зона на потребителя (т.е. конвертиране от UTC до America/Los_Angeles ).
  5. Задайте timezone на вашата база данни до UTC .

Тази опция не винаги работи, защото може да е трудно да се получи часовата зона на потребителя и следователно съветът за хеджиране да се използва TIMESTAMP WITH TIME ZONE за леки приложения. Въпреки това, нека обясня някои основни аспекти на тази опция 4 по-подробно.

Подобно на вариант 3, причината за WITH TIME ZONE е, защото времето, в което нещо се е случило, е вабсолютно момент във времето. WITHOUT TIME ZONE дава сроднина часова зона. Никога, никога, никога не смесвайте абсолютни и относителни TIMESTAMP.

От гледна точка на програмиране и последователност, уверете се, че всички изчисления са направени с помощта на UTC като часова зона. Това не е изискване на PostgreSQL, но помага при интегриране с други езици за програмиране или среди. Задаване на CHECK в колоната, за да се уверите, че записът в колоната с времеви печат има отместване на часовата зона от 0 е защитна позиция, която предотвратява няколко класа грешки (например скрипт изхвърля данни във файл и нещо друго сортира данните за времето, използвайки лексикално сортиране). Отново, PostgreSQL не се нуждае от това, за да прави правилно изчисления на дати или да преобразува между часови зони (т.е. PostgreSQL е много умел в преобразуването на времена между всякакви две произволни часови зони). За да гарантирате, че данните, влизащи в базата данни, се съхраняват с отместване от нула:

CREATE TABLE my_tbl (
  my_timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
  CHECK(EXTRACT(TIMEZONE FROM my_timestamp) = '0')
);
test=> SET timezone = 'America/Los_Angeles';
SET
test=> INSERT INTO my_tbl (my_timestamp) VALUES (NOW());
ERROR:  new row for relation "my_tbl" violates check constraint "my_tbl_my_timestamp_check"
test=> SET timezone = 'UTC';
SET
test=> INSERT INTO my_tbl (my_timestamp) VALUES (NOW());
INSERT 0 1

Не е 100% перфектен, но осигурява достатъчно силна мярка срещу стрелба, която гарантира, че данните вече са преобразувани в UTC. Има много мнения как да направите това, но според моя опит това изглежда е най-доброто на практика.

Критиките за обработката на часовата зона на базата данни са до голяма степен оправдани (има много бази данни, които се справят с това с голяма некомпетентност), но обработката на PostgreSQL с времеви марки и часови зони е доста страхотна (въпреки няколко „функции“ тук-там). Например една такава функция:

-- Make sure we're all working off of the same local time zone
test=> SET timezone = 'America/Los_Angeles';
SET
test=> SELECT NOW();
              now              
-------------------------------
 2011-05-27 15:47:58.138995-07
(1 row)

test=> SELECT NOW() AT TIME ZONE 'UTC';
          timezone          
----------------------------
 2011-05-27 22:48:02.235541
(1 row)

Обърнете внимание, че AT TIME ZONE 'UTC' премахва информацията за часовата зона и създава относителен TIMESTAMP WITHOUT TIME ZONE използвайки референтната рамка на вашата цел (UTC ).

При конвертиране от непълен TIMESTAMP WITHOUT TIME ZONE към TIMESTAMP WITH TIME ZONE , липсващата часова зона е наследена от вашата връзка:

test=> SET timezone = 'America/Los_Angeles';
SET
test=> SELECT EXTRACT(TIMEZONE_HOUR FROM NOW());
 date_part 
-----------
        -7
(1 row)
test=> SELECT EXTRACT(TIMEZONE_HOUR FROM TIMESTAMP WITH TIME ZONE '2011-05-27 22:48:02.235541');
 date_part 
-----------
        -7
(1 row)

-- Now change to UTC    
test=> SET timezone = 'UTC';
SET
-- Create an absolute time with timezone offset:
test=> SELECT NOW();
              now              
-------------------------------
 2011-05-27 22:48:40.540119+00
(1 row)

-- Creates a relative time in a given frame of reference (i.e. no offset)
test=> SELECT NOW() AT TIME ZONE 'UTC';
          timezone          
----------------------------
 2011-05-27 22:48:49.444446
(1 row)

test=> SELECT EXTRACT(TIMEZONE_HOUR FROM NOW());
 date_part 
-----------
         0
(1 row)

test=> SELECT EXTRACT(TIMEZONE_HOUR FROM TIMESTAMP WITH TIME ZONE '2011-05-27 22:48:02.235541');
 date_part 
-----------
         0
(1 row)

Изводът:

  • съхранява часовата зона на потребителя като именуван етикет (напр. America/Los_Angeles ), а не отместване от UTC (напр. -0700). )
  • използвайте UTC за всичко, освен ако няма убедителна причина да съхранявате отместване, различно от нула
  • отнасяйте всички различни от нула времена UTC като грешка при въвеждане
  • никога не смесвайте и съпоставяйте относителни и абсолютни времеви марки
  • използвайте също UTC като timezone в базата данни, ако е възможно

Бележка за произволен език за програмиране:datetime на Python Типът данни е много добър в поддържането на разликата между абсолютни и относителни времена (макар и разочароващо в началото, докато не го допълните с библиотека като PyTZ).

РЕДАКТИРАНЕ

Нека обясня малко повече разликата между относителни и абсолютни.

Абсолютното време се използва за запис на събитие. Примери:„Потребител 123 е влязъл“ или „церемонията по дипломирането започва в 28.05.2011 14:00 PST“. Независимо от вашата местна часова зона, ако можете да се телепортирате до мястото, където се е случило събитието, бихте могли да станете свидетели на случващото се събитие. Повечето данни за времето в база данни са абсолютни (и следователно трябва да бъдат TIMESTAMP WITH TIME ZONE , в идеалния случай с отместване +0 и текстов етикет, представляващ правилата, управляващи конкретната часова зона, а не отместване).

Относително събитие би било записването или планирането на времето на нещо от гледна точка на часова зона, която все още не е определена. Примери:„вратите на нашия бизнес се отварят в 8 сутринта и затварят в 21 часа“, „да се срещаме всеки понеделник в 7 сутринта за седмична среща за закуска“ или „всеки Хелоуин в 20 часа“. Като цяло относителното време се използва в шаблон или фабрика за събития, а абсолютното време се използва за почти всичко останало. Има едно рядко изключение, което си струва да се посочи, което трябва да илюстрира стойността на относителните времена. За бъдещи събития, които са достатъчно далеч в бъдещето, където може да има несигурност относно абсолютното време, в което нещо може да се случи, използвайте относителна времева марка. Ето пример от реалния свят:

Да предположим, че е 2004 г. и трябва да насрочите доставка на 31 октомври 2008 г. в 13:00 часа на западното крайбрежие на САЩ (т.е. America/Los_Angeles /PST8PDT ). Ако сте съхранили това, използвайки абсолютно време с помощта на ’2008-10-31 21:00:00.000000+00’::TIMESTAMP WITH TIME ZONE , доставката щеше да се появи в 14:00, тъй като правителството на САЩ прие Закона за енергийната политика от 2005 г., който промени правилата, регулиращи лятното часово време. През 2004 г., когато доставката е била насрочена, датата 10-31-2008 би било тихоокеанско стандартно време (+8000). ), но от 2005+ година базите данни за часови зони признават, че 10-31-2008 щеше да е Тихоокеанско лятно часово време (+0700). ). Съхраняването на относително времеви печат с часовата зона би довело до правилен график за доставка, тъй като относително времеви печат е имунизиран срещу неправилно информирано подправяне на Конгреса. Там, където границата между използването на относителни и абсолютни времена за планиране на нещата е размита линия, но моето правило е, че планирането за всичко в бъдеще по-далеч от 3-6 месеца трябва да използва относителни времеви печати (планирано =абсолютно срещу планирано =роднина ???).

Другият/последен тип относително време е INTERVAL . Пример:"сесията ще изтече 20 минути след като потребител влезе". INTERVAL може да се използва правилно с двете абсолютни времеви марки (TIMESTAMP WITH TIME ZONE ) или относителни времеви печати (TIMESTAMP WITHOUT TIME ZONE ). Също толкова правилно е да се каже „потребителска сесия изтича 20 минути след успешно влизане (login_utc + session_duration)“ или „нашата сутрешна среща за закуска може да продължи само 60 минути (recurring_start_time + meeting_length)“.

Последни обърквания:DATE , TIME , TIME WITHOUT TIME ZONE и TIME WITH TIME ZONE са всички относителни типове данни. Например:'2011-05-28'::DATE представлява относителна дата, тъй като нямате информация за часовата зона, която може да се използва за идентифициране на полунощ. По същия начин, '23:23:59'::TIME е относително, защото не знаете нито часовата зона, нито DATE представена от времето. Дори с '23:59:59-07'::TIME WITH TIME ZONE , не знаете какво е DATE би било. И накрая, DATE с часова зона всъщност не е DATE , това е TIMESTAMP WITH TIME ZONE :

test=> SET timezone = 'America/Los_Angeles';
SET
test=> SELECT '2011-05-11'::DATE AT TIME ZONE 'UTC';
      timezone       
---------------------
 2011-05-11 07:00:00
(1 row)

test=> SET timezone = 'UTC';
SET
test=> SELECT '2011-05-11'::DATE AT TIME ZONE 'UTC';
      timezone       
---------------------
 2011-05-11 00:00:00
(1 row)

Поставянето на дати и часови зони в базите данни е добро нещо, но е лесно да получите едва доловимо неверни резултати. Необходими са минимални допълнителни усилия за правилното и пълно съхраняване на информацията за времето, но това не означава, че винаги са необходими допълнителни усилия.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Запазване на часовата зона в PostgreSQL timestamptz тип

  2. Инсталации с висока достъпност на PostgreSQL Patroni

  3. Предимствата на PostgreSQL

  4. Как да наблюдавате производителността на PostgreSQL 12 с OmniDB – част 1

  5. Проблем с възстановяването на базата данни Heroku