Làm cách nào để xử lý TimeZone đúng cách trong SQL Server?


34

Máy chủ phát triển địa phương của tôi ở Trung Đông, nhưng máy chủ sản xuất của tôi ở Anh.

Tôi cần hiển thị ngày cho người dùng theo múi giờ của họ. Ví dụ: nếu người dùng ở Ả Rập Saudi thì tôi cần hiển thị thời gian theo định dạng của Ả Rập Saudi.

Tôi có nên tạo bảng cơ sở dữ liệu mới có tên TimeZone và tiết kiệm thời gian trong UTC không?


Chuyển đổi hiệu quả ngày giữa thời gian UTC và Địa phương (ví dụ: PST) trong SQL 2005 http://stackoverflow.com/questions/24797/effectively-converting-dates-b
mehdi

Đây có phải là một ứng dụng web, hay ứng dụng máy tính để bàn, hay ...? Làm thế nào điều này được thực hiện thay đổi rất nhiều bởi cơ chế phân phối khách hàng, bởi vì những gì bạn cần phụ thuộc vào phía khách hàng.
Jon Seigel

Web này cũng như điện thoại di động bản địa. Có hiệu ứng này khách hàng khác nhau khác nhau.
user960567

1
Có vẻ như câu hỏi của bạn không chỉ là về cơ sở dữ liệu, mà còn liên quan đến việc phát triển ứng dụng. Câu hỏi về Stack Overflow này là một câu hỏi phải đọc cho bạn sau đó: Thực hành tiết kiệm thời gian ban ngày và múi giờ tốt nhất
Gan

Câu trả lời:


48

Thật không có cách khắc phục nhanh cho việc này, thật không may. Quốc tế hóa một ứng dụng nên là một phần của các cuộc thảo luận thiết kế đầu tiên, vì nó thực sự đi vào cốt lõi của rất nhiều lĩnh vực khác nhau, bao gồm so sánh ngày / giờ và định dạng đầu ra.

Dù sao, để có được trên đường đua của Làm It Right, nó là điều cần thiết để lưu trữ các thông tin múi giờ với thời gian . Nói cách khác, nhận ra rằng ngày / giờ 20130407 14:50vô nghĩa nếu không có (a) bao gồm cả phần bù UTC hiện tại của múi giờ (ghi chú 1) hoặc (b) đảm bảo rằng tất cả logic chèn các giá trị này trước tiên sẽ chuyển đổi thành phần bù cố định nhất định ( rất có thể là 0). Không có một trong hai điều đó, hai giá trị thời gian nhất định là không thể so sánh được và dữ liệu bị hỏng . (Nhân tiện, phương pháp thứ hai là chơi với lửa (chú thích 2) , nhân tiện, đừng làm vậy.)

Trong SQL Server 2008+, bạn có thể lưu trữ phần bù theo thời gian trực tiếp bằng cách sử dụng datetimeoffsetkiểu dữ liệu. (Để đầy đủ, vào năm 2005 và trước đó, tôi sẽ thêm một cột thứ hai để lưu trữ giá trị bù UTC hiện tại (tính bằng phút).)

Điều này giúp ứng dụng loại máy tính để bàn dễ dàng, vì các nền tảng này thường có cơ chế tự động chuyển đổi ngày / giờ + múi giờ thành giờ địa phương và sau đó định dạng cho đầu ra, tất cả dựa trên cài đặt khu vực của người dùng.

Đối với web, vốn là một kiến ​​trúc bị ngắt kết nối, ngay cả với dữ liệu phía sau được thiết lập đúng, nó phức tạp hơn vì bạn cần thông tin về máy khách để có thể thực hiện chuyển đổi và / hoặc định dạng. Điều này thường được thực hiện thông qua cài đặt tùy chọn người dùng (ứng dụng chuyển đổi / định dạng mọi thứ trước khi xuất) hoặc chỉ hiển thị những thứ có cùng định dạng cố định và bù múi giờ cho mọi người (đó là những gì nền tảng Stack Exchange hiện đang làm).

Bạn có thể thấy làm thế nào nếu dữ liệu back-end không được thiết lập đúng cách, rất nhanh nó sẽ trở nên phức tạp và khó tin. Tôi không khuyên bạn nên đi xuống bất kỳ con đường nào trong số đó vì bạn sẽ gặp nhiều vấn đề hơn.

Lưu ý 1:

