Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

PHP, MySQL và Múi giờ

Câu trả lời này đã được cập nhật để tích lũy tiền thưởng. Câu trả lời gốc, chưa được chỉnh sửa ở dưới dòng.

Hầu như tất cả các câu hỏi được chủ sở hữu tiền thưởng thêm vào đều liên quan đến cách ngày giờ của MySQL và PHP sẽ tương tác, trong bối cảnh múi giờ.

MySQL vẫn có thảm hại hỗ trợ múi giờ , có nghĩa là trí thông minh phải ở phía PHP.

  • Đặt múi giờ kết nối MySQL của bạn sang UTC như được ghi trong liên kết ở trên. Điều này sẽ khiến tất cả lịch ngày được MySQL xử lý, bao gồm NOW() , để được xử lý một cách lành mạnh.
  • Luôn sử dụng DATETIME , không bao giờ sử dụng TIMESTAMP trừ khi bạn yêu cầu rõ ràng hành vi đặc biệt trong TIMESTAMP . Điều này ít đau đớn hơn trước đây.
    • Không sao cả để lưu trữ thời gian kỷ nguyên Unix dưới dạng số nguyên nếu bạn chẳng hạn như cho các mục đích kế thừa. Kỷ nguyên là UTC.
    • Định dạng ngày giờ ưa thích của MySQL được tạo bằng chuỗi định dạng ngày PHP Y-m-d H:i:s
  • Chuyển đổi tất cả Lịch hẹn ngày của PHP thành UTC khi lưu trữ chúng trong MySQL, đó là một điều nhỏ nhặt như được nêu bên dưới
  • Ngày tháng trả về từ MySQL có thể được chuyển giao một cách an toàn cho phương thức khởi tạo DateTime PHP. Đảm bảo bạn cũng vượt qua múi giờ UTC!
  • Chuyển đổi DateTime PHP sang múi giờ địa phương của người dùng trên echo , không sớm hơn. Rất may, phép so sánh DateTime và phép toán so với các DateTimes khác sẽ tính đến múi giờ của mỗi DateTime.
  • Bạn vẫn sử dụng cơ sở dữ liệu DST được cung cấp cùng với PHP. Luôn cập nhật các bản vá lỗi hệ điều hành và PHP của bạn! Giữ MySQL ở trạng thái vui vẻ của UTC để loại bỏ một số khó chịu DST tiềm ẩn.

Địa chỉ đó hầu hết trong số các điểm.

Điều cuối cùng là doozy:

  • Ai đó nên làm gì nếu họ đã chèn dữ liệu trước đó (ví dụ:sử dụng NOW() ) mà không cần lo lắng về múi giờ để đảm bảo mọi thứ luôn nhất quán?

Đây là một sự khó chịu thực sự. Một trong những câu trả lời khác đã chỉ ra CONVERT_TZ , mặc dù cá nhân tôi đã làm điều đó bằng cách chuyển đổi giữa các múi giờ gốc của máy chủ và UTC trong khi lựa chọn và cập nhật, vì tôi là người khó tính như vậy.

ứng dụng cũng có thể ĐẶT / Chọn DST cho chính nó cho từng người dùng.

Bạn không cần và không nên làm điều này trong kỷ nguyên hiện đại.

Các phiên bản PHP hiện đại có DateTimeZone lớp, bao gồm khả năng liệt kê các múi giờ có tên . Múi giờ được đặt tên cho phép người dùng chọn vị trí thực của họ và hệ thống tự động xác định các quy tắc DST của họ dựa trên vị trí đó.

Bạn có thể kết hợp DateTimeZone với DateTime cho một số chức năng đơn giản nhưng mạnh mẽ. Bạn chỉ cần lưu trữ và sử dụng tất cả dấu thời gian của bạn trong UTC theo mặc định và chuyển đổi chúng sang múi giờ của người dùng trên màn hình.

// UTC default
    date_default_timezone_set('UTC');
// Note the lack of time zone specified with this timestamp.
    $nowish = new DateTime('2011-04-23 21:44:00');
    echo $nowish->format('Y-m-d H:i:s'); // 2011-04-23 21:44:00
// Let's pretend we're on the US west coast.  
// This will be PDT right now, UTC-7
    $la = new DateTimeZone('America/Los_Angeles');
