condorcet-php/php-calendars

Pure PHP implementation of the Arabic (Hijri), French, Gregorian, Jewish, Julian and Persian (Jalali) calendars. Also provides a drop-in replacement for the PHP ext/calendar extension.

Maintainers

Package info

github.com/julien-boudry/PhpCalendars

Homepage

Issues

pkg:composer/condorcet-php/php-calendars

Statistics

Installs: 70

Dependents: 0

Suggesters: 0

Stars: 0

v3.0.0 2026-03-29 16:00 UTC

This package is auto-updated.

Last update: 2026-03-29 16:01:24 UTC


README

Pure PHP implementation of six historical and religious calendars, with an object-oriented API and a drop-in replacement for PHP's ext/calendar extension.

This package provides a pure PHP implementation of the Arabic (Hijri), French Republican, Gregorian, Julian, Jewish and Persian (Jalali) calendars, plus a drop-in replacement for PHP‘s ext/calendar extension.

Note

This project is a fork of fisharebest/ext-calendar, originally written by Greg Roach for the webtrees project. It modernises the codebase (PHP 8.5+, strict types, native type declarations) and continues development under the CondorcetPHP namespace.

Requirements

  • PHP (64bit) >= 8.5

Installation

composer require condorcet-php/php-calendars

Object-oriented API

All six calendars implement CalendarInterface with the following methods:

Method Description
ymdToJd(int $year, int $month, int $day): int Convert a date to a Julian Day Number
jdToYmd(int $julian_day): array Convert a Julian Day Number to [$year, $month, $day]
daysInMonth(int $year, int $month): int Number of days in a given month
monthsInYear(?int $year = null): int Number of months in a year (or the maximum if $year is null)
daysInWeek(): int Number of days in a week (7 for most calendars, 10 for the French Republican)
isLeapYear(int $year): bool Whether the given year is a leap year
jdStart(): int Lowest Julian Day Number accepted by this calendar
jdEnd(): int Highest Julian Day Number accepted by this calendar
gedcomCalendarEscape(): string GEDCOM calendar escape sequence

Available calendars

Class Calendar Months Days/week JD range
ArabicCalendar Hijri (Islamic) 12 7 1 948 440 – PHP_INT_MAX
FrenchCalendar French Republican 13 10 2 375 840 – 2 380 687
GregorianCalendar Gregorian 12 7 1 – PHP_INT_MAX
JewishCalendar Hebrew 12 or 13 7 347 998 – PHP_INT_MAX
JulianCalendar Julian 12 7 1 – PHP_INT_MAX
PersianCalendar Jalali (Iranian) 12 7 1 948 321 – PHP_INT_MAX

The Arabic and Persian calendars are exclusive to this library — they are not available in the native ext/calendar extension.

Usage example

use CondorcetPHP\PhpCalendars\ArabicCalendar;
use CondorcetPHP\PhpCalendars\FrenchCalendar;
use CondorcetPHP\PhpCalendars\GregorianCalendar;
use CondorcetPHP\PhpCalendars\JewishCalendar;
use CondorcetPHP\PhpCalendars\JulianCalendar;
use CondorcetPHP\PhpCalendars\PersianCalendar;

$calendar = new GregorianCalendar();

// Convert a date to a Julian Day Number and back
$jd = $calendar->ymdToJd(2026, 3, 29);
[$year, $month, $day] = $calendar->jdToYmd($jd);

// Leap year, days in month, months in year
$calendar->isLeapYear(2024);    // true
$calendar->daysInMonth(2024, 2); // 29
$calendar->monthsInYear();       // 12
$calendar->daysInWeek();         // 7

// Valid Julian Day range for this calendar
$calendar->jdStart(); // 1
$calendar->jdEnd();   // PHP_INT_MAX

Jewish calendar extras

JewishCalendar provides an additional method to format numbers as Hebrew numerals (UTF-8):

$jewish = new JewishCalendar();

// 13 months in a leap year
$jewish->monthsInYear(5784); // 13

// Hebrew numerals — with and without the thousands prefix
$jewish->numberToHebrewNumerals(5781, false); // "תשפ״א"
$jewish->numberToHebrewNumerals(5781, true);  // "ה׳תשפ״א"

Drop-in replacement for ext/calendar

This package also provides shim functions that are automatically registered when the native ext/calendar extension is not loaded. All 18 functions and their associated constants are supported:

All associated constants are also provided: CAL_GREGORIAN, CAL_JULIAN, CAL_JEWISH, CAL_FRENCH, CAL_NUM_CALS, CAL_DOW_DAYNO, CAL_DOW_SHORT, CAL_DOW_LONG, CAL_MONTH_GREGORIAN_SHORT, CAL_MONTH_GREGORIAN_LONG, CAL_MONTH_JULIAN_SHORT, CAL_MONTH_JULIAN_LONG, CAL_MONTH_JEWISH, CAL_MONTH_FRENCH, CAL_EASTER_DEFAULT, CAL_EASTER_ROMAN, CAL_EASTER_ALWAYS_GREGORIAN, CAL_EASTER_ALWAYS_JULIAN, CAL_JEWISH_ADD_ALAFIM_GERESH, CAL_JEWISH_ADD_ALAFIM, CAL_JEWISH_ADD_GERESHAYIM.

// Works whether ext-calendar is installed or not
print_r(cal_info(CAL_GREGORIAN));

$jd = GregorianToJD(3, 29, 2026);
echo JDDayOfWeek($jd, CAL_DOW_LONG); // "Sunday"
echo jdtojewish($jd, true, CAL_JEWISH_ADD_GERESHAYIM);

You can also call the static methods on CondorcetPHP\PhpCalendars\Shim directly, regardless of whether ext/calendar is installed:

use CondorcetPHP\PhpCalendars\Shim;

$jd = Shim::gregorianToJd(3, 29, 2026);
echo Shim::jdDayOfWeek($jd, CAL_DOW_LONG);

Known restrictions and limitations

  • The functions easter_date() and jdtounix() use PHP's timezone, instead of the operating system's timezone. These may be different.
  • Invalid arguments (wrong calendar ID, out-of-range month, etc.) throw a ValueError.
  • The French Republican calendar only covers years 1–14 (22 Sep 1792 – 31 Dec 1805).

Development and contributions

See the CHANGELOG for the full release history.

Pull requests are welcome. Please ensure you include unit-tests where applicable.

# Run the test suite (Pest)
composer test

# Run the benchmarks (native ext-calendar vs PHP implementation)
composer bench

# Static analysis
composer phpstan

# Code style
composer lint

Future plans

  • Support alternate leap-year schemes for the French calendar (true equinox, Romme, 128-year cycle) as well as the 4-year cycle.
  • Support other calendars, such as Ethiopian, Hindu, Chinese, etc.