ChrisB: falscher days-Wert bei DateTime::diff

Hi,

kann mir jemand erklären, warum mir
  ~~~php $datenow  = new DateTime('2009-12-21 12:00:00');
  $datethen = new DateTime('2009-12-20 12:00:00');
  $datediff = $datenow->diff($datethen);
  print_r($datediff);

auf meinem lokalen Testsystem (Win 7, PHP 5.3.0) folgendes ausgibt?  
  
DateInterval Object  
(  
    [y] => 0  
    [m] => 0  
    [d] => 1  
    [h] => 0  
    [i] => 0  
    [s] => 0  
    [invert] => 1  
    [days] => 6015  
)  
  
d = 1, passt.  
Aber warum days = 6015?  
  
Wenn ich das auf einem anderen System (Linux, PHP 5.3.1) teste, bekomme ich wie erwartet days = 1 heraus.  
  
date.timezone steht in beiden Fällen auf Europe/Berlin, einziger Unterschied in der Ausgabe von phpinfo() bzgl. date ist die „"Olson" Timezone Database Version”, bei mir lokal 2009.10, auf dem anderen System 2009.18.  
  
Unter bugs.php.net habe ich spontan nichts dazu passendes finden können.  
  
MfG ChrisB  
  

-- 
“Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
  1. Hallo,

    kann mir jemand erklären, warum mir
      ~~~php

    $datenow  = new DateTime('2009-12-21 12:00:00');

    $datethen = new DateTime('2009-12-20 12:00:00');
      $datediff = $datenow->diff($datethen);
      print_r($datediff);

    
    > auf meinem lokalen Testsystem (Win 7, PHP 5.3.0) folgendes ausgibt?  
    >   
    > DateInterval Object  
    > (  
    >     [y] => 0  
    >     [m] => 0  
    >     [d] => 1  
    >     [h] => 0  
    >     [i] => 0  
    >     [s] => 0  
    >     [invert] => 1  
    >     [days] => 6015  
    > )  
    >   
    > d = 1, passt.  
    > Aber warum days = 6015?  
      
    Kannst Du bitte mal die Ausgabe von  
      
    print\_r($datenow);  
    print\_r($datethen);  
      
    auf Deinem System, wo der Fehler auftritt, posten?  
      
    Viele Grüße,  
    Christian  
    
    -- 
    [Mein "Weblog"](http://del.icio.us/chris_se/servertipps) [[RSS](http://del.icio.us/rss/chris_se/servertipps)]  
    [Using XSLT to create JSON output](http://www.christian-seiler.de/projekte/xslt-json/) (Saxon-B 9.0 for Java)  
      
    »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«  
                -- [Kommentar bei TDWTF](http://thedailywtf.com/Comments/WellIntentioned-Destruction.aspx#254549)
    
    1. Hi,

      Kannst Du bitte mal die Ausgabe von

      print_r($datenow);
      print_r($datethen);

      auf Deinem System, wo der Fehler auftritt, posten?

      Klar, da ist eigentlich alles wie erwartet:

      DateTime Object
      (
          [date] => 2009-12-21 12:00:00
          [timezone_type] => 3
          [timezone] => Europe/Berlin
      )
      DateTime Object
      (
          [date] => 2009-12-20 12:00:00
          [timezone_type] => 3
          [timezone] => Europe/Berlin
      )

      Ob ich
      $datenow->diff($datethen)
      oder
      $datethen->diff($datenow)
      betrachte, ändert ausser dem Eintrag 'invert' im Ergebnis der Funktion auch nichts - 'days' bleiben 6015, während 'd' wie erwartet 1 ist, und alles andere 0.

      MfG ChrisB

      --
      “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
      1. Hallo,

        Ob ich
        $datenow->diff($datethen)
        oder
        $datethen->diff($datenow)
        betrachte, ändert ausser dem Eintrag 'invert' im Ergebnis der Funktion auch nichts - 'days' bleiben 6015, während 'd' wie erwartet 1 ist, und alles andere 0.

        Hmmmm.... Und was sagt

        var_dump($datenow->getOffset());
        var_dump($datethen->getOffset());

        ?

        Viele Grüße,
        Christian

        --
        Mein "Weblog" [RSS]
        Using XSLT to create JSON output (Saxon-B 9.0 for Java)
        »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«
                    -- Kommentar bei TDWTF
        1. Hi,

          Hmmmm.... Und was sagt

          var_dump($datenow->getOffset());
          var_dump($datethen->getOffset());

          ?

          Das sagt:
          int(3600)
          int(3600)

          MfG ChrisB

          --
          “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
          1. Hallo,

            Hmmmm.... Und was sagt

            var_dump($datenow->getOffset());
            var_dump($datethen->getOffset());

            ?

            Das sagt:
            int(3600)
            int(3600)

            Hmm, dann verstehe ich's nicht. Ich hab mir den Sourcecode von PHP diesbezüglich angesehen und ich kann mir nicht erklären, woher das kommt... (Außer irgend ein Speicherbereich wird fälschlicherweise überschrieben oder so.) Ich werde das nachher mal unter Windows ausprobieren.

            Viele Grüße,
            Christian

            --
            Mein "Weblog" [RSS]
            Using XSLT to create JSON output (Saxon-B 9.0 for Java)
            »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«
                        -- Kommentar bei TDWTF
            1. Hallo nochmal,

              Hmm, dann verstehe ich's nicht. Ich hab mir den Sourcecode von PHP diesbezüglich angesehen und ich kann mir nicht erklären, woher das kommt... (Außer irgend ein Speicherbereich wird fälschlicherweise überschrieben oder so.) Ich werde das nachher mal unter Windows ausprobieren.

              Ich hab gerade PHP 5.3.0 unter Windows nochmal seblst kompiliert und es kam folgendes bei heraus:

              DateInterval Object
              (
                  [y] => 0
                  [m] => 0
                  [d] => 1
                  [h] => 0
                  [i] => 0
                  [s] => 0
                  [invert] => 1
                  [days] => 3940024
              )

              Das heißt: Das ist definitiv ein Bug in PHP, der nicht in der Berechnungslogik selbst ist, sondern irgendwie gerät der Speicher durcheinander. Ich schaue mir das mal genauer an.

              Viele Grüße,
              Christian

              --
              Mein "Weblog" [RSS]
              Using XSLT to create JSON output (Saxon-B 9.0 for Java)
              »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«
                          -- Kommentar bei TDWTF
              1. Hallo nochmal,

                Das heißt: Das ist definitiv ein Bug in PHP, der nicht in der Berechnungslogik selbst ist, sondern irgendwie gerät der Speicher durcheinander. Ich schaue mir das mal genauer an.

                Ich habe gerade mal PHP 5.3.1 und PHP 5.3.0 mit Valgrind unter Linux verglichen und festgestellt, dass es in 5.3.0 unter Linux mit Deinem Testscript Speicherprobleme gibt (Speicher wird nicht korrekt freigegeben). Ich vermute, dass der Microsoft-Compiler unter Windows durch irgend eine etwas andere Optimierung zu dem Fehler führt, den Du siehst. Du solltest es also mal mit PHP 5.3.1 probieren statt 5.3.0 (Du kannst Dir ja die Binaries direkt als ZIP runterladen, entpacken und einfach nur die CLI-Version von PHP verwenden ohne das wirklich zu installieren, um es mal auf der Kommandozeile auszuprobieren) - vermutlich wurde das Problem da behoben.

                Viele Grüße,
                Christian

                --
                Mein "Weblog" [RSS]
                Using XSLT to create JSON output (Saxon-B 9.0 for Java)
                »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«
                            -- Kommentar bei TDWTF
                1. Hi Christian,

                  Du solltest es also mal mit PHP 5.3.1 probieren statt 5.3.0 (Du kannst Dir ja die Binaries direkt als ZIP runterladen, entpacken und einfach nur die CLI-Version von PHP verwenden ohne das wirklich zu installieren, um es mal auf der Kommandozeile auszuprobieren) - vermutlich wurde das Problem da behoben.

                  Du hast recht, wenn ich das auf diese Weise mit dem eingangs genannten Script-Schnippsel teste, erhalte ich für days eine 1 - und auch bei anderen Testwerten scheinen die Werte plausibel zu sein.

                  Danke für deine Bemühungen. Ich werde mal schauen, ob ich den days-Wert wirklich brauche, oder mit den restlichen Angaben auskomme; und ggf. mein lokales PHP bei Gelegenheit auf 5.3.1 updaten.

                  MfG ChrisB

                  --
                  “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
  2. Hallo ChrisB!

    WinXP, PHP 5.3.0 und Win Vista ebenfalls PHP 5.3.0 sagen dasselbe - ich habe aktuell keinen Zugriff auf ein (Remote-) Nicht-Windows-System mit einer ausreichend aktuellen PHP-Installation, um DateTime testen zu können :(

    Ein Linuxsystem werde ich heute abend aber nicht mehr aufsetzen und der Apfel ist leider zur Reparatur aushäusig - den Test hole ich nach.

    Die Auflösung würde mich aber sehr interessieren..

    Ciao

    GG

    --
    "If I do not seek to understand what is happening here
    - then I've got peanuts in my head!"
    (I. Hosein)
  3. Hi,

    DateInterval Object

    Aber warum days = 6015?

    Was sagt das http://www.php.net/manual/en/class.dateinterval.php zur Bedeutung des Felds days?
    Eigentlich gar nichts. Da gibt es nicht mal eine Beschreibung, welche Felder überhaupt vorhanden sind. Super-Doku.

    Wenn man sich das Beispiel auf der Konstruktor-Seite anguckt:

    [y] => 2
        [m] => 0
        [d] => 4
        [h] => 6
        [i] => 8
        [s] => 0
        [invert] => 0
        [days] => 0

    ergibt sich auch hier eine Abweichung zwischen den einbuchstabigen Feldern und dem days-Wert.
    Vielleicht ist das ja nur irgendein internes Feld, das nicht für den Gebrauch durch den Anwender der Klasse bestimmt ist.
    Aber dazu schweigt sich das Manual sehr gründlich aus ...

    cu,
    Andreas

    --
    Warum nennt sich Andreas hier MudGuard?
    O o ostern ...
    Fachfragen per Mail sind frech, werden ignoriert. Das Forum existiert.
    1. Hi,

      DateInterval Object

      Aber warum days = 6015?

      Was sagt das http://www.php.net/manual/en/class.dateinterval.php zur Bedeutung des Felds days?
      Eigentlich gar nichts. Da gibt es nicht mal eine Beschreibung, welche Felder überhaupt vorhanden sind. Super-Doku.

      Tja, für neue PHP-Features leider allzu oft „normal”.

      Wenn man sich das Beispiel auf der Konstruktor-Seite anguckt:

      [y] => 2
          [m] => 0
          [d] => 4
          [h] => 6
          [i] => 8
          [s] => 0
          [invert] => 0
          [days] => 0

      ergibt sich auch hier eine Abweichung zwischen den einbuchstabigen Feldern und dem days-Wert.

      Stimmt, seltsam.

      Vielleicht ist das ja nur irgendein internes Feld, das nicht für den Gebrauch durch den Anwender der Klasse bestimmt ist.

      DateInterval::format kennt den Formatstring-Parameter %a, definiert als: Total amount of days.
      Und wenn ich das nutze, ist es auch konsistent mit dem, was mir der Eintrag 'days' im Ergebnis-Array der diff-Methode liefert (also lokal 6015, auf dem anderen System 1).

      Deshalb gehe ich schon davon aus, dass 'days' für die Gesamtanzahl der Tage zwischen zwei Datümern stehen soll.

      MfG ChrisB

      --
      “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
  4. Hey,

    gräm dich nicht, es ist halt PHP:

      
    print_r((int) (19.99 * 100));  
    
    

    frohe Feiertage und guten Rutsch

    1. Hallo,

      gräm dich nicht, es ist halt PHP:

      print_r((int) (19.99 * 100));

        
      Es mag ja viel an PHP zu kritisieren geben aber \*das\* ist nicht die Schuld von PHP. Das ist nämlich laut IEEE 754 Double-Arithmetik das korrekte Ergebnis.  
        
      Beispiel Python:  
        
      print int(19.99\*100)  
        
      Beispiel Perl:  
        
      print int(19.99\*100);  
        
      Beispiel C:  
        
      printf ("%d\n", (int)(19.99\*100));  
        
      Beispiel Haskell:  
        
      truncate (19.99\*100)  
        
      Beispiel Ruby:  
        
      print Integer(19.99\*100)  
        
      Beispiel Javascript:  
        
      alert(parseInt(19.99\*100));  
        
      Hintergrund ist der: 19.99 kann nicht exakt dargestellt werden in Double-Arithmetik, der IEEE 754-Standard schreibt vor, dass man in solchen Fällen die nächstmögliche Zahl nehmen soll. Das ist in dem Fall:  
        
      19\.989999999999998436805981327779591083526611328125  
        
      Wenn man die im Computer mit 100 multipliziert, ist das Ergebnis:  
        
      1998\.999999999999772626324556767940521240234375  
        
      (Die Multiplikation kann auch wieder nicht exakt durchgeführt werden, da die Genauigkeit wieder nicht ausreicht.)  
        
      Wenn man diese Zahl nun in einen Integer verwandelt, werden eben alle Nachkommastellen abgeschnitten und dann bleibt nur 1998 übrig. Egal in welcher Sprache, solange sie IEEE 754 Arithmetik benutzt.  
        
      Wenn Du dagegen eine andere Sprache verwendest, die z.B. beliebig genaue Dezimalarithmetik implementiert (was \*SEHR\* viel langsamer wäre, weil das Prozessoren nicht von Haus aus können im Gegensatz zu IEEE 754), dann würdest Du natürlich das aus Deiner Sicht "korrekte" Ergebnis bekommen. Solche Arithmetik gibt's für viele bestehende Sprachen als Zusatzmodule, für PHP z.B. via die bcmath-Erweiterung.  
        
      Viele Grüße,  
      Christian  
      
      -- 
      [Mein "Weblog"](http://del.icio.us/chris_se/servertipps) [[RSS](http://del.icio.us/rss/chris_se/servertipps)]  
      [Using XSLT to create JSON output](http://www.christian-seiler.de/projekte/xslt-json/) (Saxon-B 9.0 for Java)  
        
      »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«  
                  -- [Kommentar bei TDWTF](http://thedailywtf.com/Comments/WellIntentioned-Destruction.aspx#254549)
      
  5. (Hallo|Hi(ho)|Nabend) ChrisB,

    Unter bugs.php.net habe ich spontan nichts dazu passendes finden können.

    http://bugs.php.net/bug.php?id=49778&edit=1#c155500

    6015 scheint immer dann herauszukommen, wenn der Unterschied per ->diff() berechnet wird.
    Erzeugt man ein DateInterval-Objekt mit ::createFromDateString() ist der Wert für ->days immer 0.
    (PHP 5.3.0, Win32)

    MffG
    EisFuX

    1. Hi,

      http://bugs.php.net/bug.php?id=49778&edit=1#c155500

      Danke!

      6015 scheint immer dann herauszukommen, wenn der Unterschied per ->diff() berechnet wird.

      Also wohl ein Bug in der Win-Version.

      Erzeugt man ein DateInterval-Objekt mit ::createFromDateString() ist der Wert für ->days immer 0.

      Die Erklärung dafür,

      Days is indeed not set when creating a DateInterval using the constructor. A complication with this is that it is impossible to determine the number of days when months or years are specified, since these vary in length.

      ist ja nachvollziehbar.

      MfG ChrisB

      --
      “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]