Có cách nào ngắn gọn hơn để chuyển đổi thời gian UTC thành ngày cục bộ không?


7

Tôi đang cố gắng viết một truy vấn mà các nhóm ghi lại dựa trên phần ngày cục bộ chỉ của trường thời gian UTC.

Ví dụ: nếu bảng của tôi chứa 10/19/2012 2:00:00, thì bảng đó sẽ được nhóm thành 10/18/2012, vì giờ địa phương của tôi là EST (-5h) và tôi chỉ quan tâm đến phần ngày của trường.

Tôi biết tôi chỉ có thể sử dụng DateAdd(day, DateDiff(day, 0, MyDate), 0)để lấy phần ngày chỉ từ trường datetime và tôi có thể sử dụng DateAdd(minute, DateDiff(minute, GetUtcDate(), GetDate()), MyUtcDate)để chuyển đổi một datetime UTC thành giờ ngày cục bộ.

Nhưng kết hợp cả hai là xúc phạm tôi nghiêm trọng.

Có cách nào tốt hơn cách này để chỉ lấy phần Ngày của trường UTC DateTime, được chuyển đổi thành giờ địa phương, trong SQL Server 2005 không?

  SELECT DateAdd(day, DateDiff(day, 0, DateAdd(minute, DateDiff(minute, GetUtcDate(), GetDate()), MyUtcDate)), 0)
       , Count(*)
    FROM MyTable
GROUP BY DateAdd(day, DateDiff(day, 0, DateAdd(minute, DateDiff(minute, GetUtcDate(), GetDate()), MyUtcDate)), 0)

Tôi không có câu trả lời, nhưng MINUTE phải đủ chi tiết.
Aaron Bertrand

Tôi không có năm 2005 để chơi, nhưng nó có hỗ trợ sử dụng CROSS APPLYđể bí danh một chức năng như thế này không?
JNK

@AaronBertrand Vâng, minutecó lẽ sẽ hoạt động tốt hơn second. Cập nhật câu hỏi của tôi :)
Rachel

@JNK Tôi nghĩ vậy, nhưng tôi không biết tôi sẽ làm CROSS APPLYgì :)
Rachel

SELECT FieldName FROM <table> CROSS APPLY (SELECT <calculation) AliasName(FieldName) GROUP BY FieldName
JNK

Câu trả lời:


6

Nếu bạn không phản đối việc có một chức năng làm công việc bẩn thỉu, điều này giúp làm cho câu lệnh sạch hơn:

CREATE FUNCTION LocalDateFromUTCTime
(
    @UTCDateTime datetime
)
RETURNS datetime
BEGIN
    DECLARE @diff int;
    SET @diff = datediff(hh,GetUTCDate(), GetDate());
    RETURN DATEADD(day, DATEDIFF(day, 0, DATEADD(hh, @diff, @UTCDateTime)),0);
END

Sau đó, bạn có thể làm một cái gì đó như:

SELECT dbo.LocalDateFromUTCTime(MyUTCDate), COUNT(*)
FROM MyTable
GROUP BY dbo.LocalDateFromUTCTime(MyUTCDate);

Tất nhiên, điều này làm cho tuyên bố không phải là SARGable.

Nếu tính khả dụng là mối quan tâm chính do số lượng lớn các bản ghi bạn có thể có, bạn có thể tạo chế độ xem cụ thể hóa với một chỉ mục trên trường được tính toán.


BIÊN TẬP:

Per @RichardThekiwi Khả năng SARG của câu lệnh cụ thể này không bị ảnh hưởng bởi việc sử dụng hàm vì hàm này không phải là một phần của một JOINhoặc một WHEREmệnh đề. Khi hàm được sử dụng, nó được chạy sau khi bất kỳ chỉ mục nào được sử dụng.

CSONG, không phải đoạn mã trên sẽ cắt bớt bất kỳ phần thời gian nào của ngày nhập vào hàm (đây là theo thiết kế). Do đó, bất kỳ múi giờ nào thực hiện các phút như Đảo Hoàng tử Edward ở Canada (UTC -4: 30), Ấn Độ (UTC -4: 30) và Kathmandu (UTC +5: 45)


3
NHÓM THEO và CHỌN ở đây được thực hiện sau tìm kiếm, vì vậy SARGability không thực sự đáng quan tâm, IMHO. BTW, bạn có biết rằng có 1/2 giờ bước để múi giờ (khá thường xuyên) và sử dụng ở Kathmandu UTC/GMT +5:45không?
孔夫子

Cảm ơn bạn đã làm rõ - chức năng của bạn sẽ chỉ ảnh hưởng đến tính khả dụng nếu nó là một phần của mệnh đề WHERE hoặc được sử dụng bởi THAM GIA. Và, không, tôi đã không nghĩ về múi giờ với độ phân giải phút.
Max Vernon

3

Thông thường, tôi sử dụng biểu thức này

CAST(LEFT(GetDate() - GetUtcDate() + MyUtcDate, 11) AS DATETIME)

Nhưng trên SQL Server 2008, điều đó đơn giản hóa thành

CAST(GetDate() - GetUtcDate() + MyUtcDate AS DATE)

Khác với việc đưa ra các biểu thức thay thế ở đây, nếu bạn là người thuần túy T-SQL kết hợp với các hàm DATE để thao tác dữ liệu, tôi không nghĩ có cách nào ngắn gọn hơn để lấy thời gian cục bộ ngoài việc sử dụng hàm vô hướng (như Max đã hiển thị hoặc Hàm CLR).

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.