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

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

Ответ 1

Это функция, которую я использую для преобразования из 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 в локальный)
  • Локальное время файла → системное время
  • Системное время → время

Должно быть очевидно, как отменить это.


Обратите внимание, что это преобразование учитывает переход на летнее время, как сейчас, а не как оно было/было в то время преобразовано. Тип DateUtils.TTimeZone, введенный в XE, пытается сделать именно это. Код будет выглядеть следующим образом:

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

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

Этот класс выглядит (свободно), смоделированным в классе .net TimeZone.

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

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

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

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

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

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

Я не знал, что есть SystemTimeToTzSpecificLocalTime, но просто прочитал, что Jon Skeet предпочитает TZDB для обработки часовых поясов.