Pages :
Bonjour,
Je cherche une méthode fiable qui
me renvoie une date par rapport à une date donnée.
Par exemple :
datedépart -> '12.12.1954' -21 jours -8 mois -1 an me donne la date du '21.03.1953', c'est bien ce que je dois trouver.
Par contre, le contraire, c'est à dire :
datedépart -> '21.03.1953' +21 jours +8 mois +1 an me donne la date du '11.12.1954' et pas '12.12.1954' que je voudrais trouvé.
Ci-dessous la fonction php que j'ai créé :
<?php
function dif_date($date,$d=0,$m=0,$y=0) {
	$date = new DateTime($date);
	$jr = $date->format('d');
	$mo = $date->format('m');
	$l = $date->format('L');
	If ($l == 1 && $d == '29'):
		If ($m == -1):
			$d = -29;
		EndIf;
	EndIf;
	If ($l == 0 && $d == '28'):
		If ($m == -1):
			$d = -28;
		EndIf;
	EndIf;
	If ($d >= 0):
		$r = $date->add(new DateInterval('P'.$d.'D'));
	Else:
		$r = $date->sub(new DateInterval('P'.abs($d).'D'));
	EndIf;
	If ($m >= 0):
		$r = $date->add(new DateInterval('P'.$m.'M'));
	Else:
		$r = $date->sub(new DateInterval('P'.abs($m).'M'));
	EndIf;
	If ($y >= 0):
		$r = $date->add(new DateInterval('P'.$y.'Y'));
	Else:
		$r = $date->sub(new DateInterval('P'.abs($y).'Y'));
	EndIf;
	$r->format('d.m.Y');
	return $r;
}
?>

Merci de me dire ou se trouve ce qui ne marche pas.
Etant un spécialiste du langage RPG ILE, voila comment je coderais:
/free
     dated = 21.03.1953;
     jour = 21;
     mois = 8;
     annee = 1;
     datef = dated + %days(jour) + %months(mois) + %years(annee);
 /end-free


Cela marche dans tous les sens en + ou en - ou en + et -.
CàD : jour = 21; ou jour = -21, etc..., on peut donc tout mélanger jour, mois, annee en + ou en -, le résultat sera toujours juste.
Modérateur
Le problème à résoudre, est comment tu souhaites ajouter ou modifier des durées, et pourquoi?

L'ordre dans lequel tu changes est important!

Par exemple:

Date = 21 avril.
+10 jours => 1er mai
+ 1 mois => 1er juin

Date = 21 avril.
+1 mois => 21 mai
+10 jours => 31 mai

Le problème étant que +1 mois n'est pas une valeur fixe mais relative (pouvant durer 28-31 jours)

La seule manière d'effectuer un aller-retour fixe, c'est de n'utiliser que des valeurs absolues, par exemple en n'utilisant que des jours (+422 jours -422 jours)…
Bonjour,
Je souhaite ajouter ou retrancher des jours, des mois, des années à une date de départ.
Par exemple, j'ai un formulaire comme suit :
<form action="delai.php" method="post">
	<div class="input text required">
	    <label id="label" for="date">Date</label><br><br>
	    <input id="date" name="date" maxlength="10" type="text" value="<?php if(!empty($_POST['date'])): echo htmlspecialchars($_POST['date']); Else: echo date('d.m.Y'); endif; ?>" />
					<span class="error-message"></span>
				</div><br><br>
				<div class="input text required">
					<label id="label1" for="jour">+ - Nb jour(s)</label>
					<input id="jour" name="jour" maxlength="5" type="number"  
					value="<?php if(!empty($_POST['jour'])): echo htmlspecialchars($_POST['jour']); Else: echo ($_POST['jour'] = 0); endif; ?>" />
					<div class="error-message errjour"></div>
				</div>
				<div class="input text required">
					<label id="label2" for="mois">+ - Nb Mois</label>
					<input id="mois" name="mois" maxlength="5" type="number"  
					value="<?php if(!empty($_POST['mois'])): echo htmlspecialchars($_POST['mois']); Else: echo ($_POST['mois'] = 0); endif; ?>" />
					<div class="error-message errmois"></div>
				</div>
				<div class="input text required">
					<label id="label3" for="annee">+ - Nb annee</label>
					<input id="annee" name="annee" maxlength="5" type="number"  
					value="<?php if(!empty($_POST['annee'])): echo htmlspecialchars($_POST['annee']); Else: echo ($_POST['annee'] = 0); endif; ?>" />
					<div class="error-message errann"></div>
				</div>
				<div class="submit reset">
					<input type="submit" value="Envoyer" id="envoyer"/><input type="reset" value="Effacer" id="reset" onclick="location.href=''" />
				</div>
