PHP DateTime :: Ändern Sie das Hinzufügen und Subtrahieren von Monaten

101

Ich habe viel mit dem gearbeitet DateTime classund bin kürzlich beim Hinzufügen von Monaten auf einen Fehler gestoßen, den ich für einen Fehler hielt. Nach ein wenig Recherche scheint es kein Fehler zu sein, sondern wie beabsichtigt zu funktionieren. Nach der hier gefundenen Dokumentation :

Beispiel 2 Vorsicht beim Addieren oder Subtrahieren von Monaten

<?php
$date = new DateTime('2000-12-31');

$date->modify('+1 month');
echo $date->format('Y-m-d') . "\n";

$date->modify('+1 month');
echo $date->format('Y-m-d') . "\n";
?>
The above example will output:
2001-01-31
2001-03-03

Kann jemand rechtfertigen, warum dies nicht als Fehler angesehen wird?

Hat jemand elegante Lösungen, um das Problem zu beheben und es so zu gestalten, dass +1 Monat wie erwartet und nicht wie beabsichtigt funktioniert?

tplaner
quelle
Was würden Sie von "2001-01-31" plus 1 Monat erwarten? ... "2001-02-28"? "2001-03-01"?
Artefacto
57
Persönlich würde ich erwarten, dass es 2001-02-28 sein wird.
Planer
Gleiche Geschichte mit strtotime() stackoverflow.com/questions/7119777/…
Valentin Despa
2
Ja, es ist eine ziemlich nervige Eigenart. Sie haben das Kleingedruckte gelesen, um herauszufinden, dass P1M 31 Tage beträgt. Verstehe nicht wirklich, warum die Leute es immer wieder als "richtiges" Verhalten verteidigen.
Indivision Dev
Es scheint, als ob die populäre Meinung ist, dass die Logik abrunden sollte (auf 2/28), obwohl PHP aufrundet (auf 3/1) ... obwohl ich PHPs Weg bevorzuge, aber Microsoft Excel abrundet und Webentwickler gegen Tabellenkalkulationsbenutzer antritt ...
Dave Heq

Antworten:

106

Warum ist es kein Fehler:

Das aktuelle Verhalten ist korrekt. Folgendes geschieht intern:

  1. +1 montherhöht die Monatszahl (ursprünglich 1) um eins. Dies macht das Datum 2010-02-31.

  2. Der zweite Monat (Februar) hat 2010 nur 28 Tage, daher korrigiert PHP dies automatisch, indem nur die Tage ab dem 1. Februar weiter gezählt werden. Sie landen dann am 3. März.

So bekommen Sie, was Sie wollen:

Um zu erhalten, was Sie wollen, gehen Sie wie folgt vor: Überprüfen Sie den nächsten Monat manuell. Fügen Sie dann die Anzahl der Tage hinzu, die der nächste Monat hat.

Ich hoffe, Sie können dies selbst codieren. Ich gebe nur, was zu tun ist.

PHP 5.3 Weg:

Um das richtige Verhalten zu erhalten, können Sie eine der neuen Funktionen von PHP 5.3 verwenden, mit der die Zeilengruppe für die relative Zeit eingeführt wird first day of. Diese Strophe kann in Kombination verwendet werden next month, fifth monthoder +8 monthsauf den ersten Tag des angegebenen Monats zu gehen. Anstelle dessen, +1 monthwas Sie tun, können Sie diesen Code verwenden, um den ersten Tag des nächsten Monats wie folgt abzurufen:

<?php
$d = new DateTime( '2010-01-31' );
$d->modify( 'first day of next month' );
echo $d->format( 'F' ), "\n";
?>

Dieses Skript wird korrekt ausgegeben February. Die folgenden Dinge passieren, wenn PHP diese Zeilengruppe verarbeitet first day of next month:

  1. next montherhöht die Monatszahl (ursprünglich 1) um eins. Dies macht das Datum 2010-02-31.

  2. first day of1Setzt die Tagesnummer auf , was zum Datum 2010-02-01 führt.

