2015-05-22 13 views
6

Sto lavorando con un database MongoDB. So che quando inserisci un DateTime in Mongo, lo converte in UTC. Ma sto facendo un test unitario e il mio Assert sta fallendo.DateTime ToLocalTime non riuscito

[TestMethod] 
public void MongoDateConversion() { 
    DateTime beforeInsert = DateTime.Now; 
    DateTime afterInsert; 

    Car entity = new Car { 
     Name = "Putt putt", 
     LastTimestamp = beforeInsert 
    }; 

    // insert 'entity' 
    // update 'entity' from the database 

    afterInsert = entity.LastTimestamp.ToLocalTime(); 

    Assert.AreEqual(beforeInsert, afterInsert); // fails here 
} 

Mi manca qualcosa di ovvio. Quando guardo nel debugger, posso vedere quella partita del datetime, ma l'asserzione dice ancora non lo fanno (ma lo fanno):

Result Message: Assert.AreEqual failed. Expected:<5/21/2015 8:27:04 PM>. Actual:<5/21/2015 8:27:04 PM>. 

Tutte le idee che cosa sto facendo male qui?

EDIT:

mi è venuta in mente due possibili soluzioni, entrambi i quali mi richiedono di ricordarsi di fare qualcosa (che non è sempre la cosa migliore da fare affidamento su ...):

uno è quello di utilizzare un metodo di estensione per troncare qualsiasi DateTime che esce dal database:

public static DateTime Truncate(this DateTime dateTime) { 
    var timeSpan = TimeSpan.FromMilliseconds(1); 
    var ticks = -(dateTime.Ticks % timeSpan.Ticks); 
    return dateTime.AddTicks(ticks); 
} 

l'altro, dopo aver letto http://alexmg.com/datetime-precision-with-mongodb-and-the-c-driver/, è quello di etichettare qualsiasi DateTime nella classe POCO:

public class Car : IEntity { 
    public Guid Id { get; set; } 

    [BsonDateTimeOptions(Representation = BsonType.Document)] 
    public DateTime LastTimestamp { get; set; } 
} 
+0

Vedi questo articolo che spiega MongoDB datetime precisione: http: // alexmg.com/datetime-precision-with-mongodb-and-the-c-driver/ –

risposta

1

MongoDB memorizza DateTimes come un conteggio a 64 bit di millisecondi dall'epoca UNIX. Vedi questa pagina: http://alexmg.com/datetime-precision-with-mongodb-and-the-c-driver/

Dal momento che la risoluzione del DateTime di .NET è di 100 nanosecondi, MongoDB è quasi certo di troncare qualsiasi data e ora di andata e ritorno come questa.

Hai alcune opzioni.

Opzione 1: Assicurarsi di troncare LastTimestamp quando si imposta, o prima di inserire la cronaca:

long excessTicks = timestamp.Ticks % 10000; 

timestamp= new DateTime(
    ticks: timestamp.Ticks - excessTicks, 
    kind: timestamp.Kind 
); 

Questo approccio sta per essere soggetto a errori. Chiunque imposti LastTimestamp dovrà ricordarsi di troncarlo, oppure è possibile troncare il valore prima di inserire il record, ma potrebbe essere necessario modificare l'oggetto CLR in modo imprevisto.

In alternativa, è possibile utilizzare un getter/setter e troncare LastTimestamp in millisecondi ogni volta che viene impostato. Ma questo potrebbe portare ad un altro test unitario sulla linea che fallisce per lo stesso motivo per cui questo test sta fallendo.

Opzione 2: Se precisione sub-millisecondi non è importante, basta mettere una certa tolleranza nella vostra affermazione:

TimeSpan delta = beforeInsert - afterInsert; 

Assert.IsTrue(Math.Abs(delta.TotalMilliseconds) <= 2); 
+0

Invece di 'Math.Abs' puoi anche usare' Assert.IsTrue (delta.Duration(). TotalMilliseconds <= 2); 'Il [' Duration() '] (https://msdn.microsoft.com/en -us/library/system.timespan.duration (v = vs.110) .aspx) restituisce il valore assoluto del periodo di tempo. –

1

Immagino che tu abbia una differenza nei millisecondi. Prova troncando il millisecondo come la seguente:

DateTime d = DateTime.Now; 
d = d.AddMilliseconds(-d.Millisecond); 
+0

Questo non funzionerà. DateTime.Millisecond è un numero intero. Ti dà solo la parte millisecondo del valore DateTime. Varia sempre da 0 a 999, per [voce MSDN] (https://msdn.microsoft.com/en-us/library/system.datetime.millisecond.aspx). – Daryl

1

Il test è sbagliato (o incoerenti), perché ci sarà sempre qualche differenza millisecondi prima e dopo l'inserto. Si può semplicemente convertire il datetime in una stringa formattata come dd/mm/yy hh:mm:ss e confrontare prima e dopo