PHP.de Wissenssammlung

Datum und Uhrzeit

Dieses Tutorial zeigt, an Hand von der in PHP ausgelieferten Klasse DateTime, eine Sammlung an üblichen Anwendungsszenarien. Bei den Beispielen wird durchgängig die objektorientierte Variante von DateTime verwendet. Bei etwaigen externen Beispielen kann dies abweichen bzw. wenn bewusst auf alternative Methoden zurückgegriffen wird, so wird dies explizit erwähnt.

Nachfolgende Seiten aus der PHP-Dokumentation finden in den Beispielen laufend Verwendung.

Zeitzone

Für alle nachfolgenden Beispiele wurde wie folgt die verwendete Standard-Zeitzone gesetzt.

date_default_timezone_set('Europe/Berlin');

Alternativ kann die Zeitzone auch jeweils separat im jeweiligen DateTime-Objekt im Konstruktor angegeben werden.

$dt = new DateTime('now', new DateTimeZone('Europe/Berlin'));

// bzw.

$dtZone = new DateTimeZone('Europe/Berlin');
$dt = new DateTime('now', $dtZone);

DateTime-Objekt erstellen

// Jetzt
$dt = new DateTime();
echo $dt->format('Y-m-d');
// 2015-01-19

Ebenso können auch gleich relative Formate verwendet werden.

// Morgen
$dt = new DateTime('tomorrow');
echo $dt->format('Y-m-d');
// 2015-01-20

// Übermorgen
$dt = new DateTime('+2 days');
echo $dt->format('Y-m-d');
// 2015-01-21

// Letzter Freitag im Januar (des aktuellen Jahres)
$dt = new DateTime('last friday of january');
echo $dt->format('Y-m-d');
// 2015-01-30

// Letzter Freitag im Januar 2016
$dt = new DateTime('last friday of january 2016');
echo $dt->format('Y-m-d');
// 2016-01-29

// Erster Tag (Montag) der KW2 (Kalenderwoche) von 2015
$dt = new DateTime('2015-W03'); // Woche muss zweistellig sein
echo $dt->format('Y-m-d');
// 2015-01-12 (Montag)

Von abweichenden Format-Strings erzeugen

$str = '13012015';
$format = 'dmY';
$dt = DateTime::createFromFormat($format, $str);
echo $dt->format('Y-m-d');
// 2015-01-13
$d = 18;   // 18. Tag
$y = 2015; // des Jahres 2015
$dt = DateTime::createFromFormat('z Y', sprintf('%s %s', $d - 1, $y));
echo $dt->format('Y-m-d');
// 2015-01-18

Schaltjahr

$dt = DateTime::createFromFormat('Y', '2015');
echo $dt->format('L');
// 0 (kein Schaltjahr)

$dt = DateTime::createFromFormat('Y', '2016');
echo $dt->format('L');
// 1 (Schaltjahr)

Berechnungen auf vorhandene DateTime-Objekte

$dt = new DateTime(); // 2015-01-19
$dt->modify('+2 months');
echo $dt->format('Y-m-d');
// 2015-03-19

Differenzen, Interval

$dt1 = new DateTime('2015-01-01');
$dt2 = new DateTime('2015-01-12');

$dtInterval = $dt1->diff($dt2);
echo $dtInterval->format('%R%a days');
// +11 days
// Bsp: Wie lange ist ein Benutzer schon registriert?

$now     = new DateTime(); // 2015-01-19
$regDate = new DateTime('2014-12-15');

echo $now->diff($regDate)->days;
// 35
$now      = new DateTime(); // 2016-01-14
$refDate  = new DateTime('2013-02-10');

$format = '%y Jahre, %m Monate und %d Tage.';
$period = $now->diff($refDate)->format($format);

echo $period;
// 2 Jahre, 11 Monate und 4 Tage.

Interval - Anwendungsbeispiel (“Vor x Tagen/Monaten/…”)

