Ankündigung

Einklappen
Keine Ankündigung bisher.

[Erledigt] Problem: Monat zu einem Datum addieren

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • [Erledigt] Problem: Monat zu einem Datum addieren

    Gibt es zwischenzeitlich eine in PHP implementierte Funktion, mit der man zu einem bestehenden Datum beliebig viele Monate dazu addieren kann, ohne dass man zusätzlich von Hand rumfrickeln muss, um richtige Ergebnisse zu bekommen?

    Nutzt man beispielsweise

    PHP-Code:
    $timestamp strtotime('2014-01-15');
    $ergebnis strtotime('+1 months'$timestamp); 
    // Ergebnis ist dann der 15.02.2014 
    ist das Ergebnis richtig. Probleme gibt es aber bei Schaltjahren und bei Monaten mit unterschiedlicher Anzahl von Tagen (z. B. im Februar):

    PHP-Code:
    $timestamp strtotime('2014-01-31');
    $ergebnis strtotime('+1 months'$timestamp); 
    // Ergebnis ist dann der 03.03.2014 und nicht der 28.02.2014 
    Bitte keine Diskussionen darüber, ob der 03.03.2014 nun dogmatisch "richtig" ist oder nicht. Ihr wisst ja, was ich meine . Ich hätte eben gerne, dass ich als Ergebnis den 28.02.2014 ausgespuckt bekomme und eben nicht den 03.03.2014.

    Bei MySQL funktioniert das doch auch einwandfrei und wirft korrekt den 28.02.2014 aus:

    Code:
    SELECT DATE_ADD('2015-01-31', INTERVAL '1' MONTH) AS datum;


  • #2
    Wenn es mit der SQL funktioniert dann bau Sie doch einfach in einen statement ein ?

    Kommentar


    • #3
      Moin, sieh dir mal DateTime an.

      Hatte letztens mal ne kleine Anleitung für Intervalle gebastelt.
      PHP-Code:
      <?php 
      ini_set
      ('display_errors'1); 
      error_reporting(-1);


      //$start_zeit = new DateTime();  neues Datetime-Objekt mit der aktuellen Zeit 
      $start_zeit = new DateTime('2014-01-31'); // festegelegtes Datum
      /* 
       * Neues DateInterval-Objekt 
       * P = Period, immer notwendig 
       * Y = year
       * M = month
       * D = day
       * T = Time, wird gebraucht wenn Stunden, Minuten, Sekunden angegeben werden 
       * H = hour
       * M = Minute
       * S = second
       * Beispiel: 
       * new DateInterval('P2Y4DT6H8M'); // wäre: 
       * 2 Jahre 
       * 4 Tage 
       * Zeitelemente: 
       * 6 Stunden 
       * 8 Minuten 
       */ 
      $test = new DateInterval('P1M');

      /* 
       * Um Start und Ende noch weiter einsetzen zu können, wird ein neues DateTime-Objekt aus der Startzeit erstellt 
       * Wenn du die Startzeit nicht mehr bräuchstest, könntest du den Schritt überspringen und gleich auf dem ersten Objekt 
       * add() anwenden 
       */ 
      $ende = new DateTime($start_zeit->format('Y-m-d H:i:s')); 

      /* 
       * Aufruf der Add()-Methode vom DateTime-Objekt 
       * Als Parameter wird das DateInterval übergeben 
       */ 
      $ende->add($test); 


      // Ausgabe 
      echo '<pre>'
      var_dump($start_zeit);
      var_dump($ende); 
      echo 
      '</pre>';
      Edit: Gibt allerdings auch den 03.03. aus, ich seh mich mal um, aber muss man evtl. doch manuell machen.
      Edit2: http://stackoverflow.com/questions/3...racting-months
      Relax, you're doing fine.
      RTFM | php.de Wissenssammlung | Datenbankindizes | Dateien in der DB?

      Kommentar


      • #4
        @Ghost21: ich will es ja gerade ohne Workaround ausschließlich in PHP lösen und nicht über eine externe SQL-Datenbank. Denn man hat ja auch nicht immer eine solche zur Hand.

        @VPh: dein Code liefert leider auch nur 2014-03-03 als Ergebnis zurück.

        Kommentar


        • #5
          Aus einer der Antworten vom stackoverflow-Link:
          PHP-Code:
          $time = new DateTime('2014-01-31');
          echo 
          $time->format('d-m-Y H:i') . '<br/>';

          $time->addadd_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');
              }

          Mit DateTime kann man wohl so einiges machen.
          Relax, you're doing fine.
          RTFM | php.de Wissenssammlung | Datenbankindizes | Dateien in der DB?

          Kommentar


          • #6
            Habe auch noch eine Alternative von Stackoverflow:

            PHP-Code:
            <?php
            $monthToAdd 
            1;

            $d1 DateTime::createFromFormat('Y-m-d H:i:s''2011-01-30 15:57:57');

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

            $year += floor($monthToAdd/12);
            $monthToAdd $monthToAdd%12;
            $month += $monthToAdd;
            if(
            $month 12) {
                
            $year ++;
                
            $month $month 12;
                if(
            $month === 0)
                    
            $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);
            }
            $d2->setTime($d1->format('H'), $d1->format('i'), $d1->format('s'));
            echo 
            $d2->format('Y-m-d H:i:s');
            ?>
            Quelle: http://stackoverflow.com/a/10734891

            Dennoch sind das leider alles nur Workarounds. Mir will irgendwie nicht in die Birne, dass PHP sowas nicht von Haus aus mitbringt, ohne selbst eine eigene Funktion dafür schreiben zu müssen.

            Kommentar


            • #7
              Zitat von Der Kaiser Beitrag anzeigen
              Gibt es zwischenzeitlich eine in PHP implementierte Funktion, mit der man zu einem bestehenden Datum beliebig viele Monate dazu addieren kann, ohne dass man zusätzlich von Hand rumfrickeln muss, um richtige Ergebnisse zu bekommen?
              Ja.

              Bitte keine Diskussionen darüber, ob der 03.03.2014 nun dogmatisch "richtig" ist oder nicht. Ihr wisst ja, was ich meine . Ich hätte eben gerne, dass ich als Ergebnis den 28.02.2014 ausgespuckt bekomme und eben nicht den 03.03.2014.
              Wenn du nicht verstehen willst, wie Datumsarithmetik funktioniert, bekommst du auch keine zufriedenstellende Lösung. Das Wichtigste in Kurzform:

              Monate haben im Gregorianischen Kalender eine Länge von 28 bis 31 Tagen. Solange dein Tag des Monats unter 29 bleibt, bekommst du keine Probleme beim Addieren eines "Monats". Für die Tage 29 bis 31 musst du aber definieren, was du unter "+ 1 Monat" verstehst. Es gibt prinzipiell drei Möglichkeiten:

              1) Wrap|Rollover: Man zählt die Tageszahl des aktuellen Monats hinzu. In deinem Beispiel kommt man so eben auf den 3. März.

              2.) Limit|Clipping: Der gewünschte Zieltag muss im nächsten Monat liegen. Also "schneidet" man alle Tage des übernächsten Monats ab. Du bekommst den letzten Tag im Februar (28. oder 29.).

              3.) Relative Datumsangabe: Das Ausgangsdatum ist der letzte Tag des Januars. Also ist einen Monat später der letzte Tag des Februars (wieder der 28. oder 29.).

              Die ersten beiden Methoden werden dann problematisch, wenn du mehrere Monate nacheinander addierst. Dann wandert nämlich der Tag des Monats rückwärts.

              ... und hier die Auflösung:
              PHP-Code:
              // IntlCalendar:: Objekte zählen die Monate von 0...11 (Jan...Dez)
              $gcal = new IntlGregorianCalendar(2014031);

              // Das tuts aber auch:
              //$gcal = IntlCalendar::fromDateTime('2014-01-31');

              var_dump(IntlDateFormatter::formatObject($gcal)); 
              $gcal->add(IntlCalendar::FIELD_MONTH1);
              var_dump(IntlDateFormatter::formatObject($gcal)); 

              // laesst sich auch in ein PHP-DateTime-Objekt wandeln:
              var_dump($gcal->toDateTime()); 
              Wenn man die Wurst schräg anschneidet, hält sie länger, weil die Scheiben größer sind.

              Kommentar


              • #8
                Zitat von fireweasel Beitrag anzeigen
                ... und hier die Auflösung:
                PHP-Code:
                // IntlCalendar:: Objekte zählen die Monate von 0...11 (Jan...Dez)
                $gcal = new IntlGregorianCalendar(2014031);

                // Das tuts aber auch:
                //$gcal = IntlCalendar::fromDateTime('2014-01-31');

                var_dump(IntlDateFormatter::formatObject($gcal)); 
                $gcal->add(IntlCalendar::FIELD_MONTH1);
                var_dump(IntlDateFormatter::formatObject($gcal)); 

                // laesst sich auch in ein PHP-DateTime-Objekt wandeln:
                var_dump($gcal->toDateTime()); 
                Bei mir spuckt er folgende Fehlermeldung aus:

                Class 'IntlGregorianCalendar' not found...
                Muss ich irgendwo noch irgendeine Klasse einbinden?

                Kommentar


                • #9
                  Ein Klick auf den Link von fireweasel:
                  Zitat von Manual
                  (PHP 5.5.0, PECL >= 3.0.0a1)
                  Competence-Center -> Enjoy the Informatrix
                  PHProcks!Einsteiger freundliche TutorialsPreComposed Packages

                  Kommentar


                  • #10
                    Unbeachtet dessen, ob eine solche Funktion Sinn macht, ist mit Limit|Clipping wie fireweasel schreibt ist dies doch einfach zu realisieren.
                    Die folgende Funktion soll nur als Denkansatz dienen:
                    PHP-Code:
                    function dateAddcut($strDate$month){
                      
                    $dateLast date_create($strDate)->modify('last Day of '.$month.' Month');
                      
                    $dateAdd date_create($strDate)->modify('+ '.$month.' Month');
                      return 
                    $dateAdd $dateLast $dateLast $dateAdd;
                    }

                    //Test
                    $strDate '2014-01-31';
                    $month 1;
                    echo 
                    dateAddcut($strDate$month)->format('Y-m-d');  //2014-02-28 
                    PHP-Klassen auf github

                    Kommentar


                    • #11
                      @Arne_Drews:

                      Welches Package muss ich denn dafür genau installieren?

                      Kommentar


                      • #12
                        Naja erstmal gehts um die PHP-Version! Hast Du 5.5?
                        Competence-Center -> Enjoy the Informatrix
                        PHProcks!Einsteiger freundliche TutorialsPreComposed Packages

                        Kommentar


                        • #13
                          Zitat von Arne Drews Beitrag anzeigen
                          Naja erstmal gehts um die PHP-Version! Hast Du 5.5?
                          Jep. Die läuft bei mir.

                          Kommentar


                          • #14
                            PHP5-intl muss auf dem Server installiert sein. Zumindest hat es bei mir geholfen
                            Relax, you're doing fine.
                            RTFM | php.de Wissenssammlung | Datenbankindizes | Dateien in der DB?

                            Kommentar


                            • #15
                              Zitat von VPh Beitrag anzeigen
                              PHP5-intl muss auf dem Server installiert sein. Zumindest hat es bei mir geholfen
                              Super, vielen Dank! Nun läufts bei mir.

                              Musste nur folgende kleine Hürde bewältigen:

                              1. In der Datei php.ini musste die Extension so belegt werden
                              extension="C:\[DEINPFAD]\PHP\ext\php_intl.dll"

                              2. Wenn der Apache-Webserver dann nicht neu startet, sondern die Fehlermeldung bringt, dass die Datei icuuc51.dll (bzw. eine andere Version der icuuc.dll) fehlt, sich diese Datei aber im PHP-Stammverzeichnis befindet, muss folgendes getan werden:

                              Unter Systemsteuerung --> System --> Erweiterte Systemeinstellungen --> dort auf "Umgebungsvariablen..." klicken. Dann im unteren Fenster "Systemvariablen" nach der Variablen "Path" bzw. "PATH" suchen. Diese auswählen und auf "Bearbeiten..." klicken. Nun im Feld "Wert der Variablen" ganz hinten einen Strichpunkt und dann den Pfad zu deinem PHP-Stammverzeichnis eintragen:
                              ;C:\[DEINPFAD]\PHP
                              Diese Änderung bestätigen. Sie sollte ohne Windows-Neustart funktionieren. Der Apache Webserver sollte sich nun ohne Fehlermeldung starten lassen.

                              Kommentar

                              Lädt...
                              X