2011. május 17., kedd

Convert local TDateTime to GMT/UTC


Problem/Question/Abstract:

Does anybody know of any API or component that will convert a local datetime into GMT/UTC, using the Windows settings?

Answer:

Solve 1:

function NowUTC: TDateTime;
var
  system_datetime: TSystemTime;
begin
  GetSystemTime(system_datetime);
  Result := SystemTimeToDateTime(system_datetime);
end;


Solve 2:

{ ... }
const
  MinsPerDay = 24 * 60;

function GetGMTBias: Integer;
var
  info: TTimeZoneInformation;
  Mode: DWord;
begin
  Mode := GetTimeZoneInformation(info);
  Result := info.Bias;
  case Mode of
    TIME_ZONE_ID_INVALID:
      RaiseLastOSError;
    TIME_ZONE_ID_STANDARD:
      Result := Result + info.StandardBias;
    TIME_ZONE_ID_DAYLIGHT:
      Result := Result + info.DaylightBias;
  end;
end;

function GMTNow: TDateTime;
begin
  Result := LocaleToGMT(Now);
end;

function LocaleToGMT(const Value: TDateTime): TDateTime;
begin
  Result := Value + (GetGMTBias / MinsPerDay);
end;

function GMTToLocale(const Value: TDateTime): TDateTime;
begin
  Result := Value - (GetGMTBias / MinsPerDay);
end;


Solve 3:

function MakeUTCTime(DateTime: TDateTime): TDateTime;
var
  TZI: TTimeZoneInformation;
begin
  case GetTimeZoneInformation(TZI) of
    TIME_ZONE_ID_STANDARD:
      begin
        Result := DateTime + (TZI.Bias / 60 / 24);
      end;
    TIME_ZONE_ID_DAYLIGHT:
      begin
        Result := DateTime + (TZI.Bias / 60 / 24) + TZI.DaylightBias;
      end
  else
    raise
      Exception.Create('Error converting to UTC Time. Time zone could not be determined.');
  end;
end;

It's probably worth pointing out that this function will only work if the source of the TDateTime being converted was the system clock on the local machine (rather than, say, a field in a database or disk file) and if the timezone hasn't changed (e.g. between daylight saving and standard time) since the date was recorded.

1 megjegyzés:

  1. I think this line is wrong:

    Result := DateTime + (TZI.Bias / 60 / 24) + TZI.DaylightBias;

    Should be:

    Result := DateTime + ((TZI.Bias+TZI.DaylightBias) / 60 / 24);

    Ron

    VálaszTörlés