Shamittomar
quelle
1
Was Sie also sagen, ist, dass es buchstäblich 1 Monat hinzufügt und die Tage vollständig ignoriert? Ich gehe also davon aus, dass Sie mit +1 Jahr auf ein ähnliches Problem stoßen könnten, wenn Sie es während eines Schaltjahres hinzufügen?
Planer
@evolve, ja, es literarisch fügt 1 Monat hinzu.
Shamittomar
13
Und wenn Sie 1 Monat nach dem Hinzufügen abziehen, erhalten Sie vermutlich ein völlig anderes Datum. Das scheint sehr unintuitiv zu sein.
Dan Breen
2
Tolles Beispiel für die Verwendung der neuen Strophen in PHP 5.3, wo Sie den ersten Tag, den letzten Tag, diesen Monat, den nächsten Monat und den Vormonat verwenden können.
Kim Stacks
6
Imho das ist ein Fehler. ein schwerwiegender Fehler. Wenn ich 31 Tage hinzufügen möchte, füge ich 31 Tage hinzu. Ich möchte einen Monat hinzufügen, ein Monat sollte hinzugefügt werden, nicht 31 Tage.
low_rents
11

Hier ist eine weitere kompakte Lösung, die ausschließlich DateTime-Methoden verwendet und das Objekt direkt ändert, ohne Klone zu erstellen.

$dt = new DateTime('2012-01-31');

echo $dt->format('Y-m-d'), PHP_EOL;

$day = $dt->format('j');
$dt->modify('first day of +1 month');
$dt->modify('+' . (min($day, $dt->format('t')) - 1) . ' days');

echo $dt->format('Y-m-d'), PHP_EOL;

Es gibt aus:

2012-01-31
2012-02-29
Rüdiger W.
quelle
1
Vielen Dank. Die bisher beste Lösung. Sie können den Code auch auf kürzen $dt->modify()->modify(). Funktioniert genauso gut.
Alph.Dev
10

Dies kann nützlich sein:

echo Date("Y-m-d", strtotime("2013-01-01 +1 Month -1 Day"));
  // 2013-01-31

echo Date("Y-m-d", strtotime("2013-02-01 +1 Month -1 Day"));
  // 2013-02-28

echo Date("Y-m-d", strtotime("2013-03-01 +1 Month -1 Day"));
  // 2013-03-31

echo Date("Y-m-d", strtotime("2013-04-01 +1 Month -1 Day"));
  // 2013-04-30

echo Date("Y-m-d", strtotime("2013-05-01 +1 Month -1 Day"));
  // 2013-05-31

echo Date("Y-m-d", strtotime("2013-06-01 +1 Month -1 Day"));
  // 2013-06-30

echo Date("Y-m-d", strtotime("2013-07-01 +1 Month -1 Day"));
  // 2013-07-31

echo Date("Y-m-d", strtotime("2013-08-01 +1 Month -1 Day"));
  // 2013-08-31

echo Date("Y-m-d", strtotime("2013-09-01 +1 Month -1 Day"));
  // 2013-09-30

echo Date("Y-m-d", strtotime("2013-10-01 +1 Month -1 Day"));
  // 2013-10-31

echo Date("Y-m-d", strtotime("2013-11-01 +1 Month -1 Day"));
  // 2013-11-30

echo Date("Y-m-d", strtotime("2013-12-01 +1 Month -1 Day"));
  // 2013-12-31
nicolaas thiemen francken
quelle
2
Keine allgemeine Lösung, da dies nur für bestimmte Eingaben wie den 1. des Monats funktioniert. Zum Beispiel führt dies für den 30. Januar zu Leiden.
Jens Roland
Oder Sie könnten tun$dateTime->modify('first day of next month')->modify('-1day')
Anthony
6

