Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert Local time to UTC time in Delphi? and how to convert it back from UTC to local time?

I'm using Delphi and I'm trying to store records using UTC datetime in my database and then restore it back when a client reads it in his local datetime ? any idea how to do this forth back conversion ?

like image 575
Dreamer64 Avatar asked Mar 22 '13 09:03

Dreamer64


4 Answers

This is the function that I use to convert from UTC to local.

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;

As you can see the function transforms the UTC date time as follows:

  • Date time -> system time
  • System time -> file time
  • File time -> local file time (this is the conversion from UTC to local)
  • Local file time -> system time
  • System time -> date time

It should be obvious how to reverse this.


Note that this conversion treats daylight saving as it is now rather than as it is/was at the time being converted. The DateUtils.TTimeZone type, introduced in XE, attempts to do just that. The code becomes:

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

In the other direction use ToUniversalTime.

This class appears to be (loosely) modelled on the .net TimeZone class.

A word of warning. Do not expect the attempt to account for daylight savings at the time being converted to be 100% accurate. It is simply impossible to achieve that. At least without a time machine. And that's just considering times in the future. Even times in the past are complex. Raymond Chen discusses the issue here: Why Daylight Savings Time is nonintuitive.

like image 188
David Heffernan Avatar answered Nov 04 '22 01:11

David Heffernan


you can use TzSpecificLocalTimeToSystemTime and SystemTimeToTzSpecificLocalTime from 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;
like image 26
bummi Avatar answered Nov 04 '22 01:11

bummi


In case somebody need an answer in 2020:

make sure to include

Uses 
System.DateUtils;

then for UTC

function GetUTC(dt: TDateTime): TDateTime;
begin
  result := TTimeZone.Local.ToUniversalTime(dt);
end;

and for Local Time

function GetLocalTime(dt: TDateTime):TDateTime;
begin
  result := TTimeZone.Local.ToLocalTime(dt);
end;
like image 12
Dreamer64 Avatar answered Nov 04 '22 01:11

Dreamer64


As you are using XE2, you can use the System.DateUtils.TTimeZone.

You can check this good post explaining the methods and how it works and examples : http://alex.ciobanu.org/?p=373

like image 10
Whiler Avatar answered Nov 04 '22 03:11

Whiler