Как конвертировать местное время в UTC время в Delphi XE2? и как преобразовать его обратно из UTC в местное время?

Я использую Delphi xe2, и я пытаюсь сохранить записи с помощью UTC datetime в моей базе данных, а затем восстановить его, когда клиент читает его в своем локальном datetime ? есть идеи, как это сделать?

4 ответов


Это функция, которую я использую для преобразования из UTC в местное.

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;

как вы можете видеть, функция преобразует время даты UTC следующим образом:

  • время даты - > системное время
  • системное время - > время файла
  • время файла - > локальное время файла (это преобразование из UTC в локальный)
  • локальное время файла - > системное время
  • системное время - > время даты

Это должно быть очевидно, как чтобы обратить это вспять.


обратите внимание, что это преобразование рассматривает летнее время, как это теперь а не как это было в момент преобразования. The DateUtils.TTimeZone тип, введенный в XE, пытается сделать именно это. Код становится:

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

в другом направлении использовать ToUniversalTime.

этот класс, похоже, (свободно) смоделирован на .net TimeZone класса.

слова предупреждающий. Не ожидайте попытка учитывать летнее время в то время преобразуется, чтобы быть на 100% точным. Этого просто невозможно достичь. По крайней мере без машины времени. И это только учитывая времена в будущем. Даже времена в прошлом сложны. Раймонд Чен обсуждает этот вопрос здесь: почему летнее время неинтуитивно.


Как вы используете XE2, вы можете использовать System.DateUtils.TTimeZone.

вы можете проверить это хороший пост объясняя методы и как это работает и примеры : http://alex.ciobanu.org/?p=373


вы можете использовать TzSpecificLocalTimeToSystemTime и SystemTimeToTzSpecificLocalTime из 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;

Если ваш клиент использует локальное приложение Delphi, это можно сделать с помощью системных функций даты.

однако, если вы находитесь в среде клиент / сервер (например, приложение Delphi является веб-сервером, и клиент получает только HTML-страницы), вам нужно преобразовать в локальное время пользователя по-разному. Сервер должен знать часовой пояс пользователя и преобразовывать его соответствующим образом.

также переход на летнее время может вызвать головную боль, если приложение должно преобразовать исторические данные-вам нужно знать, действовал ли DST для региона пользователя.

в этих случаях использовать тег база данных часовых поясов для Delphi может быть полезным.

TZDB предоставляет простую базу данных и специализированный класс часового пояса, который позволяет получить доступ ко всем часовым поясам, поддерживаемым базой данных часовых поясов проект.

Я не знал, что есть SystemTimeToTzSpecificLocalTime, но просто прочитал это Джон Скит предпочитает TZDB для обработки часового пояса.