web-dev-qa-db-fra.com

Comment obtenir le mois et l'année précédents par rapport à aujourd'hui en utilisant strtotime et la date?

Je dois obtenir le mois et l'année précédents, par rapport à la date du jour.

Cependant, voir l'exemple suivant.

// Today is 2011-03-30
echo date('Y-m-d', strtotime('last month'));

// Output:
2011-03-02

Ce comportement est compréhensible (jusqu’à un certain point), en raison du nombre différent de jours en février et mars, et le code de l’exemple ci-dessus est ce dont j'ai besoin, mais ne fonctionne que 100% correctement entre le 1er et le 28 de chaque mois.

Alors, comment obtenir le mois dernier ET l’année (pensez à date("Y-m")) de la manière la plus élégante possible, qui fonctionne pour tous les jours de l’année? La solution optimale sera basée sur l'analyse des arguments strtotime.

Mettre à jour. Pour clarifier un peu les exigences.

J'ai un morceau de code qui contient des statistiques des derniers mois, mais je montre d'abord les statistiques du mois dernier, puis charge les autres mois si nécessaire. C'est but prévu. Donc, pendant CE mois, je veux savoir quelle année-mois dois-je extraire afin de charger les statistiques du mois ANCIEN.

J'ai aussi un code qui est sensible au fuseau horaire (pas vraiment important pour le moment), et qui accepte une chaîne strtotime-compatible en tant qu'entrée (pour initialiser la date interne), puis permet d'ajuster la date/heure, en utilisant également des chaînes strtotime-compatibles .

Je sais que cela peut être fait avec peu de conditions et de mathématiques de base, mais c'est très compliqué, par rapport à ceci, par exemple (si cela a bien fonctionné, bien sûr):

echo tz::date('last month')->format('Y-d')

Donc, je n'ai besoin que du mois et de l'année précédents, d'une manière strtotime- compatible.

Réponse (merci, @dnagirl):

// Today is 2011-03-30
echo date('Y-m-d', strtotime('first day of last month')); // Output: 2011-02-01
55
mr.b

Jetez un coup d’œil à la classe DateTime . Les calculs doivent être effectués correctement et les formats de date sont compatibles avec strttotime. Quelque chose comme:

$datestring='2011-03-30 first day of last month';
$dt=date_create($datestring);
echo $dt->format('Y-m'); //2011-02
45
dnagirl

si le jour lui-même n'a pas d'importance, faites ceci:

echo date('Y-m-d', strtotime(date('Y-m')." -1 month"));
25
ITroubs

J'ai trouvé une réponse car j'avais le même problème aujourd'hui, qui est un 31ème. Ce n'est pas un bug dans php comme certains le suggèrent, mais c'est la fonctionnalité attendue (dans d'autres depuis). Selon ce post , ce que fait réellement strtotime est le mois précédent et ne modifie pas le nombre de jours. Donc, dans le cas d’aujourd’hui, le 31 mai, il recherche le 31 avril qui est une date invalide. Donc, cela prend alors le 30 avril, puis ajoute 1 jour après et donne le 1er mai. 

Dans votre exemple 2011-03-30, il remonterait un mois au 30 février, ce qui est invalide, car le mois de février ne compte que 28 jours. Il prend ensuite la différence entre ces jours (30-28 = 2), puis se déplace deux jours après le 28 février, soit le 2 mars.

Comme d'autres l'ont souligné, le meilleur moyen d'obtenir "le mois dernier" consiste à ajouter "premier jour de" ou "dernier jour de" à l'aide de strtotime ou de l'objet DateTime:

// Today being 2012-05-31
//All the following return 2012-04-30
echo date('Y-m-d', strtotime("last day of -1 month"));
echo date('Y-m-d', strtotime("last day of last month"));
echo date_create("last day of -1 month")->format('Y-m-d'); 

// All the following return 2012-04-01
echo date('Y-m-d', strtotime("first day of -1 month")); 
echo date('Y-m-d', strtotime("first day of last month"));
echo date_create("first day of -1 month")->format('Y-m-d');

Il est donc possible de créer une plage de dates si vous effectuez une requête, etc.

21
SeanDowney

Si vous souhaitez que l'année et le mois précédents se rapportent à une date spécifique et que vous disposiez de DateTime, procédez comme suit:

$d = new DateTime('2013-01-01', new DateTimeZone('UTC')); 
$d->modify('first day of previous month');
$year = $d->format('Y'); //2012
$month = $d->format('m'); //12
9
Timo Huovinen
date('Y-m', strtotime('first day of last month'));
6
Marek

strtotime possède le deuxième paramètre timestamp qui définit le premier paramètre par rapport au deuxième paramètre. Donc, vous pouvez faire ceci:

