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 ?
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:
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.
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;
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;
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With