DaTom: Fehler beim Vergleichen von Datumswerten?

Hallo zusammen,

Ich bastle mich zur Zeit durch jQuery und Knockout, und bin beim Vergleichen von Datumswerten gestolpert.
Und zwar hab ich zwei Knockout Bindings auf Datumswerte, und beide haben den gleichen Wert.
Im Chrome Debugger hab ich folgende Variablen und Werte stehen:

this.date1(): Fri Oct 25 2013 00:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)
this.date2(): Fri Oct 25 2013 00:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)

this.date1().toString(): "Fri Oct 25 2013 00:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)"
this.date2().toString(): "Fri Oct 25 2013 00:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)"

this.date1().getTime(): 1382652000000
this.date2().getTime(): 1382652000000

Wenn ich this.date1() == this.date2() abfrage, erhalte ich FALSE.
Wenn ich this.date1().toString() == this.date2().toString() abfrage, erhalte ich TRUE.
Wenn ich this.date1().getTime() == this.date2().getTime() abfrage erhalte ich TRUE

Warum liefert der erste Vergleich FALSE?
Ich lass mir einreden, dass ich mit == Objekte vergleiche, aber ich hab es dann auch mal mit unterschiedlichen Datumswerten funktioniert, und siehe da, es klappt tadellos (einmal 9 Uhr, einmal 10 Uhr):

this.date1(): Fri Oct 25 2013 09:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)
this.date2(): Fri Oct 25 2013 10:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)

this.date1() < this.date2(): true
this.date1() == this.date2(): false
this.date1() > this.date2(): false

Was habe ich übersehen?

Gruß
DaTom

  1. Hi,

    this.date1(): Fri Oct 25 2013 09:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)
    this.date2(): Fri Oct 25 2013 10:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)

    this.date1() < this.date2(): true
    this.date1() == this.date2(): false
    this.date1() > this.date2(): false

    Was habe ich übersehen?

    Millisekunden?

    cu,
    Andreas

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

      Danke für die rasche Antwort. Laut Javascript Referenz auf dieser Seite:

      getTime(): Liefert die Anzahl Millisekunden als Zahl zurück, die seit dem 1. Januar 1970, 0:00:00 Uhr UTC, bis zu dem im Datumsobjekt gespeicherten Zeitpunkt vergangen sind.

      Wie in meinem Beispiel erwähnt, haben die beiden Datumswerte dieselbe Anzahl Millisekunden:

      this.date1().getTime(): 1382652000000
      this.date2().getTime(): 1382652000000

      Wenn ich also die Millisekunden zweier Datumswerte vergleiche, und die Datumswerte direkt miteinander vergleiche, warum kann das eine dann true und das andere false sein?

      Gruß
      Thomas

      1. this.date1().getTime(): 1382652000000
        this.date2().getTime(): 1382652000000

        date1() ist ein Objekt. date2() ist ein anderes Objekt.
        Beide haben den selben Inhalt, sind aber verschiedene Objekte.

  2. Hallo,

    Im Chrome Debugger hab ich folgende Variablen und Werte stehen:

    this.date1(): Fri Oct 25 2013 00:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)
    this.date2(): Fri Oct 25 2013 00:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)

    Beim Ausgeben auf der Konsole wird implizit die Methode toString() des Objektes aufgerufen. Nur deshalb bekommst du diese menschenlesbare Repräsentation des Objekts. toString ist auf Date-Objekten so definiert, dass etwas sinnvolles und nicht nur der Default "[object Object]" herauskommt.

    Wenn ich this.date1() == this.date2() abfrage, erhalte ich FALSE.

    Das liegt daran, wie der Vergleichsoperator intern funktioniert. Insbesondere in dem Fall, wo keine Primitives (String, Number, Boolean…), sondern Objects verglichen werden (vollwertige Objekte).

    Wenn beide Operanden vom Typ Object sind, so wird verglichen, ob es sich um *dasselbe* Objekt handelt:

    »1. If Type(x) is the same as Type(y), then …
    f.  Return true if x and y refer to the same object. Otherwise, return false.«

    Es wird also nicht die Gleichheit der Objekte ermittelt (z.B. durch Vergleichen sämtlicher Eigenschaften), sondern lediglich die Identität geprüft (d.h. ob die beiden Objekte identisch sind, also auf dieselbe Speicherstelle verweisen).

    Ein Objekt ist nie mit einem anderen identisch, nur mit sich selbst (das bedeutet ja Identität ;)).

    var a = { prop: 1 };  
    var b = { prop: 1 };  
    alert(a == b); // false
    

    Grüße,
    Mathias

  3. Hallo,

    Ich lass mir einreden, dass ich mit == Objekte vergleiche, aber ich hab es dann auch mal mit unterschiedlichen Datumswerten funktioniert, und siehe da, es klappt tadellos (einmal 9 Uhr, einmal 10 Uhr):

    this.date1(): Fri Oct 25 2013 09:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)
    this.date2(): Fri Oct 25 2013 10:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)

    this.date1() < this.date2(): true
    this.date1() == this.date2(): false
    this.date1() > this.date2(): false

    molily hat ja bereits erläutert, wieso das Ergebnis beim Gleichheitsoperator dieses Verhalten zeigt.

    Beim Verwenden der Grösser-als- und Kleiner-als-Operatoren wird - abweichend vom Gleichheits-Operator - zuerst die "valueOf"-Funktion des Date-Objekts aufgerufen, und dieser Wert zum Vergleichen verwendet:

      
    console.clear();  
      
    d1 = new Date();  
    d2 = new Date();  
      
    // Funktion, um Aufrufe der "valueOf"-Funktion anzuzeigen  
    function dumpValueOf(name) {  
        // "valueOf"-Funktion vom Prototype aufrufen und ausführen  
        console.log(name+".valueOf: "+Date.prototype.valueOf.call(this));  
        return Date.prototype.valueOf.call(this);  
    }  
      
    // Eigene valueOf-Funktion für diese Instanz verwenden  
    d1.valueOf = function() {  
        return dumpValueOf.call(d1,"d1");  
    };  
      
    // Eigene valueOf-Funktion für diese Instanz verwenden  
    d2.valueOf = function() {  
        return dumpValueOf.call(d2,"d2");  
    };  
      
    console.log("d1 == d2: ", (d1 == d2));  // false, kein Aufruf der Funktion valueOf  
    console.log("d1 > d2: ");  
    (d1 < d2); // Aufruf der Funktion valueOf  
    console.log("d1 < d2: ");  
    (d1 < d2); // Aufruf der Funktion valueOf  
    
    

    Gruss,
    Worf

    1. Hallo Ingrid,

      console.log("d1 > d2: ");
      (d1 < d2); // Aufruf der Funktion valueOf

        
      der Code sollte natürlich korrekt - analog der Console-Ausgabe - lauten:  
      ~~~javascript
        
      console.log("d1 > d2:");  
      r = (d1 > d2); // Führt zum Aufruf der Funktion valueOf  
      console.log("-> " + r);  
      
      

      Die Prüfung auf Gleichheit eines Date-Objekts bzgl. der Werte kann wie folgt erfolgen:

        
      d1 = new Date();  
      d2 = new Date();  
      console.log("d1 == d2:");  
      r = (+d1 == +d2); // Führt zum Aufruf der Funktion valueOf  
      console.log("-> " + r); // true  
      
      

      Gruss,
      Worf