2013-03-22 34 views
10

Tôi đang sử dụng Delphi xe2 và tôi đang cố gắng lưu trữ hồ sơ bằng cách sử dụng datetime UTC trong cơ sở dữ liệu của tôi và sau đó khôi phục lại khi một khách hàng đọc nó trong datetime địa phương của mình? bất kỳ ý tưởng làm thế nào để làm điều này trở lại chuyển đổi?Làm thế nào để chuyển đổi thời gian địa phương để UTC thời gian trong Delphi XE2? và làm cách nào để chuyển đổi từ UTC sang giờ địa phương?

Trả lời

14

Đây là chức năng tôi sử dụng để chuyển đổi từ UTC sang địa phương.

function LocalDateTimeFromUTCDateTime(const UTCDateTime: TDateTime): TDateTime; 
var 
    LocalSystemTime: TSystemTime; 
    UTCSystemTime: TSystemTime; 
    LocalFileTime: TFileTime; 
    UTCFileTime: TFileTime; 
begin 
    DateTimeToSystemTime(UTCDateTime, UTCSystemTime); 
    SystemTimeToFileTime(UTCSystemTime, UTCFileTime); 
    if FileTimeToLocalFileTime(UTCFileTime, LocalFileTime) 
    and FileTimeToSystemTime(LocalFileTime, LocalSystemTime) then begin 
    Result := SystemTimeToDateTime(LocalSystemTime); 
    end else begin 
    Result := UTCDateTime; // Default to UTC if any conversion function fails. 
    end; 
end; 

Như bạn thấy chức năng biến đổi thời gian ngày UTC như sau:

  • ngày thời gian -> thời gian hệ thống
  • thời gian hệ thống -> Thời gian tập
  • thời gian File -> địa phương thời gian tệp (đây là chuyển đổi từ UTC sang địa phương)
  • Giờ tệp cục bộ -> giờ hệ thống
  • Giờ hệ thống -> ngày giờ

Nên rõ ràng cách đảo ngược điều này.


Lưu ý rằng chuyển đổi này xử lý tiết kiệm ánh sáng ban ngày vì nó là tại chứ không phải vì nó là/là vào thời điểm đó được chuyển đổi. Loại DateUtils.TTimeZone, được giới thiệu ở XE, cố gắng thực hiện điều đó. Mã trở thành:

LocalDateTime := TTimeZone.Local.ToLocalTime(UniversalDateTime); 

theo một hướng khác sử dụng ToUniversalTime.

Lớp này dường như được (lỏng lẻo) được mô hình hóa trên lớp .net TimeZone.

Một lời cảnh báo. Đừng mong đợi nỗ lực để tính tiền tiết kiệm ban ngày tại thời điểm được chuyển đổi thành chính xác 100%. Nó chỉ đơn giản là không thể đạt được điều đó. Ít nhất là không có cỗ máy thời gian.Và đó chỉ là xem xét thời gian trong tương lai. Ngay cả thời gian trong quá khứ cũng phức tạp. Raymond Chen thảo luận vấn đề ở đây: Why Daylight Savings Time is nonintuitive.

+4

chuyển đổi dữ liệu lịch sử sang dữ liệu cục bộ tại các khu vực có múi giờ tiết kiệm ánh sáng ban ngày cần xử lý đặc biệt – mjn

+0

@mjn Điều đó tùy thuộc vào yêu cầu. –

+0

Có một tham số được gọi là UTCDateTime, và một hàm có tên UTCDateTime, cả hai đều có cùng kiểu, làm cho đầu tôi bị tổn thương. Tôi nghĩ rằng mục đích sử dụng của bạn là sử dụng một hoặc cái khác, nhưng cách nó được trình bày, làm cho nó trông giống như LocalDateTimeFromUTCDateTime() muốn gọi hàm UTCDateTime, nhưng thực sự sẽ không, bởi vì nó sử dụng tham số UTCDateTime. Loại khó hiểu. –

1

Nếu khách hàng của bạn sử dụng ứng dụng Delphi cục bộ, điều này có thể được thực hiện với các chức năng ngày tháng của Hệ thống.

Tuy nhiên nếu bạn đang ở trong môi trường máy khách/máy chủ (ví dụ ứng dụng Delphi là máy chủ web và máy khách chỉ nhận các trang HTML), bạn cần phải chuyển đổi theo thời gian cục bộ của người dùng. Máy chủ cần biết múi giờ của người dùng và chuyển đổi một cách thích hợp.