// Update the DateTime's timezone...
    $nowish->setTimeZone($la);
// and show the result
    echo $nowish->format('Y-m-d H:i:s'); // 2011-04-23 14:44:00

Bằng cách sử dụng kỹ thuật này, hệ thống sẽ tự động chọn cài đặt DST chính xác cho người dùng mà không hỏi người dùng xem họ hiện đang ở trong DST hay không.

Bạn có thể sử dụng một phương pháp tương tự để hiển thị menu chọn. Bạn có thể liên tục chỉ định lại múi giờ cho đối tượng DateTime duy nhất. Ví dụ:mã này sẽ liệt kê các khu vực và thời gian hiện tại của chúng, tại thời điểm này:

$dt = new DateTime('now', new DateTimeZone('UTC')); 
foreach(DateTimeZone::listIdentifiers() as $tz) {
    $dt->setTimeZone(new DateTimeZone($tz));
    echo $tz, ': ', $dt->format('Y-m-d H:i:s'), "\n";
}

Bạn có thể đơn giản hóa quá trình lựa chọn bằng cách sử dụng một số phép thuật phía máy khách. Javascript có chỗ trống nhưng có chức năng Lớp ngày, với một phương thức chuẩn để nhận được phần bù UTC trong vài phút . Bạn có thể sử dụng điều này để giúp thu hẹp danh sách các múi giờ có khả năng xảy ra, với giả định mù mờ rằng đồng hồ của người dùng là đúng.

Hãy so sánh phương pháp này để làm điều đó cho mình. Bạn thực sự cần thực hiện phép toán ngày từng lần bạn thao túng ngày giờ, ngoài việc đưa ra một lựa chọn cho người dùng mà họ sẽ không thực sự quan tâm. Đây không chỉ là mức tối ưu, mà còn là sự điên rồ của dơi. Việc buộc người dùng ký tên khi họ muốn hỗ trợ DST là yêu cầu gây rắc rối và nhầm lẫn.

Hơn nữa, nếu bạn muốn sử dụng khung DateTime và DateTimeZone của PHP hiện đại cho việc này, bạn cần phải sử dụng Etc/GMT... không được dùng nữa chuỗi múi giờ thay vì các múi giờ được đặt tên. Những tên vùng này có thể bị xóa khỏi các phiên bản PHP trong tương lai, vì vậy sẽ không khôn ngoan nếu làm điều đó. Tôi nói tất cả những điều này từ kinh nghiệm.

tl; dr :Sử dụng bộ công cụ hiện đại, giải thoát khỏi nỗi kinh hoàng của phép toán ngày tháng. Trình bày cho người dùng danh sách có tên Múi giờ. Lưu trữ ngày của bạn bằng UTC , sẽ không bị ảnh hưởng bởi DST theo bất kỳ cách nào. Chuyển đổi ngày giờ thành múi giờ có tên đã chọn của người dùng trên màn hình , không sớm hơn.

Theo yêu cầu, đây là một vòng lặp qua các múi giờ có sẵn hiển thị độ lệch GMT của chúng trong vài phút. Tôi đã chọn những phút ở đây để chứng minh một sự thật đáng tiếc:không phải tất cả các hiệu số đều tính bằng cả giờ! Một số thực sự chuyển trước nửa giờ trong DST thay vì cả giờ. Kết quả bù đắp trong vài phút nên khớp với Date.getTimezoneOffset của Javascript .

$utc = new DateTimeZone('UTC');
$dt = new DateTime('now', $utc); 
foreach(DateTimeZone::listIdentifiers() as $tz) {
    $local = new DateTimeZone($tz);
    $dt->setTimeZone($local);
    $offset = $local->getOffset($dt); // Yeah, really.
    echo $tz, ': ', 
         $dt->format('Y-m-d H:i:s'),
         ', offset = ',
         ($offset / 60),
         " minutes\n";
}


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cú pháp DELETE của SQL - Được DBMS liệt kê

  2. Cách lấy dữ liệu mỗi giờ trong MySQL

  3. Đếm ngày giữa hai ngày, trừ ngày cuối tuần (chỉ MySQL)

  4. Tạo một chuỗi số nguyên trong MySQL

  5. Sự cố MySQL Innodb