2016-09-21 1 views
1

Ich habe Probleme mit einer Lösung für diese und Google scheint nichts (ich bin auch nicht sicher, was ich suchen), aber im Grunde, was ich Wollen Sie die letzten drei 15-Tage- Perioden zu einem bestimmten Zeitpunkt erhalten.Erhalten Sie die letzten drei 15-Tage-Perioden in PHP

Ein Zeitraum ist der 1. bis zum 15. des Monats und der 16. bis zum letzten Tag des Monats.

Lasst uns heute sagen, wir sind auf 22. September 2016. Die Datumsbereiche Ich möchte bekommen sind:

Sep 1 - Sep 15 
Aug 16 - Aug 31 
Aug 1 - Aug 15 

Ebenso, wenn wir am 12. September waren 2016 auf die Daten, die ich wollen würde erhalten sind:

Aug 16 - Aug 31 
Aug 1 - Aug 15 
Jul 16 - July 31 

Im Moment habe ich einige Pseudo-Code, der wie folgt lautet:

  1. Get Tag (Zahl)
  2. prüfen, ob mehr als 15
  3. Entdecken Sie Ihre 15-Tage-Zeitraum Datum Bereiche
  4. 2 Bereiche mehr Datum zu erhalten, weiter vor diesen

Ich denke, was ich mit hier Probleme, ist das Übersetzen 3 und 4 in PHP-Code.

Kann jemand hier Licht abwerfen?

+2

Ihre Anforderungen tatsächlich nicht aufaddieren. Sie betrachten den 1.-15. August als einen Zeitraum von 15 Tagen, aber Sie betrachten auch den 16.-31. August als einen Zeitraum von 15 Tagen, was keinen Sinn ergibt, da der August 31 Tage hat. Das eine ist eine exklusive Auswahl und das andere ist ein integrativer Bereich, was sie ** nicht 15 Tage ** macht. Vielleicht möchten Sie * den * Monat stattdessen in 2 Teile aufteilen? Zum Beispiel, wie bekommt man 2 15 Tage im Februar? – Sherif

+0

Ich nehme an, du hast Recht, ich möchte nur einen Monat in 2 Teile brechen. Der erste Teil ist immer der 1. bis zum 15. eines Monats und der zweite Teil ist der 16. bis zum letzten Tag eines Monats. – clueless

Antwort

1

Wir können diese Anforderungen in zwei verschiedene Dinge vereinfachen.

  1. Definieren Sie einen bestimmten Monat in 2 Perioden. Der erste Tag ist der 1. Tag des Monats bis zum 15. Tag des Monats. Der zweite, der 16. Tag des Monats bis zum letzten Tag des Monats.
  2. Geben Sie für ein Datum die letzten 3 Perioden nach der aktuellen Periode ab diesem Datum an.

Schritt 1

Der erste Teil ist einfach.

$date = new DateTimeImmutable("Sep 22, 2016"); 

// Period 1 (from 1st day of month to 15th) 
$p1Start = $date->modify("first day of this month"); 
$p1End = $p1Start->add(new DateInterval("P14D")); 

// Period 2 (from 16th day of month to last day of month) 
$p2Start = $p1End->add(new DateInterval("P1D")); 
$p2End = $p2Start->modify("last day of this month"); 

echo "Period 1 Starts On: {$p1Start->format('M j, Y')}\n"; 
echo "Period 1 Ends On: {$p1End->format('M j, Y')}\n\n"; 

echo "Period 2 Starts On: {$p2Start->format('M j, Y')}\n"; 
echo "Period 2 Ends On: {$p2End->format('M j, Y')}\n"; 

Output Sie von diesem erhalten ist wie erwartet:

 
Period 1 Starts On: Sep 1, 2016 
Period 1 Ends On: Sep 15, 2016 

Period 2 Starts On: Sep 16, 2016 
Period 2 Ends On: Sep 30, 2016 

Jetzt müssen Sie nur all dies in einer Funktion gesetzt und die gleiche Lösung wiederverwenden zu 2.