</form>

Je saisis donc une date et j'ajoute ou retranche les jours, mois, année en mélangeant les + et les -.
Bonjour alecour,

Tu peux faire ça plus simplement avec strtotime

$dated = '21-03-1953';
$jour = 21;
$mois = 8;
$annee = 1;
     
echo date('d.m.Y',strtotime("+$jour day $mois month $annee year",strtotime($dated)));


Smiley smile
Bonjour matmat,

D'accord, je trouve bien la date du '12.12.1954'.
Mais le contraire, soit :
$dated = '12-12-1954';
$jour = -21;
$mois = -8;
$annee = -1;
     
echo date('d.m.Y',strtotime("+$jour day $mois month $annee year",strtotime($dated)));

me donne la date du '22.03.1953' alors que je devrais avoir '21.03.1953'.
Il semblerait que cela viendrait du nombre de jour dans le mois de départ et dans le mois d'arrivée. Qu'en pensez-vous ?

En langage RPG, je n'ai pas ce souci.
Je continue la recherche.
Ce que dit kustolovic est très juste, effectivement l'ordre est très important, en effet 21 jours soustrait au 12 avril c'est normal que cela donne 22 mars étant donné que mars à 31 jours.

Donc il ne faut pas faire les opération dans le même ordre selon si tu soustrais ou ajoute:
$dated = '21-03-1953';
$jour = 21;
$mois = 8;
$annee = 1;

echo $dated.'<br />';

$date = strtotime($dated);

$date = strtotime("$annee year",$date);
$date = strtotime("$mois month",$date); 
$date = strtotime("$jour day",$date);

echo date('d.m.Y',$date).'<br />';

$date = strtotime("-$jour day",$date);
$date = strtotime("-$mois month",$date);
$date = strtotime("-$annee year",$date);   
     
echo date('d.m.Y',$date).'<br />';
Si tu t'amuses à changer l'ordre des opérations du jour et de l'année tu obtiendras des résultats différents.
Modifié par matmat (03 May 2013 - 14:46)
Bonjour matmat,
C'est bien ce que pensais. Je vais tester les différentes combinaisons,
+jours-mois+annee, etc...
Ce qui serait "génial" est que je puisse n'avoir qu'une seule methode
de traitement.
Bonjour,
Je crois que j'ai trouvé ce que je cherche, je vous soumets la fonction :

function diffDate($date,$d=0,$m=0,$y=0) {
	$date = strtotime($date);
	If ($d>=0 && $m>=0 && $y>=0):
		$date = strtotime("$y year",$date);
		$date = strtotime("$m month",$date); 
		$date = strtotime("$d day",$date);
	ElseIf (($d<=0 && $m<=0 && $y<=0) || ($d<=0 && $m>=0 && $y>=0)):
		$date = strtotime("$d day",$date);
		$date = strtotime("$m month",$date);
		$date = strtotime("$y year",$date); 
	ElseIf ($d>=0 && $m<=0 && $y<=0):
		$date = strtotime("$d day",$date);
		$date = strtotime("$m month",$date);
		$date = strtotime("$y year",$date);
	ElseIf ($d>=0 && $m<=0 && $y>=0):
		$date = strtotime("$d day",$date);
		$date = strtotime("$m month",$date);
		$date = strtotime("$y year",$date);
	ElseIf ($d>=0 && $m>=0 && $y<=0):
		$date = strtotime("$d day",$date);
		$date = strtotime("$m month",$date);
		$date = strtotime("$y year",$date);
	ElseIf ($d<=0 && $m>=0 && $y<=0):
		$date = strtotime("$d day",$date);
		$date = strtotime("$m month",$date);
		$date = strtotime("$y year",$date);
	EndIf;
	$r = date('d.m.Y',$date); 
	return $r;
}

