OVH Cloud OVH Cloud

weekday pour une date < 1970

4 réponses
Avatar
Zouplaz
Bonjour, suite à mon précédent post j'ai re-écrit ma classe date en optant
pour une représentation interne au lieu d'un timestamp.

La dernière fonction qui me pose problème doit retourner le jour de la
semaine d'une date arbitraire.

Avant j'utilisais :

date("w",$this->valDate);

avec valDate étant un timestamp.

Mais maintenant que je n'utilise plus de timestamp pour pouvoir gérer
n'importe quelle date comme puis-je faire pour connaitre le jour de la
semaine ?


Merci

4 réponses

Avatar
Olivier Miakinen

[...] maintenant que je n'utilise plus de timestamp pour pouvoir gérer
n'importe quelle date comme puis-je faire pour connaitre le jour de la
semaine ?


J'ai trouvé ceci dans la doc :
http://fr2.php.net/manual/fr/ref.calendar.php
http://fr2.php.net/manual/fr/function.cal-to-jd.php
http://fr2.php.net/manual/fr/function.jddayofweek.php

Avatar
Zouplaz
Zouplaz - :


Mais maintenant que je n'utilise plus de timestamp pour pouvoir gérer
n'importe quelle date comme puis-je faire pour connaitre le jour de la
semaine ?



Et bien j'ai trouvé une formule magique (et franchement j'y comprends rien)
dans le code pear:Date_Calc

if ($month > 2) {
$month -= 2;
}
else
{
$month += 10;
$year--;
}

$day = ( floor((13 * $month - 1) / 5) +
$day + ($year % 100) +
floor(($year % 100) / 4) +
floor(($year / 100) / 4) - 2 *
floor($year / 100) + 77);
return (($day - 7 * floor($day / 7)));

Avatar
Olivier Miakinen
[ calcul du jour de la semaine pour une date donnée ]


Et bien j'ai trouvé une formule magique (et franchement j'y comprends rien)
dans le code pear:Date_Calc

if ($month > 2) {
$month -= 2;
}
else
{
$month += 10;
$year--;
}


Cette partie est assez facilement compréhensible : on décale le comptage
des mois à partir de mars pour qu'un éventuel jour bissextile se
retrouve à la fin de l'année (et donc ne décale pas le calcul pour les
dix mois qui suivent). Ainsi, les mois de mars à décembre sont numérotés
1 à 10, tandis que l'on considère janvier et février comme étant les
mois 11 et 12 de l'année précédente.

$day = ( floor((13 * $month - 1) / 5) +
$day + ($year % 100) +
floor(($year % 100) / 4) +
floor(($year / 100) / 4) - 2 *
floor($year / 100) + 77);
return (($day - 7 * floor($day / 7)));


Ici, c'est un peu plus dur à suivre. Une recherche sur Google m'a montré
que cette formule était quand même assez connue, puisque je l'ai trouvée
dans plein de langages différents.

en basic :
http://groups.google.fr/groups?selmccb7.5521092%40news.club-internet.fr

en rexx :
http://groups.google.fr/groups?selm93BEEE8.D87087FC%40earthlink.net

en cobol :
http://groups.google.fr/groups?selm2CB1D81.7FE4%40concentric.net


Et finalement, j'ai trouvé que cette formule est due à un Allemand nommé
Zeller, dont je n'ai pas trouvé le prénom. En voici (en anglais, sorry)
l'explication :
http://mathforum.org/library/drmath/view/62324.html


[ copie et suivi vers fr.sci.maths ]

Avatar
Olivier Miakinen
Suite du décortiquage de la fonction de Zeller.


if ($month > 2) {
$month -= 2;
}
else
{
$month += 10;
$year--;
}

$day = ( floor((13 * $month - 1) / 5) +
$day + ($year % 100) +
floor(($year % 100) / 4) +
floor(($year / 100) / 4) - 2 *
floor($year / 100) + 77);
return (($day - 7 * floor($day / 7)));


Par rapport à la formule donnée sur le site mathforum.org, il y a deux
différences ici. D'abord le « + 77 », et puis le dernier calcul, qui est
« $day - 7 * floor($day / 7) », bizarrement entouré de deux paires de
parenthèses là où une seule paire suffirait (voire zéro).

Le « + 77 » est une pitoyable tentative pour éviter que le résultat de
la somme soit négatif. Je dis pitoyable car cela restreint bêtement la
validité de la formule dans le futur : si mes calculs sont exacts, le
résultat sera quand même négatif pour la première fois pour la date du
1er mars 4600. Ok, c'est loin, mais quitte à avoir une formule
universelle, autant qu'elle le soit vraiment !

Par ailleurs, pourquoi éviter que la somme soit négative ? Eh bien tout
simplement parce que souvent les calculs de modulo dans les langages de
programmation retournent des valeurs différentes d'un langage à l'autre,
pour les nombres négatifs. Par exemple, si N modulo 7 vaut 2, alors -N
modulo 7 vaudra parfois 5, parfois -2.

Or il se trouve qu'en PHP, l'expression « $day % 7 » retournera un
nombre négatif si $day est négatif (ce que l'on veut éviter), mais
l'expression « $day - 7 * floor($day / 7) » retournera bien le reste
positif que l'on attend.
Voir : <http://www.miakinen.net/vrac/modtest>.

En conclusion, on peut supprimer le + 77 du bout de code ci-dessus, mais
soit on laisse la formule finale à base de « 7 * floor ( ... / 7) »,
soit on corrige le résultat s'il est négatif. Pour prévoir d'éventuelles
modifications de la fonction floor() dans PHP 5 ou 6, je propose ce qui
suit. Noter que j'ai aussi rajouté une variable pour les siècles, ce qui
simplifie un peu l'écriture.

function zeller_dayofweek($year, $month, $day)
{
if ($month > 2) {
$month -= 2;
} else {
$month += 10;
$year--;
}

$century = floor(%year / 100);
$year %= 100;

$day = $day + floor((13*$month - 1) / 5)
+ $year + floor($year / 4)
+ floor($century / 4) - 2*$century;

$day %= 7;
if ($day < 0) $day += 7;
return ($day);
}

Et pour les amoureux de la concision :

function zeller_dayofweek($year, $month, $day)
{
$month -= 2;
if ($month < 1) { $month += 12; $year--; }
$century = floor(%year / 100);
$year %= 100;
$day = ($day + floor((13*$month - 1) / 5)
+ $year + floor($year / 4)
+ floor($century / 4) - 2*$century) % 7;
return ($day < 0 ? $day + 7 : $day);
}