2013-06-05 24 views
7

Sto cercando di ottenere un avviso quando un cliente ha il compleanno entro i prossimi 7 giorni.Confronto DateTime senza anno

ho provato con questo codice:

public bool IsBirthdayImminent 
{ 
    get { return DateOfBirth != null && DateOfBirth.Value.Date >= DateTime.Today.Date.AddDays(-7); } 
} 

Naturalmente questo non funziona, come la data è memorizzata con il suo anno (diciamo 1980/05/21) e si confronta anche l'anno . Quindi questa query non sarà mai true - beh, non se sei nato entro i prossimi sette giorni però.

Come posso modificare questa query per ignorare l'anno?

Edit:

Va bene, la query per sé non è affatto un problema. Il mio punto principale è la gestione degli anni bisestili e delle situazioni intorno a dicembre < -> gennaio.

+0

Prova: DateOfBirth.Value.Date> = DateTime.Today.Date.AddYears (DateOfBirth.Value.Date.Year - DateTime.Today.Date.Year) .AddDays (-7) – NeverHopeless

+0

Normalizza entrambe le date: crea una copia del valore DOB e impostare l'anno per essere uguale all'anno corrente. Ora paragonerai le mele alle mele. – Icarus

+0

@Idle_Mind Potresti non avere problemi con gli anni bisestili? Se, ad esempio, una delle date è il 29 febbraio 1996 e si tenta di impostarla al 29 febbraio 2013, è possibile che non si ottenga il risultato desiderato. Lo stesso vale per qualsiasi altra differenza tra le date nel corso degli anni. – Servy

risposta

8

Suggerirei di utilizzare il seguente codice. Ciò include casi intorno a dicembre - gennaio e 29 febbraio. Anche se potresti voler dare un'occhiata e correggere il 28 febbraio per essere incluso o escluso all'interno del dato days.

BirthdayImminent(new DateTime(1980, 1, 1), new DateTime(2012, 1, 2), 7); // false 
    BirthdayImminent(new DateTime(1980, 1, 1), new DateTime(2012, 12, 28), 7); // true 
    BirthdayImminent(new DateTime(1980, 2, 28), new DateTime(2012, 2, 21), 7); // true 

    private static bool BirthdayImminent(DateTime birthDate, DateTime referenceDate, int days) 
    { 
     DateTime birthdayThisYear = birthDate.AddYears(referenceDate.Year - birthDate.Year); 

     if (birthdayThisYear < referenceDate) 
      birthdayThisYear = birthdayThisYear.AddYears(1); 

     bool birthdayImminent = (birthdayThisYear - referenceDate).TotalDays <= days; 

     return birthdayImminent; 
    } 

mantenere anche il caso limite in mente Guvante postato nei commenti qui sotto.

+0

+1 per 'AddYears' invece di provare a hackerare un costruttore. Tecnicamente per 'days> = 60' la gestione dei compleanni saltati è di uno. Rendere la funzione 'AddYears' dal' birthDate' risolverebbe quella condizione del bordo ('2/29/2012.AddYears (3) .AddYears (1) == 2/28/2016'). Tuttavia, visti i requisiti, direi che il metodo è il migliore, poiché la correzione aggiunge una ridondanza non chiaramente motivata. – Guvante

+1

@Guvante Che non si applica a tutti i giorni> = 60, solo gli anni bisestili quando la data corrente è anche un anno bisestile ma prima del 28. Tuttavia, è spento per un giorno in quelle condizioni. Questo è il motivo per cui rispondo così raramente alle domande di DateTime. Sono super disordinati. – Servy

+0

@Servy: pensi che correggere la quantità di giorni bisestili tra 'birthdayThisYear' (dopo l'ultimo assegnamento) e' birthDate' sarà sufficiente? – Caramiriel

0

Impostare l'anno del birtdate in modo esplicito su DateTime.Today.Year e verrà confrontato perfettamente.

+1

Tuttavia, attenzione ai casi intorno a dicembre-gennaio. – Caramiriel

1

Qualcosa di simile a questo:

DateTime birthDate = new DateTime(2012, 12, 2); 

DateTime birthdayThisYear; 
if (birthDate.Month == 2 && birthDate.Day == 29 && DateTime.IsLeapYear(DateTime.Now.Year)) 
    birthdayThisYear = new DateTime(DateTime.Now.Year, 2, 28); 
else 
    birthdayThisYear = new DateTime(DateTime.Now.Year, birthDate.Month, birthDate.Day); 

bool birthdayImminent = birthdayThisYear > DateTime.Now && (birthdayThisYear - DateTime.Now).TotalDays <= 7; 

Come getter:

public bool IsBirthdayImminent 
{ 
    get 
    { 
     if (DateOfBirth == null) 
      return false; 
     else 
     { 
      DateTime birthdayThisYear; 
      if (birthDate.Month == 2 && birthDate.Day == 29 && DateTime.IsLeapYear(DateTime.Now.Year)) 
       birthdayThisYear = new DateTime(DateTime.Now.Year, 2, 28); 
      else 
       birthdayThisYear = new DateTime(DateTime.Now.Year, birthDate.Month, birthDate.Day); 

      return birthdayThisYear > DateTime.Now && (birthdayThisYear - DateTime.Now).TotalDays <= 7; 
     } 
    } 
} 
+2

-1 Se qualcuno è nato il 29 febbraio, questo farà un'eccezione per molti anni. – Servy

+0

@SeToY - Sembra buono. Vale anche la pena aggiungere un assegno per assicurarci che il bithdate sia in futuro, ad esempio "&& birthdayThisYear> DateTime.Now" – MarcF

+0

@Servy - Buon posto, richiederebbe un controllo per i compleanni in cui il mese è "Feb" e "Day is" 29 ', in cui l'OP deve decidere come gestire il -1 giorno. – MarcF

-1

Prova questa:

public bool IsBirthdayImminent 
{ 
    get { return DateOfBirth != null && DateOfBirth.Value.Date.AddYear(DateTime.Now.Year -DateOfBirth.Value.Year) >= DateTime.Today.Date.AddDays(-7); } 
} 
+0

Questo restituirà true se il compleanno è stato negli ultimi 7 giorni o è in qualsiasi momento tra ora e la fine dell'anno. – yoozer8

+0

non è molto elegante, mentre ci sono soluzioni migliori! e sono d'accordo con @Jim – Mehran

0

Si potrebbe usare "DayOfYear":

public bool IsBirthdayImminent 
{ 
    get { return DateOfBirth != null && Math.Abs(DateOfBirth.Value.Date.DayOfYear - DateTime.Today.DayOfYear) <= 7; } 
} 
+3

Come fa questo a gestire gli anni bisestili? Se il tuo compleanno è in un anno bisestile e dopo il 29 febbraio, il giorno dell'anno è uno più di quella data in un anno non bisestile, no? – Servy

+0

Hm, buon punto. DayOfYear restituisce appena un valore intero compreso tra 1 e 366, quindi hai ragione; ciò significherebbe compromettere i risultati. – bbar

+0

@Servy Se c'è un 29 febbraio tra 'DateofBirth.Value.Date' e' DateTime.Today', il valore di questa sottrazione sarà 1 in meno di quanto dovrebbe essere. Se ci sono due o più, sarà ancora spento di 1 giorno. –

Problemi correlati