delphiutcdelphi-12-athens

Convert any TDateTime to UTC when Timezone is known


This seems as if it should be a no-brainer. Here are the knowns. I know the datetime of a "ticket". I know its timezone because one of the properties of the Ticket is it's TimeZone as in PST/PDT,EST/EDT,CST/CDT,MST/MDT
So I have TicketTime and Ticket Timezone. TicketTime will not necessarily local to the computer that this code will run on so I can't use LocalTime. Windows should know whether it is DST/ST for any given date.

My client asks that we return all times as UTC time.

With the above, it shoudl be childs play to make this happen. But I can't get it figured out and I have not found an answer in here.

 uses
  SysUtils, DateUtils;

function ConvertToUTC(LocalDateTime: TDateTime; TimeZoneID: string): TDateTime;
var
  TZ: TTimeZone;
  UTCOffset: TTimeSpan;
begin
  // Get the time zone information
  if TimeZoneID = 'Local' then
    TZ := TTimeZone.Local
  else
    TZ := TTimeZone.Create(TimeZoneID);

  // Get the UTC offset for the given local datetime, considering DST
  UTCOffset := TZ.GetUTCOffset(LocalDateTime);
  
  // Adjust the local datetime to UTC
  Result := LocalDateTime - UTCOffset.TotalDays;
end;

procedure Test;
var
  LocalDateTime, UTCDateTime: TDateTime;
  TimeZoneID: string;
begin
  // Example local datetime
  LocalDateTime:= dtpLocal.DateTime; // DateTime of ticket
  
  // Specify the timezone ID (e.g., 'PST/PDT')
  TimeZoneID := 'PST/PDT';

  // Convert to UTC
  UTCDateTime := ConvertToUTC(LocalDateTime, TimeZoneID);
  
  // Output the result
  WriteLn('Local DateTime: ', DateTimeToStr(LocalDateTime));
  WriteLn('UTC DateTime: ', DateTimeToStr(UTCDateTime));
end;

begin
  Test;
end.

I found the above but it fails in multiple places. I have looked at TimeZoneInformation but cannot see how to pass in the Timezone or offset.

What I thought was a 10 minute script is leaving me like a ball in high weeds. Can I get a few lines to make this work?


Solution

  • It is simply

    // Adjust the local datetime to UTC
    
      Result := LocalDateTime - UTCOffset;
    

    =============================================

    To elaborate a little and answer amigojacks comment:

    TTimeSpan is a record which has a number of overloaded operators to allow you to interact with TDateTime records.

    The particular one I am using here is

    class operator subtract( const Left : TDateTime; Right : TTimeSpan ) : TDateTime;
    

    That makes the syntax I have shown perfectly legal and meaningful.