Meine Lösung für das Problem:

$startDate = new \DateTime( '2015-08-30' );
$endDate = clone $startDate;

$billing_count = '6';
$billing_unit = 'm';

$endDate->add( new \DateInterval( 'P' . $billing_count . strtoupper( $billing_unit ) ) );

if ( intval( $endDate->format( 'n' ) ) > ( intval( $startDate->format( 'n' ) ) + intval( $billing_count ) ) % 12 )
{
    if ( intval( $startDate->format( 'n' ) ) + intval( $billing_count ) != 12 )
    {
        $endDate->modify( 'last day of -1 month' );
    }
}
bernland
quelle
3
Der Befehl "clone" war die Lösung für meine Probleme mit der Variablenzuweisung. Danke dafür.
Steph Rose
4

Ich stimme der Meinung des OP zu, dass dies kontraintuitiv und frustrierend ist, aber auch die Bestimmung, was +1 monthin den Szenarien bedeutet, in denen dies geschieht. Betrachten Sie diese Beispiele:

Sie beginnen mit dem 31.01.2015 und möchten sechsmal einen Monat hinzufügen, um einen Planungszyklus für den Versand eines E-Mail-Newsletters zu erhalten. In Anbetracht der anfänglichen Erwartungen des OP würde dies zurückkehren:

  • 2015-01-31
  • 28.02.2015
  • 2015-03-31
  • 30.04.2015
  • 2015-05-31
  • 30.06.2015

Beachten Sie sofort, dass wir erwarten +1 month, last day of month1 Monat pro Iteration zu bedeuten oder alternativ hinzuzufügen, jedoch immer in Bezug auf den Startpunkt. Anstatt dies als "letzter Tag des Monats" zu interpretieren, könnten wir es als "31. Tag des nächsten Monats oder zuletzt innerhalb dieses Monats verfügbar" lesen. Dies bedeutet, dass wir vom 30. April bis zum 31. Mai anstatt bis zum 30. Mai springen. Beachten Sie, dass dies nicht darauf zurückzuführen ist, dass es sich um den "letzten Tag des Monats" handelt, sondern darauf, dass "das Datum des Startmonats am nächsten liegt".

Angenommen, einer unserer Benutzer abonniert einen anderen Newsletter, der am 30.01.2015 beginnt. Wofür ist das intuitive Datum +1 month? Eine Interpretation wäre "30. Tag des nächsten Monats oder am nächsten verfügbar", die zurückkehren würde:

  • 30.01.2015
  • 28.02.2015
  • 30.03.2015
  • 30.04.2015
  • 30.05.2015
  • 30.06.2015

Dies wäre in Ordnung, es sei denn, unser Benutzer erhält beide Newsletter am selben Tag. Nehmen wir an, dass dies ein Problem auf der Angebotsseite und nicht auf der Nachfrageseite ist. Wir befürchten nicht, dass der Benutzer sich darüber ärgert, dass er zwei Newsletter am selben Tag erhält, sondern dass sich unsere Mailserver die Bandbreite für das doppelte Senden nicht leisten können viele Newsletter. In diesem Sinne kehren wir zu der anderen Interpretation von "+1 Monat" als "Am vorletzten Tag eines jeden Monats senden" zurück, die zurückkehren würde:

  • 30.01.2015
  • 27.02.2015
  • 30.03.2015
  • 29.04.2015
  • 30.05.2015
  • 29.06.2015

Jetzt haben wir jede Überschneidung mit dem ersten Satz vermieden, aber wir landen auch am 29. April und 29. Juni, was sicherlich unseren ursprünglichen Intuitionen entspricht, die +1 montheinfach zurückkehren sollten m/$d/Yoder die m/30/Yfür alle möglichen Monate attraktiv und einfach sind . Betrachten wir nun eine dritte Interpretation der +1 monthVerwendung beider Daten:

