Certaines fonctions de PHP permettent d’obtenir des informations ayant trait au calendrier. Mais, comment les obtenir si vous n’avez pas l’extension calendar disponible ?


Partager l’article Date de Pâques et nombre de jours dans un mois en PHP sur les réseaux sociaux


L’extension Calendar de PHP est très pratique, mais la majeure partie de ses fonctionnalités est très peu utilisée dans l’ensemble.

Chez nous, en France et dans les pays francophones, les fonctions fréquemment utilisées de cette extension sont easter_date() et cal_days_in_month().

Comment faire pour avoir un équivalent si vous ne pouvez pas utiliser l’extension Calendar ? C’est ce que je vais vous montrer.

Exemple connu : Pâques

La fonction easter_date() permet d’avoir la date de Pâques pour une année donnée.

Cela est très pratique, car outre Pâques, cela permet d’avoir par déduction les dates d’autres fêtes comme l’Ascension ou la Pentecôte. Pouvoir déterminer la date de Pâques permet de déterminer tous les jours fériés ayant un date variable en France.

J’ai fait un article dernièrement avec MySQL à ce sujet. Maintenant, transposons le code en PHP. Le but est de créer une fonction prenant un paramètre int pour l’année dont on veut déterminer la date de Pâques, et qui sort un object DateTime pour manipuler la date comme on le désire.

// https://de.wikipedia.org/wiki/Gau%C3%9Fsche_Osterformel#Eine_erg.C3.A4nzte_Osterformel
function easter(int $year): \DateTime
{
    $k = intdiv($year, 100);
    $m = 15 + intdiv((3 * $k + 3), 4) - intdiv((8 * $k + 13), 25);
    $s = 2 - intdiv((3 * $k + 3), 4);
    $a = $year % 19;
    $d = (19 * $a + $m) % 30;
    $r = intdiv(($d + intdiv($a, 11)), 29);

    $og = 21 + $d - $r ;
    $sz = 7 - ($year + intdiv($year, 4) + $s) % 7;
    $oe = 7 - ($og - $sz) % 7;
    $os = $og + $oe;

    $result = new \DateTime(sprintf('%04s-03-01', $year));
    $result->add(
        \DateInterval::createFromDateString(
            sprintf('%s days', $os-1)
        )
    );
    
    return $result; 
}

Il y a d’autres implémentations avec d’autres algorithmes que vous trouverez facilement sur le net.

Jouons un peu avec notre fonction :

var_dump(easter(2022)->format('d/m/Y'));
// string(10) "17/04/2022"

var_dump(easter(2032)->format('d/m/Y'));
// string(10) "28/03/2032"

var_dump(easter(2042)->format('d/m/Y'));
// string(10) "06/04/2042"

var_dump(easter(1789)->format('d/m/Y'));
//string(10) "12/04/1789"

Voilà notre première fonction de remplacement opérationnelle ! Vous pouvez comparer à la liste des dates de Pâques.

Nombre de jours dans un mois donné

La fonction cal_days_in_month() de l’extension Calendar permet de récupérer le nombre de jours dans un mois d’une année donnée. Il est possible de spécifier un type de calendrier particulier en prime.

Si vous ne disposez pas de l’extension Calendar, alors sachez que l’utilisation des fonctionnalités des dates en natif suffisent.

Sur un objet DateTime, l’appel à la méthode format() avec l’argument 't' permet de retourner le nombre de jours dans le mois de la date pré-définie.

Par exemple, pour février 2022, on peut faire ceci :

var_dump((new DateTime('2022-02'))->format('t'));
// string(2) "28"

L’utilisation n’est pas très pratique, nous allons donc créer une fonction qui prend obligatoirement le mois, et en option, l’année. Si l’année n’est pas fournie, alors c’est l’année en cours qui est prise.

Et tant qu’à faire, on va retourner une valeur entière int, et non une chaîne de caractères string.

function daysInMonth(int $month, int $year = null): int
{
    $date = sprintf(
        '%s-%02s-01', 
        is_null($year) ? (new \DateTime())->format('Y') : $year,
        $month
    );

    return (int) (new DateTime($date))->format('t');
}

Jouons un peu avec cette fonction :

var_dump(daysInMonth(2));
// int(28)
var_dump(daysInMonth(2, 2022));
// int(28)
var_dump(daysInMonth(2, 2020));
// int(29)

C’est pas mal, maintenant protégeons-là un peu pour éviter d’entrer des valeurs impossibles comme un mois 13 ou une année hors de l’intervalle -9999/9999 :

function daysInMonth(int $month, int $year = null): int
{
    if ($month > 12 || $month < 1) {
        throw new \InvalidArgumentException('Month must be in range 1;12');
    }

    if (!is_null($year) && ($year > 9999 || $year < -9999)) {
        throw new \InvalidArgumentException('Year must be in range -9999;9999');
    }

    $date = sprintf(
        '%s-%02s-01', 
        is_null($year) ? (new \DateTime())->format('Y') : $year,
        $month
    );

    return (int) (new DateTime($date))->format('t');
}

Voyons cela :

var_dump(daysInMonth(2));
// int(28)

var_dump(daysInMonth(2, 2022));
// int(28)

var_dump(daysInMonth(2, 9999));
// int(28)

var_dump(daysInMonth(2, 19999));
// PHP Warning:  Uncaught InvalidArgumentException: Year must be in range -9999;9999 in php shell code:8
// Stack trace:
// #0 php shell code(1): daysInMonth()
// #1 {main}
//   thrown in php shell code on line 8

var_dump(daysInMonth(2, -9999));
// int(28)

var_dump(daysInMonth(2, -19999));
// PHP Warning:  Uncaught InvalidArgumentException: Year must be in range -9999;9999 in php shell code:8
// Stack trace:
// #0 php shell code(1): daysInMonth()
// #1 {main}
//   thrown in php shell code on line 8

var_dump(daysInMonth(2, 2099));
// int(28)

var_dump(daysInMonth(12, 2099));
// int(31)

var_dump(daysInMonth(13, 2099));
// PHP Warning:  Uncaught InvalidArgumentException: Month must be in range 1;12 in php shell code:4
// Stack trace:
// #0 php shell code(1): daysInMonth()
// #1 {main}
//   thrown in php shell code on line 4

var_dump(daysInMonth(-1, 2099));
// PHP Warning:  Uncaught InvalidArgumentException: Month must be in range 1;12 in php shell code:4
// Stack trace:
// #0 php shell code(1): daysInMonth()
// #1 {main}
//   thrown in php shell code on line 4

var_dump(daysInMonth(1, 2099));
// int(31)

var_dump(daysInMonth(0, 2099));
// PHP Warning:  Uncaught InvalidArgumentException: Month must be in range 1;12 in php shell code:4
// Stack trace:
// #0 php shell code(1): daysInMonth()
// #1 {main}
//   thrown in php shell code on line 4

Pas mal non ? Libre à vous de l’intégrer dans une méthode de classe par exemple.

Conclusion

J’espère que ces deux fonctions pourront vous être utile si vous vous retrouvez sans le module Calendar de PHP.

Photo de Sigmund sur Unsplash