Calendrier mensuel

Mammouth du PHP | 959 Messages

23 oct. 2008, 19:15

Bonsoir à tous !

Je poste ici car je m'apprête à réaliser un calendrier mensuel de la forme suivante :

Code : Tout sélectionner

Octobre 2008 L M M J V S D 1 2 3 4 5 6 7 8 9 10 11 12 etc...
En fait comme quand vous double-cliquez sur l'horloge de windows ou même de Mac et Linux...

Mais le truc c'est que je ne sais pas comment m'y prendre...
Quelle organisation avoir ?
J'ai commencé à faire le code (mais vraiment commencé hein :P)
Mais au fur et à mesure de ma petite progression, je me suis rendu compte des problèmes que j'avais pour faire ça...
Comme : Comment savoir le nombres de lignes "de dates", parce-que, regardez le calendrier de votre OS, à ce mois-ci, il y a 5 lignes de dates, mais pour Mars et Juin, il y en a 6... comment savoir ce genre de chose ? et c'est pas le seul problème qui se pose...

Voilà, j'aimerai donc avoir votre avis sur cela :D
Merci d'avance !

ViPHP
ViPHP | 1136 Messages

23 oct. 2008, 19:20

c'est un bon exercice pour maîtriser les dates ...

Je te renvoie vers cette page qui t'explique en détail la fonction date

http://fr2.php.net/manual/fr/function.date.php

Et celle-ci pour mktime

http://fr2.php.net/manual/fr/function.mktime.php

Apres , en jouant avec ces fonctions , tu peux facilement connaître une multitudes d'infos à partir d'une date ( jour de la semaine , nombre de semaines dans le moi , nombre de jours ds le moi ect .. )

Pour prendre un point de départ , prends comme référence le jour actuel .

Eléphant du PHP | 422 Messages

23 oct. 2008, 19:29

Une fonction magique à connaître absolument, puisqu'elle te permettra de connaître le premier jour d'un mois, ou le dernier ... ou le premier jour du mois suivant, ...

A partir de là, savoir si c'est sur 4, 5 ou 6 lignes, ça devrait être pas trop compliqué selon que le mois commence un lundi, un mardi, ...

strtotime()

Mammouth du PHP | 959 Messages

23 oct. 2008, 19:38

c'est un bon exercice pour maîtriser les dates ...
Oui, c'est justement une des raisons pourquoi je me lance dans ça :mrgreen:

Je connais déjà la fonction strtotime(), mais je ne vois pas en quoi elle est vraiment utile dans mon cas :?
le truc, c'est qu'il ne suffit pas de diviser le nombre de jours dans le mois par 7 et d'arrondir le résultat au supérieur... fais le test, tu verras...
C'est pas si simple que ça :P

ViPHP
ViPHP | 1136 Messages

23 oct. 2008, 19:43

une piste , regardes ce que te retourne cette commande ...
date("t",time());
:D

Mammouth du PHP | 959 Messages

23 oct. 2008, 20:10

Ouais ouais, elle retourne le nombre de jours dans le mois, mais comme je disais dans mon précédent message, il ne suffit pas de diviser ce nombre par 7 et de l'arrondir au supérieur que ça nous donne le nombre de ligne... regarde le mois de Mars et de Juin tu comprendra ;)

Tu vois, c'est ce genre de choses que ne vois pas comment faire3
Bon ok, ci dessous le code actuel, pas fonctionnel bien sûr :P
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Document sans titre</title>
</head>

<body>

<?php
// french ; english
$language_selection = 'french';

