NAME
Time::Keeper - dates and times with time zones, leap seconds and locales
VERSION
Version 0.12
SYNOPSIS
use Time::Keeper;
my $now = Time::Keeper->now; # UTC
my $there = Time::Keeper->now(zone => 'Asia/Tokyo');
my $here = Time::Keeper->now(zone => 'local');
my $t = Time::Keeper->new(
year => 2026, month => 10, day => 15, hour => 9,
zone => 'Europe/London',
);
print $t->year, '-', $t->month, '-', $t->day, "\n"; # 2026-10-15
print $t->zone_abbr, ' ', $t->offset, "\n"; # BST 3600
print "$t\n"; # 2026-10-15T09:00:00+01:00
my $tokyo = $t->in_zone('Asia/Tokyo'); # the same instant
my $first = $t->with(day => 1); # a new value
print $t < $tokyo ? "earlier\n" : "not earlier\n"; # not earlier: they are equal
my $e = Time::Keeper->from_epoch('1760000000.123456789', zone => '+05:30');
DESCRIPTION
Time::Keeper is a date and time library that does what Time::Piece and DateTime do between them and is much faster than either. With time zones from the IANA database, nanoseconds, leap seconds, and a calendar that runs from the year -999,999,999 to 999,999,999.
A value is one instant, a time zone, and nothing else. Values never change. A method that would change one, such as "with" or "in_zone", returns a new value and leaves the old one as it was.
A value with no zone given is in UTC. The time zones live in Time::Keeper::Zone, which is loaded the first time a named zone is asked for: a program that works only in UTC, in fixed offsets or in floating time never loads the zone data.
Names and formats come from the value's locale, any of the more than a thousand in the Unicode Common Locale Data Repository (CLDR); see "LOCALES". English is the default.
CONSTRUCTORS
Every constructor is a class method and takes its arguments as name and value pairs. An argument it does not know, or one given twice, is an error that names it.
now
my $t = Time::Keeper->now;
my $t = Time::Keeper->now(zone => 'Asia/Tokyo');
The current time, to the nanosecond where the system gives it, or the clock a test pinned (see "TESTING"). zone is described under "TIME ZONES". Every constructor also takes locale, as described under "LOCALES", and calendar, as described under "CALENDARS".
today
my $t = Time::Keeper->today(zone => 'local');
Midnight at the start of today in the zone. Where a zone's clocks jumped over midnight, as some zones' spring changes do, it is the first moment of the day that did happen: today never dies on such a day.
try_new
my $t = Time::Keeper->try_new(year => 2026, month => 2, day => 30); # undef
As "new", but undef where "new" would die, and $@ left as it was.
new
my $t = Time::Keeper->new(
year => 2026, # required
month => 10, # 1 to 12; default 1
day => 15, # default 1
hour => 9, # 0 to 23; default 0
minute => 30, # default 0
second => 0, # 0 to 59, or 60 for a leap second; default 0
nanosecond => 0, # default 0
zone => 'Europe/London',
gap => 'croak',
overlap => 'earlier',
locale => 'en-GB',
);
The value whose wall-clock time in the zone is the one given. A field out of range, or a day the month does not have, is an error that names it. gap and overlap are described under "GAPS AND OVERLAPS", and a second of 60 under "LEAP SECONDS".
last_day_of_month
my $t = Time::Keeper->last_day_of_month(year => 2028, month => 2); # 29th
As "new", with the day the last of the month and month required.
from_day_of_year
my $t = Time::Keeper->from_day_of_year(year => 2026, day_of_year => 288);
As "new", with the date given by its day of the year, 1 to 365 or 366 in a leap year.
from_iso_week
my $t = Time::Keeper->from_iso_week(year => 2026, week => 42, day => 4);
As "new", with the date given by its ISO 8601 week: the week year, the week (1 to 52, or 53 in a year that has one) and the day of the week, 1 for Monday to 7 for Sunday, Monday if not given.
from_epoch
my $t = Time::Keeper->from_epoch(1760000000);
my $t = Time::Keeper->from_epoch('1760000000.123456789', zone => 'UTC');
The instant a number of seconds after 1970-01-01T00:00:00 UTC, in the zone given. An integer, or a string of digits with up to nine decimal places, is taken exactly. A number with a fraction is rounded to the microsecond, because a floating-point number holds no more than that for times near today: pass a string when the nanoseconds matter.
from_epoch_millis
from_epoch_micros
from_epoch_nanos
my $t = Time::Keeper->from_epoch_millis(1760000000123, zone => 'Asia/Tokyo');
my $t = Time::Keeper->from_epoch_nanos('1760000000123456789');
The instant a whole number of milliseconds, microseconds or nanoseconds after the epoch: an integer, or a string of digits for one too large for the perl's integers. A fraction is an error, since "from_epoch" takes those. Negative numbers count back, so -1 millisecond is 23:59:59.999 on 31 December 1969. A leap second cannot be named this way: the epoch has no number for it.
from_object
my $t = Time::Keeper->from_object(object => $datetime);
my $t = Time::Keeper->from_object(object => $datetime, zone => 'Asia/Tokyo', locale => 'ja');
The instant of any object with a utc_rd_values method, as DateTime and the modules built on it have. The zone is zone if given, else the object's own (the name its time_zone gives), else UTC. A floating object gives a floating value.
An object without utc_rd_values but with epoch, as Time::Piece and Time::Moment have, gives the instant that returns (a string with a fraction is read exactly, as "from_epoch" reads one); its nanosecond, if it has the method, is taken too, and its tzoffset, in seconds, gives a fixed zone (UTC for an offset of zero) unless zone is given. A Time::Piece from localtime is best given zone => 'local', so the value has the machine's zone and its rules rather than one offset.
max
min
my $last = Time::Keeper->max; # +999999999-12-31T23:59:59.999999999Z
my $first = Time::Keeper->min; # -999999999-01-01T00:00:00Z
The last and first instants a value can hold, in UTC.
ACCESSORS
The date and time fields are those of the value's wall-clock time in its zone. Each is an integer.
year
The year. Years are counted astronomically: the year before 1 is 0.
month
1 to 12.
day
The day of the month, from 1.
hour
0 to 23.
hour_12
1 to 12: the hour on a twelve-hour clock, 12 at midnight and at noon. "am_pm" says which.
minute
0 to 59.
second
0 to 59, or 60 during a leap second.
nanosecond
microsecond
millisecond
The fraction of the second in each unit: 0 to 999,999,999, 999,999 and 999.
day_of_week
1 for Monday to 7 for Sunday, as ISO 8601 numbers them.
day_of_year
1 to 365, or 366 in a leap year.
quarter
1 to 4.
day_of_quarter
The day of the quarter, from 1.
week
week_year
$t->week; # 42, ISO 8601's
$t->week(locale => 1); # the locale's: 43 in the United States
The ISO 8601 week, 1 to 53, and the year it belongs to. Weeks begin on a Monday, and week 1 is the week with the year's first Thursday in it, so the first days of January can belong to the last week of the year before. With locale => 1, the week as the value's locale counts it, as "format"'s w and Y write it: from the locale's first day of the week, with week 1 the first that holds its minimum of days of January.
week_of_month
The week of the month, 0 to 5, counted as DateTime counts it: the first week is the first that has a Thursday in the month.
is_leap_year
True in a leap year.
is_weekend
is_weekday
True on a day of the locale's weekend, and true on any other day: Saturday and Sunday in most of the world, Friday and Saturday in Egypt, Thursday and Friday in Afghanistan, Sunday alone in India, as CLDR has it for the locale's territory.
days_in_month
days_in_quarter
days_in_year
The number of days in the value's month, quarter and year.
offset
The zone's offset from UTC at this instant, in seconds east of UTC.
is_dst
True when the zone is on daylight saving time at this instant. Some zones mark their winter time as daylight saving time and their summer time as standard, as Ireland does: this says what the database says.
standard_offset
The offset of the zone's standard time at this instant, in seconds east of UTC: in summer, the offset the clocks are an hour ahead of. The offset itself for a fixed zone, 0 for UTC and floating time. What the database calls standard is not always what the clocks are called: Europe/Dublin's standard time is +01:00 all year, and its winter GMT is a daylight time an hour behind it. Needs Time::Keeper::Zone 0.03 or later.
dst_offset
How far the offset in force is from the standard one: "offset" less "standard_offset". 3600 in London in July, 1800 on Lord Howe Island in January, 0 where the clocks have not moved, and -3600 in Dublin in winter.
is_utc
is_floating
True when the value is in UTC, or in floating time.
zone_name
The zone's name as it was given (a link, such as US/Eastern, keeps its own name), UTC, floating, or the offset of a fixed zone, such as +05:30.
zone_abbr
The zone's abbreviation at this instant, such as BST or JST, UTC, the offset of a fixed zone, or the empty string in floating time. Not every zone has letters for its abbreviations: many are numbers, such as +04.
locale
The value's locale, as its code: en, fr-CA.
epoch
The seconds from 1970-01-01T00:00:00 UTC, as an integer. During a leap second it is that of the midnight after it.
hires_epoch
The same with the fraction of the second, as a floating-point number.
epoch_string
The same as a string, exact to the nanosecond: give it to "from_epoch" to have the instant back.
epoch_millis
epoch_micros
epoch_nanos
The same in milliseconds, microseconds and nanoseconds, as whole numbers: the fraction below the unit is dropped, so -1 millisecond is 23:59:59.999 on 31 December 1969. Milliseconds and microseconds are an integer where one fits, and past that a floating-point number, exact below 2**53 (every millisecond of the next 280,000 years); nanoseconds are an integer on a 64-bit perl between September 1677 and April 2262, and a string of digits beyond that or on a 32-bit perl, as "epoch_string" is. During a leap second the second is that of the midnight after, as "epoch" has it.
julian_day
mjd
The Julian Day and the Modified Julian Day, with the fraction of the day. A Julian Day begins at noon UTC.
tai_offset
TAI minus UTC, in seconds: 10 from 1972, and one more after each leap second. Undefined before 1972, and in floating time. See "LEAP SECONDS".
NEW VALUES FROM OLD
with
my $first = $t->with(day => 1);
my $noon = $t->with(hour => 12, minute => 0, second => 0);
A value in the same zone with the wall-clock fields given changed and the rest as they were. It takes the fields "new" does, apart from zone, and gap and overlap. day may be last, the last day of the month; day_of_week, 1 for Monday to 7 for Sunday, moves to that day of the same ISO 8601 week, after the other fields have been set.
my $end = $t->with(month => 2, day => 'last');
my $sun = $t->with(day_of_week => 7);
my $doy = $t->with(year => 2027, day_of_year => 60);
my $wk = $t->with(week => 1, day_of_week => 1);
day_of_year, 1 to 366, and week, an ISO 8601 week of the year given or the value's own, set the date instead of month and day, and cannot be given with them; week keeps the value's day of the week unless day_of_week says otherwise.
try_with
As "with", but undef where "with" would die, and $@ left as it was.
in_zone
my $tokyo = $t->in_zone('Asia/Tokyo');
The same instant, in another zone. To or from floating time it is the wall-clock time that is kept instead, and gap and overlap may be given for that.
in_locale
my $fr = $t->in_locale('fr');
The same instant in the same zone, with names and formats from another locale.
as_utc
$t->in_zone('UTC').
as_floating
The same wall-clock time in floating time.
to_date
to_year_month
to_month_day
to_time
$t->to_date; # a Time::Keeper::Date: the wall-clock date
$t->to_year_month; # a Time::Keeper::YearMonth
$t->to_month_day; # a Time::Keeper::MonthDay
$t->to_time; # a Time::Keeper::Time: the wall-clock time of day
The value's wall-clock date or time of day, or part of the date, as a plain class with the value's locale (see "DATES WITHOUT TIMES"). During a leap second to_time gives 23:59:59.999999999, the last time of day there is. $t->date and $t->time are still the strings.
ARITHMETIC
Amounts of time are Time::Keeper::Durations. Adding one to a value adds its months first, then its days, to the wall-clock date, keeping the wall-clock time; then its minutes, 60 seconds each; then its seconds, which count leap seconds. So a day added across a change of the clocks keeps the time of day, and 24 hours added does not:
my $t = Time::Keeper->new(year => 2026, month => 3, day => 7, hour => 12,
zone => 'America/New_York');
$t->plus(days => 1); # 2026-03-08T12:00:00-04:00
$t->plus(hours => 24); # 2026-03-08T13:00:00-04:00
The difference of two values is the duration that takes the one to the other: $a->plus($b - $a) is always $b. It has the most whole months that do not go past $b, then the most whole days, then the rest as minutes and seconds. $a - $b is not always the negation of $b - $a: months are not all one length, so counting back from $b can take a different number of days than counting on from $a.
plus
my $later = $t->plus(months => 1, days => 2);
my $later = $t->plus($duration);
my $later = $t->plus(days => 1, gap => 'forward');
A new value, the duration later. It takes a duration, or the units of one by name as "new" in Time::Keeper::Duration takes them, and gap and overlap for a wall-clock time the months or days land on that did not happen or happened twice; see "GAPS AND OVERLAPS". $t + $duration is the same with the defaults.
minus
my $earlier = $t->minus(days => 2);
my $earlier = $t->minus($duration);
my $between = $b->minus($a); # a Time::Keeper::Duration
Given a duration or its units, a new value the duration earlier. Given another value, the duration from that value to this one, as above. $t - $duration and $b - $a are the same.
minus_absolute
my $d = $b->minus_absolute($a);
The time from $a to $b as seconds and nanoseconds alone, counting leap seconds: the time that passed.
delta_days
The number of days between the two values' dates, as a duration of days, never negative.
delta_md
The months and days between the two values' dates, never negative.
delta_ms
The minutes and seconds between the two values, never negative.
until
since
my $d = $a->until($b); # the same as $b - $a
my $d = $a->until($b, largest => 'hours'); # PT747H30M15.5S
my $d = $b->since($a, largest => 'weeks', smallest => 'days');
my $d = $a->until($b, smallest => 'hours', mode => 'half_ceil');
my $d = $a->until($b, smallest => 'minutes', increment => 15);
The duration from this value to $b (until), or from $a to this value (since), in the units asked for. largest is the largest unit the duration may have: years or months give months, then days, then the clock, as "minus" does; weeks or days give days, then the clock; hours or minutes give minutes of 60 seconds and then seconds; seconds and below give seconds alone, the time that passed, counting leap seconds (a leap second crossed shows in the seconds whatever the largest unit).
smallest drops the parts below it and rounds the unit's own part, to a multiple of increment for a clock unit, by mode: trunc, towards zero, the default; expand, away from it; and "round"'s floor, ceil, half_floor, half_ceil and half_even, where floor of a negative duration is away from zero. The two candidates are measured as instants from the start, so a day is as long as it was there, and a clock part that rounds up into a whole day is carried into the days.
$a->plus($a->until($b, largest => ...)) is $b for every largest; with smallest it is $b rounded.
truncate
my $monday = $t->truncate(to => 'week');
my $ms = $t->truncate(to => 'millisecond');
The start of the value's year, quarter, month, week (a Monday), day, hour, minute, second, millisecond, microsecond or nanosecond. Where that wall-clock time did not happen, the first moment after it that did.
$t->truncate(to => 'week', week_start => 7); # the Sunday
$t->truncate(to => 'week', week_start => 'locale'); # the locale's first day
week_start says what day a week begins on, 1 for Monday to 7 for Sunday, or locale for the value's locale's first day of the week: Sunday in the United States, Saturday in Egypt. "round" and "end_of" take it too.
round
my $t = $t->round(to => 'minute');
my $t = $t->round(to => 'minute', increment => 15);
my $t = $t->round(to => 'hour', increment => 6, mode => 'floor');
The start of the nearest year, quarter, month, week, day, hour, minute, second, millisecond, microsecond or nanosecond, the later of two as near.
increment rounds to a multiple of the unit: 15 minutes, 6 hours, 100 nanoseconds. It is for the clock units, and must divide the next unit up: 1 to 23 dividing 24 for an hour, a divisor of 60 for a minute or a second, of 1000 for the rest. Hours in increments are counted on the wall clock, so six-hour buckets begin at 00:00, 06:00, 12:00 and 18:00 local time whatever the day's length; a bucket whose start the clocks skipped begins at the first moment that did happen.
mode says which way:
floor the start of the value's own bucket, as truncate gives it
ceil the start of the next, unless the value is at a start
half_floor the nearer, the earlier of two as near
half_ceil the nearer, the later of two as near; the default
half_even the nearer, the even-numbered bucket of two as near,
counted from the start of the day, or of the calendar
trunc floor, and expand is ceil: for a value they are the same,
and L</until> and L<Time::Keeper::Duration/round> tell them apart
Nearer is by the time that passed, so around a change of the clocks the two candidates are not an equal number of wall-clock minutes apart.
end_of
my $last = $t->end_of(to => 'month'); # 2026-10-31T23:59:59.999999999Z
The last nanosecond of the value's year, quarter, month, week, day, hour, minute, second, millisecond, microsecond or nanosecond: the instant before the next one begins. On a day that ends in a leap second it is 23:59:60.999999999, and on a day whose midnight the clocks skipped it is the nanosecond before the first moment that did happen.
next
previous
my $monday = $t->next(day_of_week => 1);
my $friday = $t->previous(day_of_week => 5, or_same => 1);
The value's time of day on the next, or the previous, day of the week given, 1 for Monday to 7 for Sunday: strictly after, or before, the value's own day, unless or_same is true, when a value already on that day is given back as it is. gap and overlap may be given, as for "plus".
nth_in_month
last_in_month
my $thanksgiving = $t->nth_in_month(day_of_week => 4, n => 4);
my $change = $t->last_in_month(day_of_week => 7);
The value's time of day on the nth day of the week given in the value's month, n 1 to 5, or on the last of them with n -1 or last_in_month. A month with no fifth such day is an error that names it. gap and overlap as for "plus".
range
my @days = $start->range($end, by => 'day');
my @weeks = $start->range($end, by => 'week', inclusive => 0);
my @hours = $start->range($end, by => 'hour', step => 2);
my @months = $start->range($end, by => 'month', end_of_month => 'limit');
my @back = $end->range($start, by => Time::Keeper::Duration->new(days => -1));
my @safe = $start->range($end, by => 'day', gap => 'forward');
The values from the start to the end, a step apart. by is a unit name, singular or plural, or a Time::Keeper::Duration; step multiplies it. Each value is the start plus the step times its position, never the value before plus the step, so a month from 31 January gives 3 March, 31 March and 1 May, as "plus" would, and end_of_month says what a short month does. The end is included when the step lands on it, unless inclusive => 0. The step must move toward the end: a zero step, a step with parts of both signs, or an end the step walks away from is an error. gap and overlap as for "plus": a step of a day that keeps a time of day the clocks skipped dies unless told what to do. A range of more than about ten million values is refused; "iterate" has no limit.
iterate
my $next = $start->iterate($end, by => 'month');
while (my $t = $next->()) { ... }
As "range", but a code ref giving the next value each time it is called and undef after the last, for ranges too long to hold at once. Each iterator keeps its own place; a copy made for a thread continues on its own.
In another calendar
my $t = Time::Keeper->new(year => 5784, month => 6, day => 30, calendar => 'hebrew'); # 30 Adar I
$t->plus(months => 1); # 29 Adar II, wrapped to 1 Nisan
$t->plus(months => 13, end_of_month => 'limit'); # 29 Adar 5785
$t->plus(years => 1); # Adar 5785: a year without Adar I
$t->plus(years => 3)->month_code; # M05L: 5787 has one again
$b - $t; # months then days, the calendar's months
$t->truncate(to => 'year'); # 1 Tishri
In a calendar other than the Gregorian a month is the calendar's ordinal month ("CALENDARS"), so twelve months on from a day in a thirteen-month Hebrew year is the month before the same month next year. years, given by name to "plus" or "minus", are added first and keep the month by its code: a day in Adar I moved to a year with no Adar I lands in Adar, as ICU and Temporal have it, and end_of_month says what a day the month has not does. A Time::Keeper::Duration has no years of its own: its months are months, and "minus", "until" and "delta_md" give months and days, so $a + ($b - $a) is $b in every calendar. "truncate", "round" and "end_of" work on the calendar's years, quarters (three ordinal months, a thirteenth month alone in quarter 5) and months, and on the units below a week as ever; "nth_in_month" and "last_in_month" use the calendar's month; "next", "previous" and "range" are days and are the same in every calendar.
Months and the end of the month
A month added to 31 January has no 31st to land on. A duration says what to do, as its end_of_month: wrap runs on into the next month (3 March, or 2 March in a leap year), limit stops at the last day (28 February), and preserve keeps the last day of a month the last day of the month it lands in. A duration of a positive number of months wraps unless told otherwise, and one of a negative number preserves, as in DateTime.
Time::Piece's add_months and add_years are plus(months => $n) and plus(years => $n), which wrap as they do.
FORMATTING
Names and formats come from the value's locale (see "LOCALES"). Formatting gives back characters: English's time formats put a narrow no-break space (U+202F) before AM and PM, as CLDR has them.
strftime
$t->strftime('%Y-%m-%d %H:%M:%S.%3N %z');
my ($d, $tm) = $t->strftime('%F', '%T');
The conversions of C's strftime, as DateTime has them:
%a %A the day's name, short and long
%b %h %B the month's name, short and long
%c %x %X the locale's date and time, its date, its time
%C the century
%d %e the day of the month, padded with 0 and with a space
%D %F %m/%d/%y and %Y-%m-%d
%g %G %V the ISO week year in two digits and in full, the ISO week
%H %k the hour 0 to 23, padded with 0 and with a space
%I %l the hour 1 to 12, padded with 0 and with a space
%j the day of the year
%m %M %S the month, the minute, the second
%N nanoseconds; %3N milliseconds, %6N microseconds, %9N nanoseconds
%p %P AM or PM, am or pm
%r %R %T %I:%M:%S %p, %H:%M and %H:%M:%S
%s the epoch
%u %w the day of the week, 1 to 7 from Monday, 0 to 6 from Sunday
%U %W the week of the year, weeks starting on Sunday, on Monday
%y %Y the year in two digits and in full
%z %Z the offset as +HHMM, the zone's abbreviation
%n %t %% a newline, a tab, a %
%{name} what the method of that name returns
glibc's flags are taken too: %-d drops the padding, %_d pads with spaces, %0e with zeros, %^a upper-cases, and a width such as %10Y pads a number to it. The names, and %c, %x and %X, are the locale's; the numbers are ASCII digits, as the machine-readable forms strftime is used for need, except with glibc's O modifier: %Od is the day in the locale's own digits (in ar-EG, ١٥). E is read and passed over. A conversion it does not know is left as it was. During a leap second %S is 60. In floating time %z is +0000 and %Z is floating, as in DateTime. Given several patterns, strftime gives a result for each.
format
$t->format('EEEE, d MMMM y'); # Thursday, 15 October 2026
$t->format("h 'o''clock' a"); # 9 o'clock PM
A CLDR pattern, as Unicode Technical Standard 35 defines them. A run of one letter is a field, and how many letters says how it is written: M 10, MM 10, MMM Oct, MMMM October, MMMMM O. Text in single quotes is written as it is, and '' is a quote. The fields:
G era
y u year
Y week year, as the locale counts weeks
Q q quarter
M L month
w W week of the year and of the month, as the locale counts them
d D F day of the month, day of the year, weekday in the month
g modified Julian day
E e c weekday
a b B AM or PM; noon and midnight; the period of the day
h H K k j hour
m s minute, second
S fraction of a second
A milliseconds in the day
z v V zone names
Z O X x offsets
Numbers are written in the locale's own digits (see "LOCALES"), except the ISO 8601 offsets of X, x and Z.
Weeks are counted as the locale counts them: a week starts on the locale's first day, and week 1 of a year is the first to hold at least the locale's minimum of days of January. In the United States weeks start on Sunday and the week holding the 1st of January is week 1; in most of Europe they are ISO 8601's. W is 0 for the days before a month's first week. "week" and "week_year" stay ISO's.
b writes noon and midnight at exactly those times, and AM or PM at any other. B writes the locale's period of the day: in the morning, at night, du soir. A locale with no periods writes AM or PM.
The zone names are CLDR's, chosen as Unicode Technical Standard 35 says:
z zzzz the specific name: EDT, Eastern Daylight Time
v vvvv the generic name: ET, Eastern Time
V the zone's short id: usnyc
VV the zone's name: America/New_York
VVV the city: New York
VVVV the location: New York Time, France Time
O OOOO the GMT format: GMT-4, GMT-04:00, in the locale's words
A name the locale does not have falls back as the standard says: a specific name to the GMT format; a generic one to the standard name, for a zone with no daylight time within six months, then to the location, then to the GMT format. A zone's name is the one in use at the time: Indiana's Knox was on Eastern time in 1995 and is on Central time now.
Where DateTime's format_cldr departs from the standard, the standard is followed: YY is the week year in two digits, not padded to two; c and e count the days from the locale's first day of the week (Sunday in the United States), not from Monday; w, W and Y count weeks as the locale does, not as ISO 8601 does; g counts local days, from local midnight, not UTC ones; ZZZZ is GMT-04:00, not EDT-0400; ZZZZZ and X write Z for a zero offset; QQQQQ, aaaa and aaaaa have their narrow and wide forms; z, v and V are CLDR's names, not the zone's abbreviation (GMT+9, not JST, where the locale has no name for it); and numbers are in the locale's digits.
format_date
format_time
format_datetime
$t->format_date('full'); # Thursday, October 15, 2026
$t->format_time('short'); # 9:05 PM
$t->format_datetime; # Oct 15, 2026, 9:05:07 PM
The locale's own format for the date, the time, or both, at full, long, medium (the default) or short.
format_skeleton
$t->format_skeleton('yMMMd'); # Oct 15, 2026
The locale's format for a skeleton: the fields wanted, without their order or punctuation, which are the locale's. A skeleton the locale has no format for is an error. In another calendar the calendar's own skeletons come first (a y matches the yyyy they are keyed by), then the Gregorian ones; see "CALENDARS".
format_relative
$t->format_relative; # 3 hours ago
$t->format_relative(to => $then); # in 2 days
$t->format_relative(unit => 'day'); # yesterday
$t->format_relative(numeric => 'always'); # 1 day ago
$t->in_locale('fr')->format_relative(style => 'short'); # il y a 3 h
The value as a time relative to to, which is now if not given, in the locale's words, as Intl.RelativeTimeFormat writes one. unit is auto (the default: the largest of year, month, week, day, hour, minute and second with a count that is not zero), or one of them, or quarter. Days, weeks, months and years are counted on the wall-clock dates in the value's zone, so 23:00 yesterday is yesterday at 09:00 today, and hours, minutes and seconds by the time that passed. style is long, short or narrow. With numeric auto, the default, a count the locale has a word for is written as the word: yesterday, today, tomorrow, last month, now; with always it is written as a number: 1 day ago, in 0 days. Numbers are in the locale's digits.
format_interval
$a->format_interval($b, skeleton => 'yMMMd'); # Oct 15 – 17, 2026
$a->format_interval($b, skeleton => 'hm'); # 9:00 – 10:30 AM
$a->in_locale('fr')->format_interval($b, skeleton => 'yMMMd'); # 15–17 oct. 2026
The two values as an interval in the locale's words, as Intl.DateTimeFormat's formatRange writes one: the fields the skeleton names, with what the two ends share written once. The greatest field that differs, of era, year, month, day, the period of the day, hour and minute, chooses the locale's interval format for the skeleton; where the two ends agree in every field the skeleton shows, the start alone is written, as "format_skeleton" writes it; where they differ in a field the skeleton does not show, both are written in full round the locale's dash. The end is brought into the start's zone and written in the start's locale; the two are written in the order given. A skeleton the locale has no interval formats for is an error, and a value in floating time pairs only with another.
month_name
month_abbr
day_name
day_abbr
am_pm
era_name
era_abbr
quarter_name
quarter_abbr
The names, in the value's locale: October, Oct, Thursday, Thu, PM, Anno Domini, AD, 4th quarter, Q4.
ymd
mdy
dmy
hms
date
time
$t->ymd; # 2026-10-15
$t->dmy('/'); # 15/10/2026
$t->hms(''); # 090507
The date in three orders, and the time, with the separator given (- for dates and : for the time by default). date and time are ymd and hms with the default separators.
rfc3339
The RFC 3339 form: as "iso8601", and with its precision option. RFC 3339 has no form for floating time or for a year outside 0000 to 9999, and asking for one is an error.
rfc2822
Thu, 15 Oct 2026 21:05:07 -0400
The Internet Message Format's date (RFC 5322, which replaced RFC 2822), in English whatever the locale, without a fraction of a second.
rfc9557
2026-10-15T21:05:07-04:00[America/New_York]
RFC 3339 with the zone's name after it in brackets, as RFC 9557 extends it: the offset and the zone together, so a reader has the zone's rules as well as the offset at that moment. UTC is +00:00[UTC] and a fixed offset names itself. Floating time has neither. A value in another calendar ends [u-ca=hebrew], which "parse" reads back (see "CALENDARS").
http_date
Fri, 16 Oct 2026 01:05:07 GMT
The date HTTP uses (RFC 9110): the instant in GMT, in English.
PARSING
Every parser makes a value the way "new" does: a date that does not exist, a weekday that is not the date's, or a leap second that was not one is an error, and zone, gap and overlap may be given. Text that does not say its zone is read in zone, or in UTC. An error says where in the text it went wrong:
Time::Keeper->parse: cannot parse '2026-10-15T25:00' at offset 13: the hour is past 24
parse
my $t = Time::Keeper->parse('2026-10-15T09:00:00+09:00[Asia/Tokyo]');
my $t = Time::Keeper->parse('Thu, 15 Oct 2026 09:00:00 +0900');
my $t = Time::Keeper->parse('2026-10-15 09:00', zone => 'Europe/London');
Any of the standard forms:
ISO 8601, in the extended and the basic forms: calendar dates (
2026-10-15), week dates (2026-W42-4) and ordinal dates (2026-288), a year or a month alone, expanded years (+012026), times to the hour, minute or second with a fraction of the last (T09.5is half past nine),24:00as the end of the day, and an offset orZ.RFC 3339, which is ISO 8601 with a space allowed for the
T, and RFC 9557, which adds the zone's name in brackets. Where the text has an offset and a zone, the offset fixes the instant and the zone is the value's; if they disagree and the zone is marked critical ([!Asia/Tokyo]) it is an error.[u-ca=gregory]is understood; another calendar is refused, as is any other critical annotation.The Internet Message Format's date (RFC 5322 and RFC 2822), with the obsolete zone names (
EST,PDT, and the military letters, which are UTC), two-digit years, and comments; and the three forms HTTP accepts (RFC 9110), including RFC 850's and C'sasctime.@and an epoch, as GNU'sdatereads one:@1760000000.5.
try_parse
As "parse", but undef where "parse" would die, and $@ left as it was.
strptime
my $t = Time::Keeper->strptime('15/10/2026 21:05', '%d/%m/%Y %H:%M');
my $t = Time::Keeper->strptime('Thu Oct 15 9:05 PM', '%a %b %d %I:%M %p',
zone => 'America/New_York');
The text read by a "strftime" pattern. Every conversion "strftime" writes is read back, except %{method}. Names are the locale's, matched in any case, short or long, and digits may be any script's. White space in the pattern matches any amount, or none. A field the pattern does not give takes Time::Piece's default: the year 1970, January, the 1st, midnight. %y 69 to 99 is 1969 to 1999, and 00 to 68 is 2000 to 2068, as POSIX has it. %Z reads an abbreviation: UTC, GMT, UT and Z are UTC; any other could mean more than one zone and is checked against zone, which must be given, and in an overlap it says which of the two times was meant. With calendar, the date conversions read that calendar's months and years; see "CALENDARS".
try_strptime
As "strptime", but undef where it would die.
parse_cldr
my $t = Time::Keeper->parse_cldr('Thursday, 15 October 2026', 'EEEE, d MMMM y');
The text read by a CLDR pattern, as "format" writes them, in the locale given by locale. Where two numeric fields meet with nothing between (yyyyMMdd), each reads its own width. White space, and CLDR's no-break spaces, match any amount. Digits may be any script's, in any locale.
The zone's names are read back: a specific or generic name, a city, a location, or the GMT format in the locale's words or in plain GMT or UTC. A name read gives the value its zone; a specific name says standard or daylight time, which chooses between the two readings of a time in an overlap. b and B make a 12-hour time AM or PM. With calendar, the eras, years and months are the calendar's, as "CALENDARS" describes; an RFC 9557 [u-ca=] annotation in the text must agree with it.
try_parse_cldr
As "parse_cldr", but undef where it would die.
parse_interval
my ($start, $end) = Time::Keeper->parse_interval('2026-10-01/P1M');
An ISO 8601 interval: a start and an end, a start and a duration, or a duration and an end, with a / between. Both values are given back.
COMPARING AND PRINTING
Values compare with <=>, cmp and the operators made from them, so sort { $a <= $b }> and $t == $u work. Two values are equal when they are the same instant, whatever their zones. A value in floating time is a wall-clock time and not an instant: compared with any value, it is the wall-clock times that are compared. Comparing a value with anything that is not one is an error.
In a string a value is its "iso8601" form.
compare
my @sorted = sort { Time::Keeper->compare($a, $b) } @values;
-1, 0 or 1, as <=> gives.
utc_rd_values
local_rd_values
my ($days, $seconds, $nanoseconds) = $t->utc_rd_values;
The instant as DateTime counts time between modules: the day counted from 1 January of the year 1 as day 1, the seconds into it (86400 during a leap second) and the nanoseconds; in UTC, or on the value's wall clock. With them, DateTime->from_object(object => $t) works.
iso8601
2026-10-15T09:00:00+01:00
2026-10-15T09:00:00.250Z
The ISO 8601 form: the wall-clock time and the offset, Z for a value in UTC, and no offset in floating time. A zone whose offset is zero, such as London in winter, is +00:00, not Z: Z says the time is UTC and nothing about local time, as RFC 3339 has it. A fraction of a second is given in 3, 6 or 9 digits, whichever is the fewest that is exact. With precision, exactly that many digits, 0 to 9, truncated:
$t->iso8601(precision => 3); # 2026-10-15T09:00:00.123Z Years before 0 or after
9999 take ISO 8601's expanded form, such as C<+012026>.
$t->iso8601(form => 'basic'); # 20261015T090000Z
$t->iso8601(form => 'week'); # 2026-W42-4T09:00:00Z
$t->iso8601(form => 'ordinal'); # 2026-288T09:00:00Z
form chooses among ISO 8601's forms: extended, the default, with its separators; basic, without them, as file names like it; week, the week date; and ordinal, the day of the year. "parse" reads the three back, except a basic form with an expanded year, whose number of year digits ISO 8601 leaves to agreement. "rfc3339" and "rfc9557" take precision only.
TO_JSON
The "iso8601" form, for JSON encoders that call TO_JSON.
to_list
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = $t->to_list;
The nine fields localtime gives, in its conventions: the month from 0, the year less 1900, Sunday 0, the day of the year from 0, and whether the zone is on daylight saving time; the second is 60 during a leap second. For code that was fed localtime's list.
TIME ZONES
A zone argument is one of:
nothing, or
undef: UTCUTC,GMTorZ: UTCfloating: a wall-clock time with no zone, as a calendar entry might havean offset, such as
+05:30,-0800or+01: a fixed offset from UTC of under 24 hoursa zone's name from the IANA database, such as
Europe/London, in any case; see Time::Keeper::Zone for the nameslocal: this machine's zone, as "local_name" in Time::Keeper::Zone finds itanother value: its zone
GAPS AND OVERLAPS
When a zone's clocks go forward, the wall-clock times they jump over did not happen; when they go back, the times they repeat happened twice.
gap says what to do with a time that did not happen: croak, the default, dies with a message that says so; forward gives the instant it would be with the offset from before the change, which is later than the change by the length of the gap; backward gives the instant it would be with the offset from after it.
overlap says which of two instants to take: earlier, the default, or later.
Ambiguity. A value made can be asked whether its wall-clock time was one of the repeated ones, and for the other instant that reads the same. Both are worked out from the value's civil fields, however it was made: a value from an epoch is as ambiguous as one from a wall clock. The methods here, and "next_transition" and "previous_transition", need Time::Keeper::Zone 0.03 or later, and die naming it with an older one.
is_ambiguous
True when the value's wall-clock time happened twice in its zone. False in UTC, in a fixed offset and in floating time, and for a time the clocks jumped over.
other_reading
my $t = Time::Keeper->new(year => 2026, month => 11, day => 1, hour => 1, minute => 30,
zone => 'America/New_York'); # 01:30 EDT, the earlier
$t->other_reading; # 01:30 EST, an hour later
The other instant whose wall-clock time is this value's, in the same zone (a link keeps its name) and locale, or undef when there is only one.
next_transition
previous_transition
my $next = $t->next_transition; # a value, or undef
The next, or the last, instant at which the value's zone changes its offset, its DST flag or its abbreviation, as a value in the same zone and locale, or undef when there is none. The next transition is strictly after the value, the previous one strictly before it. UTC, a fixed offset and floating time never change. "transitions" in Time::Keeper::Zone lists a zone's transitions over a span.
LEAP SECONDS
A leap second is 23:59:60 UTC on one of the 27 days that ended with one, from 1972 to 2016. second => 60 is accepted at that second, in any zone (it was 08:59:60 in Tokyo), and refused at any other.
The leap seconds come from the list the International Earth Rotation and Reference Systems Service publishes. It says when no further leap second can come before:
leap_seconds_expire
my $until = Time::Keeper->leap_seconds_expire; # 2027-06-28T00:00:00Z
The list's expiry, as a value. Past it, no further leap second is known. None has been added since 2016, and leap seconds are due to be given up by 2035.
LOCALES
my $t = Time::Keeper->now(locale => 'fr');
$t->format_date('full'); # jeudi 15 octobre 2026
$t->in_locale('ja')->format_date('full');
A value's locale gives its names and formats: month and day names, eras, AM and PM, the periods of the day, the date and time formats, the formats by skeleton, the zone names, the first day of the week and the weekend, the words for relative times, durations, lists and intervals, and its digits. Every constructor and parser takes locale; "in_locale" changes it; "locale" gives it. The default is English, en, as used in the United States.
The data is the Unicode Common Locale Data Repository's, release 48.2.3, for every locale in its full set, every default-content code (fr-FR, which is fr) and CLDR's aliases for retired codes (iw is he): the codes DateTime::Locale has, and more. A code is matched without regard to case, with _ as -. Time::Keeper::Locale lists them and answers questions of each.
A locale's data is read the first time a value uses it, from one file installed beside this module, and kept for the life of the process. English is built in and reads nothing.
Digits. Where a locale writes its own digits, as 84 do (ar-EG, bn, fa, mr, my and others), "format", "format_date" and their kin write them: ١٥ أكتوبر ٢٠٢٦. DateTime writes ASCII digits in every locale. "strftime" writes ASCII digits unless asked with %O, and the fixed forms ("iso8601", "rfc2822" and the others) always do. The parsers read the digits of any script in any locale.
DATES WITHOUT TIMES
my $d = Time::Keeper::Date->new(year => 2026, month => 10, day => 15);
my $ym = Time::Keeper::YearMonth->new(year => 2026, month => 10);
my $md = Time::Keeper::MonthDay->new(month => 2, day => 29);
my $tm = Time::Keeper::Time->new(hour => 9);
my $t = $d->at($tm, zone => 'Europe/London');
A date, a time of day, a year and month, and a month and day are classes of their own: Time::Keeper::Date, Time::Keeper::Time, Time::Keeper::YearMonth and Time::Keeper::MonthDay, loaded with this module. None is a Time::Keeper value and none pretends to be: a date has no hour and no zone, a pattern letter that needs one is an error, and each compares only with its own kind. They share the arithmetic, the locales, the formats and the parsers. "to_date", "to_time", "to_year_month" and "to_month_day" take them from a value; at, on and in_year give a value or a date back.
CALENDARS
my $t = Time::Keeper->new(year => 5787, month => 1, day => 1, calendar => 'hebrew');
my $h = $t->in_calendar('hebrew'); # the same instant, read in another calendar
$h->calendar; # hebrew
$h->year; $h->month; $h->day; # 5787, 1, 1: the calendar's
$h->era; $h->era_year; # am, 5787
$h->month_code; $h->is_leap_month; # M01, 0
$h->months_in_year; $h->days_in_month; # 13, 30
$h->iso8601; $h->epoch; $h <=> $t; # the instant, calendar blind
A value is an instant in a zone, and the calendar is how its wall-clock date is read. Every constructor takes calendar, and "in_calendar" gives the same instant read in another; the default is the Gregorian, never the territory's. The accessors that name a date ("year", "month", "day", "day_of_year", "quarter", "day_of_quarter", "week_of_month", "is_leap_year", "days_in_month", "days_in_year", "days_in_quarter") answer in the value's calendar; "week" and "week_year" are ISO 8601's and stay Gregorian; the clock, the zone, the epoch, the comparisons and the ISO 8601 strings are the same in every calendar.
Months are counted from the first month of the year as Temporal counts them, so in a Hebrew leap year Adar I is the sixth month and Nisan the eighth; "month_code" gives the name that does not move, M07 for Nisan and M05L for Adar I. Quarters run over the ordinal months, three to a quarter, so a thirteenth month is quarter 5. Years are continuous and may be zero or negative; the era is a reading of the year:
gregory astronomical year bce, ce
buddhist the Gregorian year + 543 be
japanese the Gregorian year 237 eras from Taika: era0 .. era231, meiji, taisho, showa, heisei, reiwa
roc the Gregorian year - 1911 broc, roc
coptic Anno Martyrum before-am, am
ethiopic Amete Mihret aa (the year + 5500), am
ethioaa Amete Alem aa
hebrew Anno Mundi am
islamic-* Anno Hegirae ah, the years before it 0 and less, as ICU reads them
persian Anno Persico ap
indian Saka shaka
chinese, dangi the Gregorian year it begins in; era_year is ICU's count from 2637 BCE; cyclic_year 1 to 60
A Japanese day before Taika (645) is in the first era with a year of 0 or less, as ICU reads it. The calendars are proleptic: the Buddhist, Japanese and Minguo calendars are the Gregorian under another year count even before 1582, where ICU reads the Julian. The Persian calendar is ICU's 33-year arithmetic with ICU's corrections, not the equinox; Umm al-Qura is Saudi Arabia's table for 1300 to 1600 AH and the civil arithmetic outside it. The four that follow the moon and the sun, chinese, dangi, islamic and islamic-rgsa, are read from tables of what ICU computes, the Chinese and Korean years 1000 to 3000 (1000 to 3000 is also the span ICU itself warrants) and the Hijri years 390 to 2452 AH that lie within them; a day or a year outside the tables is an error that names them. A Chinese or Dangi year is named by the Gregorian year it begins in, its "cyclic_year" is its place in the cycle of sixty (1984 began one), and its leap month takes the number of the month before it with an L: 2033's leap eleventh month is M11L, the twelfth ordinal month. The tables are ICU's and keep its few disagreements with the Hong Kong Observatory, which has 2027's New Year on 6 February where ICU's new moon, at 23:56 Beijing time, gives the 7th.
Arithmetic in a calendar is described under "ARITHMETIC".
$h->in_locale('he')->format('d MMMM y'); # ד׳ בחשוון תשפ״ז
$t->in_calendar('japanese')->in_locale('ja')->format('Gy年M月d日'); # 令和8年10月15日
$t->in_calendar('chinese')->format('U r'); # bing-wu 2026
$h->format_date('full'); $h->month_name; $h->era_abbr;
$h->rfc9557; # 2026-10-15T09:00:00+00:00[UTC][u-ca=hebrew]
Time::Keeper->parse_cldr('24 Tishri 5787', 'd MMMM y', calendar => 'hebrew');
"format", "strftime", "format_date", "format_datetime", "format_skeleton", "ymd" and the name accessors write the value's calendar: CLDR's month and era names for it in the value's locale, the calendar's own date formats and skeletons, and its leap-month pattern (Sixth Monthbis, 闰六月). A locale with no names of its own for a calendar inherits its parent's, then the root's; English is built in, so every calendar works before the names file is read, and the file is read on the first use of another locale. In a pattern G is the calendar's era, y the year of the era, u the continuous year, r the Gregorian year the calendar's year began in, U the name of the cyclic year, and M or L the month: as a number the ordinal month, as ICU writes it (the Hebrew Iyar is 8 in a common year and 9 in a leap year), save that the Chinese calendars write the number in the month code, the leap month in its pattern (6bis). A Chinese or Dangi year has four numbers:
year, u 2026 the Gregorian year it began in
y 43 its place in the cycle of sixty (cyclic_year)
U bing-wu the cycle year's name (cyclic_year_name)
r 2026 the related Gregorian year
era_year, %Y 4663 ICU's continuous count from 2637 BCE
The numbering systems CLDR attaches to a calendar's patterns are honoured when those patterns are used: a Hebrew date in he is written in Hebrew letters (ד׳ בחשוון תשפ״ז, the thousands of the year dropped between 5001 and 5999 as ICU drops them), the day of a Chinese month in zh in its own numerals (初六), the first year of a Japanese era in ja as 元. A pattern of your own is written in the locale's digits. The date conversions of "strftime" (%Y %y %C %m %d %e %j %B %b %x %c) are the calendar's and %G %V %g stay ISO 8601: in_calendar('gregory') first for the Gregorian date. "rfc9557" appends [u-ca=id] for a value in another calendar; "parse" reads any known one (the date in the string is always ISO 8601, as the RFC says) and refuses one that disagrees with a calendar argument. "strptime" and "parse_cldr" take calendar: G matches the calendar's eras, y and u read the year of the era or the continuous year, r the related year, U the cyclic year beside an r that fixes the cycle, and M, L, %m and %B the calendar's month number or names and its leap pattern; a Chinese date needs a year.
The default calendar is the Gregorian everywhere, never the territory's; "preferred" in Time::Keeper::Calendar gives a territory's or a locale's calendars in CLDR's order of preference, and a locale code may carry a -u-ca- extension naming a calendar, th-u-ca-buddhist, which every constructor, "in_locale" and the parsers read as calendar when none is given and which "code" in Time::Keeper::Locale strips. The day an era began is "era_start" in Time::Keeper::Calendar.
The plain classes in a calendar other than the Gregorian, "format_relative", "format_interval" and largest => 'years' in "until", come in a later release: each dies saying so on such a value. Time::Keeper::Calendar answers questions about a calendar that need no value.
calendar
The id of the value's calendar: gregory unless it was made or read in another.
in_calendar
my $h = $t->in_calendar('hebrew');
The same instant, zone and locale, read in the calendar given (an id or an alias; see "ids" in Time::Keeper::Calendar).
era
era_year
month_code
is_leap_month
months_in_year
related_year
cyclic_year
cyclic_year_name
The era's code and the year within it; the month's code (M01 to M13, L after a leap month) and whether the month is a leap month; the months in the year; the Gregorian year the calendar's year began in (CLDR's related year); the year in the sixty-year cycle in the Chinese and Dangi calendars, and its name in the value's locale (bing-wu, 丙午 in zh), both undef in the others.
SERIALISATION
A value freezes with Storable as text: its instant, its zone by name and its locale by code, so a value frozen by one release thaws in another.
A serialiser that calls no hook, such as Struct::Codec, copies a value's bytes and gives back a working value in the same process. The bytes hold the zone by its place in Time::Keeper::Zone's table, which changes with the zone database, so bytes kept past a release of that module may name another zone: for storage, the hooks' text is the form to keep.
STORABLE_freeze
STORABLE_thaw
The Storable hooks.
FREEZE
THAW
The same for the serialisers that use Types::Serialiser's protocol: Sereal, CBOR::XS and JSON::XS with allow_tags. FREEZE gives the one string Storable gets, and THAW takes it back.
C ABI
Another extension's C can do what a value does without calling Perl: read the clock, find a zone by name, turn an instant into a wall clock in a zone and back with the same choices for gaps and overlaps, write strftime and CLDR patterns in any locale, the ISO 8601 and HTTP dates, parse every form "parse" reads, find a locale by its code, and make a Time::Keeper value or read one Perl made. Errors come back as codes rather than exceptions. A value made there is a value here, and one from here can be read there.
The interface is one header, time_keeper_abi.h, installed with the module. A consuming distribution finds it with ExtUtils::Depends:
my $pkg = ExtUtils::Depends->new('My::Module', 'Time::Keeper');
and resolves the table once, when it first needs it; the header shows how. Nothing is linked against, and the table is versioned, so the two distributions can be upgraded independently. It is at version 3: the second version appended the calendars (an instant's fields read in any calendar and back, formatting in one, the calendar a value is read in, a calendar by its id), and the third the arithmetic the methods do (plus, truncate, end_of, the weekday adjusters, a time set on a day), parse_cldr, durations, a locale's code and weekend, a date (Time::Keeper::Date, YearMonth and MonthDay) read and made, and a zone's next change of offset, each failing with the reason its method would give. Each was appended after the entries before it, so a consumer built against an older version keeps working.
THREADS
Values may be shared with or copied into threads.
CLONE
Sets up a new thread's copy of the module.
TESTING
{
local $Time::Keeper::CLOCK = Time::Keeper->parse('2026-10-15T09:00:00Z');
Time::Keeper->now; # 2026-10-15T09:00:00Z
Time::Keeper->today(zone => 'Asia/Tokyo');
$t->format_relative; # measured from the pinned clock
}
local $Time::Keeper::CLOCK = sub { $t = $t->plus(seconds => 1) };
local $Time::Keeper::CLOCK = sub { Time::Keeper->now->plus(hours => 1) };
Every reading of the clock, by "now", "today", "format_relative" without to, "compare" in Time::Keeper::Duration without a start and the C ABI's now, goes through $Time::Keeper::CLOCK when it is defined. It holds a value or an epoch, which pins the clock, or a code ref, called for each reading, that returns either. While the code ref runs the system clock is read, so the last example is a clock an hour fast. Set it with local so a test pins the clock for one block and nothing outside sees it; it is for tests, and a module that sets it for its callers is in the wrong. The pinned value's zone and locale are not taken: now applies its own arguments to the instant, as it does to the system's.
MOVING FROM TIME::PIECE AND DATETIME
Values never change. DateTime's
set,add,truncateandset_time_zonechange a value; "with", "plus", "truncate" and "in_zone" return a new one. There is noclone: a value is its own copy.UTC by default. DateTime's default is floating time and Time::Piece's
localtimeis the machine's zone; here a value with no zone is UTC, andzone => 'local'asks for the machine's.A zone is a name and a locale a code. "zone_name" and "locale" give them; Time::Keeper::Zone and Time::Keeper::Locale answer questions about them.
Arithmetic adds months before days, so
$b->minus($a)is the duration that adds back to exactly$b; DateTime adds days first, and 1.5% of its differences do not add back. "delta_md" differs from DateTime's in the same way.Gaps and overlaps are chosen with
gapandoverlap(see "GAPS AND OVERLAPS"): a time that did not happen dies unless asked otherwise, and of two that did the earlier is taken.In a string a value is RFC 3339 with its offset;
$t->strftime('%FT%T')is DateTime's form.Formatting follows CLDR where DateTime's
format_cldrdoes not (see "format"): zone names, weeks counted as the locale counts them, and the locale's own digits.DateTime->from_object(object => $t)andTime::Keeper->from_object(object => $dt)move a time between the two.
Time::Piece's names map as mon to "month", mday to "day", add_months to plus(months => $n), localtime to from_epoch($e, zone => 'local'); DateTime's as add to "plus", set to "with", set_time_zone to "in_zone", format_cldr to "format", time_zone_short_name to "zone_abbr".
SEE ALSO
Time::Keeper::Zone, DateTime, Time::Piece
AUTHOR
LNATION <email@lnation.org>
BUGS
Please report any bugs or feature requests to bug-time-keeper at rt.cpan.org, or through the web interface at https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Time-Keeper.
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)
The locale data is from the Unicode Common Locale Data Repository, Copyright (c) 1991-2026 Unicode, Inc., under the Unicode License v3.