Độ lệch UTC của múi giờ không cố định: xem xét tiết kiệm ánh sáng ban ngày trong đó độ bù UTC của vùng thay đổi theo cộng hoặc trừ một giờ. Ngoài ra ngày tiết kiệm ánh sáng ban ngày của khu vực khác nhau trên cơ sở thường xuyên. Vì vậy, sử dụng datetimeoffset(hoặc tổng hợp local timeUTC offset at that time) cho kết quả phục hồi thông tin tối đa.

Lưu ý 2:

Đó là về việc kiểm soát dữ liệu đầu vào. Mặc dù không có cách nào để chứng thực các giá trị đến, nhưng tốt hơn hết là thực thi một tiêu chuẩn đơn giản không liên quan đến tính toán. Nếu API công khai mong đợi loại dữ liệu bao gồm phần bù, yêu cầu đó sẽ rõ ràng đối với người gọi.

Nếu đó không phải là trường hợp, người gọi phải dựa vào tài liệu (nếu họ đọc nó) hoặc tính toán được thực hiện không chính xác, v.v. Có ít chế độ lỗi / lỗi hơn khi yêu cầu bù, đặc biệt là cho hệ thống phân tán ( hoặc thậm chí chỉ web / cơ sở dữ liệu trên các máy chủ riêng biệt như trường hợp ở đây).

Lưu trữ phần bù dù sao cũng giết chết hai con chim bằng một hòn đá; và ngay cả khi điều đó không bắt buộc ngay bây giờ , nó sẽ giúp khả năng có sẵn sau này nếu cần thiết. Đúng là nó chiếm nhiều dung lượng hơn, nhưng tôi nghĩ rằng nó đáng để đánh đổi vì dữ liệu sẽ bị mất nếu nó không bao giờ được ghi lại ở vị trí đầu tiên.


3
Theo tôi hiểu, phần bù không giống như múi giờ ... thời gian được lưu trữ trong datetimeoffset mất thông tin như nhận thức về thời gian tiết kiệm ánh sáng ban ngày ... Thông tin thêm: stackoverflow.com/tags/timezone/info
Peter McEvoy

1
@PeterMcEvoy DST không có liên quan ở đây. datetimeoffsetcó nghĩa là "đây là giờ địa phương của người dùng / máy tính khi sự việc xảy ra" - chúng ta không cần biết liệu DST có hiệu lực hay không, bởi vì phần bù UTC đã cho luôn luôn ở đó (được nhúng trong datetimeoffsetgiá trị).
Đại

12

Tôi đã phát triển một giải pháp toàn diện để chuyển đổi múi giờ trong SQL Server. Xem Hỗ trợ múi giờ của SQL Server trên GitHub .

Nó xử lý đúng các chuyển đổi giữa các múi giờ và đến và từ UTC, bao gồm cả thời gian tiết kiệm ánh sáng ban ngày.

Khái niệm này tương tự như giải pháp "Hộp công cụ T-SQL" được mô tả trong câu trả lời của quảng cáo, nhưng nó sử dụng múi giờ IANA / Olson / TZDB phổ biến hơn thay vì của Microsoft và nó bao gồm các tiện ích để duy trì dữ liệu dưới dạng bản phát hành mới của TZDB đi ra.

Ví dụ sử dụng (để trả lời OP):

SELECT Tzdb.UtcToLocal(sysutcdatetime(), 'Asia/Riyadh') as CurrentTimeInSaudiArabia

Xem phần đọc trên GitHub để biết thêm API và giải thích chi tiết.

Ngoài ra, lưu ý rằng vì đây là giải pháp dựa trên UDF, nên nó không được thiết kế với hiệu suất làm mục tiêu chính. Sẽ vẫn tốt hơn nếu chức năng này được tích hợp vào SQL Server, tương tự như cách CONVERT_TZchức năng tồn tại trong Oracle và MySQL.


6

SQL Server đã thực hiện các sửa đổi vào năm 2005 trở đi trong đó múi giờ bên trong được lưu trong UTC. Điều này phần lớn là do sao chép địa lý và máy chiếu HA liên quan đến vận chuyển nhật ký và việc lưu thời gian vận chuyển nhật ký ở các múi giờ khác nhau khiến phương thức cũ không thể khôi phục chúng.

