2010-03-31 31 views
25

Dado que tengo un fecha/aniversario de cumpleaños/aniversario, ¿cómo puedo determinar si esa fecha ocurrió durante un intervalo de fechas específico? Por ejemplo,Cómo determinar si el cumpleaños o el aniversario se produjo durante el intervalo de fechas

cumpleaños = 1/2/2000
rango fecha = 12/25/2008 hasta 01/03/2009

Necesito un método para determinar si es o no el cumpleaños de esta persona pasó durante esa fecha rango - preferiblemente en C#.

Primero cambié el año del cumpleaños DateTime para que coincida con el intervalo de fechas, luego solo verifico si el "nuevo" cumpleaños DateTime está entre la fecha de inicio y la finalización del intervalo de fechas ... pero cuando el rango de fechas abarca diferentes años, como en mi ejemplo anterior - Tuve que agregar una desagradable afirmación if. ¿No hay mejor manera?

+3

+1 ya que esta cuestión es mucho más complicado de lo que parece! – NibblyPig

+3

No olvide que las cosas se vuelven aún más complicadas con los años bisiestos :) –

+0

En realidad, los años bisiestos no harán ninguna diferencia :) – NibblyPig

Respuesta

8

autorización, aquí es mi opinión

public static bool IsBirthDayInRange(DateTime birthday, DateTime start, DateTime end) 
{ 
    DateTime temp = birthday.AddYears(start.Year - birthday.Year); 

    if (temp < start) 
     temp = temp.AddYears(1); 

    return birthday <= end && temp >= start && temp <= end; 
} 
2

Supongo que sus fechas están almacenadas en las variables de DateTime? Si es así, la comparación es bastante sencillo:

if (Birthday > DateRangeLower && Birthday < DateRangeUpper) { 
    // it's your birthday! 
} 

Usted puede encapsular esto en un método de extensión si se quiere:

public static bool Between(this DateTime compareDate, DateTime startDate, DateTime endDate) { 
    return compareDate > startDate && compareDate < endDate; 
} 

entonces se le puede llamar como tal:

if (Birthday.Between(DateRangeLower, DateRangeUpper) { 
    // it's your birthday 
} 

Actualización: Si desea ignorar la parte del año del cumpleaños para determinar si el aniversario de la fecha se encuentra dentro del rango, aplique lo siguiente:

if (DateRangeLower.DayOfYear <= DateRangeUpper.DayOfYear && 
    Birthday.DayOfYear > DateRangeLower.DayOfYear && Birthday.DayOfYear < DateRangeUpper.DayOfYear) { 
    // it's your birthday 
    // the days are within the date range (and the range is in a single year) 
} 
else if (DateRangeLower.DayOfYear > DateRangeUpper.DayOfYear && 
    Birthday.DayOfYear < DateRangeLower.DayOfYear && Birthday.DayOfYear > DateRangeUpper.DayOfYear) { 
    // it's your birthday 
    // note, we're actually checking to see if the date is outside of the 
    // original date's days to handle the case where the dates span a year end boundary 
    // this only works if the dates are not more than 1 year apart 
} 
+2

Creo que te refieres a Cumpleaños = y <=. –

+0

No estoy seguro de que esto es lo que el OP está buscando. Su situación implica cambiar el valor de Cumpleaños * a * el rango (en función del año) para ver si cae dentro o fuera del rango. – LBushkin

+0

Vaya ... buen lugar @Mongus. @davekaro puede hacer que la fecha de comparación sea inclusiva si lo necesita cambiando a> = y <= (y posiblemente usando .Fecha para ignorar partes de tiempo si es necesario) – Dexter

1

Puede usar la propiedad DayOfYear de los objetos DateTime.

if ((birthday.DayOfYear >= start.DayOfYear) && (birthday.DayOfYear <= end.DayOfYear)) { 
    ... 
} 
+1

Esto caería si el rango es 01/11/2008 - 01/03/2009. –

+0

cierto - tal vez su situación le permita usar esto - de lo contrario, parece que ha vuelto a una declaración desagradable. Creo que tanascius tiene la idea correcta. – Ray

+0

Esto no funcionaría si la persona no nació antes del rango que se está probando. Verifique mi respuesta para una posible solución. –

0
if (Birthday.Month >= DateRangeLower.Month && Birthday.Month <= DateRangeUpper.Month 
     && Birthday.Day>= DateRangeLower.Day && Birthday.Day<= DateRangeUpper.Day) { 
//Partytime... 
} 
+0

Espera, pensé que esta era la respuesta correcta, pero no lo es: si tu fecha es del 1 de enero al 3 de marzo y tu cumpleaños es el 6 de feb, este código no funcionará. – NibblyPig

+0

No es correcto, pero está cerca. Debe verificar el mes y solo si Cumpleaños.Mes == DateRangeLower.Month o Birthday.Month == DateRangeUpper.Month luego verifique el día también. –

+0

Ambos tienen razón, gracias. Un pequeño error lógico de mi parte. =) – chriszero

1

