Я использую Delphi xe2, и я пытаюсь хранить записи с использованием UTC datetime в моей базе данных и затем восстанавливать его, когда клиент читает его в своем локальном datetime? любая идея, как сделать это обратно обратное преобразование?
Как конвертировать локальное время в UTC в Delphi XE2? и как его вернуть с UTC по местному времени?
Ответ 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 для обработки часовых поясов.