Heute gibts mal etwas ungewohntes
Nämlich einen kleinen PHP-Artikel von mir zum Thema Datumsangaben.
Da ich momentan an einem Projekt für die Firma arbeite bei dem ich mit Feiertagen arbeiten muss, habe ich mich ein wenig mit den Datumsfunktionen von PHP beschäftigt.
Während die fixen Feiertage ja kein Problem darstellen und auch die auf Ostern bezogenen Feiertage leicht zu berechnen sind (z.B. dank der easter_date() Funktion) stolperte ich über das Problem “Muttertag” (und ähnliche Feiertage).
Der Muttertag findet ja nicht an einem fixen Datum sondern am zweiten Sonntag im Mai statt – nur wie drückt man sowas relativ elegant im Code aus?
Meine erste Idee war natürlich die offensichtliche: vom ersten Mai an mit einer for-Schleife solange das Datum um einen Tag erhöhen bis date(‘w’,$datum) zweimal Sonntag liefert. Allerdings fand ich die Lösung “unschön”. Ausserdem lässt sich sowas nicht wirklich gut in der Datenbank ablegen (wo ich die Feiertage konfigurierbar ablegen wollte).
Faul wie ich als Programmierer nun mal bin habe ich also google gefragt und hab tatsächlich folgende Lösung gefunden die schon etwas eleganter ist:
echo date('d.m.Y', mktime(0, 0, 0, 5, (14 - date('w', mktime(0, 0, 0, 5, 0, 2009))), 2009));Ein Problem dabei ist, dass wohl nur die wenigsten auf einen Blick sagen können was da passiert (Falls es Euch interessiert: am einfachsten geht man von innen nach aussen vor *g* dann versteht man den Code recht schnell) und wirklich praktisch in der Datenbank speicherbar ist sowas auch nicht.
Das dann z.B. noch so zu adaptieren, dass man auch den dritten Mittwoch im September finden kann oder den vierten Dienstag im Januar dürfte relativ umständlich sein.
Und an dieser Stelle kommt eine PHP-Funktion ins Spiel die vermutlich viele schonmal irgendwo gesehen haben aber über die sie nie viel nachgedacht haben: strtotime().
Nehmen wir nochmal den Muttertag. Aus dem unlesbaren Beispiel von vorhin wird dank strtotime() das hier:
echo date('d.m.Y',strtotime('second sunday',mktime(0,0,0,5,0,2009)));Was ich persönlich viel einfacher und verständlicher finde 
Wichtig dabei ist nur, dass man nicht vom 5.1.2009 als Datum ausgeht. Dann würde die Routine fehlerhafte Ergebnisse ausgeben wenn der 1.5 ein Sonntag ist da “second sunday” bewirkt, dass der zweite Sonntag nach dem Datum zurückgeliefert wird (ist der 1. ein Sonntag ist der zweite Sonntag danach logischerweise der dritte Sonntag des Monats).
Analog zu dem obigen Beispiel wäre dann der dritte Freitag des Juli:
echo date('d.m.Y',strtotime('third friday',mktime(0,0,0,7,0,2009)));Statt “first”, “second”, etc. kann man übrigens auch normale Zahlen angeben (“2 sunday”).
Ähnlich funktioniert es auch z.B. den letzten Donnerstag eines Monats herauszubekommen.
echo date('d.m.Y',strtotime('last thursday',mktime(0,0,0,7,1,2009)));würde den Donnerstag vor dem 1.7 zurückliefern – also den letzten Donnerstag des Juni (analog kann man auch -1 statt “last” schreiben).
Und richtig praktisch ist, dass man auch direkt eine Angabe wie “1 July 2009, last Thursday” nutzen kann (was den gleichen Effekt wie das oben angegebene Stück Code hat). Und sowas lässt sich sehr bequem in der Datenbank ablegen und ist sogar relativ einfach zu verstehen (Kleine Randnotiz: strtotime() kann übrigens auch mit Angaben wie “+1 week 2 days 4 hours 2 seconds”, “next Friday”, etc. umgehen).
Wer also in einem Projekt mit solchen Angaben arbeiten muss sollte sich die Funktion einmal genauer ansehen. Gerade auch für automatisierte Vorgänge ist das praktisch (“Newsletter am letzten Freitag des Monats versenden”, “Datenbankwartung am zweiten Mittwoch eines Monats”, usw.).
Mit “etwas” mehr Aufwand wäre natürlich auch ein Parser für echte Ausdrücke wie “Dritter Sonntag im April” möglich – aber man muss es ja nicht übertreiben 
Für mein Projekt habe ich mich nun dazu entschieden die Feiertage so in der Datenbank abzulegen, dass ich nur eine einfache “Formel” für strtoformat() ablege und aus dieser dann in einer zweiten Tabelle die Feiertage erzeugen kann. Grob gesagt liegt in meiner Datenbank für den Muttertag z.B. “30 April %YEAR% + 2 Sunday” als Formel und ein kleines Stück Code ersetzt %YEAR% z.B. durch 2009-2015 und schreibt die so gewonnenen Daten in eine extra Tabelle. Die Tabelle wird dann ggf. aktualisiert wenn neue Feiertage angelegt werden oder bestehende gelöscht werden. So habe ich immer alle relevanten Feiertage in einer Tabelle und kann direkt darauf zugreifen ohne später zusätzliche Berechnungen machen zu müssen. Das ist eventuell nicht die eleganteste Lösung aber dafür eine, die sehr einfach zu handhaben ist.
(( Es wäre nett wenn ihr in den Kommentaren schreiben könnten ob ihr in Zukunft öfter mal solche Artikel lesen wollt oder ob euch die bisherige Form des Blogs lieber ist und ich lieber die Klappe halten soll
))



