MySQL có nên đặt múi giờ thành UTC không?


149

Câu hỏi tiếp theo của /server/191331/should-servers-have-their-timezone-set-to-gmt-utc

Múi giờ MySQL nên được đặt thành UTC hay nó nên được đặt thành cùng múi giờ với máy chủ hoặc PHP được đặt? (Nếu không phải là UTC)

Những ưu và khuyết điểm là gì?


stackoverflow.com/a/1650406/175071 chia sẻ lý do chính đáng để sử dụng UTC
Timo Huovinen

UTC không phải là múi giờ. UTC là một tiêu chuẩn, GMT là múi giờ. zachholman.com/talk/utc-is-enough-for-everyone-right
agoldev

Một lý do tuyệt vời khác để sử dụng UTC dba.stackexchange.com/questions/161416/NH
Timo Huovinen

Câu trả lời:


533

Dường như không có vấn đề gì về múi giờ trên máy chủ miễn là bạn có thời gian phù hợp với múi giờ hiện tại, biết múi giờ của các cột thời gian mà bạn lưu trữ và nhận thức được các vấn đề về thời gian tiết kiệm ánh sáng ban ngày.

Mặt khác, nếu bạn có quyền kiểm soát múi giờ của các máy chủ mà bạn làm việc cùng thì bạn có thể đặt mọi thứ thành UTC trong nội bộ và không bao giờ lo lắng về múi giờ và DST.

Dưới đây là một số lưu ý tôi đã thu thập về cách làm việc với các múi giờ như một hình thức áo choàng cho bản thân và những người khác có thể ảnh hưởng đến múi giờ mà người đó sẽ chọn cho máy chủ của mình và cách anh ấy / cô ấy sẽ lưu trữ ngày và giờ.

MySQL Timezone Chcoateet

Ghi chú:

  1. Thay đổi múi giờ sẽ không thay đổi datetime hoặc dấu thời gian được lưu trữ , nhưng nó sẽ chọn một datetime khác từ các cột dấu thời gian
  2. Cảnh báo! UTC có giây nhảy vọt, chúng trông giống như '2012-06-30 23:59:60' và có thể được thêm ngẫu nhiên, với thông báo trước 6 tháng, do tốc độ quay của trái đất chậm lại
  3. GMT nhầm lẫn giây, đó là lý do tại sao UTC được phát minh.

  4. Cảnh báo! các múi giờ khu vực khác nhau có thể tạo ra cùng một giá trị thời gian do thời gian tiết kiệm ánh sáng ban ngày

  5. Cột dấu thời gian chỉ hỗ trợ ngày 1970-01-01 00:00:01 đến 2038-01-19 03:14:07 UTC, do một giới hạn .
  6. Bên trong một cột dấu thời gian MySQL được lưu trữ dưới dạng UTC nhưng khi chọn ngày, MySQL sẽ tự động chuyển đổi nó thành múi giờ phiên hiện tại.

    Khi lưu trữ một ngày trong dấu thời gian, MySQL sẽ cho rằng ngày đó nằm trong múi giờ của phiên hiện tại và chuyển đổi nó thành UTC để lưu trữ.

  7. MySQL có thể lưu trữ một phần ngày trong các cột datetime, chúng trông giống như "2013-00-00 04:00:00"
  8. MySQL lưu trữ "0000-00-00 00:00:00" nếu bạn đặt cột thời gian là NULL, trừ khi bạn đặc biệt đặt cột thành cho phép null khi bạn tạo nó.
  9. Đọc này

Để chọn cột dấu thời gian ở định dạng UTC

không có vấn đề gì về múi giờ của phiên MySQL hiện tại:

SELECT 
CONVERT_TZ(`timestamp_field`, @@session.time_zone, '+00:00') AS `utc_datetime` 
FROM `table_name`

Bạn cũng có thể đặt múi giờ của sever hoặc toàn cầu hoặc hiện tại thành UTC và sau đó chọn dấu thời gian như sau:

