Skip to content
Alexandru Ciobanu edited this page Nov 4, 2020 · 12 revisions

Checking the version of the database

Each distribution/version of TZDB contains a fully-compiled version of latest IANA database. To check the version that is included in a specific distribution of TZDB a method DbVersion is available:

uses TZDB;
begin
  WriteLn('This TZDB uses version ', TBundledTimeZone.DbVersion); 
end;

Obtaining an arbitrary time zone

The following code retrieves a time zone instance for Europe/Amsterdam. The instance needs to be freed after use if the constructor is used to create it (rather than the factory method).

var
  LAmsterdam: TBundledTimeZone;
begin
  LAmsterdam := TBundledTimeZone.Create('Europe/Amsterdam');
  ...
  ...
  LAmsterdam.Free;
end;

The same example but using a factory method for better caching support. In this case the instance must not be freed since it is cached internally.

var
  LAmsterdam: TBundledTimeZone;
begin
  LAmsterdam := TBundledTimeZone.GetTimeZone('Europe/Amsterdam');
  ...
  ...
end;

Enumerating the available time zones

The following example simply displays all time zones that are known to TZDB.

var
  LTZID: string;
begin
  // Write each time zone ID on the console 
  for LTZID in TBundledTimeZone.KnownTimeZones(true) do
    WriteLn(LTZID);
end;

❗️Note that true has been passed to KnownTimeZones method. This parameter controls whether aliases are included into the output. TZDB also includes a large number of aliases for each time zone ID. For example Australia/Darwin time zone has an alias of AUS Central Standard Time (Windows naming); and Etc/GMT+1 has an alias of GMT+1. The query operations automatically look up aliases so do not have to worry about them.

Converting local times

The following example shows a simple program that takes an arbitrary local time (in current time zone) and then displays the time as seen in Sydney, Australia.

var
  LSydney: TBundledTimeZone;
  LMadeUpLocalTime, LUniversalTime,
    LSydneyTime: TDateTime;
begin
  // Get the Sydney time zone 
  LSydney := TBundledTimeZone.GetTimeZone('Australia/Sydney');

  // Encode a local date/time value -- 14th March 2009 at 12:45:00 PM 
  LMadeUpLocalTime := EncodeDateTime(2009, 03, 14, 12, 45, 00, 00);

  // Find out what was the time in Sydney at that moment 
  LUniversalTime := TTimeZone.Local.ToUniversalTime(LMadeUpLocalTime);
  LSydneyTime := LSydney.ToLocalTime(LUniversalTime);

  WriteLn(Format('When in my time zone the time was %s, in Sydney it was %s.',
   [DateTimeToStr(LMadeUpLocalTime), DateTimeToStr(LSydneyTime)]));
end;

Advanced features

The example below shows how to use the GetYearBreakdown method to calculate the number of days observing the DST.

var
  LTZ: TBundledTimeZone;
  LSegments: TYearSegmentArray;
  LSegment: TYearSegment;
  LDays: Integer;
begin
  // Get the TZ and break a year into segments.
  LTZ := TBundledTimeZone.GetTimeZone('Europe/Paris');
  LSegments := LTZ.GetYearBreakdown(2019);

  // Iterate all segments to find the DST ones 
  // (yes, there might be multiple DSTs per year!):
  LDays := 0;
  for LSegment in LSegments do
  begin
    if LSegment.LocalType = lttDaylight then
      // Calculate the number of days between the start and the of the segment.
      Inc(LDays, DaysBetween(LSegment.EndsAt, LSegment.StartsAt)); 
  end;

  WriteLn('There are a total of ', LDays, ' DST days in time zone "', LTZ.ID, '".');
end;

The same can be achieved by using a set of helper methods:

var
  LTZ: TBundledTimeZone;
  LDays: Integer;
begin
  // Get the TZ and break a year into segments.
  LTZ := TBundledTimeZone.GetTimeZone('Europe/Paris');

  // A simpler form that takes care of some complexity but only works 
  // for simple time zones.
  if LTZ.HasDaylightTime(2019) then
    LDays := DaysBetween(LTZ.DaylightTimeEnd(2019), LTZ.DaylightTimeStart(2019))
  else 
    LDays := 0;
 
  WriteLn('There are a total of ', LDays, ' DST days in time zone "', LTZ.ID, '".');
end;

❗️Methods such as DaylightTimeEnd or StandardTimeStart etc. are unsafe for serious use as they will fail to account for time zones that have more than one DST.