31. Januar

  • 2015-01-31
  • 03.03.2015
  • 2015-03-31
  • 2015-05-01
  • 2015-05-31
  • 2015-07-01

30. Januar

  • 30.01.2015
  • 2015-03-02
  • 30.03.2015
  • 30.04.2015
  • 30.05.2015
  • 30.06.2015

Das Obige hat einige Probleme. Der Februar wird übersprungen, was sowohl ein Problem für das Angebotsende sein kann (z. B. wenn eine monatliche Bandbreitenzuweisung vorliegt und der Februar verschwendet wird und der März verdoppelt wird) als auch für das Nachfrageende (Benutzer fühlen sich vom Februar betrogen und nehmen den zusätzlichen März wahr als Versuch, einen Fehler zu korrigieren). Beachten Sie andererseits, dass die beiden Datumsangaben:

  • niemals überlappen
  • sind immer am selben Datum, wenn dieser Monat das Datum hat (also sieht das Set vom 30. Januar ziemlich sauber aus)
  • sind alle innerhalb von 3 Tagen (in den meisten Fällen 1 Tag) nach dem als "korrekt" geltenden Datum.
  • sind alle mindestens 28 Tage (ein Mondmonat) von ihrem Nachfolger und Vorgänger entfernt, also sehr gleichmäßig verteilt.

Angesichts der letzten beiden Sätze wäre es nicht schwierig, eines der Daten einfach zurückzusetzen, wenn es außerhalb des tatsächlichen Folgemonats liegt (also zurück zum 28. Februar und 30. April im ersten Satz) und keinen Schlaf über das zu verlieren gelegentliche Überlappung und Abweichung vom Muster "letzter Tag des Monats" gegenüber dem Muster "vorletzter Tag des Monats". Die Erwartung, dass die Bibliothek zwischen "am schönsten / natürlichsten", "mathematischer Interpretation von 31.02. Und anderen Monatsüberläufen" und "relativ zum ersten oder letzten Monat" wählt, endet jedoch immer damit, dass die Erwartungen von jemandem nicht erfüllt werden und Einige Zeitpläne müssen das "falsche" Datum anpassen, um das reale Problem zu vermeiden, das durch die "falsche" Interpretation entsteht.

Auch hier würde ich erwarten +1 month, dass ein Datum zurückgegeben wird, das tatsächlich im folgenden Monat liegt. Es ist jedoch nicht so einfach wie die Intuition und angesichts der Auswahl ist es wahrscheinlich die sichere Wahl, die Erwartungen der Webentwickler mit Mathematik zu erfüllen.

Hier ist eine alternative Lösung, die immer noch so klobig ist wie jede andere, aber ich denke, sie hat gute Ergebnisse:

foreach(range(0,5) as $count) {
    $new_date = clone $date;
    $new_date->modify("+$count month");
    $expected_month = $count + 1;
    $actual_month = $new_date->format("m");
    if($expected_month != $actual_month) {
        $new_date = clone $date;
        $new_date->modify("+". ($count - 1) . " month");
        $new_date->modify("+4 weeks");
    }
    
    echo "* " . nl2br($new_date->format("Y-m-d") . PHP_EOL);
}

Es ist nicht optimal, aber die zugrunde liegende Logik lautet: Wenn das Hinzufügen von 1 Monat zu einem anderen Datum als dem erwarteten nächsten Monat führt, verschrotten Sie dieses Datum und fügen Sie stattdessen 4 Wochen hinzu. Hier sind die Ergebnisse mit den beiden Testdaten:

31. Januar

  • 2015-01-31
  • 28.02.2015
  • 2015-03-31
  • 28.04.2015
  • 2015-05-31
  • 28.06.2015

30. Januar

  • 30.01.2015
  • 27.02.2015
  • 30.03.2015
  • 30.04.2015
  • 30.05.2015
  • 30.06.2015

