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.