2016-01-26 14 views
8

Sto cercando di confrontare due DateTimes in un minuto da un DateTime.Now e una voce SQL. Vedo che il problema è che i tick sono leggermente off a causa del tipo che viene restituito dal DB. Tuttavia non riesco a capire un lavoro in giro.C# DateTime down to minute from linq

Questo è il mio DateTime per afferrare

DateTime toGrab = DateTime.Now.AddMinutes(10) 
           .AddSeconds(-DateTime.Now.Second)  
           .AddMilliseconds(-DateTime.Now.Millisecond); 

e c'è la mia espressione LINQ.

cc.DBAppointments.Where(c => c.StartDate == toGrab && c.Approved == 1).ToList(); 

Qualche consiglio?

+2

Stai chiamando 'DateTime.Now' più volte, questo potrebbe darti risultati diversi. –

risposta

6

ho intenzione di assumere che si sta utilizzando Entity Framework per questo. Se è sufficiente confrontare il datetime fino a minuti, è possibile utilizzare System.Data.Entity.DbFunctions per accedere a funzioni canoniche in linq-to-entity. È possibile utilizzare questo per esempio:

cc.DBAppointments 
    .Where(c => DbFunctions.DiffMinutes(c.StartDate,DateTime.Now) == 0 && c.Approved == 1) 
    .ToList(); 

In questo modo si ha accesso ad avanzato confronto sql datetime e non si hanno a che fare trucchi aggiungendo secondi/millisecondi al vostro DateTime.Now. Questa funzione sarà ignorare tutto più piccolo di minuti.

+2

Questo è ancora più puro di quanto sembri, poiché EF traduce 'DateTime.Now' nella funzione t-SQL' SysDateTime() ', quindi il confronto corrisponde esattamente al momento in cui il database esegue la query. Teoricamente, una variabile 'DateTime' da un client potrebbe essere inattiva quando viene finalmente valutata. Per non parlare delle differenze (non così teoriche) tra gli orologi client e server. –

+0

Questo è il trucco che ho sempre dimenticato del dbfunctions, solo una piccola correzione della risorsa è System.Data.Entity. – SernOne

+0

@SernOne Grazie per averlo indicato, modificato –

1

Change

DateTime toGrab = DateTime.Now.AddMinutes(10) 
           .AddSeconds(-DateTime.Now.Second) 
           .AddMilliseconds(-DateTime.Now.Millisecond); 

Per

DateTime now = DateTime.Now; 
DateTime toGrab = now.AddMinutes(10) 
        .AddSeconds(-now.Second) 
        .AddMilliseconds(-now.Millisecond); 

Su una nota diversa, v'è alcuna ragione per cui si avrebbe bisogno di prendere un appuntamento al millisecondo esatto? Sembra molto incline a perdere i record?

Modifica

Inoltre, nel database, il valore è diverso da 2015-12-10 10:33:48.3732015-12-10 10:33:48.374 anche se sono 1 milisecond a parte. Se vuoi ottenere una gamma più ampia, puoi fare c.StartDate >= startDate && c.StartDate <= endDate && c.Approved == 1

+0

Si noti che questo ancora non ti darà un chiaro "in cima al minuto", dal momento che ci sono più dettagli in "DateTime" di un millisecondo. –

4

Stai facendo più riferimenti a DateTime.Now, che probabilmente ha un valore diverso ogni volta. Il seguente dovrebbe funzionare meglio:

var now = DateTime.Now; 
var toGrab = now.Date.AddHours(now.Hour).AddMinutes(now.Minute + 10); 

Si noti che, al fine di ottenere un chiaro "superiore del minuto", aggiungendo ore e minuti ad una data avrebbe funzionato meglio che cercare di rimuovere i secondi e millesimi di secondo, perché non c'è più dettaglio in un DateTime di millisecondi.

1

Si può fare comparisons on TimeSpan oggetti, il che significa che si può fare in questo modo:

TimeSpan oneMinute = new TimeSpan(0, 1, 0); 
cc.DBAppointments.Where(c => 
    DateTime.Now.AddMinutes(10).Subtract(c.StartDate) < oneMinute && 
    c.Approved == 1).ToList(); 

Naturalmente se c.StartDate è meno di 9 minuti in futuro, la sottrazione avrà un risultato di < - 1 minuto. Non sono sicuro che il tuo obiettivo sia entro 1 minuto. Se questo è il caso, è possibile aggiungere .Duration() per l'equazione, che restituirà l'assoluto valore della TimeSpan :

cc.DBAppointments.Where(c => 
    DateTime.Now.AddMinutes(10).Subtract(c.StartDate).Duration() < oneMinute && 
    c.Approved == 1).ToList();