DateTime-Lite
view release on metacpan or search on metacpan
t/10.timezone.t view on Meta::CPAN
# NOTE: Error handling: unknown arguments
subtest 'Error handling: unknown arguments' => sub
{
my $tz;
{
local $SIG{__WARN__} = sub{};
$tz = DateTime::Lite::TimeZone->new( name => 'UTC', Names => 'UTC' );
}
ok( !defined( $tz ), 'new(): unknown arg returns undef' );
like( DateTime::Lite::TimeZone->error . '', qr/unknown argument/i, 'new(): error mentions unknown argument' );
like( DateTime::Lite::TimeZone->error . '', qr/'Names'/, "new(): error names the offending key" );
# Valid args still work
$tz = DateTime::Lite::TimeZone->new( name => 'UTC' );
ok( defined( $tz ), 'new(): valid args still work' );
};
# NOTE: POSIX footer lookup for future dates beyond stored transitions
#
# The tz.sqlite3 DB has stored transitions only up to 2007 for NY and 1996 for
# Paris. Dates beyond those thresholds require the POSIX TZ string from the
# TZif footer (zones.footer_tz_string) to determine the correct offset and DST
# status.
subtest 'POSIX footer lookup' => sub
{
# Unix-to-RD epoch offset used internally by DateTime::Lite
my $U = 62_135_683_200;
my $ny = DateTime::Lite::TimeZone->new( name => 'America/New_York' );
my $paris = DateTime::Lite::TimeZone->new( name => 'Europe/Paris' );
my $tok = DateTime::Lite::TimeZone->new( name => 'Asia/Tokyo' );
my $syd = DateTime::Lite::TimeZone->new( name => 'Australia/Sydney' );
# Helper: fake DT object with a fixed RD seconds value
my $fake = sub
{
my $rd = shift( @_ );
return( bless( { _rd => $rd }, 'FakeDTForFooter' ) );
};
# Future UTC offset lookups via _lookup_span -> POSIX footer
is( $ny->offset_for_datetime( $fake->( timegm(0,0,12,15,0,126) + $U ) ),
-18000, 'NY 2026-01-15: winter EST (footer UTC lookup)' );
is( $ny->offset_for_datetime( $fake->( timegm(0,0,15,4,6,126) + $U ) ),
-14400, 'NY 2026-07-04: summer EDT (footer UTC lookup)' );
is( $ny->is_dst_for_datetime( $fake->( timegm(0,0,12,15,0,126) + $U ) ),
0, 'NY 2026-01-15: is_dst=0 (footer)' );
is( $ny->is_dst_for_datetime( $fake->( timegm(0,0,15,4,6,126) + $U ) ),
1, 'NY 2026-07-04: is_dst=1 (footer)' );
is( $ny->short_name_for_datetime( $fake->( timegm(0,0,12,15,0,126) + $U ) ),
'EST', 'NY 2026-01-15: abbr=EST (footer)' );
is( $ny->short_name_for_datetime( $fake->( timegm(0,0,15,4,6,126) + $U ) ),
'EDT', 'NY 2026-07-04: abbr=EDT (footer)' );
is( $paris->offset_for_datetime( $fake->( timegm(0,0,12,15,0,126) + $U ) ),
3600, 'Paris 2026-01-15: winter CET (footer)' );
is( $paris->offset_for_datetime( $fake->( timegm(0,0,15,4,6,126) + $U ) ),
7200, 'Paris 2026-07-04: summer CEST (footer)' );
is( $tok->offset_for_datetime( $fake->( timegm(0,0,12,15,0,126) + $U ) ),
32400, 'Tokyo 2026: JST +9h, no DST (footer)' );
is( $tok->is_dst_for_datetime( $fake->( timegm(0,0,12,15,0,126) + $U ) ),
0, 'Tokyo 2026: is_dst=0 (footer)' );
# DST boundary precision for NY 2026
# DST start: 2026-03-08 02:00 EST = 07:00 UTC
is( $ny->offset_for_datetime(
$fake->( timegm(0,0,6,8,2,2026) + $U ) ),
-18000, 'NY 2026-03-08 06:00Z: still EST (1h before DST start)' );
is( $ny->offset_for_datetime(
$fake->( timegm(0,0,7,8,2,2026) + $U ) ),
-14400, 'NY 2026-03-08 07:00Z: EDT (exactly at DST start)' );
# DST end: 2026-11-01 02:00 EDT = 06:00 UTC
is( $ny->offset_for_datetime(
$fake->( timegm(0,0,6,1,10,2026) + $U ) ),
-18000, 'NY 2026-11-01 06:00Z: EST (at DST end)' );
# Southern hemisphere: Australia/Sydney (DST in austral summer)
# AEST-10AEDT,M10.1.0,M4.1.0/3
is( $syd->offset_for_datetime( $fake->( timegm(0,0,12,15,0,126) + $U ) ),
39600, 'Sydney 2026-01-15: AEDT +11h (austral summer, footer)' );
is( $syd->is_dst_for_datetime( $fake->( timegm(0,0,12,15,0,126) + $U ) ),
1, 'Sydney 2026-01-15: is_dst=1 (austral summer, footer)' );
is( $syd->offset_for_datetime( $fake->( timegm(0,0,12,1,6,126) + $U ) ),
36000, 'Sydney 2026-07-02: AEST +10h (austral winter, footer)' );
is( $syd->is_dst_for_datetime( $fake->( timegm(0,0,12,1,6,126) + $U ) ),
0, 'Sydney 2026-07-02: is_dst=0 (austral winter, footer)' );
# Future local-time lookups via _lookup_span_local -> POSIX footer
my $dt_local_win = DateTime::Lite->new(
year => 2026,
month => 1,
day => 15,
hour => 12,
time_zone => 'floating',
);
my $dt_local_sum = DateTime::Lite->new(
year => 2026,
month => 7,
day => 4,
hour => 19,
time_zone => 'floating',
);
is( $ny->offset_for_local_datetime( $dt_local_win ),
-18000, 'NY 2026-01 local winter: EST (footer local lookup)' );
is( $ny->offset_for_local_datetime( $dt_local_sum ),
-14400, 'NY 2026-07 local summer: EDT (footer local lookup)' );
( run in 1.046 second using v1.01-cache-2.11-cpan-d8267643d1d )