(Mein Code ist ein Chaos und würde in einem mehrjährigen Szenario nicht funktionieren. Ich begrüße jeden, der die Lösung mit eleganterem Code umschreibt, solange die zugrunde liegende Prämisse intakt bleibt, dh wenn +1 Monat ein funky Datum zurückgibt, verwenden Sie +4 Wochen stattdessen.)

Anthony
quelle
4

Ich habe eine Funktion erstellt, die ein DateInterval zurückgibt, um sicherzustellen, dass beim Hinzufügen eines Monats der nächste Monat angezeigt wird, und die Tage danach entfernt werden.

$time = new DateTime('2014-01-31');
echo $time->format('d-m-Y H:i') . '<br/>';

$time->add( add_months(1, $time));

echo $time->format('d-m-Y H:i') . '<br/>';



function add_months( $months, \DateTime $object ) {
    $next = new DateTime($object->format('d-m-Y H:i:s'));
    $next->modify('last day of +'.$months.' month');

    if( $object->format('d') > $next->format('d') ) {
        return $object->diff($next);
    } else {
        return new DateInterval('P'.$months.'M');
    }
}
AR
quelle
4

In Verbindung mit Shamittomars Antwort könnte dies dann sein, um Monate "sicher" hinzuzufügen:

/**
 * Adds months without jumping over last days of months
 *
 * @param \DateTime $date
 * @param int $monthsToAdd
 * @return \DateTime
 */

public function addMonths($date, $monthsToAdd) {
    $tmpDate = clone $date;
    $tmpDate->modify('first day of +'.(int) $monthsToAdd.' month');

    if($date->format('j') > $tmpDate->format('t')) {
        $daysToAdd = $tmpDate->format('t') - 1;
    }else{
        $daysToAdd = $date->format('j') - 1;
    }

    $tmpDate->modify('+ '. $daysToAdd .' days');


    return $tmpDate;
}
patrickzzz
quelle
Ich danke dir sehr!!
Geckos
2

Ich habe mit dem folgenden Code einen kürzeren Weg gefunden:

                   $datetime = new DateTime("2014-01-31");
                    $month = $datetime->format('n'); //without zeroes
                    $day = $datetime->format('j'); //without zeroes

                    if($day == 31){
                        $datetime->modify('last day of next month');
                    }else if($day == 29 || $day == 30){
                        if($month == 1){
                            $datetime->modify('last day of next month');                                
                        }else{
                            $datetime->modify('+1 month');                                
                        }
                    }else{
                        $datetime->modify('+1 month');
                    }
echo $datetime->format('Y-m-d H:i:s');
Rommel Paras
quelle
1

Hier ist eine Implementierung einer verbesserten Version von Juhanas Antwort in einer verwandten Frage:

<?php
function sameDateNextMonth(DateTime $createdDate, DateTime $currentDate) {
    $addMon = clone $currentDate;
    $addMon->add(new DateInterval("P1M"));

    $nextMon = clone $currentDate;
    $nextMon->modify("last day of next month");

    if ($addMon->format("n") == $nextMon->format("n")) {
        $recurDay = $createdDate->format("j");
        $daysInMon = $addMon->format("t");
        $currentDay = $currentDate->format("j");
        if ($recurDay > $currentDay && $recurDay <= $daysInMon) {
            $addMon->setDate($addMon->format("Y"), $addMon->format("n"), $recurDay);
        }
        return $addMon;
    } else {
        return $nextMon;
    }
}

Bei dieser Version wird davon $createdDateausgegangen, dass es sich um einen wiederkehrenden monatlichen Zeitraum handelt, z. B. ein Abonnement, das an einem bestimmten Datum wie dem 31. begonnen hat. Es dauert immer $createdDateso spät, dass sich "Wiederholungstermine" nicht auf niedrigere Werte verschieben, wenn sie durch weniger wertvolle Monate verschoben werden (z. B. bleiben alle 29., 30. oder 31. Wiederholungstermine am 28. nach dem Bestehen nicht hängen durch ein Nicht-Schaltjahr Februar).

