- Overview
- Installation
- How to use
- License
- Contributing
Models time as immutable value objects for PHP, including instants, durations, periods, timezones, time-of-day, local
dates, and day-of-week. All instants are normalized to UTC with microsecond precision, with strict parsing, formatting,
and arithmetic operations. Declared as final readonly class for language-level immutability, with structural equality
provided by the tiny-blocks value-object contract.
composer require tiny-blocks/timeThe library provides immutable value objects for representing points in time, quantities of time, and time intervals. All instants are normalized to UTC internally.
An Instant represents a single point on the timeline, always stored in UTC with microsecond precision.
Captures the current moment with microsecond precision, normalized to UTC.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Instant;
$instant = Instant::now();
$instant->toIso8601(); # 2026-02-17T10:30:00+00:00$instant->toUnixSeconds(); # 1771324200$instant->toDateTimeImmutable(); # DateTimeImmutable (UTC, with microseconds)Parses a date-time string with an explicit UTC offset. The value is normalized to UTC regardless of the original offset.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Instant;
$instant = Instant::fromString(value: '2026-02-17T13:30:00-03:00');
$instant->toIso8601(); # 2026-02-17T16:30:00+00:00$instant->toUnixSeconds(); # 1771345800The offset accepts the ISO 8601 zulu designator (Z) as an alias for +00:00, with or without fractional seconds.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Instant;
$instant = Instant::fromString(value: '2026-02-17T10:30:00Z');
$instant->toIso8601(); # 2026-02-17T10:30:00+00:00$instant->toUnixSeconds(); # 1771324200Parses a database date-time string as UTC, with or without microsecond precision (e.g. MySQL DATETIME
or DATETIME(6)).
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Instant;
$instant = Instant::fromString(value: '2026-02-17 08:27:21.106011');
$instant->toIso8601(); # 2026-02-17T08:27:21+00:00$instant->toDateTimeImmutable()->format('Y-m-d H:i:s.u'); # 2026-02-17 08:27:21.106011Also supports timestamps without fractional seconds:
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Instant;
$instant = Instant::fromString(value: '2026-02-17 08:27:21');
$instant->toIso8601(); # 2026-02-17T08:27:21+00:00Creates an Instant from a Unix timestamp in seconds.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Instant;
$instant = Instant::fromUnixSeconds(seconds: 0);
$instant->toIso8601(); # 1970-01-01T00:00:00+00:00$instant->toUnixSeconds(); # 0Returns a new Instant shifted forward or backward by a Duration.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Duration;
useTinyBlocks\Time\Instant;
$instant = Instant::fromString(value: '2026-02-17T10:00:00+00:00');
$instant->plus(duration: Duration::fromMinutes(minutes: 30))->toIso8601(); # 2026-02-17T10:30:00+00:00$instant->plus(duration: Duration::fromHours(hours: 2))->toIso8601(); # 2026-02-17T12:00:00+00:00$instant->minus(duration: Duration::fromSeconds(seconds: 60))->toIso8601(); # 2026-02-17T09:59:00+00:00Re-anchors the instant in a timezone (UTC when omitted), shifts the local calendar date by whole months or years with
the same day clamping as LocalDate, and normalizes the result back to UTC. The local time of day, including
microseconds, is preserved.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Instant;
$instant = Instant::fromString(value: '2026-01-31T10:00:00+00:00');
$instant->plusMonths(months: 1)->toIso8601(); # 2026-02-28T10:00:00+00:00 (clamped)$instant->plusYears(years: 1)->toIso8601(); # 2027-01-31T10:00:00+00:00$instant->minusMonths(months: 1)->toIso8601(); # 2025-12-31T10:00:00+00:00$instant->minusYears(years: 1)->toIso8601(); # 2025-01-31T10:00:00+00:00Passing a timezone re-anchors the shift in that zone. When the resulting local wall time does not exist because of a spring-forward gap, PHP shifts it forward by the gap.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Instant;
useTinyBlocks\Time\Timezone;
$newYork = Timezone::from(identifier: 'America/New_York');
$instant = Instant::fromString(value: '2026-02-08T07:30:00+00:00');
# The local time 2026-02-08 02:30 plus one month targets the non-existent local 2026-03-08 02:30,# so PHP resolves it forward to 03:30 -04:00.$instant->plusMonths(months: 1, zone: $newYork)->toIso8601(); # 2026-03-08T07:30:00+00:00Returns the absolute Duration between two Instant objects.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Instant;
$start = Instant::fromString(value: '2026-02-17T10:00:00+00:00');
$end = Instant::fromString(value: '2026-02-17T11:30:00+00:00');
$duration = $start->durationUntil(other: $end);
$duration->toSeconds(); # 5400$duration->toMinutes(); # 90$duration->toHours(); # 1The result is always non-negative regardless of direction:
$end->durationUntil(other: $start)->toSeconds(); # 5400Provides strict temporal ordering between two Instant instances.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Instant;
$earlier = Instant::fromString(value: '2026-02-17T10:00:00+00:00');
$later = Instant::fromString(value: '2026-02-17T10:30:00+00:00');
$earlier->isBefore(other: $later); # true$earlier->isAfter(other: $later); # false$earlier->isBeforeOrEqual(other: $later); # true$earlier->isAfterOrEqual(other: $later); # false$later->isAfter(other: $earlier); # true$later->isAfterOrEqual(other: $earlier); # trueBy default toIso8601() emits seconds only. Pass a Precision value to include fractional seconds in the output.
Existing callers that omit the argument are unaffected.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Instant;
useTinyBlocks\Time\Precision;
$instant = Instant::fromString(value: '2026-05-23T12:55:10.272097+00:00');
$instant->toIso8601(); # 2026-05-23T12:55:10+00:00$instant->toIso8601(precision: Precision::Seconds); # 2026-05-23T12:55:10+00:00$instant->toIso8601(precision: Precision::Microseconds); # 2026-05-23T12:55:10.272097+00:00$instant->toIso8601(precision: Precision::Milliseconds); # 2026-05-23T12:55:10.272+00:00Instant carries a #[ScalarCodec], so tiny-blocks/mapper rebuilds it from an ISO 8601 string and writes it back to
the same form, with no mapping to register. As a field on a larger object the value stays a scalar at second precision,
matching the default of toIso8601().
<?phpdeclare(strict_types=1);
useTinyBlocks\Mapper\Mapper;
useTinyBlocks\Time\Instant;
finalreadonlyclass Event
{
publicfunction__construct(publicInstant$occurredAt, publicstring$name)
{
}
}
$mapper = Mapper::create();
$event = $mapper->toObject(type: Event::class, source: ['occurredAt' => '2026-02-17T10:30:00+00:00', 'name' => 'launch']);
$mapper->toArray(source: $event); # ['occurredAt' => '2026-02-17T10:30:00+00:00', 'name' => 'launch']A Duration represents an immutable, unsigned quantity of time measured in seconds. It has no reference point on the
timeline. It expresses only "how much" time.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Duration;
$zero = Duration::zero();
$seconds = Duration::fromSeconds(seconds: 90);
$minutes = Duration::fromMinutes(minutes: 30);
$hours = Duration::fromHours(hours: 2);
$days = Duration::fromDays(days: 7);All factories reject negative values:
Duration::fromMinutes(minutes: -5); # throws InvalidSeconds<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Duration;
$thirtyMinutes = Duration::fromMinutes(minutes: 30);
$fifteenMinutes = Duration::fromMinutes(minutes: 15);
$thirtyMinutes->plus(other: $fifteenMinutes)->toSeconds(); # 2700 (45 minutes)$thirtyMinutes->minus(other: $fifteenMinutes)->toSeconds(); # 900 (15 minutes)Subtraction that would produce a negative result throws an exception:
$fifteenMinutes->minus(other: $thirtyMinutes); # throws InvalidSecondsReturns the number of times one Duration fits wholly into another. The result is truncated toward zero:
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Duration;
$total = Duration::fromMinutes(minutes: 90);
$slot = Duration::fromMinutes(minutes: 30);
$total->divide(other: $slot); # 3Division by a zero Duration throws an exception:
$total->divide(other: Duration::zero()); # throws InvalidSeconds<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Duration;
$short = Duration::fromMinutes(minutes: 15);
$long = Duration::fromHours(hours: 2);
$short->isLessThan(other: $long); # true$long->isGreaterThan(other: $short); # true$short->isZero(); # false
Duration::zero()->isZero(); # trueConversions truncate toward zero when the duration is not an exact multiple:
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Duration;
$duration = Duration::fromSeconds(seconds: 5400);
$duration->toSeconds(); # 5400$duration->toMinutes(); # 90$duration->toHours(); # 1$duration->toDays(); # 0A MonotonicClock exposes a high-resolution counter for measuring elapsed time, conceptually distinct from Duration:
Duration is a wall-clock quantity measured in whole seconds, while a monotonic reading is an opaque nanosecond counter
whose absolute value carries no calendar meaning and is only useful as the delta between two readings on the same clock.
The default SystemMonotonicClock implementation is backed by PHP's hrtime(true).
Returns the current monotonic reading as an integer nanosecond count. The value has no calendar meaning. Treat it as an opaque counter and only compare it to another reading from the same clock.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\SystemMonotonicClock;
$clock = newSystemMonotonicClock();
$clock->nanoseconds(); # 12345678901234 (an opaque counter, not a calendar value)Subtract two successive readings on the same clock to obtain the elapsed interval in nanoseconds. Readings are guaranteed to be non-decreasing.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\SystemMonotonicClock;
$clock = newSystemMonotonicClock();
$start = $clock->nanoseconds();
# Perform the operation whose latency is being measured.usleep(1000);
$elapsedNanos = $clock->nanoseconds() - $start;A Stopwatch separates the act of measuring from the value being measured. It captures a starting reading from a
MonotonicClock and exposes the accumulated interval as an Elapsed value object. The clock is injected explicitly so
the time source stays under the caller's control, and reading the interval is idempotent: invoking elapsed() more than
once returns successive measurements from the same starting reading.
Elapsed is a pure value object expressed in nanoseconds. It is distinct from Duration, which models wall-clock
seconds, and nanosecond and second granularities are kept in separate types so the intent of each measurement stays
explicit at the call site.
Captures the current reading of the provided monotonic clock and returns a stopwatch anchored to that moment.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Stopwatch;
useTinyBlocks\Time\SystemMonotonicClock;
$stopwatch = Stopwatch::start(clock: newSystemMonotonicClock());Returns an Elapsed measuring the interval between the starting reading and the current reading of the same clock.
toMilliseconds() converts the nanosecond count to milliseconds rounded to two decimal places.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Stopwatch;
useTinyBlocks\Time\SystemMonotonicClock;
$stopwatch = Stopwatch::start(clock: newSystemMonotonicClock());
# Perform the operation whose latency is being measured.usleep(1500);
$stopwatch->elapsed()->toMilliseconds(); # 1.5The starting reading is captured once and never changes. Each call to elapsed() returns a new Elapsed measured from
that same anchor, so successive calls report a non-decreasing series of intervals.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Stopwatch;
useTinyBlocks\Time\SystemMonotonicClock;
$stopwatch = Stopwatch::start(clock: newSystemMonotonicClock());
usleep(1000);
$firstReading = $stopwatch->elapsed();
usleep(1000);
$secondReading = $stopwatch->elapsed();
$firstReading->toMilliseconds(); # approximately 1.0$secondReading->toMilliseconds(); # approximately 2.0A Period represents a half-open time interval [from, to) between two UTC instants. The start is inclusive and the
end is exclusive.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Instant;
useTinyBlocks\Time\Period;
$period = Period::from(
from: Instant::fromString(value: '2026-02-17T10:00:00+00:00'),
to: Instant::fromString(value: '2026-02-17T11:00:00+00:00')
);
$period->from->toIso8601(); # 2026-02-17T10:00:00+00:00$period->to->toIso8601(); # 2026-02-17T11:00:00+00:00The start must be strictly before the end:
Period::from(from: $later, to: $earlier); # throws InvalidPeriod<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Duration;
useTinyBlocks\Time\Instant;
useTinyBlocks\Time\Period;
$period = Period::startingAt(
from: Instant::fromString(value: '2026-02-17T10:00:00+00:00'),
duration: Duration::fromMinutes(minutes: 90)
);
$period->from->toIso8601(); # 2026-02-17T10:00:00+00:00$period->to->toIso8601(); # 2026-02-17T11:30:00+00:00$period->duration()->toSeconds(); # 5400$period->duration()->toMinutes(); # 90The check is inclusive at the start and exclusive at the end:
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Instant;
$period->contains(instant: Instant::fromString(value: '2026-02-17T10:00:00+00:00')); # true (start, inclusive)$period->contains(instant: Instant::fromString(value: '2026-02-17T10:30:00+00:00')); # true (middle)$period->contains(instant: Instant::fromString(value: '2026-02-17T11:30:00+00:00')); # false (end, exclusive)Two half-open intervals [A, B) and [C, D) overlap when A < D and C < B:
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Duration;
useTinyBlocks\Time\Instant;
useTinyBlocks\Time\Period;
$periodA = Period::startingAt(
from: Instant::fromString(value: '2026-02-17T10:00:00+00:00'),
duration: Duration::fromHours(hours: 1)
);
$periodB = Period::startingAt(
from: Instant::fromString(value: '2026-02-17T10:30:00+00:00'),
duration: Duration::fromHours(hours: 1)
);
$periodA->overlapsWith(other: $periodB); # true$periodB->overlapsWith(other: $periodA); # trueAdjacent periods do not overlap:
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Duration;
useTinyBlocks\Time\Instant;
useTinyBlocks\Time\Period;
$first = Period::startingAt(
from: Instant::fromString(value: '2026-02-17T10:00:00+00:00'),
duration: Duration::fromHours(hours: 1)
);
$second = Period::startingAt(
from: Instant::fromString(value: '2026-02-17T11:00:00+00:00'),
duration: Duration::fromHours(hours: 1)
);
$first->overlapsWith(other: $second); # falseA DayOfWeek represents a day of the week following ISO 8601, where Monday is 1 and Sunday is 7.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\DayOfWeek;
useTinyBlocks\Time\Instant;
$instant = Instant::fromString(value: '2026-02-17T10:30:00+00:00');
$day = DayOfWeek::fromInstant(instant: $instant);
$day; # DayOfWeek::Tuesday$day->value; # 2<?phpdeclare(strict_types=1);
useTinyBlocks\Time\DayOfWeek;
DayOfWeek::Monday->isWeekday(); # true
DayOfWeek::Monday->isWeekend(); # false
DayOfWeek::Saturday->isWeekday(); # false
DayOfWeek::Saturday->isWeekend(); # trueReturns the number of days forward from one day to another, always in the range [0, 6]. The distance is measured
forward through the week:
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\DayOfWeek;
DayOfWeek::Monday->distanceTo(other: DayOfWeek::Wednesday); # 2
DayOfWeek::Friday->distanceTo(other: DayOfWeek::Monday); # 3 (forward through Sat, Sun, Mon)
DayOfWeek::Monday->distanceTo(other: DayOfWeek::Monday); # 0A TimeOfDay represents a time of day (hour and minute) without date or timezone context. Values range from 00:00 to
23:59.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\TimeOfDay;
$time = TimeOfDay::from(hour: 8, minute: 30);
$time->hour; # 8$time->minute; # 30Parses a string in HH:MM or HH:MM:SS format. When seconds are present, they are discarded:
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\TimeOfDay;
$time = TimeOfDay::fromString(value: '14:30');
$time->hour; # 14$time->minute; # 30Also accepts the HH:MM:SS format commonly returned by databases:
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\TimeOfDay;
$time = TimeOfDay::fromString(value: '08:30:00');
$time->hour; # 8$time->minute; # 30$time->toString(); # 08:30Extracts the time of day from an Instant in UTC:
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Instant;
useTinyBlocks\Time\TimeOfDay;
$instant = Instant::fromString(value: '2026-02-17T14:30:00+00:00');
$time = TimeOfDay::fromInstant(instant: $instant);
$time->hour; # 14$time->minute; # 30<?phpdeclare(strict_types=1);
useTinyBlocks\Time\TimeOfDay;
$midnight = TimeOfDay::midnight(); # 00:00$noon = TimeOfDay::noon(); # 12:00<?phpdeclare(strict_types=1);
useTinyBlocks\Time\TimeOfDay;
$morning = TimeOfDay::from(hour: 8, minute: 0);
$afternoon = TimeOfDay::from(hour: 14, minute: 30);
$morning->isBefore(other: $afternoon); # true$morning->isAfter(other: $afternoon); # false$morning->isBeforeOrEqual(other: $afternoon); # true$afternoon->isAfterOrEqual(other: $morning); # trueReturns the Duration between two times. The second time must be after the first:
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\TimeOfDay;
$start = TimeOfDay::from(hour: 8, minute: 0);
$end = TimeOfDay::from(hour: 12, minute: 30);
$duration = $start->durationUntil(other: $end);
$duration->toMinutes(); # 270<?phpdeclare(strict_types=1);
useTinyBlocks\Time\TimeOfDay;
$time = TimeOfDay::from(hour: 8, minute: 30);
$time->toMinutesSinceMidnight(); # 510$time->toDuration()->toSeconds(); # 30600$time->toString(); # 08:30A LocalDate is a value object representing a calendar date (year, month, day) without time and without timezone. Dates
are always in the proleptic Gregorian calendar and restricted to the range 0001–9999.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\LocalDate;
$date = LocalDate::of(year: 2026, month: 5, day: 23);
$date->year(); # 2026$date->month(); # 5$date->dayOfMonth(); # 23$date->toIso8601(); # 2026-05-23Accepts only the canonical ISO 8601 date format YYYY-MM-DD. Any other format raises InvalidLocalDate.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\LocalDate;
$date = LocalDate::fromString(value: '2026-05-23');
$date->toIso8601(); # 2026-05-23<?phpdeclare(strict_types=1);
useTinyBlocks\Time\LocalDate;
useTinyBlocks\Time\Timezone;
$today = LocalDate::today(zone: Timezone::from(identifier: 'America/Sao_Paulo'));
$today->toIso8601(); # 2026-05-23<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Instant;
useTinyBlocks\Time\Timezone;
$instant = Instant::fromString(value: '2026-05-23T12:00:00+00:00');
$date = $instant->toLocalDate(zone: Timezone::utc());
$date->toIso8601(); # 2026-05-23atTime is the inverse of Instant::toLocalDate. A LocalDate and a TimeOfDay are both civil values, so the
timezone is what turns them into a point on the timeline.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\LocalDate;
useTinyBlocks\Time\TimeOfDay;
useTinyBlocks\Time\Timezone;
$date = LocalDate::of(year: 2026, month: 6, day: 15);
$instant = $date->atTime(
time: TimeOfDay::from(hour: 0, minute: 0),
zone: Timezone::from(identifier: 'America/Sao_Paulo')
);
$instant->toIso8601(); # 2026-06-15T03:00:00+00:00Daylight saving leaves two civil times that are not one-to-one with the timeline, and both resolve deterministically. A time inside the spring-forward gap does not exist, and it maps to the same instant as the first civil time after the gap. A time inside the fall-back overlap happens twice, and it maps to the earlier of the two, the one still on the pre-transition offset.
$springForward = LocalDate::of(year: 2026, month: 3, day: 8);
$newYork = Timezone::from(identifier: 'America/New_York');
# 02:30 does not exist on this day, so it lands where 03:30 lands.$springForward->atTime(time: TimeOfDay::from(hour: 2, minute: 30), zone: $newYork)->toIso8601();
# 2026-03-08T07:30:00+00:00<?phpdeclare(strict_types=1);
useTinyBlocks\Time\LocalDate;
$earlier = LocalDate::of(year: 2026, month: 1, day: 1);
$later = LocalDate::of(year: 2026, month: 12, day: 31);
$earlier->isBefore(other: $later); # true$earlier->isBeforeOrEqual(other: $later); # true$later->isAfter(other: $earlier); # true$later->isAfterOrEqual(other: $earlier); # true<?phpdeclare(strict_types=1);
useTinyBlocks\Time\LocalDate;
$date = LocalDate::of(year: 2026, month: 5, day: 23);
$date->plusDays(days: 10)->toIso8601(); # 2026-06-02$date->minusDays(days: 30)->toIso8601(); # 2026-04-23Shifts the year and month, then clamps the day to the last valid day of the target month. A negative count shifts in the opposite direction.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\LocalDate;
$date = LocalDate::of(year: 2026, month: 1, day: 31);
$date->plusMonths(months: 1)->toIso8601(); # 2026-02-28 (clamped, February has 28 days)$date->plusYears(years: 2)->toIso8601(); # 2028-01-31$date->minusMonths(months: 2)->toIso8601(); # 2025-11-30 (clamped, November has 30 days)$date->minusYears(years: 1)->toIso8601(); # 2025-01-31Because the day is clamped, the shift is not associative. Adding a month and then subtracting it does not always restore the original day.
$date->plusMonths(months: 1)->minusMonths(months: 1)->toIso8601(); # 2026-01-28LocalDate carries a #[ScalarCodec], so tiny-blocks/mapper rebuilds it from a YYYY-MM-DD string and writes it
back to the same date-only form, instead of widening to a full datetime.
<?phpdeclare(strict_types=1);
useTinyBlocks\Mapper\Mapper;
useTinyBlocks\Time\LocalDate;
finalreadonlyclass Holiday
{
publicfunction__construct(publicLocalDate$date, publicstring$name)
{
}
}
$mapper = Mapper::create();
$holiday = $mapper->toObject(type: Holiday::class, source: ['date' => '2026-05-23', 'name' => 'Labor Day']);
$mapper->toArray(source: $holiday); # ['date' => '2026-05-23', 'name' => 'Labor Day']A Timezone is a value object representing a single valid IANA timezone identifier.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Timezone;
$timezone = Timezone::from(identifier: 'America/Sao_Paulo');
$timezone->value; # America/Sao_Paulo$timezone->toString(); # America/Sao_Paulo<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Timezone;
$timezone = Timezone::utc();
$timezone->value; # UTC<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Timezone;
$timezone = Timezone::from(identifier: 'Asia/Tokyo');
$dateTimeZone = $timezone->toDateTimeZone();
$dateTimeZone->getName(); # Asia/TokyoAn immutable collection of Timezone objects.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Timezone;
useTinyBlocks\Time\Timezones;
$timezones = Timezones::from(
Timezone::from(identifier: 'America/Sao_Paulo'),
Timezone::from(identifier: 'America/New_York'),
Timezone::from(identifier: 'Asia/Tokyo')
);
$timezones->count(); # 3<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Timezones;
$timezones = Timezones::fromStrings('UTC', 'America/Sao_Paulo', 'Europe/London');
$timezones->count(); # 3$timezones->toStrings(); # ["UTC", "America/Sao_Paulo", "Europe/London"]Returns all Timezone objects in the collection:
$timezones->all(); # [Timezone("UTC"), Timezone("America/Sao_Paulo"), Timezone("Europe/London")]Searches for a specific IANA identifier within the collection. Returns null if not found.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Timezones;
$timezones = Timezones::fromStrings('UTC', 'America/Sao_Paulo', 'Asia/Tokyo');
$timezones->findByIdentifier(iana: 'Asia/Tokyo'); # Timezone("Asia/Tokyo")$timezones->findByIdentifier(iana: 'Europe/London'); # nullSearches for a specific IANA identifier within the collection. Returns UTC if not found.
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Timezones;
$timezones = Timezones::fromStrings('UTC', 'America/Sao_Paulo', 'Asia/Tokyo');
$timezones->findByIdentifierOrUtc(iana: 'Asia/Tokyo'); # Timezone("Asia/Tokyo")$timezones->findByIdentifierOrUtc(iana: 'Europe/London'); # Timezone("UTC")<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Timezones;
$timezones = Timezones::fromStrings('America/Sao_Paulo', 'Asia/Tokyo');
$timezones->contains(iana: 'Asia/Tokyo'); # true$timezones->contains(iana: 'America/New_York'); # falseReturns all timezone identifiers as plain strings:
<?phpdeclare(strict_types=1);
useTinyBlocks\Time\Timezones;
$timezones = Timezones::fromStrings('UTC', 'America/Sao_Paulo', 'Europe/London');
$timezones->toStrings(); # ["UTC", "America/Sao_Paulo", "Europe/London"]Time is licensed under MIT.
Please follow the contributing guidelines to contribute to the project.