2008-11-13 19 views
17

Esto es lo que estoy tratando de hacer: Dada una fecha, un día de la semana y un número entero n, determine si la fecha es n el día del mes.¿Cómo puedo determinar si una fecha determinada es el N ° día entre semana del mes?

Por ejemplo:

  • de entrada de 1/1/2009,Monday,2 sería falso porque 1/1/2009 no es el segundo lunes

  • de entrada de 11/13/2008,Thursday,2 regresarían verdad porque es el segundo jueves

¿Cómo puedo mejorar esta implementación?

private bool NthDayOfMonth(DateTime date, DayOfWeek dow, int n) 
{ 
    int d = date.Day; 
    return date.DayOfWeek == dow && (d/ 7 == n || (d/ 7 == (n - 1) && d % 7 > 0)); 
} 

Respuesta

12

Se puede cambiar el cheque de la semana así que la función sería el siguiente:

private bool NthDayOfMonth(DateTime date, DayOfWeek dow, int n){ 
    int d = date.Day; 
    return date.DayOfWeek == dow && (d-1)/7 == (n-1); 
} 

Aparte de eso, se ve bastante bueno y eficiente.

1

Here es lo que MSDN tiene que decir. Su VB, pero se traduce fácilmente.

+0

que hace lo contrario de lo que quiero – Kevin

8

La respuesta es this website. Copie/pegue aquí en caso de que el sitio se pierda alguna vez.

public static DateTime FindTheNthSpecificWeekday(int year, int month,int nth, System.DayOfWeek day_of_the_week) 
{ 
    // validate month value 
    if(month < 1 || month > 12) 
    { 
     throw new ArgumentOutOfRangeException("Invalid month value."); 
    } 

    // validate the nth value 
    if(nth < 0 || nth > 5) 
    { 
     throw new ArgumentOutOfRangeException("Invalid nth value."); 
    } 

    // start from the first day of the month 
    DateTime dt = new DateTime(year, month, 1); 

    // loop until we find our first match day of the week 
    while(dt.DayOfWeek != day_of_the_week) 
    { 
     dt = dt.AddDays(1); 
    } 

    if(dt.Month != month) 
    { 
     // we skip to the next month, we throw an exception 
     throw new ArgumentOutOfRangeException(string.Format("The given month has less than {0} {1}s", nth, day_of_the_week)); 
    } 

    // Complete the gap to the nth week 
    dt = dt.AddDays((nth - 1) * 7); 

    return dt; 
} 
+0

esto también hace lo contrario de lo que quiero – Kevin

+0

Si era exactamente lo que Kevin necesitaba, esto era todo lo que necesitaba. Gracias por publicarlo –

+0

el cheque para el mes válido debe hacerse después de que se agreguen los días. if (dt.Month! = month) siempre es verdadero después de que se encuentra el primer día de la semana del mes – SQueek

1

Parece que el idioma indica los métodos de fecha/día para una fecha determinada. Si alguien estaba interesado, puede leer sobre Zeller's congruence.

No creo que eso es lo que querían que hicieras, pero podrías encontrar el día de la semana del primer día de un mes a partir de eso. Ahora que lo pensé, podría encontrar el día de la semana del día dado como N y obtener ese módulo 7.

Oh, espera, es la Octava ocurrencia de un día de la semana (como el domingo) o como el Nth weekday del mes! De acuerdo, veo los ejemplos.

Tal vez sería hacer una diferencia si se pudiera construir una fecha como el primero de un mes ..

Dado que es ocurrencia enésima de un día de la semana, y que no se puede juega con cualquier tipo de datos de fecha y hora, y tiene acceso tanto a un día de la semana como a funciones de día del mes. ¿Sería el domingo un cero?

1) Primero, el día de la semana debería coincidir con el día de la semana.
2) N tendría que ser al menos 1 y como máximo 4.
3) El día del mes oscilaría entre n * 7 * día de la semana + 1 yn * 7 * día de la semana + 6 para el mismo n.
- Déjame pensar en eso. Si el domingo fue el primero ... 0 * 7 * 0 + 1 = 1 y el sábado 6 sería 0 * 7 * 0 + 6.

Creo que los puntos 1 y 3 anteriores son suficientes, ya que una función de obtención del día del mes no debería violar 2.

(* first try, this code sucks *) 

