Parsen von Strings zu DateTime

Heute gehe ich ein wenig auf das parsen von Datum- / Zeit-strings zu einem \DateTime Objekt mittels der Funktion DateTime::createFromFormat.

Nehmen wir beispielsweise an das wir einen String haben im folgendem Format 04.07.2019 18:59:59.123.

Wenn wir diesen parsen wollen müssen wir PHP irgendwie mitteilen, wie dieses Datumsformat aufgebaut ist.
Hier zu würden wir bei dem angegebenen String folgendes Format angeben d.m.Y H:i:s.v.

Das bedeutet, dass unser Datum mit einem zweistelligen Tag beginnt, dann eine zweistellige Monatsangabe und eine vierstellige Jahresangabe.
Die darauf folgende Zeit besteht dann wiederum aus einer zweistelligen Stundenangabe, einer zweistelligen Minutenangabe, einer zweistelligen Sekundenangabe und zum Schluss eine dreistellige Milisekunden angabe.

Nehmen an wir würden jetzt beispielsweise von einer Fremdquelle Daten importieren und diese Fremdquelle ein Feld mit einem Datumsformat schickt, welches varieren kann dann müssen wir darauf agil und hoffentlich auch elegant reagieren können.
Nehmen wir mal an wir bekommen in dieser Fremdquelle folgende Datumsangaben benötigen aber die Angabe der Millisekunden garnicht:

2019-07-04T15:03:23.123
2019-07-04T18:31:35.54
2019-07-04T20:27:34

Wie können wir also nun unser Datumsformat so angeben, dass wir nicht per if oder ähnliches vorher prüfen dass es ein bestimmtes Format ist?

Ganz einfach. Wir geben unser Datumsformat im folgenden Stil an:

Y-m-d\TH:i:s+

Das + am Ende sorgt dafür, dass alles was nach den Sekunden kommt verworfen wird.

Somit hätten wir bei folgendem Code:

<?php

$dtFormat = 'Y-m-d\\TH:i:s+';
$outputFormat = 'Y-m-d H:i:s';

$dateTimeToParse = [
  '2019-07-04T15:03:23.123',
  '2019-07-04T18:31:35.54',
  '2019-07-04T20:27:34',
];

foreach ($dateTimeToParse as $dateTime) {
  $parsedDateTime = \DateTime::createFromFormat($dtFormat, $dateTime);
  var_dump($parsedDateTime->format($outputFormat));
}

Folgende Ausgabe:

string(19) "2019-07-04 15:03:23"
string(19) "2019-07-04 18:31:35"
string(19) "2019-07-04 20:27:34"

Es gibt noch weitere Fälle die wir durch das parsen von Datumsformaten abbilden können.
Stellen wir uns nun vor wir hätten nur ein Datum:

15.12.1988
11.06.1991
14.04.1998
05.11.2014

Dies zu parsen ist im Prinzip ganz einfach. Wir könnten hier für auch einfach new \DateTime('15.12.1988') nutzen dies wäre flexibel und würde auch andere Datumsformate die übergeben werden würden parsen.
Da wir aber eigentlich versuchen sollten so explizit wie möglich zu parsen wäre hier DateTime::createFromFormat() die bessere Art und weise. Da im Falle einer Formatänderung wir einen entsprechenden Fehler bekommen würden bzw das Datum nicht geparst werden würde.
Beim nutzen des flexiblen Konstruktors der \DateTime Klasse wüssten wir nicht ob und wann sich was geändert hat.

Das parsen des Datums wäre auch mit DateTime::createFromFormat() ganz einfach.
Nehmen wir an wir parsen wie folgt:

<?php

$dtFormat = 'd.m.Y';
$outputFormat = 'Y-m-d H:i:s';

$datesToParse = [
  '15.12.1988',
  '11.06.1991',
  '14.04.1998',
  '05.11.2014',
];

foreach ($datesToParse as $date) {
  $parsedDateTime = \DateTime::createFromFormat($dtFormat, $date);
  var_dump($parsedDateTime->format($outputFormat));
}

Nun die zur Ausgabe:

string(19) "1988-12-15 20:04:16"
string(19) "1991-06-11 20:04:16"
string(19) "1998-04-14 20:04:16"
string(19) "2014-11-05 20:04:16"

Wie man sehen kann wurde das Datum korrekt übernommen ABER wir haben auch eine Zeitangabe drin. Wieso eigentlich? Wir haben ja nicht angegeben, dass wir auch die Zeit haben wollen.
Das hat einen ganz simplen Grund. Beim Parsen des Datums wird das Objekt im default mit unserem Format geparst und alle nicht angegebenen Felder werden entsprechend mit der aktuellen Systemzeit gesetzt, in meinem Fall war es zur Ausführungszeit 20:04:16.

Wie lösen wir nun dieses Problem?

Auch dafür gibt es ein Format Parameter - das Zeichen |. Dieses Zeichen gibt an, dass alle nicht gesetzten beziehungsweise nicht geparsten Felder auf die Unix Epoch Time gesetzt werden.

Betrachten wir das vorherige Beispiel nun mit der "kleinen" Anpassung:

<?php

$dtFormat = 'd.m.Y|';
$outputFormat = 'Y-m-d H:i:s';

$datesToParse = [
  '15.12.1988',
  '11.06.1991',
  '14.04.1998',
  '05.11.2014',
];

foreach ($datesToParse as $date) {
  $parsedDateTime = \DateTime::createFromFormat($dtFormat, $date);
  var_dump($parsedDateTime->format($outputFormat));
}

Nun lautet die Ausgabe:

string(19) "1988-12-15 00:00:00"
string(19) "1991-06-11 00:00:00"
string(19) "1998-04-14 00:00:00"
string(19) "2014-11-05 00:00:00"

Und genau das wollten wir erreichen.

Am besten macht ihr euch mit den Formaten und dem parsen von Datums- und Zeitangaben vertraut. Denn PHP hat in der hinsicht noch viel mehr Parameter zu bieten.

Ismail Özgün Turan am

Kommentare 0