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

datetime so với datetimeoffset trong SQL Server:Sự khác biệt là gì?

Bài viết này nêu bật những điểm khác biệt chính giữa ngày giờ datetimeoffset kiểu dữ liệu trong SQL Server.

Cả hai kiểu dữ liệu đều được sử dụng để lưu trữ các giá trị ngày và giờ. Nhưng có sự khác biệt đáng kể giữa hai.

Có lẽ sự khác biệt rõ ràng nhất là datetimeoffset lưu trữ chênh lệch múi giờ, trong khi ngày giờ không.

Một điểm khác biệt quan trọng khác là datetimeoffset cho phép bạn chỉ định độ chính xác (lên đến 7 chữ số thập phân). Điều này có nghĩa là datetimeoffset các giá trị có thể khác nhau về kích thước lưu trữ của chúng, tùy thuộc vào độ chính xác đang được sử dụng.

Ngày giờ mặt khác, có kích thước và độ chính xác lưu trữ cố định.

Nói chung, bạn nên tránh sử dụng datetime trừ khi bạn có lý do chính đáng để sử dụng nó (chẳng hạn như hỗ trợ một hệ thống kế thừa). Ngoài ra, datetime2 loại đối sánh gần hơn so với datetimeoffset , vì vậy tốt hơn bạn nên sử dụng nó nếu bạn không cần chênh lệch múi giờ.

Dù bằng cách nào, đây là bảng so sánh ngày giờ datetimeoffset :

Tính năng datetimeoffset ngày giờ
Tuân thủ SQL (ANSI &ISO 8601) Không
Phạm vi ngày 0001-01-01 đến 9999-12-31 1753-01-01 đến 9999-12-31
Phạm vi thời gian 00:00:00 đến 23:59:59.9999999 00:00:00 đến 23:59:59.997
Độ dài ký tự tối thiểu 26 vị trí
tối đa 34 vị trí
tối thiểu 19 vị trí
tối đa 23 vị trí
Kích thước bộ nhớ 8 đến 10 byte, tùy thuộc vào độ chính xác *

* Cộng với 1 byte để lưu trữ độ chính xác trong một số trường hợp. Xem bên dưới để biết thêm thông tin.

8 byte
Độ chính xác 100 nano giây Được làm tròn đến gia số .000, .003 hoặc .007 giây
Độ chính xác phân số giây do người dùng xác định Không
Khoảng chênh lệch múi giờ -14:00 đến +14:00 Không có
Nhận biết và bảo toàn độ lệch múi giờ Không
Nhận biết tiết kiệm ánh sáng ban ngày Không Không

Ví dụ 1 - So sánh Cơ bản

Trong mọi trường hợp, đây là một ví dụ nhanh để chứng minh sự khác biệt cơ bản giữa datetime datetimeoffset .

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = @thedatetimeoffset;
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Kết quả:

+------------------------------------+-------------------------+
| datetimeoffset                     | datetime                |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.5555555 +07:30 | 2025-05-21 10:15:30.557 |
+------------------------------------+-------------------------+

Ở đây, tôi đã đặt ngày giờ biến thành cùng một giá trị với datetimeoffset Biến đổi. Điều này khiến giá trị được chuyển đổi thành datetime và sau đó chúng ta có thể sử dụng SELECT để xem giá trị của mỗi biến.

Trong trường hợp này, bộ datetimeoffset giá trị bao gồm chênh lệch múi giờ và 7 chữ số thập phân. Ngày giờ mặt khác, không bao gồm chênh lệch múi giờ và nó chỉ có 3 chữ số thập phân. Hơn nữa, chữ số phân số thứ ba của nó được làm tròn lên. Điều này là do độ chính xác của nó luôn được làm tròn đến các gia số .000, .003 hoặc .007 giây.

Ví dụ 2 - Đặt giá trị từ chữ viết chuỗi

Trong ví dụ trước, ngày giờ giá trị đã được chỉ định bằng cách đặt nó thành giá trị giống như bộ datetimeoffs giá trị. Khi chúng tôi làm điều đó, SQL Server thực hiện một chuyển đổi ngầm định để dữ liệu “khớp” với kiểu dữ liệu mới.

Nếu chúng tôi cố gắng chỉ định cùng một giá trị trực tiếp cho ngày giờ biến chúng tôi gặp lỗi:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = '2025-05-21 10:15:30.5555555 +07:30';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Kết quả:

Msg 241, Level 16, State 1, Line 5
Conversion failed when converting date and/or time from character string.

Điều này là do ngày giờ kiểu dữ liệu không hỗ trợ một chuỗi ký tự có độ lệch múi giờ. Ngoài ra, nó không hỗ trợ các ký tự chuỗi có nhiều hơn 3 chữ số thập phân.

Vì vậy, nếu chúng tôi loại bỏ độ lệch múi giờ, nhưng vẫn giữ tất cả các giây phân số, chúng tôi sẽ vẫn gặp lỗi:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = '2025-05-21 10:15:30.5555555';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Kết quả:

Msg 241, Level 16, State 1, Line 5
Conversion failed when converting date and/or time from character string.

Để làm cho nó hoạt động, chúng tôi cần chỉ định một giá trị có không quá 3 chữ số thập phân:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = '2025-05-21 10:15:30.555';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Kết quả:

+------------------------------------+-------------------------+
| datetimeoffset                     | datetime                |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.5555555 +07:30 | 2025-05-21 10:15:30.557 |
+------------------------------------+-------------------------+

