NAME
Time::Str::Util - Binary search and time zone database utilities
SYNOPSIS
use Time::Str::Util qw( find_tzdb_directory
valid_tzdb_timezone valid_posix_timezone
lower_bound upper_bound range_bounds );
# Locate system zoneinfo directory
my $tzdir = find_tzdb_directory(); # /usr/share/zoneinfo or undef
# Validate timezone names
valid_tzdb_timezone('America/New_York'); # true
valid_posix_timezone('EST5EDT,M3.2.0,M11.1.0'); # true
my @sorted = (10, 20, 30, 40, 50);
my $i = lower_bound(\@sorted, 25); # 2 (first element >= 25)
my $j = upper_bound(\@sorted, 30); # 3 (first element > 30)
# With optional bounds
my $k = lower_bound(\@sorted, 25, 1, 4); # search within [1, 4)
# Range query: indices of elements in [15, 35]
my ($lo, $hi) = range_bounds(\@sorted, 15, 35); # (1, 3)
DESCRIPTION
This module provides binary search functions for sorted integer arrays and utilities for locating the system's IANA Time Zone Database. All functions are exportable on request. Use :all to import everything.
FUNCTIONS
Binary Search
lower_bound
my $index = lower_bound($arrayref, $value);
my $index = lower_bound($arrayref, $value, $lo, $hi);
Returns the index of the first element in the sorted array that is greater than or equal to $value. If all elements are less than $value, returns the length of the array (one past the last index).
Optional $lo and $hi parameters restrict the search to the half-open range [$lo, $hi). Defaults to [0, length).
range_bounds
my ($lo, $hi) = range_bounds($arrayref, $min_value, $max_value);
Returns a pair of indices ($lo, $hi) defining the half-open range [$lo, $hi) of elements within [$min_value, $max_value]. $lo is the index of the first element >= $min_value (via binary search), and $hi is the index of the first element > $max_value (via linear scan from $lo).
This is optimized for cases where few elements fall within the range, as the linear scan avoids a second binary search.
Croaks if $min_value > $max_value.
upper_bound
my $index = upper_bound($arrayref, $value);
my $index = upper_bound($arrayref, $value, $lo, $hi);
Returns the index of the first element in the sorted array that is strictly greater than $value. If all elements are less than or equal to $value, returns the length of the array.
Optional $lo and $hi parameters restrict the search to the half-open range [$lo, $hi). Defaults to [0, length).
Time Zone Database
find_tzdb_directory
my $dir = find_tzdb_directory();
Returns the path to the system's IANA Time Zone Database directory (zoneinfo), or undef if no valid directory is found.
The search order is:
- 1.
$ENV{TZDIR}if set and the directory exists. - 3. macOS: /var/db/timezone/zoneinfo (symlink to the active version).
A candidate directory is accepted only if it exists and contains a UTC file.
Validation
valid_tzdb_timezone
my $bool = valid_tzdb_timezone($string);
Returns true if $string is structurally valid as an IANA Time Zone Database timezone name (e.g., America/New_York, Europe/Stockholm, Etc/GMT+5, UTC).
A valid name consists of one or more path components separated by /. Each component starts with a letter, followed by letters or digits, with optional _, +, or - separators introducing additional alphanumeric segments.
This is a structural check only; it does not verify that the timezone exists in the database.
valid_posix_timezone
my $bool = valid_posix_timezone($string);
Returns true if $string is structurally valid as a POSIX TZ string (IEEE Std 1003.1).
A POSIX TZ string has the form:
std offset [dst [offset] , start [/time] , end [/time]]
Examples:
EST5EDT,M3.2.0,M11.1.0 # US Eastern
CET-1CEST,M3.5.0/2,M10.5.0/3 # Central European
UTC0 # Fixed UTC
Transition rules may use Mm.w.d (month/week/weekday), Jn (Julian day excluding Feb 29), or n (zero-based Julian day including Feb 29) forms.
This validates the syntactic structure of the string only, not the semantic validity of field values (e.g., month ranges, day ranges). Quoted timezone designations (<+05>) as used in TZif extensions are not part of the POSIX standard and are not accepted.
SEE ALSO
AUTHOR
Christian Hansen
COPYRIGHT AND LICENSE
Copyright (C) 2026 by Christian Hansen
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.