Do đó, việc lưu mọi thứ nội bộ trong thời gian UTC cho phép SQL Server hoạt động tốt trên toàn cầu. Đây là một trong những lý do tại sao tiết kiệm ánh sáng ban ngày là một vấn đề khó giải quyết trong Windows, bởi vì các sản phẩm MS khác như Outlook cũng lưu ngày / giờ trong nội bộ như UTC và tạo ra một phần bù cần được vá.

Tôi làm việc trong một công ty nơi chúng tôi có hàng ngàn máy chủ (không phải máy chủ MS SQL, nhưng tất cả các loại máy chủ) trải rộng trên toàn thế giới và nếu chúng tôi không ép buộc mọi thứ phải đi theo UTC, tất cả chúng tôi sẽ phát điên rất nhanh.


5

Tôi đã phát triển và xuất bản dự án Hộp công cụ T-SQL trên T-SQL trên codeplex để giúp bất kỳ ai đấu tranh với việc xử lý datetime và múi giờ trong SQL Server. Đó là nguồn mở và hoàn toàn miễn phí sử dụng.

Nó cung cấp các UDF chuyển đổi thời gian dễ dàng bằng cách sử dụng T-SQL đơn giản với các bảng cấu hình bổ sung ngoài hộp.

Trong ví dụ của bạn, bạn có thể sử dụng mẫu sau:

SELECT [DateTimeUtil].[UDF_ConvertLocalToLocalByTimezoneIdentifier] (
    'GMT Standard Time', -- the original timezone in which your datetime is stored
    'Middle East Standard Time', -- the target timezone for your user
    '2014-03-30 01:55:00' -- the original datetime you want to convert
)

Điều này sẽ trả về giá trị datetime đã chuyển đổi cho người dùng của bạn.

Có thể tìm thấy danh sách tất cả các múi giờ được hỗ trợ trong bảng "DateTimeUtil.Timezone" trong cơ sở dữ liệu Hộp công cụ T-SQL.


Một bộ công cụ như vậy dường như sẽ giúp ích rất nhiều cho nhà phát triển. Tuy nhiên, một hàm vô hướng là một hộp đen cho trình tối ưu hóa truy vấn. Điều đó có nghĩa là khi tôi áp dụng hàm của bạn cho một cột, các bảng cấu hình mà bạn đang đề cập sẽ được nhấn nhiều lần vì có các hàng trong tập kết quả (giả sử tôi chỉ sử dụng hàm trong mệnh đề SELECT). Đó không phải là một viễn cảnh tốt đẹp về hiệu suất. Tuy nhiên, tôi chưa thực sự kiểm tra bộ công cụ của bạn, vì vậy tôi không thể chắc chắn, đó chỉ là mối quan tâm chung dựa trên những gì tôi biết.
Andriy M

Chắc chắn, bạn đã đúng từ góc độ hiệu suất. Các bảng truy vấn UDF không được thiết kế cho các hoạt động dữ liệu hàng loạt, nhưng để sử dụng dễ dàng. Tuy nhiên, họ thực hiện khá ok lên tới khoảng 100.000 hồ sơ trên máy của tôi.
ADSS

2
Nếu một người phải xử lý nhiều hồ sơ hơn trong trường hợp sử dụng của mình và vấn đề về hiệu suất, bạn nên nghĩ đến việc duy trì dữ liệu được tính toán trước. Nhưng ngay cả sau đó, các UDF này có thể giúp duy trì các giá trị thời gian trong các múi giờ cần thiết.
ADSS

Từ quan điểm của tôi, vấn đề này không phải là về hiệu suất, và nhiều hơn về việc chỉ có các chức năng cơ bản trong đó. Để có thể trả về thông tin chính xác từ một truy vấn là điều đầu tiên. Làm việc với một số bảng tạm thời để lưu trữ mọi thứ và sau đó tham khảo trong truy vấn hoặc tuy nhiên bạn xử lý nó để cải thiện hiệu suất đi kèm.
Hành động Dan

1

Tôi có thể thiếu một cái gì đó rõ ràng, nhưng nếu tất cả những gì bạn muốn làm là hiển thị ngày bằng định dạng ngôn ngữ và múi giờ của người dùng, cách đơn giản nhất là luôn lưu trữ ngày trong UTC trong cơ sở dữ liệu và để ứng dụng khách chuyển đổi từ UTC sang cục bộ múi giờ và sử dụng cài đặt khu vực người dùng để định dạng ngày phù hợp.

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.