Revision history for Perl distribution DateTime-Lite
v0.5.0 2026-04-16T15:26:07+0900
- Added the method resolve_abbreviation() in DateTime::Lite::TimeZone
- Corrected method _nearest_zone() to use $class instead of $self
- Implemented a check for the availability of SQLite math functions
(SQLite version >= 3.35.0; March 2021)
- Added a private method, _dbh_add_user_defined_functions(), to add the missing math
functions with User Defined Functions if missing. _dbh_add_user_defined_functions()
is only called by relevant methods, so those math functions are added only when
necessary.
v0.4.0 2026-04-14T10:27:25+0900
- Fixed t/12.tz_database.t on Windows (Strawberry Perl): replaced
POSIX::mktime with Time::Local::timegm for pre-1970 timestamps,
which POSIX::mktime cannot handle on Windows.
- Added start_of( $unit ) mutator, which modifies the datetime object in place
to the first instant of the given unit.
Supported units are second, minute, hour, day, week, local_week, month, quarter,
year, decade, and century.
Delegates to truncate() for most units; decade and century are handled independently.
Returns the modified object on success.
- Added end_of( $unit ) mutator: modifies the datetime object in place to
the last nanosecond of the given unit (i.e. the nanosecond before the
start of the next unit).
Supports the same units as start_of().
Handles variable-length units such as months and leap years correctly without
hardcoding boundary values.
Returns the modified object on success.
- Added test suite t/15.start_end_of.t covering all supported units for both
start_of() and end_of(), including edge cases such as February in leap and
non-leap years, quarter boundaries, decade and century boundaries, timezone and
locale preservation, and invalid unit handling.
- Added POD documentation for posix_tz_lookup() under a new =head1 LOW-LEVEL XS UTILITIES
section in DateTime::Lite, documenting the XS function signature, all supported
POSIX TZ string rule forms (Jn, n, Mm.w.d), the RFC 9636 extensions for TZif v3+,
and the structure of the returned hashref.
v0.3.0 2026-04-13T07:30:23+0900
- Added GPS coordinate-based timezone resolution to DateTime::Lite::TimeZone::new().
Passing C<latitude> and C<longitude> (decimal degrees) instead of C<name>
finds the nearest canonical IANA timezone using the haversine great-circle
distance against the reference coordinates stored in the C<zones> table of C<tz.sqlite3> (derived from
IANA C<zone1970.tab>). No new dependencies.
Note: this is an approximation based on one representative point per zone;
it is accurate for most locations but may give incorrect results near timezone
boundaries or in enclaves. For more boundary-precise resolution, see
L<Geo::Location::TimeZoneFinder>.
- Added private method _nearest_zone() to DateTime::Lite::TimeZone, implementing
the haversine query entirely within SQLite via asin(), sqrt(), cos() and sin()
functions. Only canonical zones with coordinates are considered.
- Added input validation for latitude (-90..90) and longitude (-180..180), with
proper error() returns rather than die().
- Updated DateTime::Lite::TimeZone POD to document the coordinate-based resolution,
its approximation caveat, and the valid parameter ranges.
- Added t/14.tz_coordinates.t with 10 subtests covering: Tokyo, Paris, New York,
Taipei, Sydney, Buenos Aires (southern hemisphere); integration with
DateTime::Lite->now(); and input validation for missing, out-of-range, and
non-numeric parameters.
v0.2.0 2026-04-11T20:48:09+0900
- BCP47 -u-tz- locale extension support: if the locale tag carries a
Unicode timezone extension, such as C<he-IL-u-ca-hebrew-tz-jeruslm>,
and no explicit C<time_zone> argument is supplied to the constructor,
the corresponding IANA canonical timezone name is resolved automatically
via C<Locale::Unicode->tz_id2names()>.
Explicit C<time_zone> always takes priority.
No new dependencies: the BCP47 timezone to Olson canonical timezone
resolution uses the static in-memory hash in C<Locale::Unicode>, so no
SQLite query, and thus super fast.
- _set_locale() rewritten: now uses C<Scalar::Util::blessed()> instead
of C<ref()> to distinguish objects from unblessed references; This was
a carry over from the way DateTime is doing.
Returns the C<DateTime::Locale::FromCLDR> object instead of C<undef> to allow
the BCP47 timezone resolution in C<_new()>.
Unblessed references now return a proper error instead of an undefined behaviour;
replaced C<die()> with C<pass_error()> for consistency with the no-die philosophy.
- Added support for 'local' timezone name in DateTime::Lite::TimeZone::new().
The local timezone is resolved automatically without any external module
dependency, using OS-specific detection strategies:
- Unix/Linux/macOS/FreeBSD/OpenBSD/NetBSD/Solaris/AIX/HP-UX/OS2/Cygwin:
$ENV{TZ}, /etc/localtime symlink or binary match, /etc/timezone,
/etc/TIMEZONE, /etc/sysconfig/clock, /etc/default/init.
- Windows (MSWin32, NetWare): $ENV{TZ} then Windows Registry via
Win32::TieRegistry (optional, not a hard dependency).
- Android: $ENV{TZ}, getprop persist.sys.timezone, then 'UTC'.
- VMS: TZ, SYS$TIMEZONE_RULE, SYS$TIMEZONE_NAME, UCX$TZ, TCPIP$TZ.
- Symbian, EPOC, MS-DOS, Mac OS 9 and earlier: $ENV{TZ} only.
- Added OS dispatch aliases for darwin, cygwin, freebsd, openbsd, netbsd, solaris,
aix, hpux, os2, netware, symbian, epoc, dos, macos.
- Updated DateTime::Lite::TimeZone POD to document 'local' resolution strategy per OS.
- Added t/10.timezone.t subtest for 'local' timezone resolution via $ENV{TZ}.
v0.1.0 2026-04-10T06:12:47+0900
- Initial release.
- Full port of DateTime 1.66 API.
- Dependencies reduced from ~10 non-core to 3 (DateTime::TimeZone,
DateTime::Locale::FromCLDR, Locale::Unicode).
- Specio, Params::ValidationCompiler, Try::Tiny, namespace::autoclean all
eliminated.
- XS layer ported from DateTime.xs with 4 new functions:
_rd_to_epoch, _epoch_to_rd, _normalize_nanoseconds, _compare_rd.
- Pure-Perl fallback (DateTime::Lite::PP) for environments without a C compiler.
- No die() in normal error paths: DateTime::Lite::Exception used throughout,
errors returned as undef in scalar context.
- DateTime::Lite::Infinite provides singleton Future/Past objects.
- Locale data via DateTime::Locale::FromCLDR + Locale::Unicode::Data (SQLite backend,
no generated Perl locale files).
- Includes DateTime::Lite::TimeZone based thoroughly on the IANA Olson data
accessible with a SQLite database.
- Replaced the shallow Perl clone() with an XS deep copy (DateTime-Lite.xs):
- Root object scalar fields are copied with newSVsv().
- Nested blessed hashrefs (tz, locale) are copied with a new static
helper dtl_clone_flat_hv(), then re-blessed into the original stash.
The RV is created first with newRV_noinc() before calling sv_bless(),
which requires an RV not a raw HV pointer.
- The local_c cache (plain hashref) is also deep-copied, eliminating
any shared state between original and clone.
- Non-HV references (formatter objects, etc.) are shallow-copied with
newSVsv(), acceptable since formatters are effectively immutable.
- Implemented a TZif footer POSIX parser in XS, based on IANA code (public domain).
- New file dtl_posix.h: self-contained C header containing eight functions
derived from tzcode localtime.c (is_digit, getzname, getqzname, getnum,
getsecs, getoffset, getrule, transtime) plus dtl_year_to_jan1() and the
public entry point dtl_posix_tz_lookup(). All symbols prefixed dtl_;
no dynamic allocation, no system calls, no global state.
- New XS function DateTime::Lite::posix_tz_lookup(class_or_self,
unix_secs, tz_string): parses any POSIX TZ footer and returns
{ offset, is_dst, short_name } or undef. Handles Jn, n, Mm.w.d
rules; quoted <name> abbreviations; fractional offsets; negative and
>24 h transition times (RFC 9636 s3.3.2 v3+ extensions); southern-
hemisphere DST (start > end).
- DateTime::Lite::TimeZone::_posix_tz_lookup() is now a thin Perl wrapper that
delegates to the XS function.
- Implemented process-level memory cache to DateTime::Lite::TimeZone.
The cache is opt-in and activated either per-call or class-wide:
use_cache_mem => 1 argument to new() enables it for that call;
DateTime::Lite::TimeZone->enable_mem_cache enables it globally.
Three new class methods: enable_mem_cache(), disable_mem_cache(),
clear_mem_cache(). Cache is keyed by both input name and canonical
name after alias resolution, so "US/Eastern" and "America/New_York"
share the same cached object.
- Implemented three-layer span cache to DateTime::Lite::TimeZone, active
when use_cache_mem => 1 or enable_mem_cache() is set:
Layer 1 - object cache: TimeZone->new() returns the cached object
keyed by zone name and canonical name, bypassing SQLite entirely.
Layer 2 - span cache: _lookup_span() and _lookup_span_local() store
the last matched span boundaries per cached TZ object. Subsequent
calls within the same span return the cached result in ~0.5 us
instead of ~45 us (SQL query). SQL extended with utc_start/utc_end
and local_start/local_end columns for range checks.
Layer 3 - POSIX footer cache: For zones with a footer TZ string
(e.g. America/New_York), the DST rule calculation result is cached
by calendar day. Pre-check added BEFORE the SQL query so future
dates skip the database entirely on subsequent calls.