Locale-Falle mit IntlCalendar::fromDateTime()

Mit PHP 5.5 wurde auch die Extension für die Internationalisierung um neue Klassen erweitert. Eine besonders interessante Erweiterung ist die Klasse IntlCalendar, in der verschiedene neue Funktionen bereitgestellt werden um mit Lokalisierungen von Jahren, Wochen oder Tagen umzugehen zu können. Dabei handelt es sich jedoch nicht um Besonderheiten in der Darstellung von Zeit, sondern mehr […]

Während IntlCalendar::createInstance() den aktuellen Zeitpunkt für Berechnungen zur Verfügung stellt, lässt sich mit IntlCalendar::fromDateTime() aus einem PHP DateTime (alternativ auch ein String) ein IntlCalendar-Objekt erstellen.

// createInstance$calendar= IntlCalendar::createInstance('Europe/Berlin','de_DE'); // fromDateTime$dateTime=new DateTime('25.01.2014',new DateTimeZone('Europe/Berlin'));$calendar= IntlCalendar::fromDateTime($dateTime);

Da in vielen Projekten DateTime verwendet wird, bietet es sich geradezu an, daraus ein IntlCalendar-Objekt zu erstellen. Wer sich die Factory-Methoden jedoch genau angesehen hat, wird sofort etwas festgestellen: fromDateTime() bietet keine Möglichkeit, eine Locale wie de_DE zu übergeben. Stattdessen wird der Standardwert aus der php.ini verwendet. Sichtbar wird der Fehler dann, wenn zwar die Formatierung über IntlDateFormatter wie die aus dem entsprechenden Land aussieht, jedoch z.B. die Woche mit einem ganz anderen Tag beginnt.

$dateTime=new DateTime('25.01.2014',new DateTimeZone('Europe/Berlin'));$calendar= IntlCalendar::fromDateTime($dateTime); // int 1 for Sunday, string en_USvar_dump($calendar->getFirstDayOfWeek(),$calendar->getLocale(Locale::VALID_LOCALE));

Das IntlCalendar-Objekt übernimmt zwar die Zeitzone aus DateTime, jedoch enthält DateTime keine Lokalisierung. Im oberen Beispiel-Code wird der Sonntag als erster Tag der Woche (int 1) und der Locale-String en_us (Standardwert) zurückgegeben. Vielleicht wird der eine oder andere auf die Idee kommen nun per ini_set() oder über Locale::setDefault() die Lokalisierung zu übergeben, jedoch darf man hier nicht vergessen das dieser Wert global als Standard gesetzt wird. Mehrere IntlCalendar-Objekte mit unterschiedlichen Lokalisierungen wären damit nicht möglich wenn IntlCalendar::fromDateTime() verwendet wird. Außerdem kann das Setzen des Werts auf globaler Ebene auch unerwünschte Nebeneffekte im weiteren Verlauf mit sich bringen.

Wer anhand eines DateTime-Objekts ein IntlCalendar erzeugen möchte, kann sich selbst eine Factory erstellen und verzichtet auf IntlCalendar::fromDateTime(). Das könnte folgendermaßen aussehen:

function create_from_date_time(DateTime $dateTime,$locale){$calendar= IntlCalendar::createInstance($dateTime->getTimeZone(),(string)$locale);$calendar->setTime($dateTime->getTimestamp()*1000); return$calendar;} $calendar= create_from_date_time(new DateTime('25.01.2014',new DateTimeZone('Europe/Berlin')),'de_DE'); // int 2 for Monday, string de_DEvar_dump($calendar->getFirstDayOfWeek(),$calendar->getLocale(Locale::VALID_LOCALE));

Wir verwenden wieder IntlCalendar::createInstance() und übergeben neben dem Lokalisierungs-String auch die Zeitzone aus dem DateTime. Der erste Parameter ist da sehr flexibel, da er mit einem String, einem DateTimeZone- oder einem IntlTimeZone-Objekt umgehen kann. Im Fehlerfall würde IntlCalendar::createInstance() NULL als Wert zurückgeben, also wäre hier noch ein ErrorHandling angebracht. Beim Setzen der Zeitwerte nehmen wir den Timestamp aus DateTime und übergeben diesen mit IntlCalendar::setTime(). Zu beachten ist, dass IntlCalendar mit Millisekunden arbeitet und der Timestamp mit 1000 multipliziert werden muss.

Noch schöner ist es natürlich, diese Funktionalität in einer Klasse zu haben, je nachdem wie euer Projekt aufgebaut ist und euer Coding-Standard aussieht.

Original gefunden auf http://www.mageblog.de: Locale-Falle mit IntlCalendar::fromDateTime()

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s