Qu'en pensez-vous ?
Je m'en vais le simplifier encore.
Modérateur
Que peu importe le langage utilisé ou la complexité de la méthode mise en place, quand tu additionnes des pommes et des bananes pour obtenir des poires, tu n'auras jamais un résultat précis.
Additionner des jours mois et années à une date aura toujours un résultat relatif Quelle que soit la méthode utilisée.

Pour t'en convaincre: 31 mars + 1 mois ça donne quoi? 30 avril ou 1er mai? (en php ce sera 1er mai), donc 31 mars + 1mois +1mois donnera soit 30 mai ou 1er juin, alors que 31 mars + 2 mois donnera 31 mai.
alecour a écrit :


function diffDate($date,$d=0,$m=0,$y=0) {
	$date = strtotime($date);
	If ($d>=0 && $m>=0 && $y>=0):
		$date = strtotime("$y year",$date);
		$date = strtotime("$m month",$date); 
		$date = strtotime("$d day",$date);
	ElseIf (($d<=0 && $m<=0 && $y<=0) || ($d<=0 && $m>=0 && $y>=0)):
		$date = strtotime("$d day",$date);
		$date = strtotime("$m month",$date);
		$date = strtotime("$y year",$date); 
	ElseIf ($d>=0 && $m<=0 && $y<=0):
		$date = strtotime("$d day",$date);
		$date = strtotime("$m month",$date);
		$date = strtotime("$y year",$date);
	ElseIf ($d>=0 && $m<=0 && $y>=0):
		$date = strtotime("$d day",$date);
		$date = strtotime("$m month",$date);
		$date = strtotime("$y year",$date);
	ElseIf ($d>=0 && $m>=0 && $y<=0):
		$date = strtotime("$d day",$date);
		$date = strtotime("$m month",$date);
		$date = strtotime("$y year",$date);
	ElseIf ($d<=0 && $m>=0 && $y<=0):
		$date = strtotime("$d day",$date);
		$date = strtotime("$m month",$date);
		$date = strtotime("$y year",$date);
	EndIf;
	$r = date('d.m.Y',$date); 
	return $r;
}

Qu'en pensez-vous ?


Que ça ferait une belle affiche pour un film d'horreur. Smiley lol
Les mois sont peut être une notion approximative pour les machines mais qui est un repère pour nous, c'est donc normal de chercher à les utiliser.

Imaginons para exemple un système qui calcul une date de grossesse vous ne pouvez pas faire une interface en jours, il y a plein de cas ou nous sommes obligé d’additionner des mois et des jours.

J'ai eu une fois un problème similaire avec les semaines, vous saviez par exemple que le 29 décembre peut faire parti de la première semaine de l'année qui suit? Smiley biggol Donc pareil il a fallut écrire une vingtaine de ligne de code de film d'horreur pour prendre en compte les différents cas.

C'est plutôt le calendrier lui même qui est mal foutu en fait, les mois sont originellement lié a un cycle lunaire qui n'en est plus un depuis que l'on a eu l'idée de le caler sur l'année solaire , et ça fait 2000 ans qu'on bricole avec...
Modifié par matmat (04 May 2013 - 20:28)
Modérateur
Je ne dis pas qu'il ne faut pas se servir des mois, mais qu'on ne peut s'en servir comme système de transformation précis. On prend une date, on ajoute 9 mois et on obtient une date d'accouchement. Très bien, de toute façon c'est une approximation. D'ailleurs si on veut plus de précisions, en fait dans le domaine de l'accouchement on calcule en semaines (39 depuis la fécondation ou 41 depuis les règles), les «neufs mois» sont une approximation pour se faire une idée, pas un système de calcul.