Aquí está mi solución. Usa DayOfYear para encontrar una coincidencia. Pero debe tener cuidado, si el DayOfYear de la fecha de inicio es posterior al DayOfYear de la fecha de finalización. Asumo, que la fecha de inicio es anterior a la fecha de finalización:

private static bool HasBirthDay(DateTime birthday, DateTime start, DateTime end) 
{ 
    Debug.Assert(start < end); 
    if(start.DayOfYear < end.DayOfYear) 
    { 
     if(birthday.DayOfYear > start.DayOfYear && birthday.DayOfYear < end.DayOfYear) 
     { 
      return true; 
     } 
    } 
    else 
    { 
     if(birthday.DayOfYear < end.DayOfYear || birthday.DayOfYear > start.DayOfYear) 
     { 
      return true; 
     } 
    } 
    return false; 
} 

// DayOfYear(start date) > DayOfYear(end date) 
var start = new DateTime(2008, 12, 25); 
var end = new DateTime(2009, 1, 3); 
Debug.Assert(HasBirthDay(new DateTime(2000, 1, 2), start, end)); 
Debug.Assert(HasBirthDay(new DateTime(2000, 12, 26), start, end)); 
Debug.Assert(!HasBirthDay(new DateTime(2000, 1, 5), start, end)); 
Debug.Assert(!HasBirthDay(new DateTime(2000, 12, 24), start, end)); 

// DayOfYear(start date) < DayOfYear(end date) 
start = new DateTime(2008, 10, 25); 
end = new DateTime(2008, 11, 3); 
Debug.Assert(HasBirthDay(new DateTime(2000, 10, 26), start, end)); 
Debug.Assert(!HasBirthDay(new DateTime(2000, 12, 5), start, end)); 
Debug.Assert(!HasBirthDay(new DateTime(2000, 1, 24), start, end)); 
+0

¿Hay alguna razón para el downvote? Me gustaría saber cuándo hay un error en este código. Por favor, deje un comentario – tanascius

2

respuesta Actualizado para incluir la normalización límite superior mencionado por SLC. Esto debería funcionar para los casos en que la persona no nació el 29/02.

DateTime birthday = new DateTime(2000, 2, 1); 

DateTime min = new DateTime(2008, 12, 25); 
DateTime max = new DateTime(2009, 3, 1); 

DateTime nLower = new DateTime(min.Year, birthday.Month, birthday.Day); 
DateTime nUpper = new DateTime(max.Year, birthday.Month, birthday.Day); 

if (birthday.Year <= max.Year && 
    ((nLower >= min && nLower <= max) || (nUpper >= min && nUpper <= max))) 
{ 
    // Happy birthday 
    Console.WriteLine("Happy birthday"); 
} 

Y ahora una versión que se ocupa de las personas nacidas en el día (29/02):

public static bool IsBirthdayInRange(
    DateTime birthday, DateTime min, DateTime max) 
{ 
    var dates = new DateTime[] { birthday, min }; 
    for (int i = 0; i < dates.Length; i++) 
    { 
     if (dates[i].Month == 2 && dates[i].Day == 29) 
     { 
      dates[i] = dates[i].AddDays(-1); 
     } 
    } 

    birthday = dates[0]; 
    min = dates[1]; 

    DateTime nLower = new DateTime(min.Year, birthday.Month, birthday.Day); 
    DateTime nUpper = new DateTime(max.Year, birthday.Month, birthday.Day); 

    if (birthday.Year <= max.Year && 
     ((nLower >= min && nLower <= max) || (nUpper >= min && nUpper <= max))) 
    { 
     return true; 
    } 

    return false; 
} 
+0

Volví a publicar esta solución, esta es la manera de hacerlo, básicamente, configure su año de entrada para tener el mismo año que los límites inferiores de la búsqueda. Puede que tenga que hacerlo también para el límite superior, en el caso anterior, si el bday es 1983 10 5 y el rango es 1985 10 6 a 1986 10 10 ya que el IF fallará en la parte normalizada> = min. – NibblyPig

+0

¿Y qué sucede en un año bisiesto? Por ejemplo, cuando 'birthday' es' 29/02/1984' y 'min' es' 01/10/2005'? – LukeH

+0

No creo que esto funcione para las fechas que proporcioné en mi pregunta original. Usando mis fechas, la fecha normalizada será 1/2/2008, que no es> = al "mínimo" (25/12/2008). – davekaro

1

El punto crucial de su problema es averiguar qué año para asignar al cumpleaños con el fin de asegúrese de que puede realizar una comparación de rango válida.

Usted tiene dos sub-casos relativos a la gama que usted necesita para hacer frente a:

  1. El LowerBound tiene el mismo año que el límite superior
  2. El LowerBound tiene un año diferente de la del límite superior

EDITAR: No hay suficiente café. Ignora mi respuesta anterior.

Debe ajustar las fechas en función del mes/día del cumpleaños que está examinando.

No siempre se puede usar el año límite superior porque el cumpleaños podría caer en un mes que es mayor que el mes límite superior. Una alternativa simple es realizar el control dos veces: una vez con el año límite superior y luego otra vez el año anterior. Este se encarga de los casos de límites año:

var birthday = DateTime.Parse("1/2/2000"); 
var lowerBound = DateTime.Parse("12/25/2008"); 
var upperBound = DateTime.Parse("1/3/2009"); 

var adjustA = new Birthday(upperBound.Year, birthday.Month, birthday.Day); 
var adjustB = adjustA.AddYears(-1); 

var isInBounds = (adjustA >= lowerBound && adjustA <= upperBound) || 
       (adjustB >= lowerBound && adjustB <= upperBound); 
+0

Si la persona nace en el año 2010, todavía diría que tiene un cumpleaños en ese rango. Proporcioné una posible solución al verificar solo el año y luego normalizar el cumpleaños para la comparación. –

+0

Su constructor DateTime es incorrecto. Su solución no coincide con 12/26/2000 – tanascius

+0

¿Y qué sucede, por ejemplo, cuando 'someBirthday' es' 29/02/2008' y 'upperBoundDate' es' 25/03/2009'? – LukeH

0

Usted puede ser mejor que haga un dibujo para esto.

El problema es fundamentalmente determinar si existe una N tal que el N aniversario de la persona se encuentre en el rango o no.

Puede tomar una línea de base y hacer un cálculo de número de día con un módulo, que manejaría la renovación del año (pero los años bisiestos pueden causar errores uno a uno).

Otra alternativa que podría hacer una representación más sencilla es que, como los cumpleaños forman una cuadrícula 1-D en la línea de calendario, para que un cumpleaños NO caiga dentro del rango, el rango debe estar completamente entre los cumpleaños de la persona en sucesivos años: es decir, NO (BirthdayY1 < RangeStart & & RangeEnd < BirthdayY2).

Por lo general, cuando realizamos este tipo de análisis fue en meses completos, por lo que fue mucho más simple encontrar todos los cumpleaños en mayo, por ejemplo, para obtener tarjetas de cumpleaños.

0

ajustar el cumpleaños al año = 2000, la fecha a partir del año = 2000, y la hasta la fecha para el año 2000. Si la fecha es a antes de la fecha de, establecer el hasta la fecha para el año 2001.

Después de eso travesuras, desde arriba:

if (Birthday > DateRangeLower && Birthday < DateRangeUpper) { 
    // it's your birthday! 
} 
0

¿este trabajo !!!

for(int i = startDate.year; i <= endDate.year; i++) 
{ 
    DateTime newBD = new DateTime(i, BD.month, BD.day); 
    if((DateTime.Compare(newBD, startDate) >= 0) && (DateTime.Compare(newBD, endDate) <= 0))   
    { 
     //gotcha 
     break; 
    } 
} 
1

que acababa de convertir todas las fechas a tiempo de la época, y luego hacer una comparación directa.

me encontré con esta conversión here, con ligeras modificaciones

int epoch = (int)({Beginning/Ending Date} - new DateTime(1970, 1, 1)).TotalSeconds; 

Así que todo el conjunto de código no sería más que

int StartDateInEpoch = (int)(StartDate - new DateTime(1970, 1, 1)).TotalSeconds; 
int EndDateInEpoch = (int)(EndDate - new DateTime(1970, 1, 1)).TotalSeconds; 
int TargetDateInEpoch = (int)(TargetDate - new DateTime(1970, 1, 1)).TotalSeconds; 

if (StartDateInEpoch < TargetDateInEpoch && TargetDateInEpoch <= EndDateInEpoch) 
    return true; 
1

una respuesta diferente, moviendo todas las fechas para un año específico.

public static bool IsBirthDayInRange(DateTime birthday, DateTime start, DateTime end) 
{ 
    // This could be any date... 
    var epoch = new DateTime(1970, 1, 1); 

    // Start date is always epoch, end date is epoch + range span 
    DateTime endDateInEpoch = epoch.AddSeconds((end - start).TotalSeconds); 
    // Move the bithday back to epoch.Year 
    DateTime birthDayInEpoch = birthday.AddYears(epoch.Year - birthday.Year); 

    return birthday <= end && epoch < birthDayInEpoch && birthDayInEpoch <= endDateInEpoch; 
} 
0

Éste debe manejar correctamente los años bisiestos:

public static bool IsBirthdayInRange(DateTime birthday, DateTime from, DateTime to) 
{ 
    if (to < from) 
    { 
     throw new ArgumentException("The specified range is not valid"); 
    } 

    int year = from.Year; 
    int month = birthday.Month; 
    int day = birthday.Day; 
    if (from.DayOfYear > to.DayOfYear && birthday.DayOfYear < from.DayOfYear) 
    { 
     year++; 
    } 
    if (month == 2 && day == 29 && !DateTime.IsLeapYear(year)) 
    { 
     // Assuming people born on February 29 celebrate their birthday 
     // one day earlier on non-leap years 
     day--; 
    } 
    DateTime bDate = new DateTime(year, month, day); 
    return bDate >= from.Date && bDate <= to.Date; 
} 
Cuestiones relacionadas