Also ich würde mich ebenfalls über weitere PHP-Artikel freuen.
Super sache. Kannst ruhig öfters etwas über PHP schreiben.
@Topic: Sehr elegante Lösung. Werd ich mir gleich mal merken.
ldap:
utf8_encode und utf8_decode sind deine Freunde…
Wow, ein PHP-Artikel von DIR?
Nein, mal im Ernst: Grad solche Sachen sind super hilfreich, da kann man echt nicht genug von bekommen. Ich hab lang genug an irgendwelchen Code-Problemen gesessen, um dann, nachdem ich eine Lösung gefunden hatte, zu erfahren, daß der Kollege nebenan das Problem letzte Woche schon gelöst hatte…
Zum Snippet selbst:
Eine sehr elegante Lösung. Ich hab bei Datumskram immer die Calendar Class von Monte Ohrt genommen, die glaub ich mittlerweile ins PEAR Repository eingegliedert wurde. Da kann man dann auch recht einfach Datumskalkulationen durchführen. Nur wegen des Muttertagsproblems jedoch nochmal > 100k Code zu includen wäre hier jedoch mit Kanonen auf Spatzen geschossen.
Also: Weiter so, mehr davon!
Hmmm… wolltest Du nicht neue Artikel schreiben, Herr Co-Autor ? Ich meine mich da an eine Nachricht erinnern zu können…………… *lach*
Ja, eine PEAR-Klasse zu dem Thema hatte ich auch gesehen (Date_Holidays) aber ich find das immer Overkill wegen irgendeiner Kleinigkeit gleich PEAR einzubinden. Im schlimmsten Fall handelt man sich da direkt eine Unmenge von Abhängigkeiten ein. Und mein “Feiertage einigermassen elegant in der DB ablegen” Problem löste Date_Holidays ja auch nicht
Hallo Christian,
mir geht´s da wie Kevin. Im Moment ist der Artikel nicht mehr als ein “nice to know”, aber wer weiß, wann man´s brauch…
Wenn du schon dabei bist die Wünsche deiner Leser umgehend zu erfüllen (siehe Turicon): ich gerade ein Problem mit dem LDAP. Ich lasse die Benutzer sich über ihre LDAP-Kennung anmelden (session mit PHP). Funktioniert soweit ganz gut, außer bei Leuten, die einen Umlaut im Namen haben
Leider habe ich keinen Einfluss auf den LDAP und kenne da nicht wirklich aus. Dessen Admin hat mir mitgeteilt, dass das Ding UTF-8 verwendet. Hast du da nicht auch was? 
Mit LDAP hab ich mich noch nicht wirklich beschäftigt. Aber versuch doch mal den Namen per utf8_encode() nach UTF8 zu konvertieren und Dich dann mit dem konvertierten Namen anzumelden. Das wäre jetzt so meine spontane, erste Idee.
Für mich als Netzwerker und eher unbegabten Programmierer ist es immer nützlich, dieses “Darüber hast du schon mal was gelesen”-Gefühl zu haben, da bei uns aus historischen Gründen Design und Funktionen der Intranet-Server nicht Sache der Entwicklung, sondern der Netzwerk-Gruppe sind.
Also ruhig mehr davon!
Kann man von solchen „Snippets“ genug bekommen? Klare Antwort: Nein! Bitte mehr davon.
BTW: Gibt es eigentlich ein gutes und einfaches Programm zur Verwaltung solcher Codefragmente? Am Besten Plattform übergreifend?
sehe ich auch so
Mehr davon bitte.
Finde sowas total hilfreich, die verschiedenen Ansätze zu sehen.
Hey, auch wenn ich das gerade nicht benötige, es ist immer gut zu sehen, wie andere an Problemlösungen rangehen. Also für mich darfs gerne auch ab und an ein PHP Post sein ;D