Felix Riesterer: Zeitzonen in PHP5 - Auswahl wie zusammenstellen?

Liebe Mitlesende,

in meinem selbstgestrickten CMS möchte ich wegen dem Zeitzonenzwang in PHP5 (date_default_timezone_set) eine Auswahl anbieten, die für den "Standort" (im Sinne des Betreiberstandortes) dieser Website gelten soll. Auf php.net gibt es auch eine recht umfangreiche Liste von unterstützten Zeitzonen-Strings.

Meinen eigenen Größenwahn mal beiseite lassend: Welche Zeitzonen sollten in einer Auswahl sinnvollerweise enthalten sein? Militärische Zeitzonen scheinen für ein ziviles CMS irgendwie widersinnig.

Meine erste Idee war, dass ich alle Strings etwa so aufliste:

<select name="timezone">  
    <optgroup label="Africa">  
        <option value="Africa/Abidjan">Abidjan</option>  
...  
        <option value="Africa/Windhoek">Windhoek</option>  
    </optgroup>  
    <optgroup label="Europe">  
        <option value="Europe/Amsterdam">Amsterdam</option>  
...  
        <option value="Europe/Berlin">Berlin</option>  
...  
    </optgroup>  
</select>

Gibt es da schon etwas fertiges, welches ich einfach übernehmen kann? Idealerweise hätte ich gerne noch eine Möglichkeit, dass die Optionen in einer jeweiligen Landessprache (in meinem CMS kann man eine Sprache auswählen, in der das System dann alles anzeigt) angezeigt werden... ;-)

Liebe Grüße,

Felix Riesterer.