function getPeriods($dateString) { 
    $date = new DateTimeImmutable($dateString); 

    // Period 1 (from 1st day of month to 15th) 
    $p1Start = $date->modify("first day of this month"); 
    $p1End = $p1Start->add(new DateInterval("P14D")); 

    // Period 2 (from 16th day of month to last day of month) 
    $p2Start = $p1End->add(new DateInterval("P1D")); 
    $p2End = $p2Start->modify("last day of this month"); 

    return [ 
     "period1" => ["start" => $p1Start, "end" => $p1End], 
     "period2" => ["start" => $p2Start, "end" => $p2End], 
    ]; 
} 
Schritt zu erhalten

Also sagen wir, Sie beginnen mit einem Datum wie 12. September 2016. Sie können herausfinden, in welchem ​​Zeitraum dieses Datum fällt, indem Sie den Rückgabewert von dieser Funktion wie folgt überprüfen.

$date = "Sep 12, 2016"; 
$periods = getPeriods($date); 
if ($date >= $periods["period1"]["start"] && $date <= $periods["period1"]["end"]) { 
    // It's in Period1 
} else { 
    // It's in Period2 
} 

Schritt 2

Lassen Sie uns jetzt nur diese Funktion ein wenig ändern, so zu vereinfachen, dass die Lösung auf erweitert werden kann. So nennen wir es getPeriod anstelle von getPeriods und haben es nur eine Periode von einem bestimmten Datum zurückgeben.

function getPeriod($dateString) { 
    $periods = []; 
    $date = new DateTimeImmutable($dateString); 

    // Period 1 (from 1st day of month to 15th) 
    $p1Start = $date->modify("first day of this month"); 
    $p1End = $p1Start->add(new DateInterval("P14D")); 

    // Period 2 (from 16th day of month to last day of month) 
    $p2Start = $p1End->add(new DateInterval("P1D")); 
    $p2End = $p2Start->modify("last day of this month"); 

    // Figure out which period the given date belongs in 
    if ($date >= $p1Start && $date <= $p1End) { 
     $period = ["start" => $p1Start, "end" => $p1End]; 
    } else { 
     $period = ["start" => $p2Start, "end" => $p2End]; 
    } 

    return $period; 
} 

So den vorherigen Zeitraum ab diesem Zeitpunkt bekommen wir nur einfach das start Datum der aktuellen Periode, von dieser Funktion zurück, subtrahieren 1 Tag ab, dass, und das neue Datum zurückschicken zu die Funktion erneut, um die vorherige Periode zu erhalten.

Ebenso erhalten die nächste Zeit nehmen Sie nur das end Datum, 1 Tag hinzu, und das zurück an die Funktion zu senden.

Endergebnis

Hier ist ein Beispiel.

// We want up to 3 periods previous to this given date's period. 

$date = "Sep 12, 2016"; 
$periods = []; 
$currentPeriod = getPeriod($date); 
for ($i = 0; $i < 3; $i++) { 
    $currentPeriod = $periods[] = getPeriod($currentPeriod["start"]->sub(new DateInterval("P1D"))->format("c")); 
} 

// Print out the period dates 

$i = 1; 
foreach($periods as $period) { 
    echo "Period $i: {$period['start']->format('M j, Y')} - {$period['end']->format('M j, Y')}\n"; 
    $i++; 
} 

Output ist das, was man erwarten würde ...

 
Period 1: Aug 16, 2016 - Aug 31, 2016 
Period 2: Aug 1, 2016 - Aug 15, 2016 
Period 3: Jul 16, 2016 - Jul 31, 2016 
+0

Funktioniert wie ein Charme. Vielen Dank. Auch für die ausführliche Erklärung. – clueless

1
function getDateRangesStartingFrom(\Carbon\Carbon $date, $numberOfMonths = 3) 
{ 
    $ranges = []; 

    for ($i = 0; $i < $numberOfMonths; $i++) 
    { 
     $month = []; 

     /** 
     * Generates the first 01-15 range. 
     */ 
     $rangeOne = \Carbon\Carbon::createFromFormat('Y-m-d', "{$date->year}-{$date->month}-01")->addMonths($i); 
     $rangeTwo = (clone $rangeOne)->addDays(14); 

     $month[] = [$rangeOne, $rangeTwo]; 

     /** 
     * Generates the second 16-X (depending on the month) range. 
     */ 
     $rangeThree = (clone $rangeTwo)->addDays(1); 
     $rangeFour = (clone $rangeTwo)->addDays($rangeOne->daysInMonth - 15); 

     $month[] = [$rangeThree, $rangeFour]; 

     /** 
     * We push all the ranges into the global array so we can return it later. 
     */ 
     $ranges[$rangeOne->format('F')] = $month; 
    } 

    return $ranges; 
} 