function isNthGivenDayInMonth(date : dateTime; 
           dow : dayOfWeek; 
           N : integer) : boolean; 
    var B, A : integer (* on or before and after day of month *) 
    var Day : integer (* day of month *) 
    begin 
    B := (N-1)*7 + 1; A := (N-1)*7 + 6; 
    D := getDayOfMonth(date); 
    if (dow <> getDayOfWeek(date) 
     then return(false) 
     else return((B <= Day) and (A >= Day)); 
    end; (* function *) 

Espero que no haya ningún error en ese lol!
[editar: sábado habría sido el séptimo, y el límite superior por encima de (N-1)*7 + 7.]
Su solución parece que coincidiría con 2 semanas diferentes? Parece que siempre regresaría a cero los domingos? Debería haber hecho un pseudocódigo en C# .. cortocircuito & & es como mi if .. ¿No debería el domingo el primer partido para N = 1 en los meses que comienzan el domingo?

d/ 7 == n 

que resultaría en (either 0 or 1)/7 == 1, que no puede ser cierto! Su || capta el (n-1) también, Robert tiene eso. ¡Ve con la respuesta de Robert Wagner! ¡Son solo 2 líneas, el corto es bueno! Tener (Day-1) mod 7
[editar: (Day-1) div 7] elimina mis variables innecesarias y 2 líneas de configuración.

Para el registro, esto se debe verificar para los casos límite y así sucesivamente, como si el 31 de agosto fuera domingo o sábado.
[edit: Debería haber marcado el caso de fin de semana también. ! Lo sentimos]

0

En this answer, el siguiente código necesita ser volteado:

// Complete the gap to the nth week 
dt = dt.AddDays((nth - 1) * 7); 

if(dt.Month != month) 
{ 
// we skip to the next month, we throw an exception 
throw new ArgumentOutOfRangeException(”The given month has less than ” nth.ToString() ” ” 
day_of_the_week.ToString() “s”); 
} 
0

La mayoría de las respuestas anteriores son parcialmente exacta o innecesariamente compleja. Puede probar esta función más simple, que también verifica si la fecha dada es la última, enésimo día del mes.

public static bool IsNthDayofMonth(this DateTime date, DayOfWeek weekday, int N) 
    { 
     if (N > 0) 
     { 
      var first = new DateTime(date.Year, date.Month, 1); 
      return (date.Day - first.Day)/ 7 == N - 1 && date.DayOfWeek == weekday; 
     } 
     else 
     { 

      var last = new DateTime(date.Year, date.Month, 1).AddMonths(1).AddDays(-1); 
      return (last.Day - date.Day)/7 == (Math.Abs(N) - 1) && date.DayOfWeek == weekday; 
     } 
0

En caso de que quiera una lista de fechas para un espacio de tiempo (no sólo uno) para el enésimo DayOfWeek de un mes, puede utilizar esto:

internal static List<DateTime> GetDatesForNthDOWOfMonth(int weekNum, DayOfWeek DOW, DateTime beginDate, DateTime endDate) 
{ 
    List<DateTime> datesForNthDOWOfMonth = new List<DateTime>(); 
    int earliestDayOfMonth = 1; 
    int latestDayOfMonth = 7; 
    DateTime currentDate = beginDate; 

    switch (weekNum) 
    { 
     case 1: 
      earliestDayOfMonth = 1; 
      latestDayOfMonth = 7; 
      break; 
     case 2: 
      earliestDayOfMonth = 8; 
      latestDayOfMonth = 14; 
      break; 
     case 3: 
      earliestDayOfMonth = 15; 
      latestDayOfMonth = 21; 
      break; 
     case 4: 
      earliestDayOfMonth = 22; 
      latestDayOfMonth = 28; 
      break; 
    } 

    while (currentDate < endDate) 
    { 
     DateTime dateToInc = currentDate; 
     DateTime endOfMonth = new DateTime(dateToInc.Year, dateToInc.Month, DateTime.DaysInMonth(dateToInc.Year, dateToInc.Month)); 
     bool dateFound = false; 
     while (!dateFound) 
     { 
      dateFound = dateToInc.DayOfWeek.Equals(DOW); 
      if (dateFound) 
      { 
       if ((dateToInc.Day >= earliestDayOfMonth) && 
        (dateToInc.Day <= latestDayOfMonth)) 
       { 
        datesForNthDOWOfMonth.Add(dateToInc); 
       } 
      } 
      if (dateToInc.Date.Equals(endOfMonth.Date)) continue; 
      dateToInc = dateToInc.AddDays(1); 
     } 
     currentDate = new DateTime(currentDate.Year, currentDate.Month, 1); 
     currentDate = currentDate.AddMonths(1); 
    } 
    return datesForNthDOWOfMonth; 
} 

... y llamada de esta manera:

// This is to get the 1st Monday in each month from today through one year from today 
DateTime beg = DateTime.Now; 
DateTime end = DateTime.Now.AddYears(1); 
List<DateTime> dates = GetDatesForNthDOWOfMonth(1, DayOfWeek.Monday, beg, end); 
// To see the list of dateTimes, for verification 
foreach (DateTime d in dates) 
{ 
    MessageBox.Show(string.Format("Found {0}", d.ToString())); 
} 

Usted podría conseguir el segundo viernes de cada mes, así:

List<DateTime> dates = GetDatesForNthDOWOfMonth(2, DayOfWeek.Friday, beg, end); 

... etc.

Cuestiones relacionadas