### French
$calendar_txt['french']['mois'] = array('', 'Janvier', 'F&eacute;vrier', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Ao&ucirc;t', 'Septembre', 'Octobre', 'Novembre', 'D&eacute;cembre');
$calendar_txt['french']['jours'] = array('Lundi', 'Mardi', 'Mercredi','Jeudi', 'Vendredi', 'Samedi',	'Dimanche');
### English
$calendar_txt['english']['mois'] = array('', 'January', 'February', 'March',	'April', 'May', 'June', 'July', 'August', 'September', 'October','November', 'December');
$calendar_txt['english']['jours'] = array('Monday', 'Tuesday', 'Wednesday','Thursday', 'Friday', 'Saturday','Sunday');


$annee = '2008';
$mois = '10';

$texte_mois = $calendar_txt[$language_selection]['mois'][date('n')];

// hour minute second month  day  year
$premier_jour_du_mois = date("w", mktime(0, 0, 0, $mois, 01, $annee));
$nb_jours_restants = 7-$premier_jour_du_mois;

$nb_semaines_ds_mois = ceil(date("t", mktime( 0, 0, 0, $mois, 1, $annee))/7);

?>

<table width="200" border="1">
	<tr>
		<td colspan="7"><?php echo $texte_mois.' '.$annee; ?></td>
	</tr>
    
	<tr>
		<td>L</td>
		<td>M</td>
		<td>M</td>
		<td>J</td>
		<td>V</td>
		<td>S</td>
		<td>D</td>
	</tr>
    
    <?php
	for( $i = 0; $i <= $premier_jour_du_mois-2; $i++){
		// "-" voulant dire "rien"
		echo '<td>-</td>';
	}
	for( $i = 0; $i <= $nb_jours_restants; $i++){
		// "J" en attendant... pour dire qu'il y aura quelque chose...
		// Si déjà on arrive à mettre en place les emplacements des jours...
		echo '<td>J</td>';
	}
	?>
    
</table>
</body>
</html>
Pour ce mois-ci, la première ligne fonctionne, mais si je change de mois dans la variable $mois... :roll:
Déjà quand il y aura plus de problème avec ça... on pourra chercher à comprendre comment récupérer le nombre de lignes qu'il faut ;)

Merci de votre aide !

ViPHP
ViPHP | 3607 Messages

23 oct. 2008, 20:22

Hello!
Si tu veux t'inspirer, ou pas te casser la tête à tout refaire: http://www.phpfrance.com/forums/voir_sujet-22523.php
très bonne source ;)

ViPHP
ViPHP | 1136 Messages

23 oct. 2008, 20:27

Avec une date , au format timestamp , tu peux connaître le nombre de jour dans le moi .. c'est déjà une chose .

Tu peux connaitre aussi Jour de la semaine au format numérique par exemple ...
ce qui permet déjà de positionner ton jour sur une colonne.

Imaginons que tu prennes comme référence le premier du moi car il y a toujours un premier du moi ..
tu sais dans quelle colonne le placer imaginons un mercredi ton "tableau commence donc comme ça"
l m m j v s d
* * 1 2 3 4 5

Dans une semaine , il y a aussi toujours 7 jours ... donc , à la construction de ton tableau , toutes les 7 valeurs tu ajoutes une ligne (les * comptent pour une valeur ) ... regardes du coté des modulos pratique dans ces cas là ..

Ainsi de suite jusqu'à la fin du moi :-)

Et voilà sur le principe .. maintenant , il y a certainement , d'autres façons de procéder mais celle ci doit fonctionner sans probléme ..

Mammouth du PHP | 959 Messages

23 oct. 2008, 21:01

Oula :?
Le code de la Class est très difficile je trouve ! :shock:
Je pensais pas que le code d'un simple calendrier pouvait être autant difficile !

Je vais étudier comment ça marche exactement ;)

Merci jojolapine et Cobaye qui à dû s'arracher les cheveux :P
Merci quand même à toi stopher pour ton aide :)

Eléphant du PHP | 422 Messages

24 oct. 2008, 10:47

Le truc, c'est qu'il ne suffit pas de diviser le nombre de jours dans le mois par 7 et d'arrondir le résultat au supérieur...
Je crois que le premier réflexe que l'on a quand on s'attaque à ces problèmes de calendrier, c'est de vouloir entrer dans des calculs avec des arrondis, des divisions, des modulos, des mktime avec le nombre de secondes par jour, ... et que cela devient rapidement très complexe et incompréhensible.

Or, on est dans un cas ici où le dénombrement des possibilités est faible et peut-être traité à la main : 4 longueurs de mois x 7 jours de démarrage = 28 cas possibles pour le nombre de lignes qui peuvent être regroupés dans ce tableau fait en quelques minutes.

Code : Tout sélectionner

Dernier jour et nombre de lignes en fonction du jour de début et du nombre de mois Lu Ma Me Je Ve Sa Di 28 Di(4) Lu(5) Ma(5) Me(5) Je(5) Ve(5) Sa(5) 29 Lu(5) Ma(5) Me(5) Je(5) Ve(5) Sa(5) Di(5) 30 Ma(5) Me(5) Je(5) Ve(5) Sa(5) Di(5) Lu(6) 31 Me(5) Je(5) Ve(5) Sa(5) Di(5) Lu(6) Ma(6)
A partir de là, c'est relativement simple de voir qu'il y a 4 cas "exceptionnels" : 1 à 4 lignes et 3 à 6 lignes. C'est vrai que c'est intellectuellement moins satisfaisant qu'une solution purement mathématique, mais on s'en sort avec un simple switch.
<?php
//Lecture du datetime passé en paramètre ; si vide prendre date courante
$dt = $_GET["dt"]; //Calcul du mois format US + année
if ($dt) {
	$month = date ("F Y", $dt);
} else {
	$month = date ("F Y");
}
$firstdt = strtotime("1 ".$month);
$firstcol = dateEur($firstdt);	//Premier jour du mois 0 Lu, 1 Ma, ...
$days = date("t", $firstdt);		//Nombre de jours du mois
$nextdt = strtotime("+1 month", $firstdt);		//dt du mois suivant
$prevdt = strtotime("-1 month", $firstdt);		//dt du mois précédent