Hier ist ein Treibercode zum Testen des Algorithmus:

$createdDate = new DateTime("2015-03-31");
echo "created date = " . $createdDate->format("Y-m-d") . PHP_EOL;

$next = sameDateNextMonth($createdDate, $createdDate);
echo "   next date = " . $next->format("Y-m-d") . PHP_EOL;

foreach(range(1, 12) as $i) {
    $next = sameDateNextMonth($createdDate, $next);
    echo "   next date = " . $next->format("Y-m-d") . PHP_EOL;
}

Welche Ausgänge:

created date = 2015-03-31
   next date = 2015-04-30
   next date = 2015-05-31
   next date = 2015-06-30
   next date = 2015-07-31
   next date = 2015-08-31
   next date = 2015-09-30
   next date = 2015-10-31
   next date = 2015-11-30
   next date = 2015-12-31
   next date = 2016-01-31
   next date = 2016-02-29
   next date = 2016-03-31
   next date = 2016-04-30
derekm
quelle
1

Dies ist eine verbesserte Version von Kasihasis Antwort in einer verwandten Frage. Dadurch wird eine beliebige Anzahl von Monaten zu einem Datum korrekt addiert oder subtrahiert.

public static function addMonths($monthToAdd, $date) {
    $d1 = new DateTime($date);

    $year = $d1->format('Y');
    $month = $d1->format('n');
    $day = $d1->format('d');

    if ($monthToAdd > 0) {
        $year += floor($monthToAdd/12);
    } else {
        $year += ceil($monthToAdd/12);
    }
    $monthToAdd = $monthToAdd%12;
    $month += $monthToAdd;
    if($month > 12) {
        $year ++;
        $month -= 12;
    } elseif ($month < 1 ) {
        $year --;
        $month += 12;
    }

    if(!checkdate($month, $day, $year)) {
        $d2 = DateTime::createFromFormat('Y-n-j', $year.'-'.$month.'-1');
        $d2->modify('last day of');
    }else {
        $d2 = DateTime::createFromFormat('Y-n-d', $year.'-'.$month.'-'.$day);
    }
    return $d2->format('Y-m-d');
}

Beispielsweise:

addMonths(-25, '2017-03-31')

wird ausgegeben:

'2015-02-28'
Hải Phong
quelle
0

Wenn Sie nur vermeiden möchten, einen Monat zu überspringen, können Sie so etwas ausführen, um das Datum zu ermitteln und eine Schleife für den nächsten Monat auszuführen. Reduzieren Sie das Datum um eins und überprüfen Sie es erneut bis zu einem gültigen Datum, an dem $ Starting_calculated eine gültige Zeichenfolge für strtotime ist (dh mysql datetime oder "now"). Dies findet das Ende des Monats um 1 Minute bis Mitternacht statt, anstatt den Monat zu überspringen.

    $start_dt = $starting_calculated;

    $next_month = date("m",strtotime("+1 month",strtotime($start_dt)));
    $next_month_year = date("Y",strtotime("+1 month",strtotime($start_dt)));

    $date_of_month = date("d",$starting_calculated);

    if($date_of_month>28){
        $check_date = false;
        while(!$check_date){
            $check_date = checkdate($next_month,$date_of_month,$next_month_year);
            $date_of_month--;
        }
        $date_of_month++;
        $next_d = $date_of_month;
    }else{
        $next_d = "d";
    }
    $end_dt = date("Y-m-$next_d 23:59:59",strtotime("+1 month"));
user1590391
quelle
0

Wenn Sie strtotime()nur verwenden$date = strtotime('first day of +1 month');

Primoz Rom
quelle
0

Ich musste einen Termin für 'diesen Monat im letzten Jahr' bekommen und es wird ziemlich schnell unangenehm, wenn dieser Monat Februar in einem Schaltjahr ist. Ich glaube jedoch, dass dies funktioniert ...: - / Der Trick scheint darin zu bestehen, Ihre Änderung auf den 1. Tag des Monats zu stützen.