date('Y-m', strtotime('-1 month', time()))
5
dieend

si je comprends bien la question que vous voulez juste le mois dernier et l'année dans laquelle elle se trouve:

<?php

  $month = date('m');
  $year = date('Y');
  $last_month = $month-1%12;
  echo ($last_month==0?($year-1):$year)."-".($last_month==0?'12':$last_month);

?>

Voici l'exemple: http://codepad.org/c99nVKG8

5
Neal

heh, ce n'est pas un bug comme l'a mentionné une personne. c'est le comportement attendu car le nombre de jours dans un mois est souvent différent. Le moyen le plus simple d’obtenir strtotime le mois précédent serait probablement d’utiliser un mois à partir du premier de ce mois.

$date_string = date('Y-m', strtotime('-1 month', strtotime(date('Y-m-01'))));
4
dqhendricks

Je pense que vous avez trouvé un bug dans la fonction strtotime. Chaque fois que je dois contourner ce problème, je me retrouve toujours à faire des calculs sur les valeurs mois/année. Essayez quelque chose comme ça: 

$LastMonth = (date('n') - 1) % 12;
$Year      =  date('Y') - !$LastMonth;
2
Zach Rattner

En effet, le mois précédent a moins de jours que le mois en cours. J'ai corrigé cela en vérifiant d'abord si le mois précédent comptait moins de jours que le courant et en modifiant le calcul en fonction.

S'il y a moins de jours, obtenez le dernier jour de -1 mois, sinon, obtenez le jour actuel -1 mois:

if (date('d') > date('d', strtotime('last day of -1 month')))
{
    $first_end = date('Y-m-d', strtotime('last day of -1 month'));
}
else
{
    $first_end = date('Y-m-d', strtotime('-1 month'));
}
1
RJD22

Peut-être un peu plus long que ce que vous voulez, mais j’ai utilisé plus de code que nécéssaire pour être plus lisible.

Cela dit, le résultat obtenu est identique à celui que vous obtenez: que voulez-vous/attendez-vous?

//Today is whenever I want it to be.
$today = mktime(0,0,0,3,31,2011);

$hour   = date("H",$today);
$minute = date("i",$today);
$second = date("s",$today);
$month  = date("m",$today);
$day    = date("d",$today);
$year   = date("Y",$today);

echo "Today: ".date('Y-m-d', $today)."<br/>";
echo "Recalulated: ".date("Y-m-d",mktime($hour,$minute,$second,$month-1,$day,$year));

Si vous souhaitez simplement connaître le mois et l'année, définissez simplement le jour sur '01' au lieu de prendre 'aujourd'hui':

 $day = 1;

Cela devrait vous donner ce dont vous avez besoin. Vous pouvez simplement régler les heures, les minutes et les secondes à zéro et ne pas vouloir les utiliser.

 date("Y-m",mktime(0,0,0,$month-1,1,$year);

Réduit un peu ;-)

1
Codecraft
//return timestamp, use to format month, year as per requirement
function getMonthYear($beforeMonth = '') {
    if($beforeMonth !="" && $beforeMonth >= 1) {
        $date = date('Y')."-".date('m')."-15";
        $timestamp_before = strtotime( $date . ' -'.$beforeMonth.' month' );
        return $timestamp_before;
    } else {
        $time= time();
        return $time;
    }
}


//call function
$month_year = date("Y-m",getMonthYear(1));// last month before  current month
$month_year = date("Y-m",getMonthYear(2)); // second last month before current month
0
Mukesh

Si une solution DateTime est acceptable, cet extrait renvoie l'année du mois dernier et le mois dernier en évitant le piège possible lorsque vous l'exécutez en janvier.

function fn_LastMonthYearNumber()
{
 $now = new DateTime();
 $lastMonth = $now->sub(new DateInterval('P1M'));
 $lm= $lastMonth->format('m');
 $ly= $lastMonth->format('Y');
 return array($lm,$ly);
}
0
zzapper
function getOnemonthBefore($date){
    $day = intval(date("t", strtotime("$date")));//get the last day of the month
    $month_date = date("y-m-d",strtotime("$date -$day days"));//get the day 1 month before
    return $month_date;
}

La date qui en résulte dépend du nombre de jours que comprend le mois en entrée. Si l'entrée est le mois de février (28 jours), 28 jours avant le 5 février est le 8 janvier. Si l'entrée est le 17 mai, 31 jours avant le 16 avril.

NOTE: l'entrée prend la date complète ('y-m-d') et les sorties ('y-m-d'), vous pouvez modifier ce code en fonction de vos besoins. 

0
Elijah Dadibalos