--
ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
  1. Hallo Ingrid,

    wenn man auf die passenden Suchbegriffe stößt, dann ist das alles wesentlich leichter.

    Aktuell benutze ich (nach dieser Anleitung) die in PHP hinterlegten Werte (DateTimeZone::listIdentifiers), um daraus dynamisch eine Auswahlliste zu erzeugen:

    $template = '<select name="timezones"></select>';  
      
    $timezone_list = '';  
    $c = '';  
      
    foreach (DateTimeZone::listIdentifiers() as $v) {  
        if (preg_match( '~^(America|Antartica|Arctic|Asia|Atlantic|Europe|Indian|Pacific)/~', $v)) {  
            $e = preg_split('~/~', $v, 2, PREG_SPLIT_NO_EMPTY); // obtain continent, city  
      
            if ($c != $e[0]) {  
                if (!empty($c)) {  
                    $timezone_list .= '</optgroup>';  
                }  
      
                $timezone_list .= sprintf(  
                    '<optgroup label="%s">',  
                    htmlspecialchars($e[0])  
                );  
            }  
      
            $city = $e[1];  
            $c = $e[0];  
      
            $timezone_list .= sprintf(  
                '<option value="%1$s">%2$s</option>',  
                htmlspecialchars($v),  
                htmlspecialchars($city)  
            );  
        }  
    }  
      
    $timezone_list = sprintf('%s</optgroup>', $timezone_list);  
      
    $template = preg_replace(  
        '~(?is)(<select .*?name="timezone".*?>[\r\n])~',  
        '$1'.$timezone_list,  
        $template  
    );
    

    Liebe Grüße,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
    1. Danke für den Tip. Bisher hatte ich dazu ne Tabelle in der Datenbank benutzt, die kann ich jetzt einmotten :)

      Ja, hier lernt man durch lesen auch immer wieder was.

      1. Liebe(r) M.,

        Danke für den Tip.

        öhm... ja, gerne! Hätte ich mich beim Suchen nicht derart dämlich bei den Suchbegriffen angestellt, wäre es zu diesem Thread nie gekommen.

        Bisher hatte ich dazu ne Tabelle in der Datenbank benutzt, die kann ich jetzt einmotten :)

        Kommt darauf an. Ich hätte gerne noch gewusst, welchen Aufwand es bedeutet, die Angaben in verschiedenen Landessprachen anzuzeigen. Alternativ dürfen die Ortsnamen auch gerne in ihrer jeweils eigenen Landessprache und -schrift angezeigt werden.

        Ja, hier lernt man durch lesen auch immer wieder was.

        Einer der Gründe, warum mich das Forum nach wie vor fasziniert, auch wenn ich mittlerweile bedeutend weniger Zeit finde, mich dort aufzuhalten...

        Liebe Grüße,

        Felix Riesterer.

        --
        ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
        1. Kommt darauf an. Ich hätte gerne noch gewusst, welchen Aufwand es bedeutet, die Angaben in verschiedenen Landessprachen anzuzeigen. Alternativ dürfen die Ortsnamen auch gerne in ihrer jeweils eigenen Landessprache und -schrift angezeigt werden.

          Der Aufwand war bei mir, dass ich eine Spalte mit der Zone hab (z.B. Europe) und eine Subzone (z.B. Berlin)
          Wenn der User die Zone auswählt werden die entsprechenden Subzonen nachgeladen und als Dropdown angeboten.

          Übersetzt hab ich das nicht, aber da ich mein System komplett auf gettext umgestellt hab, ist das praktisch nur eine zusätzliche Datei für die Sprache. Allerdings stellt bei mir der User die Zeitzone unabhängig von der Sprache ein, damit werden die Zeitzonen, falls eine Übersetzung vorhanden, immer in der gewählten Sprache ausgegeben.

          Davon, die Zeitzonen nur in der entsprechenden Landesprache anzuzeigen, rate ich ab. Wenn ich mich in einem anderen Land aufhalte, will ich evtl. zwar die Zeitzone einstellen aber wenn ich die Sprache nicht kann (Extremfall: Russland. Kann 3 Brocken russisch aber absolut nix kyrilisch, wäre ein reines Ratespiel)

          Ich empfehle, Zeitzone und Sprache völlig unabhängig.

          1. @@M.:

            nuqneH

            Ich empfehle, Zeitzone und Sprache völlig unabhängig.

            Ich empfehle die Angabe der Zeitzone in Zahlen.

            Qapla'

            --
            „Talente finden Lösungen, Genies entdecken Probleme.“ (Hans Krailsheimer)
            1. Moin!

              @@M.:

              nuqneH

              Ich empfehle, Zeitzone und Sprache völlig unabhängig.

              Ich empfehle die Angabe der Zeitzone in Zahlen.

              Das ist keine Angabe der Zeitzone, sondern der Offset zu UTC.

              Sowas ist für nur genau eine Zeitangabe praktikabel, aber der Sinn von Zeitzonen ist, dass man darin auch die Umschaltung zur Sommerzeit codiert, bzw. auch eventuelle Abweichungen und Veränderungen vom Offset selbst, und das immer historisch betrachtet auf die gesamte Vergangenheit eines Ortes (bzw. der Fläche identischer Zeitregularien).

              - Sven Rautenberg

              1. @@Sven Rautenberg:

                nuqneH

                Ich empfehle die Angabe der Zeitzone in Zahlen.

                Das ist keine Angabe der Zeitzone, sondern der Offset zu UTC.

                Was prinzipiell dasselbe ist.

                Sowas ist für nur genau eine Zeitangabe praktikabel, aber der Sinn von Zeitzonen ist, dass man darin auch die Umschaltung zur Sommerzeit codiert

                Nein. Wenn wir auf Sommerzeit umstellen, dann wechseln wir die Zeitzone: von MEZ (+01:00) zu MESZ (+02:00).

                bzw. auch eventuelle Abweichungen und Veränderungen vom Offset selbst, und das immer historisch betrachtet auf die gesamte Vergangenheit eines Ortes (bzw. der Fläche identischer Zeitregularien).

                Was du meinst, ist eher Locale als Zeitzone.

                Qapla'

                --
                „Talente finden Lösungen, Genies entdecken Probleme.“ (Hans Krailsheimer)
                1. Moin!

                  Sowas ist für nur genau eine Zeitangabe praktikabel, aber der Sinn von Zeitzonen ist, dass man darin auch die Umschaltung zur Sommerzeit codiert

                  Nein. Wenn wir auf Sommerzeit umstellen, dann wechseln wir die Zeitzone: von MEZ (+01:00) zu MESZ (+02:00).

                  Super-Feature. Dann darf ich als User also zweimal im Jahr wie früher alle meine externen Accounts von MEZ nach MESZ umstellen und zurück, nur weil der Programmierer zu blöde war, statt Offset die Zeitzone zu verwenden.

                  - Sven Rautenberg

                  1. Super-Feature. Dann darf ich als User also zweimal im Jahr wie früher alle meine externen Accounts von MEZ nach MESZ umstellen und zurück, nur weil der Programmierer zu blöde war, statt Offset die Zeitzone zu verwenden.

                    Vielleicht sind Gunnars Projekte ja so langweilig, dass dadurch die User wenigstens zweimal im Jahr vorbeischauen SCNR

                  2. @@Sven Rautenberg:

                    nuqneH

                    Nein. Wenn wir auf Sommerzeit umstellen, dann wechseln wir die Zeitzone: von MEZ (+01:00) zu MESZ (+02:00).

                    Super-Feature. Dann darf ich als User also zweimal im Jahr wie früher alle meine externen Accounts von MEZ nach MESZ umstellen und zurück, nur weil der Programmierer zu blöde war, statt Offset die Zeitzone zu verwenden.

                    Hm, mal ein bisschen Polemik oder hattest du nicht verstanden, worauf ich hinauswollte?

                    Natürlich möchte man als Nutzer nicht seine Uhren zweimal im Jahr umstellen. Jede (elektonische) Uhr, die auch das Datum kennt, sollte dies automatisch tun können. (Was aber Probleme aufwirft, wenn die Regeln für die Sommerzeit mal wieder geändert werden, wie damals, als die Sommerzeit von 6 auf 7 Monate ausgedehnt wurde (Umstellung Ende Oktober statt Ende September).)

                    Die Einstellung dafür wäre aber sowas wie „lokale Zeit von Berlin“ (oder Nest deiner Wahl) und NICHT „Mitteleuropäische Zeit“. Weil eben in Berlin (oder Nest deiner Wahl) nicht ganzjährig die Mitteleuropäische Zeit gilt.

                    Um Missverständnissen vorzubeugen, sollte man die richtigen Begriffe verwenden und nicht von Zeitzonen sprechen, wenn man nicht Zeitzonen meint. Leider hat Felix im OP schon fälschlicherweise von „Zeitzonen“ gesprochen.

                    Qapla'

                    --
                    „Talente finden Lösungen, Genies entdecken Probleme.“ (Hans Krailsheimer)
                    1. Om nah hoo pez nyeetz, Gunnar Bittersmann!

                      Um Missverständnissen vorzubeugen, sollte man die richtigen Begriffe verwenden und nicht von Zeitzonen sprechen, wenn man nicht Zeitzonen meint.

                      Es ist sogar noch ein wenig komplizierter, denn auch dein "Wechsel der Zeitzone" stimmt nicht. Zeitzonen sind rein geografisch bestimmte Gebiete der Erde. Welche Zeit in dieser Zone gilt, ist noch wieder eine andere Frage.

                      Zeitzone != Zonenzeit

                      genau wie

                      Unfallauto != Autounfall

                      Es gibt die mitteleuropäische Zeitzone, deren Zonenzeit als mittlere Ortszeit des 15°-Meridians definiert ist. Im Sommer gilt davon abweichend eine andere Regelung.

                      Matthias

                      --
                      Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Bache und Bachelor.

                    2. Moin!

                      Nein. Wenn wir auf Sommerzeit umstellen, dann wechseln wir die Zeitzone: von MEZ (+01:00) zu MESZ (+02:00).

                      Super-Feature. Dann darf ich als User also zweimal im Jahr wie früher alle meine externen Accounts von MEZ nach MESZ umstellen und zurück, nur weil der Programmierer zu blöde war, statt Offset die Zeitzone zu verwenden.

                      Hm, mal ein bisschen Polemik oder hattest du nicht verstanden, worauf ich hinauswollte?

                      Natürlich möchte man als Nutzer nicht seine Uhren zweimal im Jahr umstellen. Jede (elektonische) Uhr, die auch das Datum kennt, sollte dies automatisch tun können. (Was aber Probleme aufwirft, wenn die Regeln für die Sommerzeit mal wieder geändert werden, wie damals, als die Sommerzeit von 6 auf 7 Monate ausgedehnt wurde (Umstellung Ende Oktober statt Ende September).)

                      Die Einstellung dafür wäre aber sowas wie „lokale Zeit von Berlin“ (oder Nest deiner Wahl) und NICHT „Mitteleuropäische Zeit“. Weil eben in Berlin (oder Nest deiner Wahl) nicht ganzjährig die Mitteleuropäische Zeit gilt.

                      Ich sehe, du hast das Problem verstanden. Genau deshalb gibts diese Zeitzonen, die das Feature "Automatische Umstellung bei Sommerzeit" enthalten. Und genau die will man als User haben.

                      Um Missverständnissen vorzubeugen, sollte man die richtigen Begriffe verwenden und nicht von Zeitzonen sprechen, wenn man nicht Zeitzonen meint. Leider hat Felix im OP schon fälschlicherweise von „Zeitzonen“ gesprochen.

                      Die IANA-Zeitzonen sind Zeitzonen. Wie heißen die Dinger in deinem Sprachgebrauch?

                      - Sven Rautenberg

            2. Tach,

              Ich empfehle, Zeitzone und Sprache völlig unabhängig.

              Ich empfehle die Angabe der Zeitzone in Zahlen.

              das setzt allerdings voraus, dass die User die entsprechende Zahl ihres Heimatortes kennen; dass wir uns im Moment in +2 und in 'nem halben Jahr in +1 befinden, ist kein so verbreitetes Wissen, aber es spricht ja nix dagegen, beides zur Auswahl zu stellen.

              mfg
              Woodfighter

            3. Ich empfehle die Angabe der Zeitzone in Zahlen.

              Ich werde dieser Empfehlung nicht folgen, da ich meinen Usern nichts vorsetze, was 99,8% nicht verstehen.
              Weisst du alle Zeitzonen auswendig? Ich nicht, und daher halte ich diese ANgabe für absolut kontraproduktiv.

              Komfort ist, wenn ein User seine Zeitzone anhand des Landes einstellt und die Software den Offset selbst berechnet.

    2. Moin!

      Aktuell benutze ich (nach dieser Anleitung) die in PHP hinterlegten Werte (DateTimeZone::listIdentifiers), um daraus dynamisch eine Auswahlliste zu erzeugen:

      Das ist vermutlich der grausamste Code, den man schreiben kann, um so eine Liste zu erstellen. Der verwendet ja an nahezu JEDER Stelle reguläre Ausdrücke nur deshalb, weil man's kann - und dies keinesfalls effizient.

      Mein persönlicher Favorit ist, wie zu Beginn grandios ein "Template" für das Select-Feld definiert wird, und am Ende mit einem recht opulenten regulären Ausdruck die erzeugte Optionsliste hineingequetscht wird. WTF?

      Weiteres Highlight: Mit dem ERSTEN regulären Ausdruck suchen, ob eine Zeitzone zu einer der gewünschten Regionen gehört, und dann mit einem ZWEITEN regulären Ausdruck Region und Zone trennen. Und dies auch noch mit einem STATISCHEN Zeichen.

      Stattdessen im ersten Ausdruck die derzeit schon vorhandenen Klammern zu benutzen, um den dort gefundenen Ausdruck danach wiederzuverwenden (und man könnte dann auch noch Klammern für den zweiten Teil einfügen) war wohl abwegig:

        
          if (preg_match( '~^(America|Antartica|Arctic|Asia|Atlantic|Europe|Indian|Pacific)/(.*)$~', $v, $e)) {  
              $e; // schon fertig, der erste Teil steht allerdings in $e[1], nicht in [0], der zweite in [2], nicht in [1]. In [0] steht der gesamte String  
      
      

      $template = '<select name="timezones"></select>';

      $timezone_list = '';
      $c = '';

      foreach (DateTimeZone::listIdentifiers() as $v) {
          if (preg_match( '~^(America|Antartica|Arctic|Asia|Atlantic|Europe|Indian|Pacific)/~', $v)) {
              $e = preg_split('~/~', $v, 2, PREG_SPLIT_NO_EMPTY); // obtain continent, city

      if ($c != $e[0]) {
                  if (!empty($c)) {
                      $timezone_list .= '</optgroup>';
                  }

      $timezone_list .= sprintf(
                      '<optgroup label="%s">',
                      htmlspecialchars($e[0])
                  );
              }

      $city = $e[1];
              $c = $e[0];

      $timezone_list .= sprintf(
                  '<option value="%1$s">%2$s</option>',
                  htmlspecialchars($v),
                  htmlspecialchars($city)
              );
          }
      }

      $timezone_list = sprintf('%s</optgroup>', $timezone_list);

      $template = preg_replace(
          '~(?is)(<select .?name="timezone".?>[\r\n])~',
          '$1'.$timezone_list,
          $template
      );

        
       - Sven Rautenberg
      
      1. Lieber Sven Rautenberg,

        danke für Deinen Denkanstoß!

        Mein persönlicher Favorit ist, wie zu Beginn grandios ein "Template" für das Select-Feld definiert wird, und am Ende mit einem recht opulenten regulären Ausdruck die erzeugte Optionsliste hineingequetscht wird. WTF?

        Das "grandiose" Template ist in wirklichkeit ein vollständiges HTML-Dokument, welches für die Einstellungen-Seite aus einer HTML-Datei geladen wird. Im obigen Beispiel wurde das Dokument auf das <select>-Element verkürzt.

        Meine Lösung nutzt nun SimpleXML, um diese lästige verschachtelte Stringerzeugung etwas besser zu strukturieren. Ob das Konstrukt letzten Endes besser lesbar ist (also der PHP-Code, nicht der erzeugte HTML-Code) ist eine andere Frage.

        $template = file_get_contents('template-settings-menue.html');  
          
        $timezone_list = simplexml_load_string('<?xml version="1.0" encoding="UTF-8"?><select name="timezone"></select>');  
        $og = null;  
          
        foreach (DateTimeZone::listIdentifiers() as $v) {  
            if (preg_match('~^(America|Antartica|Arctic|Asia|Atlantic|Europe|Indian|Pacific)/(.*)$~', $v, $e)) {  
                if ($og === null || $og['label'] != $e[1]) {  
                    $og = $timezone_list->addChild('optgroup');  
                    $og->addAttribute('label', $e[1]);  
                }  
          
                $o = $og->addChild('option', $e[2]);  
                $o->addAttribute('value', $e[0]);  
            }  
        }  
          
        $timezone_list = preg_replace('~(?is)^[^\r\n]*[\r\n]*~', '', $timezone_list->asXML());  
          
        $template = preg_replace(  
            '~(?is)<select name="timezone".*?</select>~',  
            $timezone_list,  
            $template  
        );
        

        Liebe Grüße,

        Felix Riesterer.

        --
        ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
    3. Hi,

      Aktuell benutze ich (nach dieser Anleitung) die in PHP hinterlegten Werte (DateTimeZone::listIdentifiers), um daraus dynamisch eine Auswahlliste zu erzeugen:

      Da hier ein Gruppenwechsel implementiert wird, um die Zeitzonen nach Kontinenten in Optgroups zusammenzufassen, ist eine Sortierung nach Kontinenten Voraussetzung – ist die durch DateTimeZone::listIdentifiers *garantiert*? Im Handbuch habe ich dazu keinen expliziten Hinweis gefunden.

      MfG ChrisB

      --
      RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
      1. Lieber ChrisB,

        der Gruppenwechsel nach Kontinenten ist ein Notbehelf, um diese vielen Angaben irgendwie vernünftig zu gruppieren.

        Die Gruppierung nach dem PHP-Handbuch scheint sich an Kontinenten zu orientieren. Also habe ich das so übernommen (und die Anleitung, die ich nutzte, auch), ohne jetzt streng eine Unterteilung nach Kontinenten anzustreben.

        Liebe Grüße,

        Felix Riesterer.

        --
        ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
  2. Moin Moin!

    Ich schmeiß mal einen alten Thread in die Runde. Rechne komplett in UTC, lasse den Server in UTC laufen, und baue auf dem Client aus der UTC die jeweilige lokale Zeit und umgekehrt. Der Browser kennt in aller Regel die lokale Zeitzone inklusive aller Schweinereien wie 15-Minuten-Offsets, Sommerzeit, Hochsommerzeit, usw. Schlicht, weil jemand bei der Betriebssystem-Installation mal gesagt hat, dass der Rechner in der selben Zeitzone steht wie eine relativ nahe gelegene große Stadt.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
    1. Lieber Alexander (HH),

      das Zeitzonenproblem habe ich nur, weil PHP5 bei der Verwendung der date()-Funktion zwingend eine Einstellung erfordert, die in der php.ini nicht unbedingt gesetzt sein muss. Bei shared-hosting kommt man als Kunde nicht unbedingt an eine php.ini heran, vor allem dann nicht, wenn die Servereinstellungen keine lokalen php.ini-Dateien erlauben. Daher bin ich auf date_set_default_timezone ausgewichen, wofür ich aber (irgend)einen Wert benötige. Um diesen Wert nicht völlig sinnbefreit zu setzen, dachte ich daran, den User des CMS eine für seinen Standort einigermaßen sinnvolle Auswahl treffen zu lassen.

      Was wäre denn, wenn ich "UTC" als Wert nähme? Was würde dann bei Abfragen à la date('Y-m-d H:i:s') passieren?

      Liebe Grüße,

      Felix Riesterer.

      --
      ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
      1. Moin Moin!

        Was wäre denn, wenn ich "UTC" als Wert nähme? Was würde dann bei Abfragen à la date('Y-m-d H:i:s') passieren?

        Was PHP treibt, will ich meistens gar nicht wissen, das macht nur Kopfschmerzen.

        Wenn date() als Default die aktuelle Zeit nimmt, und Zeitzonen-Angaben berücksichtigt, müßte das Ergebnis eine Zeitangabe in UTC sein, d.h. eine oder zwei Stunden Unterschied zur in Deutschland üblichen Zeitangabe.

        Das PHP-Manual schwafelt bei fehlendem Timestamp aber etwas von lokaler Zeit, was definitiv etwas anderes ist als eine Zeitangabe in UTC. In der englischen Fassung steht dort schlicht current time. Beide Fassungen verweisen auf den Rückgabewert von time(). time() soll in der deutschen und der englischen Fassung die Sekunden seit 1970-01-01 00:00:00 GMT liefern. Beide Fassungen beziehen sich explizit auf die "Unix Epoch". Schade nur, dass Unix-Zeiten als Anzahl der Nicht-Schaltsekunden seit 1970-01-01 00:00:00 UTC definiert sind, und gängige Betriebssysteme eben diese Definiton verwenden. Aktuell weichen diese beiden Definitionen um 25 Sekunden voneinander ab.

        Das Schöne an der Konstruktion aus dem alten Thread ist aber gerade, dass Du dich mit Datumsfunktionen nur auf dem Client herumschlagen mußt, und das dort die Zeitzonenprobleme bereits durch die Installation von Betriebssystem und Browser erledigt sind. In PHP siehst Du nur einen großen Integer. date() würdest Du nur als Fallback für Clients ohne aktiviertes Javascript nutzen, sinnigerweise mit "c", "r", "Y-m-d H:i:s I",  "Y-m-d H:i:s T",oder "Y-m-d H:i:s e" als Format.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".