//Calcul du nombre de lignes du calendrier : 5 lignes la plupart du temps
$lines = 5;
switch ($days) {
	case 28: if ($firstcol == 0) {$lines = 4;} break;	//4 lignes si début = Lu
	case 30: if ($firstcol == 6) {$lines = 6;} break;	//6 lignes si début = Di
	case 31: if ($firstcol >= 5) {$lines = 6;} break;	//6 lignes si début = Sa ou Di
}

//Affichage
echo "<table border='1'>\n";
//Ligne de navigation
echo "<tr>";
echo "<td><a href='?dt=$prevdt'><</td>";
echo "<td colspan='5' align='center'>$month</td>";
echo "<td><a href='?dt=$nextdt'>></td>";
echo "</tr>\n";
echo "<tr><td>Lu</td><td>Ma</td><td>Me</td><td>Je</td><td>Ve</td><td>Sa</td><td>Di</td></tr>\n";
$day = 1;
for ($i=0; $i<$lines; $i++) {
	echo "<tr>\n";
	for ($j=0; $j<7; $j++) {
		echo "<td>";
		switch ($i) {
			case 0:		//Première ligne incomplète : remplir à partir du "firstcol"
				if ($j<$firstcol) {echo "&nbsp;";} else {echo $day; $day++;}
			break;
			default:	//Lignes suivantes : remplir jusqu'au dernier jour du mois
				if ($day <= $days) {echo $day; $day++;} else {echo "&nbsp;";}
			break;
		}
		echo "</td>";
	}
	echo "</tr>\n";
}
echo "</table>\n";


//Fonction qui renvoie 0 pour Lu, 1 pour Ma, ...
function dateEur($dt) {
	$d = date('w', $dt);
	if ($d == 0) {return 6;} else {return $d - 1;}
}

?>
Modifié en dernier par caroube le 24 oct. 2008, 12:04, modifié 2 fois.

ViPHP
ViPHP | 1136 Messages

24 oct. 2008, 11:54

Une alternative alors .. car moi j'aime les modulos :D et je trouve ça plus simple ..
Maintenant les goûts et les couleurs
//récupére le mois courant
(int)$jour	=	1;
(int)$Mnow	=	date("m");
(int)$Ynow	=	date("Y");

//cree le timestamp du 01/moiscourant/anneecourante
$TtimeStamps	=	mktime(1,1,1,$Mnow,1,$Ynow);

//recupere le nombre de jours dans le mois
$NbDayInMonth	=	date("t",$TtimeStamps);

//le 01/moiscourant/anneecourante est un quel jour ?
//1 => Lun 7=>Dim 
$JStart	=	date("N",$TtimeStamps);

(int)$emplacement	=	1;
//affichage
echo "<table><tr><td>Lu</td><td>Ma</td><td>Me</td><td>Je</td><td>Ve</td><td>Sa</td><td>Di</td></tr><tr>";

		for( ;$jour <= $NbDayInMonth;$emplacement++ )
		{
				if( $JStart-1 > 0 )
				{
					echo '<td>*</td>';
					$JStart--;
					continue 1;
				}
				//affichage du jour 
				echo '<td>'.$jour.'</td>';
				
				$jour++;
				//test si l'on doir changer de ligne
				if( $emplacement%7	==	0 )
				{
					echo '</tr><tr>';
				}
		}
	echo '
	</tr>
</table>
';
Ce qui donne :

Image

Eléphant du PHP | 422 Messages

24 oct. 2008, 12:11

@stopher : tu ne viendrais pas du monde C, toi ? :lol:

Modérateur PHPfrance
Modérateur PHPfrance | 2575 Messages

24 oct. 2008, 15:10

=D> Bravo messieurs caroube et stopher pour ces solutions dont j'ai bien aimé le principe simpliste.

Voici une autre solution inspirée des votre, mais qui se différencie par le fait qu'à l'affichage du jour, on trouve son emplacement par rapport au jour de la semaine par la fonction date("N") :
<?php
//base des dates en français
$getNomMoisFr = array('', 'Janvier', 'F&eacute;vrier', 'Mars', 'Avril', 'Mai', 'Juin'
, 'Juillet', 'Ao&ucirc;t', 'Septembre', 'Octobre', 'Novembre', 'D&eacute;cembre');

