NAME
DateTime::Lite::TimeZone - Lightweight timezone support for DateTime::Lite
SYNOPSIS
use DateTime::Lite::TimeZone;
my $tz = DateTime::Lite::TimeZone->new( name => 'Asia/Tokyo' ) ||
die( DateTime::Lite::TimeZone->error );
my $dt = DateTime::Lite->now( time_zone => $tz );
# Alias
my $tz2 = DateTime::Lite::TimeZone->new( name => 'US/Eastern' );
# Fixed offset
my $tz3 = DateTime::Lite::TimeZone->new( name => '+09:00' );
# Special zones
my $utc = DateTime::Lite::TimeZone->new( name => 'UTC' );
my $flt = DateTime::Lite::TimeZone->new( name => 'floating' );
# Single-argument shorthand
my $tz4 = DateTime::Lite::TimeZone->new( 'Europe/Paris' );
# Memory cache (three-layer: object + span + POSIX footer)
# Enable once at application start-up for best performance:
DateTime::Lite::TimeZone->enable_mem_cache;
# Or per-call:
my $tz5 = DateTime::Lite::TimeZone->new(
name => 'America/New_York',
use_cache_mem => 1,
);
DateTime::Lite::TimeZone->disable_mem_cache; # disables and clears
DateTime::Lite::TimeZone->clear_mem_cache; # clears without disabling
# Offset and DST queries
use DateTime::Lite;
my $dt = DateTime::Lite->now( time_zone => $tz );
my $offset_secs = $tz->offset_for_datetime( $dt ); # e.g. -18000
my $local_off = $tz->offset_for_local_datetime( $dt ); # from wall-clock time
my $is_dst = $tz->is_dst_for_datetime( $dt ); # 1 or 0
my $abbr = $tz->short_name_for_datetime( $dt ); # e.g. "EDT"
printf "%s", $tz->offset_as_string( $offset_secs ); # "-0500"
printf "%s", $tz->offset_as_string( $offset_secs, ':' ); # "-05:00"
# Parse an offset string to seconds:
my $secs = DateTime::Lite::TimeZone->offset_as_seconds( '-05:00' ); # -18000
# Zone metadata
$tz->name; # canonical name, e.g. "America/New_York"
$tz->is_olson; # 1 if an IANA named zone
$tz->is_utc; # 1 if UTC
$tz->is_floating; # 1 if floating
$tz->has_dst; # 1 if zone ever observes DST
$tz->country_codes; # arrayref of ISO 3166-1 alpha-2 codes, e.g. ['US']
$tz->countries; # arrayref of hashrefs with full country data
$tz->coordinates; # e.g. "+404251-0740023"
$tz->comment; # free-text annotation from IANA data
$tz->latitude;
$tz->longitude;
$tz->tz_version; # IANA release string, e.g. "2026a"
$tz->tzif_version; # TZif binary format version (1, 2, 3, or 4)
$tz->footer_tz_string; # POSIX TZ string for recurring DST rules
$tz->transition_count;
$tz->type_count;
$tz->leap_count;
# Zone discovery
my $all = DateTime::Lite::TimeZone->all_names; # array reference
my @all = DateTime::Lite::TimeZone->all_names;
my $cats = DateTime::Lite::TimeZone->categories; # array reference
my @cats = DateTime::Lite::TimeZone->categories;
my $in_cat = DateTime::Lite::TimeZone->names_in_category('America'); # array reference
my @in_cat = DateTime::Lite::TimeZone->names_in_category('America');
my $in_cc = DateTime::Lite::TimeZone->names_in_country('JP'); # array reference
my @in_cc = DateTime::Lite::TimeZone->names_in_country('JP');
my $is_valid = DateTime::Lite::TimeZone->is_valid_name('Asia/Tokyo'); # 1
my $aliases = DateTime::Lite::TimeZone->aliases; # hashref alias => canonical
my %aliases = DateTime::Lite::TimeZone->aliases; # hash alias => canonical
my $links = $tz->links; # arrayref of alias names
# Database access (low-level)
my $path = DateTime::Lite::TimeZone->datafile; # path to tz.sqlite3
# Raw SQLite queries via public view methods (return DBI statement handles):
# $tz->zones, $tz->spans, $tz->transition, $tz->types,
# $tz->aliases, $tz->countries, $tz->leap_second, $tz->metadata
# Error handling
my $bad = DateTime::Lite::TimeZone->new( name => 'Mars/Olympus' );
if( !defined( $bad ) )
{
warn DateTime::Lite::TimeZone->error; # "Unknown time zone 'Mars/Olympus'"
}
$tz->fatal(1); # make errors die instead of warn+return undef
# Object context is detected even in errors, but allows the chain to unfold until the end to avoid the typical: "Can't call method "%s" on an undefined value"
# See https://perldoc.perl.org/perldiag#Can't-call-method-%22%25s%22-on-an-undefined-value
my $bad = DateTime::Lite::TimeZone->new( name => 'Mars/Olympus' )->name;
DESCRIPTION
DateTime::Lite::TimeZone is a drop-in replacement for DateTime::TimeZone designed to eliminate its heavy dependency and memory footprint.
DateTime::TimeZone loads 85 modules at startup, including the entire Specio, Params::ValidationCompiler, and Exception::Class stacks, simply to validate constructor arguments. DateTime::Lite::TimeZone replaces all of that with a single DBD::SQLite query against a compact bundled database (tz.sqlite3).
You may also be interested in the Unicode CLDR (Common Locale Data Repository) with the module Locale::Unicode::Data, which provides richer timezone information, such as metazones, regions, and historical timezone data.
For example:
my $cldr = Locale::Unicode::Data->new;
my $ref = $cldr->timezone( timezone => 'Asia/Tokyo' );
This would return an hash reference with the following information:
{
timezone_id => 281,
timezone => 'Asia/Tokyo',
territory => 'JP',
region => 'Asia',
tzid => 'japa',
metazone => 'Japan',
tz_bcpid => 'jptyo',
is_golden => 1,
is_primary => 0,
is_preferred => 0,
is_canonical => 0,
}
You can also returns all the timezones for a country code:
my $array_ref = $cldr->timezones( territory => 'US' );
Would return 55 results, such as:
{
alias => [qw( America/Atka US/Aleutian )],
is_canonical => 1,
is_golden => 1,
is_preferred => 0,
is_primary => 0,
metazone => "Hawaii_Aleutian",
region => "America",
territory => "US",
timezone => "America/Adak",
timezone_id => 55,
tz_bcpid => "usadk",
tzid => "haal",
}
You can also get the localised city name for a time zone:
my $ref = $cldr->timezone_city(
locale => 'de',
timezone => 'Asia/Tokyo',
);
which would return:
{
tz_city_id => 7486,
locale => 'de',
timezone => 'Asia/Tokyo',
city => 'Tokio',
alt => undef,
}
And if you want to access historical information:
my $ref = $cldr->timezone_info(
timezone => 'Europe/Simferopol',
start => '1994-04-30T21:00:00',
);
which would return:
{
tzinfo_id => 594,
timezone => 'Europe/Simferopol',
metazone => 'Moscow',
start => '1994-04-30T21:00:00',
until => '1997-03-30T01:00:00',
}
or, maybe:
my $ref = $cldr->timezone_info(
timezone => 'Europe/Simferopol',
start => ['>1992-01-01', '<1995-01-01'],
);
This is handy if you do not know the exact date, and want to provide a range instead.
Database schema
The bundled tz.sqlite3 uses the following main tables:
aliases-
Alias-to-zone_id FK mappings (such as
US/EasterntoAmerica/New_York) metadata-
Key/value pairs including the tzdata version
spans-
Pre-computed time spans derived from transitions and types, indexed for fast range lookup
types-
Local time type records from the TZif files
zones-
Canonical IANA zone names with country codes and coordinates
Fallback mode
If DBD::SQLite is not available, or the bundled tz.sqlite3 cannot be found, DateTime::Lite::TimeZone falls back transparently to DateTime::TimeZone and emits a one-time warning, if warning is permitted.
If DateTime::TimeZone is not available, then it dies.
CONSTRUCTOR
new
my $zone = DateTime::Lite::TimeZone->new( 'Asia/Tokyo' );
my $zone = DateTime::Lite::TimeZone->new(
name => 'Asia/Tokyo',
fatal => 1, # Makes all error fatal
);
A new DateTime::Lite::TimeZone object can be instantiated by either passing the timezone as a single argument, or as an hash, such as name => 'Asia/Tokyo'
Recognised forms:
- Named IANA timezones such as
America/New_York,Europe/Paris. - Aliases such as
US/Eastern,Japan. - Fixed-offset strings such as
+09:00,-0500. - The special names
UTC,floating, andlocal. -
The
localname instructsDateTime::Lite::TimeZoneto determine the system's local timezone automatically, without requiring any external modules. The detection strategy is OS-specific, relying on $^O:- Linux, macOS (darwin), FreeBSD, OpenBSD, NetBSD, Solaris, AIX, HP-UX, OS/2, Cygwin
-
Tries, in order:
$ENV{TZ}the
/etc/localtimesymlink target or a binary match against/usr/share/zoneinfo/etc/timezone(Debian/Ubuntu)/etc/TIMEZONEwith aTZ=line (Solaris, HP-UX)/etc/sysconfig/clockwith aZONE=orTIMEZONE=line (RedHat/CentOS)/etc/default/initwith aTZ=line (older Unix)
- Windows (MSWin32, NetWare)
-
Tries
$ENV{TZ}first, then reads the timezone name from the Windows Registry (SYSTEM/CurrentControlSet/Control/TimeZoneInformation) and maps it to an IANA name using the CLDRwindowsZones.xmltable. RequiresWin32::TieRegistry(available on CPAN; not a hard dependency). - Android
-
Tries
$ENV{TZ}, thengetprop persist.sys.timezone, then falls back toUTC. - VMS
-
Checks the environment variables
TZ,SYS$TIMEZONE_RULE,SYS$TIMEZONE_NAME,UCX$TZ, andTCPIP$TZ. - Symbian, EPOC, MS-DOS, Mac OS 9 and earlier
-
Checks
$ENV{TZ}only.
If the local timezone cannot be determined, an error is set and
undefis returned in scalar context, or an empty list in list context. In chaining (object context), it returns a dummy object (DateTime::Lite::Null) to avoid the typicalCan't call method '%s' on an undefined value.
An optional use_cache_mem => 1 argument activates the process-level memory cache for this call. When set, subsequent calls with the same zone name (or its alias) return the cached object without a database query. See "MEMORY CACHE" for details and for the class-level "enable_mem_cache" alternative.
# Each of these hits the cache after the first construction:
my $tz = DateTime::Lite::TimeZone->new(
name => 'America/New_York',
use_cache_mem => 1,
);
Returns the new object on success. On error, sets the exception object with error() and returns undef in scalar context, or an empty list in list context. In method-chaining (object) context, returns a DateTime::Lite::NullObject to avoid the error Can't call method '%s' on an undefined value. At the end of the chain, undef or an empty list will still be returned though.
MEMORY CACHE
By default, each call to "new" constructs a fresh object with a SQLite query. For applications that construct DateTime::Lite::TimeZone objects repeatedly with the same zone name, a three-layer cache is available.
Layer 1 - Object cache: When enabled, the second and subsequent calls for the same zone name return the original object directly from a hash, bypassing the database entirely.
Layer 2 - Span cache: Each cached TimeZone object stores the last matched UTC and local time span. Calls to offset_for_datetime and offset_for_local_datetime skip the SQLite query when the timestamp falls within the cached span's [utc_start, utc_end) or [local_start, local_end) range.
Layer 3 - POSIX footer cache: For zones where current dates are governed by a recurring DST rule (POSIX TZ footer string), the result of the footer calculation is cached by calendar day. DST transitions happen twice a year; on all other days the cached result is returned without re-evaluating the rule.
Together these three layers reduce the per-call cost of DateTime::Lite->new( time_zone => 'America/New_York' ) from ~430 µs to ~25 µs, putting it on par with DateTime.
Cache entries are keyed by the name passed to "new", plus the canonical name (after alias resolution). Both US/Eastern and America/New_York therefore map to the same cached object.
Cached objects are immutable in normal use. All public accessors are read-only, so sharing an object across callers is safe.
enable_mem_cache
Class method. Activates the memory cache for all subsequent "new" calls.
DateTime::Lite::TimeZone->enable_mem_cache;
# Every new() call now hits the cache after the first construction:
my $tz = DateTime::Lite::TimeZone->new( name => 'America/New_York' );
my $tz2 = DateTime::Lite::TimeZone->new( name => 'America/New_York' );
# $tz and $tz2 are the same object
Equivalent to passing use_cache_mem => 1 on every "new" call, but more convenient when you want the cache active for the lifetime of the process. Returns the class name to allow chaining.
disable_mem_cache
Class method. Disables the memory cache and clears all cached entries. Subsequent "new" calls will construct fresh objects.
DateTime::Lite::TimeZone->disable_mem_cache;
Returns the class name.
clear_mem_cache
Class method. Empties the cache without disabling it. The next "new" call for any zone name will re-query the database and re-populate the cache.
Useful if the tz.sqlite3 database has been replaced at runtime (an unusual operation):
DateTime::Lite::TimeZone->clear_mem_cache;
Returns the class name.
METHODS
aliases
# Checking for errors too
my $aliases = DateTime::Lite::TimeZone->aliases ||
die( DateTime::Lite::TimeZone->error );
my( %aliases ) = DateTime::Lite::TimeZone->aliases ||
die( DateTime::Lite::TimeZone->error );
my $aliases = $zone->aliases ||
die( $zone->error );
my( %aliases ) = $zone->aliases ||
die( $zone->error );
This can be called as an instance method, or as a class function.
This returns a hash of all the zones aliases (the old, deprecated names) to their corresponding canonical names.
For example:
Japan -> Asia/Tokyo
In scalar context, it returns an hash reference, and in list context, it returns an hash.
If an error occurred, this sets an exception object, and returns undef in scalar context, and an empty list in list context. The exception object can then be retrieved with "error"
all_names
# Checking for errors too
my $names = DateTime::Lite::TimeZone->all_names ||
die( DateTime::Lite::TimeZone->error );
my( @names ) = DateTime::Lite::TimeZone->all_names ||
die( DateTime::Lite::TimeZone->error );
my $names = $zone->all_names ||
die( $zone->error );
my( @names ) = $zone->all_names ||
die( $zone->error );
This can be called as an instance method, or as a class function.
This returns a list of all the time zone names sorted alphabetically. This list does not include zone alias (a.k.a. "links").
In scalar context, it returns an array reference, and in list context, it returns an array.
If an error occurred, this sets an exception object, and returns undef in scalar context, and an empty list in list context. The exception object can then be retrieved with "error"
categories
# Checking for errors too
my $categories = DateTime::Lite::TimeZone->categories ||
die( DateTime::Lite::TimeZone->error );
my( @categories ) = DateTime::Lite::TimeZone->categories ||
die( DateTime::Lite::TimeZone->error );
my $categories = $zone->categories ||
die( $zone->error );
my( @categories ) = $zone->categories ||
die( $zone->error );
This can be called as an instance method, or as a class function.
This returns a list of all time zone categories. A category is the part, if any, that precedes the forward slash of a zone name. For example, in Asia/Tokyo, the category would be Asia. However, with the special zone Factory, there would not be any category.
In scalar context, it returns an array reference, and in list context, it returns an array.
If an error occurred, this sets an exception object, and returns undef in scalar context, and an empty list in list context. The exception object can then be retrieved with "error"
category
my $zone = DateTime::Lite::TimeZone->new( name => "Asia/Tokyo" );
say $zone->category; # Asia
my $zone = DateTime::Lite::TimeZone->new( name => "UTC" );
say $zone->category; # undef
Returns the part of the time zone name before the first slash, such as Asia in Asia/Tokyo
comment
Returns the optional zone comment from zone1970.tab, such as "Mountain Time - south Idaho and east Oregon".
Returns undef in scalar context, or an empty list in list context if no comment is recorded.
coordinates
Returns the compact coordinate string from zone1970.tab, such as +3518+13942 for Tokyo. Returns undef in scalar context, or an empty list in list context when there are no coordinates, such as UTC, floating, and fixed-offset zones.
country_codes
Returns an arrayref of ISO 3166-1 alpha-2 country codes associated with this timezone, such as ["JP"] or ["US","CA"].
Returns undef in scalar context, or an empty list in list context when the timezone has no countries associated, such as UTC, floating, and fixed-offset zones.
countries
# Checking for errors too
my $countries = DateTime::Lite::TimeZone->countries ||
die( DateTime::Lite::TimeZone->error );
my( @countries ) = DateTime::Lite::TimeZone->countries ||
die( DateTime::Lite::TimeZone->error );
my $countries = $zone->countries ||
die( $zone->error );
my( @countries ) = $zone->countries ||
die( $zone->error );
This can be called as an instance method, or as a class function.
This returns a list of all the ISO 3166 2-letters country codes sorted alphabetically, and in lower-case. Those codes can be used to call "names_in_country".
In scalar context, it returns an array reference, and in list context, it returns an array.
If an error occurred, this sets an exception object, and returns undef in scalar context, and an empty list in list context. The exception object can then be retrieved with "error"
If you want to convert a country to its locale name, you can use the Unicode CLDR database designed specifically for this.
For example, using the locale en:
use Locale::Unicode::Data;
my $cldr = Locale::Unicode::Data->new;
my $ref = $cldr->territory_l10n( locale => 'en', territory => 'JP', alt => undef );
# Returns an hash reference like this:
{
terr_l10n_id => 13385,
locale => 'en',
territory => 'JP',
locale_name => 'Japan',
alt => undef,
}
And, if you want to look up the ISO3166 code based on the locale country name, you could do something like this. Here we search for the country code matching アメリカ, which is America in Japanese:
use strict;
use warnings;
use utf8;
use open ':std' => ':utf8';
use Data::Pretty qw( dump );
use Locale::Unicode::Data;
my $cldr = Locale::Unicode::Data->new;
my $all = $cldr->territories_l10n( locale => 'ja' );
foreach my $ref ( @$all )
{
if( $ref->{locale_name} =~ /アメリカ/ &&
$ref->{territory} =~ /^[A-Z]{2}$/ ) # Because a territory, in Unicode CLDR, can also be a 3-digits code
{
say dump( $ref );
}
}
which would produce something like this:
{
alt => undef,
locale => "ja",
locale_name => "アメリカ合衆国",
terr_l10n_id => 26334,
territory => "US",
}
datafile
Returns the absolute path to the bundled tz.sqlite3 database file.
designation_charcount
Returns the total size of abbreviation string table (in bytes).
This is equivalent to TZif header field charcnt, including trailing NUL bytes.
error
my $ex = $zone->error;
Returns the last exception object, if any.
fatal
Sets or gets the fatal property for this object.
When enabled, any error will trigger a fatal exception and call "die" in perlfunc
footer_tz_string
Returns the footer portion of the timezone.
has_dst
This is an alias for "has_dst_changes"
has_dst_changes
Returns true if the timezone observes daylight saving time transitions.
is_canonical
my $zone = DateTime::Lite::TimeZone->new( 'Japan' );
say $zone->is_canonical; # false
my $zone = DateTime::Lite::TimeZone->new( 'Asia/Tokyo' );
say $zone->is_canonical; # true
Returns true if the timezone name provided is a canonical one, false otherwise.
is_dst_for_datetime( $dt )
Returns true if $dt falls within a DST period for this timezone.
is_floating
Returns true for the special floating timezone.
is_olson
Returns true for IANA/Olson-sourced timezones.
is_utc
Returns true for the UTC timezone and for fixed-offset +0000.
is_valid_name
say DateTime::Lite::TimeZone->is_valid_name( 'Singapore' ); # true
say $zone->is_valid_name( 'Singapore' ); # true
say DateTime::Lite::TimeZone->is_valid_name( 'Paris' ); # false
say $zone->is_valid_name( 'Paris' ); # false
say DateTime::Lite::TimeZone->is_valid_name( 'Asia/Seoul' ); # true
say $zone->is_valid_name( 'Asia/Seoul' ); # true
This takes a canonical timezone or a timezone alias, and returns true if the value provided is valid, or false otherwise.
This sets an exception object, an returns an error only if no value was provided, so you may want to check if the value returned is defined.
Contrary to DateTime::TimeZone, passin a DateTime::TimeZone::Alias does not make that zone valid. This class, adhere strictly to the IANA time zones.
isstd_count
Returns the number of standard time (a.k.a "standard/wall") indicators.
This "must either be zero or equal to "typecnt".
isut_count
Returns the number of UT/local time indicators.
This "must either be zero or equal to "typecnt".
latitude
Returns the latitude for this zone, as a real number, if any.
links
This is an alias for "aliases"
longitude
Returns the longitude for this zone, as a real number, if any.
name
my $zone = DateTime::Lite::TimeZone->new( name => 'Japan' );
say $zone->name; # Asia/Tokyo
Returns the canonical timezone name, such as Asia/Tokyo.
This means that if you provide an alias upon instantiation, it will be resolved, and accessible with this method.
names_in_category
# Checking for errors too
my $names = DateTime::Lite::TimeZone->names_in_category( 'Asia' ) ||
die( DateTime::Lite::TimeZone->error );
my( @names ) = DateTime::Lite::TimeZone->names_in_category( 'Asia' ) ||
die( DateTime::Lite::TimeZone->error );
my $names = $zone->names_in_category( 'America' ) ||
die( $zone->error );
my( @names ) = $zone->names_in_category( 'America' ) ||
die( $zone->error );
This takes a category, which under this class means the left-hand side of the zone name, separated by a forward slash. So, with the example of Asia/Seoul, the category would be Asia.
With this category provided, this returns a list of the name on the left-hand side of the first forward slash.
For example:
For Asia/Taipei, the category would be Asia, and the list would return among the 74 results, the name Taipei.
For the category America, there would be 121 results, and of which Indiana/Vincennes whose full timezone is America/Indiana/Vincennes, would also be returned.
In scalar context, it returns an array reference, and in list context, it returns an array.
If an error occurred, this sets an exception object, and returns undef in scalar context, and an empty list in list context. The exception object can then be retrieved with "error"
names_in_country
# Checking for errors too
my $names = DateTime::Lite::TimeZone->names_in_country( 'US' ) ||
die( DateTime::Lite::TimeZone->error );
my( @names ) = DateTime::Lite::TimeZone->names_in_country( 'US' ) ||
die( DateTime::Lite::TimeZone->error );
my $names = $zone->names_in_country( 'US' ) ||
die( $zone->error );
my( @names ) = $zone->names_in_country( 'US' ) ||
die( $zone->error );
This takes a 2-letter ISO3166 country code, and returns a list of all the time zones associated with it.
This is case insensitive, so a country code provided, such as US or us would be treated equally.
In scalar context, it returns an array reference, and in list context, it returns an array.
If an error occurred, this sets an exception object, and returns undef in scalar context, and an empty list in list context. The exception object can then be retrieved with "error"
The order of the time zones returned is the same ones as set by IANA database.
offset_as_seconds
This takes an offset as a string, such as +09:00, and this returns the number of seconds represented by that offset either as a signed integer.
If no value was provided, or if that value is not comprised in the range -99:59:59 to +99:59:59, or, if the offset string provided does not match any of the following 2 patterns, then this sets an error object, and returns undef in scalar context or an empty list in list context.
The supported offset patterns are (sign defaults to + if absent):
- Colon form:
[+-]H:MM,[+-]HH:MM,[+-]HH:MM:SS -
The regular expression is:
\A([+-])?(\d{1,2}):(\d{2})(?::(\d{2}))?\zExamples:
+09:00,-02:00,9:0:0 - Compact form:
[+-]HHMM,[+-]HHMMSS -
The regular expression is:
/\A([+-])?(\d{2})(\d{2})(\d{2})?\z/Examples:
+0900,-0200,0900,+090000,090000 - The special string
"0"(returns0).
offset_as_string
say DateTime::Lite::TimeZone->offset_as_string(32400); # +0900
say DateTime::Lite::TimeZone->offset_as_string(32400, ':' ); # +09:00
say $zone->offset_as_string(32400); # +0900
say $zone->offset_as_string(32400, ':'); # +09:00
Class or instance method. This converts a numeric UTC offset in seconds to a formatted string such as +0900 (default) or +09:00 (with ':' as separator).
Drop-in compatible with "offset_as_string" in DateTime::TimeZone.
offset_for_datetime
my $offset = $zone->offset_for_datetime( $dt );
This takes a DateTime::Lite object, and returns the UTC offset in seconds applicable to that object.
Upon error, then this sets an error object, and returns undef in scalar context or an empty list in list context.
offset_for_local_datetime
my $offset = $zone->offset_for_local_datetime( $dt );
This takes a DateTime::Lite object, and returns the UTC offset in seconds given a local (wall-clock) time.
Used internally during timezone conversion.
Upon error, then this sets an error object, and returns undef in scalar context or an empty list in list context.
short_name_for_datetime
say $zone->short_name_for_datetime( $dt );
This takes a DateTime::Lite object, and returns the abbreviated timezone name applicable, such as JST or EDT.
transition_count
Returns the number of transitions record for this timezone.
Equivalent to TZif header field timecnt
type_count
Returns the number of types for this timezone.
tz_version
Returns the IANA tzdata version string from the database metadata table, such as 2026a.
tzif_version
Returns the timezone version string from the timezone data.
The possible values are 1, 2, 3 or 4
ERROR HANDLING
Upon error, this class methods sets an exception object, and return undef in scalar context, and an empty list in list context. The exception is accessible via:
my $err = DateTime::Lite::TimeZone->error; # class method
my $err = $tz->error; # instance method
The exception stringifies to a human-readable message including the source file and line number.
If the instance option fatal has been enabled, then any error triggered will be fatal.
EPOCH CONVENTION
The tz.sqlite3 database stores span boundaries as Unix seconds (seconds since 1970-01-01T00:00:00 UTC), matching the raw values from the TZif binary files. DateTime::Lite uses Rata Die seconds (seconds since 0001-01-01T00:00:00).
The conversion constant is:
UNIX_TO_RD = 62_135_683_200
All lookup methods subtract UNIX_TO_RD from $dt->utc_rd_as_seconds before querying the database. NULL span boundaries represent ±infinity (before the first recorded transition, and after the last).
BUILDING THE DATABASE
The bundled tz.sqlite3 is generated by running:
perl scripts/build_tz_database.pl [--verbose, --debug 3]
This fetches the latest tzcode and tzdata release from IANA, verifies the GPG signature, compiles it with zic(1), and populates the database. Run this script once per tzdata release, then commit the updated lib/DateTime/Lite/tz.sqlite3.
SQL SCHEMA
The SQLite SQL schema is available in the file scripts/cldr-schema.sql
The data are populated into the SQLite database using the script located in scripts/build_tz_database.pl and the data accessible from https://ftp.iana.org/tz/releases
The SQL schema used to create the SQLite database is available in the scripts directory of this distribution in the file tz_schema.sql
The tables used are as follows, in alphabetical order:
aliases
aliasA string field, case insensitive.
zone_idAn integer field.
countries
codeA string field, case insensitive.
nameA string field, case insensitive.
leap_second
leap_sec_idAn integer field.
zone_idAn integer field.
leap_indexAn integer field.
occurrence_timeAn integer field.
correctionAn integer field.
is_expirationA boolean field.
Defaults to false
metadata
keyA string field.
valueA string field.
spans
span_idAn integer field.
zone_idAn integer field.
type_idAn integer field.
span_indexAn integer field.
utc_startAn integer field.
utc_endAn integer field.
local_startAn integer field.
local_endAn integer field.
offsetAn integer field.
is_dstA boolean field.
Defaults to false
short_nameA string field, case insensitive.
transition
trans_idAn integer field.
zone_idAn integer field.
trans_indexAn integer field.
trans_timeAn integer field.
type_idAn integer field.
types
type_idAn integer field.
zone_idAn integer field.
type_indexAn integer field.
utc_offsetAn integer field.
is_dstA boolean field.
abbreviationA string field, case insensitive.
designation_indexAn integer field.
is_standard_timeA boolean field.
is_ut_timeA boolean field.
is_placeholderA boolean field.
Defaults to false
zones
zone_idAn integer field.
nameA string field, case insensitive.
canonicalA boolean field.
Defaults to true
has_dstA boolean field.
Defaults to false
countriesA string array field.
coordinatesA string field.
latitudeA real field.
longitudeA real field.
commentA string field.
tzif_versionAn integer field.
footer_tz_stringA string field.
transition_countAn integer field.
type_countAn integer field.
leap_countAn integer field.
isstd_countAn integer field.
isut_countAn integer field.
designation_charcountAn integer field.
categoryA string field, case insensitive.
subregionA string field, case insensitive.
locationA string field, case insensitive.
SEE ALSO
DateTime::Lite, DateTime::TimeZone, Locale::Unicode::Data
RFC 9636 (The Time Zone Information Format (TZif)) https://www.rfc-editor.org/rfc/rfc9636
Locale::Unicode::Data for historical data of time zones, metazones, and BCP47 time zones data.
AUTHOR
Jacques Deguest <jack@deguest.jp>
COPYRIGHT & LICENSE
Copyright(c) 2026 DEGUEST Pte. Ltd.
All rights reserved
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.