Dù bằng cách nào, ngày giờ sẽ luôn giữ một giá trị khác với datetimeoffset , bởi vì nó không bao gồm chênh lệch múi giờ. Điều này sẽ đúng ngay cả khi chúng ta sử dụng cùng độ chính xác giây phân số và giá trị giây phân số.

Để chứng minh điều này, đây là điều sẽ xảy ra nếu chúng tôi chỉ định cùng một giá trị cho datetimeoffset :

DECLARE 
  @thedatetimeoffset datetimeoffset(3), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.123';
SET @thedatetime = '2025-05-21 10:15:30.123';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Kết quả:

+------------------------------------+-------------------------+
| datetimeoffset                     | datetime                |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.1230000 +00:00 | 2025-05-21 10:15:30.123 |
+------------------------------------+-------------------------+

Trong trường hợp này, datetimeoffset sử dụng thang điểm 3, cung cấp cho nó 3 chữ số thập phân (giống như datetime ). Điều này được thực hiện bằng cách sử dụng datetimeoffset (3) khi khai báo biến.

Tôi cũng đã thay đổi giây phân số để ngày giờ sẽ không làm tròn chúng (để cả hai giá trị chia sẻ chính xác cùng một phần phân số).

Bất kể, datetimeoffset vẫn thêm độ lệch múi giờ, được đặt thành giá trị mặc định của nó là +00:00.

Lưu ý rằng hệ thống của tôi hiển thị các số không ở cuối trên datetimeoffset ‘S phần thập phân, nhưng giá trị chỉ sử dụng 3 chữ số thập phân.

Ví dụ 3 - Kích thước bộ nhớ

Ngày giờ kiểu dữ liệu sử dụng 8 byte.

datetimeoffset kiểu dữ liệu sử dụng 8, 9 hoặc 10 byte, tùy thuộc vào độ chính xác của nó.

Do đó, bạn sẽ không tiết kiệm bất kỳ kích thước bộ nhớ nào bằng cách sử dụng datetime .

Tuy nhiên, nếu bạn chuyển đổi bộ datetimeoffs giá trị vào một hằng số nhị phân, nó sẽ thêm 1 byte để lưu trữ độ chính xác.

Đây là điều sẽ xảy ra nếu chúng tôi sử dụng DATALENGTH() hàm để trả về số byte được sử dụng cho mỗi giá trị của chúng ta:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = @thedatetimeoffset;
SELECT 
  DATALENGTH(@thedatetimeoffset) AS 'datetimeoffset',
  DATALENGTH(@thedatetime) AS 'datetime';

Kết quả

+------------------+------------+
| datetimeoffset   | datetime   |
|------------------+------------|
| 10               | 8          |
+------------------+------------+

Như mong đợi, 10 byte cho datetimeoffset và 8 byte cho datetime .

Nhưng nếu chúng tôi chuyển đổi chúng thành varbinary , chúng tôi nhận được những điều sau:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = @thedatetimeoffset;
SELECT 
  DATALENGTH(CAST(@thedatetimeoffset AS varbinary(16))) AS 'datetimeoffset',
  DATALENGTH(CAST(@thedatetime AS varbinary(16))) AS 'datetime';

Kết quả

+------------------+------------+
| datetimeoffset   | datetime   |
|------------------+------------|
| 11               | 8          |
+------------------+------------+

Một byte bổ sung được thêm vào datetimeoffset giá trị nhưng không theo ngày giờ giá trị. Điều này là do bộ datetimeoffset giá trị cần thêm một byte để lưu trữ độ chính xác (vì độ chính xác do người dùng xác định). Ngày giờ mặt khác giá trị có độ chính xác cố định, vì vậy không cần phải lưu trữ độ chính xác cùng với giá trị.

Nhiều nhà phát triển giả định rằng chuyển đổi thành varbinary là đại diện cho cách SQL Server thực sự lưu trữ các giá trị ngày và giờ. Tuy nhiên điều này chỉ đúng một phần.

Mặc dù đúng là SQL Server lưu trữ các giá trị ngày và giờ của nó ở dạng thập lục phân, nhưng giá trị hex đó không thực sự bao gồm độ chính xác khi lưu trữ datetimeoffset các giá trị. Điều này là do độ chính xác được bao gồm trong định nghĩa cột.

Để biết thêm chi tiết về cách lưu trữ kiểu dữ liệu này trong cơ sở dữ liệu, hãy xem Tìm hiểu về Kích thước Lưu trữ ‘datetimeoffset’ trong SQL Server.

Tôi nên sử dụng "datetime" hay "datetimeoffset"?

Nếu bạn cần bao gồm chênh lệch múi giờ, thì bạn sẽ cần sử dụng datetimeoffset . Nếu không, thì ngày giờ có thể đủ.

Tuy nhiên, Microsoft khuyên bạn nên sử dụng datetime2 cho công việc mới, vì nó có nhiều lợi ích so với datetime .

Xem datetime so với datetime2 để so sánh về các loại dữ liệu này.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. T-SQL - Bí danh sử dụng =so với as

  2. PIVOT trong sql 2005

  3. Đổi tên Kiểu dữ liệu do người dùng xác định trong SQL Server (T-SQL)

  4. Cách liệt kê tất cả các ràng buộc mặc định với các cột trong cơ sở dữ liệu SQL Server - Hướng dẫn sử dụng SQL Server / TSQL Phần 92

  5. Giới thiệu về SQL Server 2017