Thời gian tiết kiệm ánh sáng ban ngày có thể gây đau đầu nếu ứng dụng cần chuyển đổi dữ liệu lịch sử - bạn cần biết liệu có hiệu ứng DST cho vùng của người dùng hay không.

Trong các trường hợp sử dụng này, Time Zone Database for Delphi có thể hữu ích.

TZDB cung cấp một cơ sở dữ liệu đơn giản và một lớp múi giờ chuyên dụng cho phép truy cập vào tất cả các múi giờ được hỗ trợ bởi dự án Time Zone Cơ sở dữ liệu .

Tôi không biết rằng có SystemTimeToTzSpecificLocalTime nhưng chỉ đọc Jon Skeet prefers TZDB để xử lý múi giờ.

9

Khi bạn đang sử dụng XE2, bạn có thể sử dụng System.DateUtils.TTimeZone.

Bạn có thể kiểm tra good post này giải thích các phương pháp và cách thức hoạt động và các ví dụ: http://alex.ciobanu.org/?p=373

9

bạn có thể sử dụng TzSpecificLocalTimeToSystemTime và SystemTimeToTzSpecificLocalTime từ kernel32.

var 
    Form1: TForm1; 

function TzSpecificLocalTimeToSystemTime(lpTimeZoneInformation: PTimeZoneInformation; var lpLocalTime, lpUniversalTime: TSystemTime): BOOL; stdcall; 
function SystemTimeToTzSpecificLocalTime(lpTimeZoneInformation: PTimeZoneInformation; var lpUniversalTime,lpLocalTime: TSystemTime): BOOL; stdcall; 

implementation 

function TzSpecificLocalTimeToSystemTime; external kernel32 name 'TzSpecificLocalTimeToSystemTime'; 
function SystemTimeToTzSpecificLocalTime; external kernel32 name 'SystemTimeToTzSpecificLocalTime'; 

{$R *.dfm} 


Function DateTime2UnivDateTime(d:TDateTime):TDateTime; 
var 
TZI:TTimeZoneInformation; 
LocalTime, UniversalTime:TSystemTime; 
begin 
    GetTimeZoneInformation(tzi); 
    DateTimeToSystemTime(d,LocalTime); 
    TzSpecificLocalTimeToSystemTime(@tzi,LocalTime,UniversalTime); 
    Result := SystemTimeToDateTime(UniversalTime); 

end; 

Function UnivDateTime2LocalDateTime(d:TDateTime):TDateTime; 
var 
TZI:TTimeZoneInformation; 
LocalTime, UniversalTime:TSystemTime; 
begin 
    GetTimeZoneInformation(tzi); 
    DateTimeToSystemTime(d,UniversalTime); 
    SystemTimeToTzSpecificLocalTime(@tzi,UniversalTime,LocalTime); 
    Result := SystemTimeToDateTime(LocalTime); 
end; 


procedure TForm1.Button1Click(Sender: TObject); 
var 

Date,Univdate,DateAgain:TDateTime; 

begin 
    Date := Now; 
    Univdate := DateTime2UnivDateTime(Date); 
    DateAgain := UnivDateTime2LocalDateTime(Univdate); 
    Showmessage(DateTimeToStr(Date) +#13#10 + DateTimeToStr(Univdate)+#13#10 + DateTimeToStr(DateAgain)); 
end; 
+0

Bạn có biết liệu SystemTimeToTzSpecificLocalTime có hỗ trợ thông tin thời gian tiết kiệm ánh sáng ban ngày "lịch sử" không, như tzdb? – mjn

+0

Chức năng SystemTimeToTzSpecificLocalTime có thể tính thời gian cục bộ không đúng theo các điều kiện sau: Múi giờ sử dụng chênh lệch UTC khác nhau cho năm cũ và năm mới. Thời gian UTC được chuyển đổi và giờ địa phương được tính toán là trong các năm khác nhau. http://msdn.microsoft.com/de-de/library/windows/desktop/ms724949(v=vs.85).aspx – bummi

+1

Có một lỗi nhỏ trong mã ở trên. Trong UnivDateTime2LocalDateTime, dòng DateTimeToSystemTime (d, LocalTime); nên đọc DateTimeToSystemTime (d, UniversalTime); –

Các vấn đề liên quan