//récupére la date par GET ou date courante
$jourActuel		= (int)($_GET["jour"]?$_GET["jour"]:date("d"));
$moisActuel		= (int)($_GET["mois"]?$_GET["mois"]:date("m"));
$anneeActuelle	= (int)($_GET["annee"]?$_GET["annee"]:date("Y"));
//
$nomMoisActuel	= $getNomMoisFr[$moisActuel];
$dateActuelle	= strtotime(sprintf("%s-%s-%s", $anneeActuelle, $moisActuel, $jourActuel));
//
//récupére le nombre de jours dans le mois
$nbJoursMois	= date("t", $dateActuelle);
//menu de navigation annee/mois
$nextAnnee = date("Y", strtotime("+1 year", $dateActuelle));        //année suivante
$prevAnnee = date("Y", strtotime("-1 year", $dateActuelle));        //année précédente
$nextMois = date("m", strtotime("+1 month", $dateActuelle));        //mois suivant
$prevMois = date("m", strtotime("-1 month", $dateActuelle));        //mois précédent

//affichage
$numJourSemaine	= 1;
$jour 			= 1;
//
echo "<table>
<tr><th colspan='7'>
<a href='?annee=$prevAnnee&mois=$moisActuel&jour=$jourActuel'><<</a> &nbsp; 
<a href='?annee=$anneeActuelle&mois=$prevMois&jour=$jourActuel'><</a> &nbsp;
<a href='?annee=$anneeActuelle&mois=$nextMois&jour=$jourActuel'>></a> &nbsp; 
<a href='?annee=$nextAnnee&mois=$moisActuel&jour=$jourActuel'>>></a> &nbsp;
</th></tr>
<tr><th colspan='7'>$nomMoisActuel $anneeActuelle</th></tr>
<tr><th>Lu</th><th>Ma</th><th>Me</th><th>Je</th><th>Ve</th><th>Sa</th><th>Di</th></tr><tr>";
//affichage des jours
while($jour <= $nbJoursMois) {
	//date du jour traité
	$dateTraitée 				= sprintf("%d-%d-%d", $anneeActuelle, $moisActuel, $jour);
	$numJourSemaineDateTraitée 	= (int)date("N", strtotime($dateTraitée));
	//afficher le jour à son emplacement par rapport au jour de la semaine
	if ($numJourSemaineDateTraitée == $numJourSemaine){
		//couleur de fond pour sélectionner le jour actuel
		if ($jour == $jourActuel) $couleurFond = "yellow"; else $couleurFond="";
		//ajouter une sélection d'une jour sur clic de l'utilisateur
		$eventSelection = " style='cursor:pointer' onClick = \"alert('$dateTraitée')\" ";
		//Afficher le jour à son empalcement
		echo "<td bgcolor='$couleurFond' $eventSelection >$jour</td>"; 
		$jour ++; //passer au jour suivant du mois
	}
	else echo "<td>&nbsp;</td>"; //emplacement vide
    //passer au jour suivant de la semaine
	$numJourSemaine ++;
    if ($numJourSemaine > 7) { //Audela de Dimance 
    	echo "</tr><tr>";
		$numJourSemaine = 1; //retour au Lundi
	}
}
//
echo "</tr></table>"; 
?>
Edit: J'ai rajouté quelques truc pour la finition.
Modifié en dernier par sadeq le 24 oct. 2008, 16:08, modifié 5 fois.
--------//////----//---//----//////
-------//---//----//---//----//---//
------//////----//////-----//////
-----||--------||--||---||
Prendre le recul n'est pas une perte de temps.


ps: Affrontez moi dans l'arène

ViPHP
ViPHP | 1136 Messages

24 oct. 2008, 15:27

@sadeq merci ... :)

Bon aller , histoire de compléter pour avoir un code sans "Notice" , on a tous oublié de définir notre time Zone
(si Version de PHP >= 5.1.0)

il faut ajouter en début de code la ligne suivante pour notre cas :
date_default_timezone_set('Europe/Paris');
Sauf si vous l'avez déjà défini dans votre php.ini

http://fr3.php.net/manual/fr/datetime.c ... e.timezone

Et là , plus de notices ...

Voilà c'était juste histoire de compléter :D

Mammouth du PHP | 959 Messages

24 oct. 2008, 16:19

:shock:

Alors là bravo les gars ! =D> =D>

En effet c'est BEAUCOUP plus simple... Fallait y penser !
Mais bon, après faut écrire le code :P

Merci à vous !
Je vais mettre ce code à ma sauce :D
Alors là je mets le [Résolu] ^^