Auf Basis der obigen Ansätze ist bspw. nachfolgende konkrete Anwendung “Vor x Tagen/Monaten/…“ möglich. Basis und Codebeispiel entstammen diesen PHP.de-Forumsbeitrag.

$ts = 1517580600;

$date = new DateTime('now');
$date->setTimestamp($ts);

$now = new DateTime('now');
$diff = $now->diff($date);

$aPairs = [
    'y' => 'Jahr',
    'm' => 'Monat',
    'd' => 'Tag',
    'h' => 'Stunde',
    'i' => 'Minute',
    's' => 'Sekunde',
];

$interval = 0;

foreach ($aPairs as $att => $unit) {
    if ($diff->{$att} > 0) {
        $interval = $diff->{$att};
        break;
    }
}

// ev. Pluralform erzeugen
if ($interval !== 1 ) {
    $unit .= 'en';
    $unit = str_replace('een', 'en', $unit);
}

// Ausgabe
printf('Thema erstellt vor %s %s.', $interval, $unit);

Ergibt testweise bei folgenden Eingabe die als Kommentar nebenstehenden Ausgaben.

$ts = time();           // Thema erstellt vor 0 Sekunden.
$ts = time() - 1800;    // Thema erstellt vor 30 Minuten.
$ts = time() - 3600;    // Thema erstellt vor 1 Stunde.
$ts = time() - 1036800; // Thema erstellt vor 12 Tagen.

Perioden

Will man bspw. eine Auflistung, mit den kommenden Samstagen (hier der nächsten zwei Monate), so kann man hier z.B. DatePeriod nutzen.

// heute Fr. 13.01.2017

$dtStart = new DateTimeImmutable('this saturday'); // Datum von
$dtEnd   = $dtStart->modify('+2 months');          // Datum bis

$period = new DatePeriod(
    $dtStart,
    new DateInterval('P1W'), // Periode: 1 Woche
    $dtEnd
);

foreach ($period as $date) {
    echo $date->format('D. d.m.Y') . "\n";
}

/*
Sat. 14.01.2017
Sat. 21.01.2017
Sat. 28.01.2017
Sat. 04.02.2017
Sat. 11.02.2017
Sat. 18.02.2017
Sat. 25.02.2017
Sat. 04.03.2017
Sat. 11.03.2017
*/

Vergleiche

$dt1 = new DateTime('now');
$dt2 = new DateTime('tomorrow');

var_dump($dt1 == $dt2); // false
var_dump($dt1 < $dt2);  // true
var_dump($dt1 > $dt2);  // false

Kalenderwochen

// erster Tag von KW2 in 2015
$dt = new DateTime('2015-W03'); // Woche muss zweistellig sein
echo $dt->format('Y-m-d');
// 2015-01-12 (Montag)

// alternativ
$dt = new DateTime();
$dt->setISODate(2015, 3);
echo $dt->format('Y-m-d');
// 2015-01-12 (Montag)
// Tag gehört zu welcher Kalenderwoche
$dt = new DateTime('2015-01-15');
echo $dt->format('W');
// 03
// Wie viele Kalenderwochen hat das Jahr ... ?
$ultimo = '2015-12-31';
$dt = new DateTime($ultimo);
echo ($dt->format('W') > 52) ? 53 : 52;
// 53

Quartal

In welchem Quartal ein Datum liegt, kann bsp. wie folgt berechnet werden.

$dt = new DateTime('2015-08-10');

$monat = $dt->format('n'); // Monat ohne führender Null
$quartal = floor(($monat - 1) / 3) + 1;

echo $quartal;  // 3

Deutsche Tages- und Monatsnamen

Wochentage

$aWeekdayNamesDE = [
    'Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'
];
$dt = new DateTime();
echo $aWeekdayNamesDE[$dt->format('w')];  // 'w': 0 (für Sonntag) bis 6 (für Samstag)
// Montag (heute Mo. 2015-01-12)

Monate