$this_month_last_year_end = new \DateTime();
$this_month_last_year_end->modify('first day of this month');
$this_month_last_year_end->modify('-1 year');
$this_month_last_year_end->modify('last day of this month');
$this_month_last_year_end->setTime(23, 59, 59);
Einfach nur hoch
quelle
0
$ds = new DateTime();
$ds->modify('+1 month');
$ds->modify('first day of this month');
Tim Graham
quelle
1
Sie müssen Ihre Antwort erklären. Nur-Code-Antworten gelten als minderwertig
Machavity
Danke dir! Dies ist die bisher sauberste Antwort. Wenn Sie die letzten 2 Zeilen wechseln, wird immer der richtige Monat angezeigt. Ein großes Lob!
Danny Schoemann
0
$month = 1; $year = 2017;
echo date('n', mktime(0, 0, 0, $month + 2, -1, $year));

wird ausgegeben 2(Februar). wird auch für andere Monate funktionieren.

galki
quelle
0
$current_date = new DateTime('now');
$after_3_months = $current_date->add(\DateInterval::createFromDateString('+3 months'));

Für Tage:

$after_3_days = $current_date->add(\DateInterval::createFromDateString('+3 days'));

Wichtig:

Die Methode add()der DateTime-Klasse ändert den Objektwert so, dass nach dem Aufrufen add()eines DateTime-Objekts das neue Datumsobjekt zurückgegeben und das Objekt selbst geändert wird.

MiharbKH
quelle
0

Sie können dies auch mit date () und strtotime () tun. Zum Beispiel, um dem heutigen Datum 1 Monat hinzuzufügen:

date("Y-m-d",strtotime("+1 month",time()));

Wenn Sie die datetime-Klasse verwenden möchten, ist dies ebenfalls in Ordnung, dies ist jedoch genauso einfach. Weitere Details hier

PHP-Süchtiger
quelle
0

Die akzeptierte Antwort erklärt bereits, warum dies kein Aber ist, und einige andere Antworten stellen eine saubere Lösung mit PHP-Ausdrücken wie dar first day of the +2 months. Das Problem mit diesen Ausdrücken ist, dass sie nicht automatisch vervollständigt werden.

Die Lösung ist jedoch recht einfach. Zunächst sollten Sie nützliche Abstraktionen finden, die Ihren Problembereich widerspiegeln. In diesem Fall ist es ein ISO8601DateTime. Zweitens sollte es mehrere Implementierungen geben, die eine gewünschte Textdarstellung bringen können. Zum Beispiel Today, Tomorrow, The first day of this month, Future- alle eine spezifische Implementierung darstellt ISO8601DateTimeKonzept.

In Ihrem Fall benötigen Sie also eine Implementierung TheFirstDayOfNMonthsLater. Es ist leicht zu finden, wenn man sich die Liste der Unterklassen in einer IDE ansieht. Hier ist der Code:

$start = new DateTimeParsedFromISO8601String('2000-12-31');
$firstDayOfOneMonthLater = new TheFirstDayOfNMonthsLater($start, 1);
$firstDayOfTwoMonthsLater = new TheFirstDayOfNMonthsLater($start, 2);
var_dump($start->value()); // 2000-12-31T00:00:00+00:00
var_dump($firstDayOfOneMonthLater->value()); // 2001-01-01T00:00:00+00:00
var_dump($firstDayOfTwoMonthsLater->value()); // 2001-02-01T00:00:00+00:00

Das Gleiche gilt für die letzten Tage eines Monats. Weitere Beispiele für diesen Ansatz finden Sie hier .

Vadim Samokhin
quelle
-2
     $date = date('Y-m-d', strtotime("+1 month"));
     echo $date;
Mohammed F. Ghazo
quelle