encoder: PHP Komponenten aus DateTime auslesen

Seit längerem bin ich wieder etwas in PHP unterwegs und dachte die Klasse DateTime wäre die beste Wahl um Zeitpunkte zu handhaben.

Auf der Seite finde ich allerdings nichts womit ich die einzelnen Komponenten auslesen kann. Zum Beispiel möchte ich den Wochentag eines Datums wissen.
Bleibt mir hier wirklich nichts anderes übrig als diesen Wert mittels format als String zu holen?
(genauer gesagt einen Parser rausfinden lassen was ich haben will, ihn das dann als String formatieren lassen und PHP diesen String später wieder in eine Zahl umrechnen lassen, weil ich mit der verschiedene Tests mache)

Ja ich weiß PHP rechnet alles um wie es meint dass ich es haben möchte und ich habe mich mit diesen Vorgehensweise auch notgedrungen abgefunden.
Dass ich in dieser Klasse keine Felder für Tag, Monat usw. finde so wie es DateInterval der Fall ist, finde ich trotzdem befremdlich genug um hier nachzufragen.

  1. Lieber encoder,

    (genauer gesagt einen Parser rausfinden lassen was ich haben will, ihn das dann als String formatieren lassen und PHP diesen String später wieder in eine Zahl umrechnen lassen, weil ich mit der verschiedene Tests mache)

    Warum glaubst Du, dass das eine notwendige Vorgehensweise wäre? Ich gehe davon aus, dass intern Unix-Zeit als Grundlage verwendet wird, ähnlich wie in JavaScript auch. Und auch in JavaScript musst Du explizit angeben, welches Detail Du von Deinem Date-Objekt genau haben willst. Mit DateTime in PHP verhält es sich sehr ähnlich.

    Dass ich in dieser Klasse keine Felder für Tag, Monat usw. finde so wie es DateInterval der Fall ist, finde ich trotzdem befremdlich genug um hier nachzufragen.

    Wahrscheinlich denkst Du in Datumsfragen anders, als die Macher von PHP oder JavaScript. Immer daran denken: Tage, Monate und Jahre sind immer eine Frage der Zeitzone! Dafür sind diese Objekte da, dass sie das berücksichtigen, um Dir je nach Format/RFC die Dinge exakt zu berechnen. Aber in PHP gefällt mir, dass Strings wie "+4 days" oder "last wednesday" verstanden werden. In JavaScript gibt es das nicht.

    Liebe Grüße

    Felix Riesterer

    1. Warum glaubst Du, dass das eine notwendige Vorgehensweise wäre?

      Ich finde etliche Beispiele die alle mit dem Formatstring "w" arbeiten. date('w', $d) ist überall zu finden. Da ist auch keine Zeitzone im Spiel. Mein Gedanke war jetzt, obs da nicht ein besser lesbares $d->dayOfWeek gibt.
      DateTimeInterface::format gibt es noch, damit lässt sich die Stringdarstellung erzeugen. Aber auch ohne Zeitzone.
      Wie genau ist dein Hinweis gemeint?

      Wahrscheinlich denkst Du in Datumsfragen anders, als die Macher von PHP oder JavaScript.

      Das mag sein, ich kanns leider nicht beantworten denn ich weiß noch nicht wie die denken 😀

      1. Lieber encoder,

        date('w', $d) ist überall zu finden. Da ist auch keine Zeitzone im Spiel.

        aha, jetzt kommen wir der Sache näher. Ich meine mich zu erinnern, dass die Sache mit den Timezones seit PHP5 stringenter gehandhabt wird. Jedenfalls kommt man mit date_default_timezone_get() an die intern verwendete Timezone ran. Man kann sie für sein Script auch ändern.

        Mein Gedanke war jetzt, obs da nicht ein besser lesbares $d->dayOfWeek gibt.

        Nö, wozu auch? Es gibt ja schon den w-Schalter.

        DateTimeInterface::format gibt es noch, damit lässt sich die Stringdarstellung erzeugen. Aber auch ohne Zeitzone.

        An die Zeitzone kommst Du auf anderem Weg. Siehe oben. Wenn Du eine Zeitzonenangabe in Deinem Datumswert ausgeben willst, hast Du wieder andere Schalter, die Dir einen String nach irgendeiner Norm (ISO/RFC/etc.) erzeugen können.

        Wie genau ist dein Hinweis gemeint?

        Mein Hinweis war, dass Deine Erwartungshaltung anhand der Komplexität des Themas an sich eine in meinen Augen unpassende ist.

        Wahrscheinlich denkst Du in Datumsfragen anders, als die Macher von PHP oder JavaScript.

        Das mag sein, ich kanns leider nicht beantworten denn ich weiß noch nicht wie die denken 😀

        Die denken in „intern UNIX-Timestamp, extern auf Wunsch berechnet“. Dafür verwenden sie in PHP diese Schalter bei der Stringerzeugung. Die Zeitzone selbst ist in einem PHP-Setting hinterlegt, das per Script auch abgeändert werden kann, damit die Stringerzeugung in Deinem Sinne funktioniert.

        Liebe Grüße

        Felix Riesterer

    2. Dass ich in dieser Klasse keine Felder für Tag, Monat usw. finde so wie es DateInterval der Fall ist, finde ich trotzdem befremdlich genug um hier nachzufragen.

      Wahrscheinlich denkst Du in Datumsfragen anders, als die Macher von PHP oder JavaScript. Immer daran denken: Tage, Monate und Jahre sind immer eine Frage der Zeitzone! Dafür sind diese Objekte da, dass sie das berücksichtigen, um Dir je nach Format/RFC die Dinge exakt zu berechnen. Aber in PHP gefällt mir, dass Strings wie "+4 days" oder "last wednesday" verstanden werden. In JavaScript gibt es das nicht.

      Die Macher von JavaScript haben die Methode Date.prototype.getDay() zur Ermittlung des Wochentages vorgesehen. Selbiges gibt es für Monat, Tag, DayOfYear etc. Ich denke, darauf will encoder hinaus.

      Im Temporal-Proposal sind zudem auch zeitzonenlose "plainDates" vorgesehen, die für viele Anwendungen vollkommen ausreichend sein dürften.

      1. Hallo Random2356,

        wenn er nicht PHP sprechen würde, dann würde er darauf hinauswollen, ja.

        Natürlich könnte man V8Js installieren und darin die Date-Klasse verwenden - aber... 😉

        Rolf

        --
        sumpsi - posui - obstruxi
  2. Hallo encoder,

    es kommt halt drauf an, was Du brauchst. PHP möchte Dir die Mühe abnehmen, UTC Timestamps passend umzurechnen.

    Was fehlt, ist eine getDateParts() Methode, da stimme ich Dir zu. Das geht aber relativ einfach:

    function getDateParts(DateTime $dt) {
       return getdate($now->getTimestamp() + $now->getOffset());
    }
    

    Damit bekommst Du ein getdate() Array. Und wenn Du magst, dann leite von DateTime eine EncoderDateTime Klasse ab und bau das dort als Methode ein.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hallo encoder,

      es kommt halt drauf an, was Du brauchst. PHP möchte Dir die Mühe abnehmen, UTC Timestamps passend umzurechnen.

      Was fehlt, ist eine getDateParts() Methode, da stimme ich Dir zu. Das geht aber relativ einfach:

      function getDateParts(DateTime $dt) {
         return getdate($now->getTimestamp() + $now->getOffset());
      }
      

      meinst Du

      <?php
      
      $now = new DateTime();
      var_dump( $now );
      
      function getDateParts(DateTime $dt) {
          return getdate($dt->getTimestamp() + $dt->getOffset());
      }
      var_dump( getDateParts( $now ) );
      

      Ausgaben:

      php test.php 
      object(DateTime)#1 (3) {
        ["date"]=>
        string(26) "2023-09-02 17:32:17.629707"
        ["timezone_type"]=>
        int(3)
        ["timezone"]=>
        string(3) "UTC"
      }
      array(11) {
        ["seconds"]=>
        int(17)
        ["minutes"]=>
        int(32)
        ["hours"]=>
        int(17)
        ["mday"]=>
        int(2)
        ["wday"]=>
        int(6)
        ["mon"]=>
        int(9)
        ["year"]=>
        int(2023)
        ["yday"]=>
        int(244)
        ["weekday"]=>
        string(8) "Saturday"
        ["month"]=>
        string(9) "September"
        [0]=>
        int(1693675937)
      }
      
      1. Ich glaube ja, dass das Problem darin besteht, dass PHP für Server gemacht wurde (→ Zeitzone zumeist UTC) während JS/ECMA eigentlich für Browser gedacht istwar (→ Zeitzone des jeweiligen Benutzers). Daraus ergeben sich unterschiedliche Ansätze, betreffend der „Einfachheit der Beachtung der Zeitzonen“…

        Deshalb habe ich mal was konstruiert:

        <?php
        
        function getDatePartsUTC( DateTime $dt ) {
            $arr = getdate(
        		$dt -> getTimestamp() + $dt -> getOffset()
        	);
        
        	# Only to make the array full compatible to getDatePartsLocal():
            $arr['TimezoneName']    = 'UTC';
            $arr['TimezoneOffset']  = '00:00';
            $arr['TimezoneOffsetS'] = 0;
            return $arr;
        }
        
        function getDatePartsLocal( DateTime $dt, $TimeZoneName ) {
        
        	$dt -> setTimezone(
        		new DateTimeZone( $TimeZoneName )
        	);
            $arr = getdate(
        		$dt -> getTimestamp() + $dt -> getOffset()
        	);
            $arr['TimezoneName']    = $TimeZoneName ;
            $arr['TimezoneOffset']  = $dt -> format('P');
            $arr['TimezoneOffsetS'] = (int)$dt -> format('Z');
            return $arr;
        }
        
        
        $now = new DateTime();
        #var_dump( $now );
        
        echo "Stunde in UTC:" . PHP_EOL;
        #var_dump( getDatePartsUTC( $now ) );
        $a = getDatePartsUTC( $now );
        echo $a['hours'] . PHP_EOL;
        
        ### Show:
        ### https://www.php.net/manual/de/timezones.php
        ### https://raw.githubusercontent.com/leon-do/Timezones/main/timezone.json
        $zones = [
        	'Europe/Moscow',
        	'Europe/Berlin',
        	'Europe/Lisbon',
        	'UTC'
        ];
        foreach ( $zones as $zone ) {
        	echo "\nStunde für: $zone" . PHP_EOL;
        	#var_dump( getDatePartsLocal( $now, $zone ) );
        	$a = getDatePartsLocal( $now, $zone );
        	echo  $a['hours'] . PHP_EOL;
        }
        
        

        Ausgaben auf Rechner mit Default-Zeitzone UTC (Server):

        fastix@raspi4:/tmp $ php test.php 
        Stunde in UTC:
        8
        
        Stunde für: Europe/Moscow
        11
        
        Stunde für: Europe/Berlin
        10
        
        Stunde für: Europe/Lisbon
        9
        
        Stunde für: UTC
        8
        

        Ausgaben auf Rechner mit Default-Zeitzone Europe/Berlin (Desktop):

        fastix@mini:/tmp$ php test.php 
        Stunde in UTC:
        8
        
        Stunde für: Europe/Moscow
        11
        
        Stunde für: Europe/Berlin
        10
        
        Stunde für: Europe/Lisbon
        9
        
        Stunde für: UTC
        8
        

        [x] sind identisch. Scheint zu funktioneren.