NAME
Time::Str::Calendar - Gregorian calendar validation and computation
SYNOPSIS
use Time::Str::Calendar qw( valid_ymd ymd_to_rdn ymd_to_dow
ymd_to_doy yd_to_ymd
nth_dow_in_month
rdn_to_ymd resolve_century );
# Validate a date
valid_ymd(2024, 2, 29); # true (leap year)
valid_ymd(2023, 2, 29); # false
# Rata Die Number
my $rdn = ymd_to_rdn(2024, 12, 24); # 739244
# Day of week (1=Mon .. 7=Sun)
my $dow = ymd_to_dow(2024, 12, 24); # 2 (Tuesday)
# Day of year (1-366)
my $doy = ymd_to_doy(2024, 12, 24); # 359
# Day of year to date
my ($m, $d) = yd_to_md(2024, 359); # (12, 24)
# Rata Die to date
my ($y, $m, $d) = rdn_to_ymd(739244); # (2024, 12, 24)
# Resolve two-digit year
my $year = resolve_century(24, 1950); # 2024
DESCRIPTION
This module provides Gregorian calendar functions for date validation, day numbering, and century resolution. All functions operate on integer values and are exportable on request. Use :all to import everything.
FUNCTIONS
leap_year
my $bool = leap_year($year);
Returns true if the given year is a leap year in the Gregorian calendar.
month_days
my $days = month_days($year, $month);
Returns the number of days in the given month (28-31), accounting for leap years.
Croaks if month is out of range [1, 12].
valid_ymd
my $bool = valid_ymd($year, $month, $day);
Returns true if the given date is valid in the Gregorian calendar. Checks year (1-9999), month (1-12), and day range for the given month, accounting for leap years.
ymd_to_rdn
my $rdn = ymd_to_rdn($year, $month, $day);
Returns the Rata Die Number for the given date (day 1 = 0001-01-01).
Croaks if year is out of range [1, 9999], month is out of range [1, 12], or day is out of range [1, 31].
The date is not validated; use valid_ymd first if the input is untrusted.
rdn_to_ymd
my ($year, $month, $day) = rdn_to_ymd($rdn);
Converts a Rata Die Number back to a Gregorian date.
Croaks if rdn is out of range [1, 3652059].
rdn_to_dow
my $dow = rdn_to_dow($rdn);
Returns the day of week for the given Rata Die Number as an integer (1=Monday .. 7=Sunday).
Croaks if rdn is out of range [1, 3652059].
ymd_to_doy
my $doy = ymd_to_doy($year, $month, $day);
Returns the day of year (1-366) for the given date.
Croaks if year is out of range [1, 9999], month is out of range [1, 12], or day is out of range [1, 31].
The date is not validated; use valid_ymd first if the input is untrusted.
yd_to_md
my ($month, $day) = yd_to_md($year, $day);
Converts a year and day of year (1-366) to a Gregorian date.
Croaks if year is out of range [1, 9999], or day is out of range [1, 366].
The date is not validated; use valid_yd first if the input is untrusted.
ymd_to_dow
my $dow = ymd_to_dow($year, $month, $day);
Returns the day of week as an integer (1=Monday .. 7=Sunday).
Croaks if year is out of range [1, 9999], month is out of range [1, 12], or day is out of range [1, 31].
The date is not validated; use valid_ymd first if the input is untrusted.
nth_dow_in_month
my $day = nth_dow_in_month($year, $month, $ord, $dow);
Returns the day of month for the ord-th occurrence of weekday dow in the given month and year.
$dow uses the ISO convention (1=Monday .. 7=Sunday).
$ord is a signed ordinal:
1 to 4 count forward from the start of the month.
-1 to -4 count backward from the end of the month (
-1= last,-2= second-to-last, etc.).
# 2nd Sunday of March 2024 (US spring forward)
nth_dow_in_month(2024, 3, 2, 7) # 10
# Last Sunday of October 2024 (EU fall back)
nth_dow_in_month(2024, 10, -1, 7) # 27
# 4th Thursday of November 2024 (US Thanksgiving)
nth_dow_in_month(2024, 11, 4, 4) # 28
# Last Monday of May 2024 (US Memorial Day)
nth_dow_in_month(2024, 5, -1, 1) # 27
Croaks if year is out of range [1, 9999], month is out of range [1, 12], ord is out of range [-4, -1] or [1, 4], or dow is out of range [1, 7].
resolve_century
my $resolved = resolve_century($year, $pivot_year);
Resolves a two-digit year (0-99) to a four-digit year using the given pivot year. Years below the pivot offset map to the next century; others map to the pivot's century.
resolve_century(24, 1950) # 2024
resolve_century(49, 1950) # 2049
resolve_century(50, 1950) # 1950
resolve_century(99, 1950) # 1999
Croaks if year is out of range [0, 99] or pivot_year is out of range [0, 9899].
SEE ALSO
Time::Str, Time::Str::Token, Time::Str::Regexp
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.