Delphi TZDB Architecture

Understanding the pavkam/tzdb Library Wrapper
THE PROBLEM

Dependency Chaos

Relying on Windows for Time Zone logic is risky:

  • Outdated Registries: Users who don't run Windows Updates have old DST rules.
  • Inconsistent APIs: Windows IDs (e.g., "Pacific Standard Time") don't match standard IANA IDs (e.g., "America/Los_Angeles").
  • Portability: Windows logic doesn't map 1:1 to Linux/Android/iOS.
  • Support: "Samoa skipped a day in 2011" - old Windows versions break this.
BUILD PIPELINE
🌍

IANA Source

Raw files downloaded from IANA.

africa northamerica
⚙️

TZCompile

Delphi utility parses raw text and generates resource.

TZCompile.dpr
📦

Resource

Compressed binary data embedded in your exe.

TZDB.res
🚀

Your App

Reads internal resource, ignoring OS settings.

TBundledTimeZone
RUNTIME CONCEPTS

TBundledTimeZone

Important: This is a standalone class, not a descendant of TTimeZone. It mimics the API for familiarity.

Lookup by ID

Uses standard IANA strings ("Europe/Paris") which are consistent across all platforms and databases (Postgres, Mongo).

Self-Contained

When you update the library (recompile), you update the rules. You control the version, not Microsoft.

API Compatibility: Provides methods like ToLocalTime, ToUniversalTime, and GetUtcOffset that mirror standard Delphi logic, but operates on its own internal data structures.

Thread Safety: The resource reading is thread-safe, making it suitable for high-load server applications (e.g., DataSnap, RAD Server).

DELPHI USAGE

Example Implementation

uses
  System.DateUtils,
  TZDB; // The magic unit

var
  NY_Zone: TBundledTimeZone; // Specific type, not TTimeZone
  MyTime: TDateTime;
begin
  // 1. Get specific zones by IANA ID
  NY_Zone := TBundledTimeZone.GetTimeZone('America/New_York');

  // 2. Convert Time
  MyTime := Now; 
  WriteLn('NY Time: ' + 
    NY_Zone.ToLocalTime(MyTime).ToString);
    
  // 3. List all available zones
  for var ID in TBundledTimeZone.KnownTimeZones do
    WriteLn(ID);
    
  // 4. Clean up manually (since it's not owned by system)
  // (Though often cache handles lifecycle)
end;