$aMonthNamesDE = [
    'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni',
    'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'
];
$dt = new DateTime();
echo $aMonthNamesDE[$dt->format('n')-1];
// Januar (heute 2015-01-12)

Ergänzend sei auch auf diese Beiträge/Threads hingewiesen:

Überschneidungen Zeiträume

Üblicherweise lagert man diese Vergleiche direkt an die Datebank aus. Hier dennoch als Beispiel eine PHP-Variante.

function overlap_timespans($sBegin1, $sEnd1, $sBegin2, $sEnd2, $sTimeTolerance = '') {

    $dt1_begin = new DateTime($sBegin1);
    $dt1_end   = new DateTime($sEnd1);

    $dt2_begin = new DateTime($sBegin2);
    $dt2_end   = new DateTime($sEnd2);

    // correct tolerance if given
    if (!empty($sTimeTolerance)) {
        $dt1_begin->modify('-'.$sTimeTolerance);
        $dt1_end->modify('-'.$sTimeTolerance);
    }

    // check for possible overlaps

    // 2 encolsures 1, or is the same
    if ($dt2_begin <= $dt1_begin && $dt2_end >= $dt1_end) {
        return true;
    }

    // 2 begins within 1
    if ($dt2_begin >= $dt1_begin && $dt2_begin <= $dt1_end) {
        return true;
    }

    // 2 ends within 1
    if ($dt2_end >= $dt1_begin && $dt2_end <= $dt1_end) {
        return true;
    }

    // no overlap
    return false;
}


var_dump( overlap_timespans('14:00', '15:00', '15:00', '16:00') ); // true
var_dump( overlap_timespans('14:00', '15:00', '15:00', '16:00', '1 minute') ); // false

var_dump( overlap_timespans('2015-02-01', '2015-02-02', '2015-02-02', '2015-02-03') ); // true
var_dump( overlap_timespans('2015-02-01', '2015-02-02', '2015-02-02', '2015-02-03', '1 minute') ); // false

Sternzeichen

Um das Sternzeichen eines Datums zu ermitteln, kann beispielsweise folgender Ansatz aus dem PHP.de-Forum verwendet werden.

function getSignOfZodiacFromDate($date) {
    // $date is an object of DateTime or a string
    if (is_string($date)) {
         $date = new DateTime($date);
    }
    if (!$date instanceof DateTime) {
        return false;
    }
    $monthDay = $date->format('md');
    // SignsOfZodiac: to('md') => sign
    $signs = array(
        '0120' => 'Steinbock',
        '0219' => 'Wassermann',
        '0320' => 'Fische',
        '0420' => 'Widder',
        '0520' => 'Stier',
        '0621' => 'Zwilling',
        '0722' => 'Krebs',
        '0823' => 'Löwe',
        '0923' => 'Jungfrau',
        '1023' => 'Waage',
        '1122' => 'Skorpion',
        '1221' => 'Schütze',
        '1231' => 'Steinbock'
    );
    foreach ($signs as $toMonthDay => $sign) {
        if ($monthDay <= $toMonthDay) {
            return $sign;
        }
    }
    return false;
}


// als string
echo getSignOfZodiacFromDate('today'); // Fische (heute 10.03.2015)
echo getSignOfZodiacFromDate('15.01.1984'); // Steinbock

// als objekt
$oDate = new DateTime('03.04.1981');
echo getSignOfZodiacFromDate($oDate); // Widder

Ostern

Zu diesem Thema gibt es im Forum einige Threads

Dieser Beitrag wird zur Zeit diskutiert und wurde zuletzt von hausl verändert.

Beiträge die zur Diskussion gestellt werden, enthalten mitunter Informationen bei denen wir uns noch bezüglich der finalen Darstellung absprechen müssen. Gedulde dich etwas, wir stellen diesen Beitrag fertig, sobald die Diskussion beendet ist.

An diesem Beitrag waren bisher beteiligt: hausl