$ranges = getDateRangesStartingFrom(\Carbon\Carbon::createFromFormat('Y-m-d', '2016-09-22')); 

var_dump($ranges); 

Dies ist, wie ich es tun würde.

Ich benutze Carbon, so dass der Umgang mit Daten viel einfacher ist, gehen Sie es aus!

Ich habe eine Funktion mit dem Namen getDateRangesStartingFrom(\Carbon\Carbon $date) erstellt, die einen Parameter übernimmt, der angibt, ab welchem ​​Datum (oder dem Monat im Wesentlichen, da es uns interessiert) die Bereiche beginnen sollten, um die Bereiche zu generieren.

Ich mache dann eine Schleife von $numberOfMonths Iterationen, um die Generierung zu beginnen.

Zuerst erstellen wir den ersten Teil des Bereichs, indem wir das Jahr und den Monat des Anfangsdatums verwenden. Dann füge ich den Iterator-Index hinzu, der angibt, in welchem ​​Monat wir uns befinden. Zweitens erstellen wir ein zweites Datum, das die zweite Hälfte des ersten Bereichs darstellt (1-15).

Danach erstellen wir die anderen zwei Teile, indem wir die Tage im Monat von den zuvor hinzugefügten Tagen subtrahieren, so dass wir die verbleibenden Tage des Monats erhalten.

Wir schieben alle diese Bereiche in eine Funktionsbereichsvariable und geben die Ergebnisse zurück.

Sherif's answer is good as well aber nehmen Sie dies als Alternative, wenn Sie Carbon ausprobieren möchten.

+0

Ich könnte tatsächlich diese verwenden, weil ich bereits Carbon verwende. Vielen Dank. – clueless

1

Versucht, eine Lösung zu finden, die so einfach wie möglich geschrieben wurde. Ich habe einige Kommentare im Code. Ich denke, das macht deutlich, wie Code funktioniert. überprüfen Sie den Code here

<?php 

// use one of the two examples. 
// $now = DateTime::createFromFormat('Y-m-d', '2016-09-12'); 
$now = new DateTime(); 

print_r(getPeriods($now)); 

function getPeriods(DateTime $now) 
{ 
    $currentDay = $now->format('d'); 

    $dates = []; // Hold all date ranges 
    $start = clone $now; 
    $end = clone $now; 

    if ($currentDay > 15) { // For dates after 15th day of month 
     // Starting period is the first day of previous month 
     $start->modify('first day of previous month'); 
     //Ending date is the 15th day of this month 
     $end->modify('first day of this month')->modify('14 days'); 
    } else { // For dates before 15th day of month 
     //Starting period is the 16th day of the previous of previous month. 
     $start->modify('first day of previous month') 
      ->modify('first day of previous month') 
      ->modify('15 days'); 
     //Ending period is the last day of previous month 
     $end->modify('last day of previous month'); 
    } 
    $dates[] = $start; 
    $i = 2; 

    // $c will hold all intermediate dates of periods between 
    // $start and $end 
    $c = clone $start; 
    while ($c < $end) { 
     if ($c->format('d') > 15) { 
      // if we are in the 16th of the month, 
      // give me the last day of the month 
      $c->modify('last day of this month'); 
     } else { 
      // give me the 15th day of month 
      $c->modify('14 days'); 
     } 
     $dates[] = clone $c; // always clone $c so can not change other references 
     if ($i > 0) { 
      $c->modify('1 day'); 
      $dates[] = clone $c; 
     } 
     $i--; 
    } 

    return array_chunk($dates, 2); 
} 
+0

Sieht ziemlich solide aus. Vielen Dank. – clueless

Verwandte Themen