SELECT `timestamp_field` FROM `table_name`

Để chọn thời gian hiện tại trong UTC:

SELECT UTC_TIMESTAMP();
SELECT UTC_TIMESTAMP;
SELECT CONVERT_TZ(NOW(), @@session.time_zone, '+00:00');

Kết quả ví dụ: 2015-03-24 17:02:41

Để chọn thời gian hiện tại trong múi giờ phiên

SELECT NOW();
SELECT CURRENT_TIMESTAMP;
SELECT CURRENT_TIMESTAMP();

Để chọn múi giờ đã được đặt khi máy chủ khởi chạy

SELECT @@system_time_zone;

Chẳng hạn, trả về "MSK" hoặc "+04: 00" cho thời gian ở Matxcơva, có (hoặc là) một lỗi MySQL trong đó nếu được đặt thành bù số thì nó sẽ không điều chỉnh thời gian tiết kiệm ánh sáng ban ngày

Để có được múi giờ hiện tại

SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);

Nó sẽ trả về 02:00:00 nếu múi giờ của bạn là +2: 00.

Để lấy dấu thời gian UNIX hiện tại (tính bằng giây):

SELECT UNIX_TIMESTAMP(NOW());
SELECT UNIX_TIMESTAMP();

Để lấy cột dấu thời gian dưới dạng dấu thời gian UNIX

SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`

Để lấy cột thời gian UTC dưới dạng dấu thời gian UNIX

SELECT UNIX_TIMESTAMP(CONVERT_TZ(`utc_datetime`, '+00:00', @@session.time_zone)) FROM `table_name`

Nhận thời gian múi giờ hiện tại từ số nguyên dấu thời gian UNIX dương

SELECT FROM_UNIXTIME(`unix_timestamp_int`) FROM `table_name`

Nhận thời gian UTC từ dấu thời gian UNIX

SELECT CONVERT_TZ(FROM_UNIXTIME(`unix_timestamp_int`), @@session.time_zone, '+00:00') 
FROM `table_name`

Nhận thời gian múi giờ hiện tại từ số nguyên dấu thời gian UNIX âm

SELECT DATE_ADD('1970-01-01 00:00:00',INTERVAL -957632400 SECOND) 

Có 3 vị trí nơi múi giờ có thể được đặt trong MySQL:

Lưu ý: Một múi giờ có thể được đặt ở 2 định dạng:

  1. phần bù từ UTC: 'EST: 00', '+10: 00' hoặc '-6: 00'
  2. dưới dạng múi giờ được đặt tên: 'Châu Âu / Helsinki', 'Hoa Kỳ / Miền Đông' hoặc 'MET'

Các múi giờ được đặt tên chỉ có thể được sử dụng nếu các bảng thông tin múi giờ trong cơ sở dữ liệu mysql đã được tạo và điền.

trong tập tin "my.cnf"

default_time_zone='+00:00'

hoặc là

timezone='UTC'

@@ biến toàn cầu.time_zone

Để xem giá trị nào chúng được đặt thành

SELECT @@global.time_zone;

Để đặt giá trị cho nó, hãy sử dụng một trong hai:

SET GLOBAL time_zone = '+8:00';
SET GLOBAL time_zone = 'Europe/Helsinki';
SET @@global.time_zone='+00:00';

@@ session.time_zone

SELECT @@session.time_zone;

Để thiết lập, sử dụng một trong hai:

SET time_zone = 'Europe/Helsinki';
SET time_zone = "+00:00";
SET @@session.time_zone = "+00:00";

cả biến "@@ global.time_zone" và "@@ session.time_zone" có thể trả về "HỆ THỐNG" có nghĩa là họ sử dụng múi giờ được đặt trong "my.cnf".

Để tên múi giờ hoạt động (ngay cả đối với múi giờ mặc định), bạn phải thiết lập các bảng thông tin múi giờ của mình cần được điền: http://dev.mysql.com/doc/refman/5.1/en/time-zone-support. html

Lưu ý: bạn không thể làm điều này vì nó sẽ trả về NULL:

SELECT 
CONVERT_TZ(`timestamp_field`, TIMEDIFF(NOW(), UTC_TIMESTAMP), '+00:00') AS `utc_datetime` 
FROM `table_name`

Thiết lập bảng múi giờ mysql

Để CONVERT_TZlàm việc, bạn cần các bảng múi giờ được điền

SELECT * FROM mysql.`time_zone` ;
SELECT * FROM mysql.`time_zone_leap_second` ;
SELECT * FROM mysql.`time_zone_name` ;
SELECT * FROM mysql.`time_zone_transition` ;
SELECT * FROM mysql.`time_zone_transition_type` ;

Nếu chúng trống, hãy lấp đầy chúng bằng cách chạy lệnh này

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

nếu lệnh này cung cấp cho bạn lỗi " dữ liệu quá dài cho cột 'viết tắt' ở hàng 1 ", thì có thể nguyên nhân là do một ký tự NULL được thêm vào cuối chữ viết tắt múi giờ

cách khắc phục để chạy cái này

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
(if the above gives error "data too long for column 'abbreviation' at row 1")
mysql_tzinfo_to_sql /usr/share/zoneinfo > /tmp/zut.sql

echo "SET SESSION SQL_MODE = '';" > /tmp/mysql_tzinfo_to.sql
cat /tmp/zut.sql >> /tmp/mysql_tzinfo_to.sql

mysql --defaults-file=/etc/mysql/my.cnf --user=verifiedscratch -p mysql < /tmp/mysql_tzinfo_to.sql

(đảm bảo quy tắc dst máy chủ của bạn được cập nhật zdump -v Europe/Moscow | grep 2011 https://chrisjean.com/updating-daylight-saving-time-on-linux/ )

Xem toàn bộ lịch sử chuyển đổi DST (Giờ tiết kiệm ánh sáng ban ngày) cho mỗi múi giờ

SELECT 
tzn.Name AS tz_name,
tztt.Abbreviation AS tz_abbr,
tztt.Is_DST AS is_dst,
tztt.`Offset` AS `offset`,
DATE_ADD('1970-01-01 00:00:00',INTERVAL tzt.Transition_time SECOND)  AS transition_date
FROM mysql.`time_zone_transition` tzt
INNER JOIN mysql.`time_zone_transition_type` tztt USING(Time_zone_id, Transition_type_id)
INNER JOIN mysql.`time_zone_name` tzn USING(Time_zone_id)
-- WHERE tzn.Name LIKE 'Europe/Moscow' -- Moscow has weird DST changes
ORDER BY tzt.Transition_time ASC

CONVERT_TZ cũng áp dụng mọi thay đổi DST cần thiết dựa trên các quy tắc trong các bảng trên và ngày bạn sử dụng.

Lưu ý:
Theo tài liệu , giá trị bạn đặt cho time_zone không thay đổi, ví dụ: nếu bạn đặt nó là "+01: 00", thì time_zone sẽ được đặt thành phần bù từ UTC, do đó không tuân theo DST, do đó, không tuân theo DST, vì vậy nó sẽ giữ nguyên quanh năm

Chỉ các múi giờ được đặt tên sẽ thay đổi thời gian trong thời gian tiết kiệm ánh sáng ban ngày.

Chữ viết tắt như CETsẽ luôn là thời gian mùa đông và CESTsẽ là thời gian mùa hè trong khi +01: 00 sẽ luôn là UTCthời gian + 1 giờ và cả hai sẽ không thay đổi với DST.

Các systemmúi giờ sẽ là múi giờ của máy chủ nơi mysql được cài đặt (trừ khi mysql thất bại trong việc xác định nó)

Bạn có thể đọc thêm về làm việc với DST tại đây

Câu hỏi liên quan:

Nguồn:


Vì vậy, nếu tôi có loại cột của tôi được đặt thành dấu thời gian. Và time_zone của tôi là +12: 00 và tôi muốn cập nhật một cột bằng cách sử dụng ngày / giờ dựa trên utc, có cách nào để đưa múi giờ vào câu lệnh cập nhật hay tôi nên sử dụng convert_tz. Ví dụ. Cập nhật tablethiết lập modified= '2016/07/07 08:10 EST: 00'
bội thu

2
@bumperbox mysql luôn giả định rằng ngày bạn cung cấp cột dấu thời gian nằm trong cùng múi giờ với máy chủ mysql, vì vậy bạn cần chuyển đổi ngày của mình từ múi giờ +12: 00 sang múi giờ của máy chủ mysql để cập nhật. Đây là lý do tại sao tôi sử dụng UTC trên máy chủ mysql và chuyển đổi bất kỳ ngày nào thành UTC trước khi lưu trữ.
Timo Huovinen

5
Một trong những câu trả lời hay nhất, nhiều thông tin nhất mà tôi đã gặp trong nhiều năm sử dụng SO. Cảm ơn bạn.
Mitya

CẢNH BÁO!!! Bất kỳ việc sử dụng hoặc chuyển đổi từ, giờ địa phương trong múi giờ DST sẽ bị sai một giờ trong một giờ mỗi năm khi kết thúc tiết kiệm ánh sáng ban ngày. Điều này ảnh hưởng UNIX_TIMESTAMP(NOW());cũng như tất cả các mục đích sử dụng của bạn trong CONVERT_TZ()đó một trong các tham số là `@@ session.time_zone. Để chuyển đổi thời gian dữ liệu UTC đáng tin cậy sang dấu thời gian UNIX, về cơ bản bạn phải đặt thời gian phiên_zone trước.
Doin