Si par contre on souhaite faire des séries de calculs, et garantir un résultat cohérent à la fin, la seule et unique façon de faire, c'est d'utiliser des unités à durées définies (par exemple la seconde). Puis de transformer cela en dates et durées intelligibles juste pour l'affichage.

De la même manière le mètre est une durée précise, pourtant dans le langage courant je vais dire «c'est pas loin» ou «à dix minutes à pied» plutôt que de dire à «729.3 m», pourtant ça me viendrait pas à l'idée de faire un système de calcul qui repose sur des additions et soustractions de pas loin et de «minutes à pied» pour obtenir un résultat précis…

a écrit :
J'ai eu une fois un problème similaire avec les semaines, vous saviez par exemple que le 29 décembre peut faire parti de la première semaine de l'année qui suit? Smiley biggol Donc pareil il a fallut écrire une vingtaine de ligne de code de film d'horreur pour prendre en compte les différents cas.

Bof, avec le système de date en PHP (et dans la plupart des languages) tu additionnes simplement et il passera à l'année comme un grand, je ne vois pas où est le problème. Faisable en une ligne de code. Tu calcules avec des valeurs fixes et ensuite tu sors ton numéro de semaine à l'aise…
Modifié par kustolovic (04 May 2013 - 21:18)
En même temps, les sites qui font des calculs pour la grossesse (pour l'avoir vu, entre autre sur doctissimo), c'est simple :

date donnée par la personne (transformé en temps UNIX) + 39*7*24*60*60 puis conversion de date Smiley rolleyes
kustolovic a écrit :

Bof, avec le système de date en PHP (et dans la plupart des languages) tu additionnes simplement et il passera à l'année comme un grand, je ne vois pas où est le problème. Faisable en une ligne de code. Tu calcules avec des valeurs fixes et ensuite tu sors ton numéro de semaine à l'aise…


Amen ! Oubliez date() et les timetamp UNIX. Datetime en PHP et MySQL est nickel pour les calculs de date et c'est vraiment simple à utiliser. Introduire des timestamp et des bidouilles à base de date(), strtotime() et compagnie n'amènent que des maux de tête et du code inutilement lourd.
Mon exemple de la date d'accouchement n'est pas forcement très pertinent, on pourrais imaginer un système de calcul de loyer alors, dans ce cas nous avons besoin d'un calcul par mois. Exemple dans lequel on prendra le nombre de jour du mois, para exemple du 10 mars au 10 septembre, la durée d'un mois seras donc le nombre de jour du mois.
C'est sûr que cela aiderais alecour de savoir quel est le but du calcul...

kustolovic a écrit :

Bof, avec le système de date en PHP (et dans la plupart des languages) tu additionnes simplement et il passera à l'année comme un grand, je ne vois pas où est le problème. Faisable en une ligne de code. Tu calcules avec des valeurs fixes et ensuite tu sors ton numéro de semaine à l'aise…


Précisément le cas c'est présenté ici http://www.e-radio.edu.mx/Esta-semana , Imaginons que tu es comme paramètre semaine 52 de 2012, comment obtiens tu en une ligne de code la semaine et l'année suivante? Chassant qu'il faut que ça marche aussi pour 2009 et 2013.
Modifié par matmat (05 May 2013 - 00:32)
Bonjour à tous,
Ci-dessous la fonction définitive et elle me convient :

function dif_date($date,$d=0,$m=0,$y=0) {
	$date = strtotime($date);
	If ($d>=0 && $m>=0 && $y>=0):
		$date = strtotime("$y year",$date);
		$date = strtotime("$m month",$date); 
		$date = strtotime("$d day",$date);
	ElseIf (($d<=0 && $m<=0 && $y<=0) || ($d<=0 && $m>=0 && $y>=0) || ($d>=0 && $m<=0 && $y<=0)
	|| ($d>=0 && $m<=0 && $y>=0) || ($d>=0 && $m>=0 && $y<=0) || ($d<=0 && $m>=0 && $y<=0)):
		$date = strtotime("$d day",$date);
		$date = strtotime("$m month",$date);
		$date = strtotime("$y year",$date); 
	EndIf;
	$r = date('d.m.Y',$date); 
	return $r;
} 

Merci de m'avoir aidé.
Modérateur
@alecour,

ça reste une horreur, mais si tu veux continuer ainsi pourquoi ça:
ElseIf (($d<=0 && $m<=0 && $y<=0) || ($d<=0 && $m>=0 && $y>=0) || ($d>=0 && $m<=0 && $y<=0)
	|| ($d>=0 && $m<=0 && $y>=0) || ($d>=0 && $m>=0 && $y<=0) || ($d<=0 && $m>=0 && $y<=0)):

au lieu de ça? :
else:

p.s: je trouve la syntaxe alternative if: endif; très bien pour des templates mais pour du code php if {} est bien plus clair:

  <?php if (TRUE): ?>
    <h1>Mon titre</h1>
    <p>Bla bla bla</p>
  <?php endif; ?>

  <?php
  if (TRUE) {
    action1();
    action2();
  }
  ?>

Et au passage c'est elseif et non pas ElseIf. http://www.php.net/manual/fr/control-structures.alternative-syntax.php

matmat a écrit :
Mon exemple de la date d'accouchement n'est pas forcement très pertinent, on pourrais imaginer un système de calcul de loyer alors, dans ce cas nous avons besoin d'un calcul par mois. Exemple dans lequel on prendra le nombre de jour du mois, para exemple du 10 mars au 10 septembre, la durée d'un mois seras donc le nombre de jour du mois.
C'est sûr que cela aiderais alecour de savoir quel est le but du calcul...

Heuu pour les loyers, on s'en tape du nombre de jours, le loyer est le même. Donc oui on calcule par mois, et ça peut devenir un poil plus complexe. En général on se balade sur le 1er du mois pour faire les calculs et éviter les problèmes et on sort le dernier jour du mois au besoin. Après ça dépend des cas des législations de ton pays/région des termes de contrats etc.

matmat a écrit :
Précisément le cas c'est présenté ici http://www.e-radio.edu.mx/Esta-semana , Imaginons que tu es comme paramètre semaine 52 de 2012, comment obtiens tu en une ligne de code la semaine et l'année suivante? Chassant qu'il faut que ça marche aussi pour 2009 et 2013.


Fingers in the nose:

$d = new DateTime("2012-W52-1");
print $d->format('l j.m.Y | W').'<br>'; // Monday 24.12.2012 | 52
$d = new DateTime("2012-W53-1");
print $d->format('l j.m.Y | W').'<br>'; // Monday 31.12.2012 | 01
$d = new DateTime("2009-W53-1");
print $d->format('l j.m.Y | W').'<br>'; // Monday 28.12.2009 | 53
$d = new DateTime("2013-W53-1");
print $d->format('l j.m.Y | W').'<br>'; // Monday 30.12.2013 | 01

// Pour reprendre l'exemple cité: on crée l'objet selon les 2 paramètres reçu en se plaçant sur le lundi
// Puis on ajoute 1 semaine (1W) ou 7 jours (7D) pour avoir la semaine suivante et construire le lien
$d = new DateTime("2012-W52-1");
$d->add(new DateInterval('P1W'));
$link = 'http://www.e-radio.edu.mx/Esta-semana?year=' . $d->format('Y') . '&week=' . $d->format('W');
print $link . '<br>'; //   http://www.e-radio.edu.mx/Esta-semana?year=2012&week=01
 

$d = new DateTime("2009-W52-1");
$d->add(new DateInterval('P1W'));
$link = 'http://www.e-radio.edu.mx/Esta-semana?year=' . $d->format('Y') . '&week=' . $d->format('W');
print $link . '<br>'; //   http://www.e-radio.edu.mx/Esta-semana?year=2009&week=53
 

// PS, pour répondre à la question, en une ligne de code, mais c'est moins lisible ^^:
$yearWeek = new DateTime("$year-W$week-1")->add(new DateInterval('P1W'))->format('Y-W');
J'imaginais plutôt une location type gîte, il est possible qu'il fasse ajouter des jours et des mois pour calculer le tarifs.
Je suis tout à fait d'accord avec ta réflexion, j'imagine juste que si alecour cherche une solution c'est qu'il y a un surement un problème, bien que certes quand il n'y a pas de solution c'est souvent qu'il n'y a pas de problème...
$d = new DateTime("2012-W52-1");
$d->add(new DateInterval('P1W'));
$link = 'http://www.e-radio.edu.mx/Esta-semana?year=' . $d->format('Y') . '&week=' . $d->format('W');
print $link . '<br>'; //    http://www.e-radio.edu.mx/Esta-semana?year=2012&week=01
C'est un peu la méthode que j'avais utilisé au début mais le problème c'est que ça t'envoie un an en arrière... www.e-radio.edu.mx/Esta-semana?year=2012&week=1 alors que le résultat attendu est http://www.e-radio.edu.mx/Esta-semana?year=2013&week=01

Tout simplement parceque le lundi de la première semaine de 2013 et en 2012...

C'est pas non plus un problème insoluble, mais j'ai du rajouter quelques lignes, c'est juste pour souligner les mesures "humaines" reste approximative et que les bricolages sont souvent inévitable.

Un autre exemple de code de film d'horreur pourtant bien utile, c'est quand on utilise "depuis", comme dans Yahoo réponses par exemple, publier depuis un mois, deux semaines etc... pareil je n'ai jamais trouvé de méthode bien propre pour faire ça. Pourtant à lire j'aime bien, ça parle à l'utilisateur.
Modifié par matmat (05 May 2013 - 19:52)
Modérateur
matmat a écrit :
J'imaginais plutôt une location type gîte, il est possible qu'il fasse ajouter des jours et des mois pour calculer le tarifs.

Bof non, si tu tariffies en jours tu calcule en jours plutôt que de faire des calculs de fou.

matmat a écrit :
C'est un peu la méthode que j'avais utilisé au début mais le problème c'est que ça t'envoie un an en arrière... www.e-radio.edu.mx/Esta-semana?year=2012&amp;week=1 alors que le résultat attendu est http://www.e-radio.edu.mx/Esta-semana?year=2013&amp;week=01


Ah ouais c'est pas faux, ma faute, mais pas besoin de bricolage, juste de doc!


$d = new DateTime("2012-W52-1");
$d->add(new DateInterval('P1W'));
$link = 'http://www.e-radio.edu.mx/Esta-semana?year=' . $d->format('[b]o[/b]') . '&week=' . $d->format('W');
print $link . '<br>'; //  http://www.e-radio.edu.mx/Esta-semana?year=2013&week=01
 


a écrit :
o => L'année ISO-8601. C'est la même valeur que Y, excepté que si le numéro de la semaine ISO (W) appartient à l'année précédente ou suivante, cette année sera utilisé à la place. (ajouté en PHP 5.1.0)


Si tu étais sur une version inférieure de PHP, il aurait mieux valu transmettre une date en paramètre: http://www.e-radio.edu.mx/Esta-semana?day=2012-12-31 ce qui aurait aussi pu régler le problème.

Dans 99% des cas, le bricolage est dû à une erreur de conception ou a des connaissances insuffisantes, là c'était dans la forme de tes URLS ou de la doc de date().
Modifié par kustolovic (05 May 2013 - 20:24)
Oui tout à fait, je ne sais plus pourquoi initialement j'avais utilisé les semaines, je crois que c'était surtout pour l’expérience Smiley biggol , je n'avais jamais travaillé avec cette notion de semaine. C'est sûr que d'aller de lundi en lundi aurais été surement plus simple.

C'est super cette année "o", j'avais pas vu! C'est effectivement beaucoup plus simple et même essentiel pour les calendriers par semaines, je vais actualiser mon code, merci!
Pages :