1
@Flimm hoàn toàn đúng, tôi đã quên sửa nó một thời gian trước đây.
Timo Huovinen

3

Đây là một ví dụ hoạt động:

jdbc:mysql://localhost:3306/database?useUnicode=yes&characterEncoding=UTF-8&serverTimezone=Europe/Moscow

2

PHP và MySQL có cấu hình múi giờ mặc định của riêng họ. Bạn nên đồng bộ hóa thời gian giữa cơ sở dữ liệu và ứng dụng web, nếu không bạn có thể chạy một số vấn đề.

Đọc hướng dẫn này: Cách đồng bộ hóa các múi giờ PHP và MySQL của bạn


Về cơ bản, đó là hai dòng mã: date_default_timezone_set("America/Los_Angeles");và hoạt động mysql_query("SET time_zone='" . date('P', time()) . "'");rất thanh lịch!
Noumenon

3
@Noumenon Cẩn thận với điều đó! Tôi đã gãi đầu sáng nay vì đó chính xác là những gì tôi đang làm, và một số thời gian của tôi đã hết một giờ. Điều tôi nghi ngờ là việc sử dụng múi giờ có tên sẽ chính xác hơn khi có DST. Nếu bạn sử dụng America / New_York, MySQL sẽ biết về DST và sẽ lưu trữ ngày thích hợp. Nếu bạn chỉ đặt nó thành -04: 00 như bạn có ở đây, nó sẽ không xem xét tính toán DST.
nathanb

1
Hãy kiểm tra xem mysql có biết chính xác về DST không, các quy tắc DST có được cập nhật thường xuyên không và các bảng mysql liên quan cũng cần cập nhật (xem phần dưới cùng trong câu trả lời của tôi)
Timo Huovinen

1

Những ưu và nhược điểm là khá giống nhau. Nó phụ thuộc vào việc bạn có muốn điều này hay không.

Hãy cẩn thận, nếu múi giờ của MySQL khác với thời gian hệ thống của bạn (ví dụ PHP), việc so sánh thời gian hoặc in ấn với người dùng sẽ liên quan đến một số vấn đề.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.