Como encontrar a terceira sexta-feira em um mês com c #?

Dada uma data (do tipo DateTime ), como encontro a terceira sexta-feira no mês dessa data?

Eu não testei isso, mas como a terceira sexta-feira não pode ocorrer antes do dia 15 do mês, crie um novo DateTime, em seguida, apenas incremente até chegar a uma sexta-feira.

 DateTime thirdFriday= new DateTime(yourDate.Year, yourDate.Month, 15); while (thirdFriday.DayOfWeek != DayOfWeek.Friday) { thirdFriday = thirdFriday.AddDays(1); } 

Vou repetir a minha resposta daqui com uma pequena adição.

A versão agnóstica de linguagem:

Para obter o primeiro dia específico do mês, comece com o primeiro dia do mês: aaaa-mm-01. Use qualquer function disponível para fornecer um número correspondente ao dia da semana; em c # isso seria DateTime.DayOfWeek . Subtraia esse número do dia que você está procurando; por exemplo, se o primeiro dia do mês for quarta-feira (3) e você estiver procurando por sexta-feira (5), subtraia 3 de 5, deixando 2. Se a resposta for negativa, adicione 7. Finalmente, adicione isso ao primeiro o mês; no meu exemplo, a primeira sexta-feira seria a terceira.

Para obter a última sexta-feira do mês, encontre a primeira sexta-feira do mês seguinte e subtraia 7 dias.

Para obter a terceira sexta-feira do mês, adicione 14 dias à primeira sexta-feira.

Segui o algoritmo User: Mark Ransom e escrevi um localizador de dia generalizado. Por exemplo, para obter a terceira sexta-feira de dezembro de 2013,

 int thirdFriday = DayFinder.FindDay(2013, 12, DayOfWeek.Friday, 3); 

E aqui está a definição da function. Não possui loops iterativos, então é eficiente.

 public class DayFinder { //For example to find the day for 2nd Friday, February, 2016 //=>call FindDay(2016, 2, DayOfWeek.Friday, 2) public static int FindDay(int year, int month, dayOfWeek Day, int occurance) { if (occurance <= 0 || occurance > 5) throw new Exception("Occurance is invalid"); DateTime firstDayOfMonth = new DateTime(year, month, 1); //Substract first day of the month with the required day of the week var daysneeded = (int)day - (int)firstDayOfMonth.DayOfWeek; //if it is less than zero we need to get the next week day (add 7 days) if (daysneeded < 0) daysneeded = daysneeded + 7; //DayOfWeek is zero index based; multiply by the Occurance to get the day var resultedDay = (daysneeded + 1)+ (7*(occurance-1)); if(resultedDay > (firstDayOfMonth.AddMonths(1) - firstDayOfMonth).Days) throw new Exception(String.Format("No {0} occurance(s) of {1} in the required month", occurance, day.ToString())); return resultedDay; } } 

Versão ligeiramente mais otimizada:

  DateTime Now = DateTime.Now; DateTime TempDate = new DateTime(Now.Year, Now.Month, 1); // find first friday while (TempDate.DayOfWeek != DayOfWeek.Friday) TempDate = TempDate.AddDays(1); // add two weeks TempDate = TempDate.AddDays(14); 

Provavelmente, é melhor abstrair isso para um método para fazer qualquer combinação de data / dia:

(Método de extensão)

 public static bool TryGetDayOfMonth(this DateTime instance, DayOfWeek dayOfWeek, int occurance, out DateTime dateOfMonth) { if (instance == null) { throw new ArgumentNullException("instance"); } if (occurance <= 0 || occurance > 5) { throw new ArgumentOutOfRangeException("occurance", "Occurance must be greater than zero and less than 6."); } bool result; dateOfMonth = new DateTime(); // Change to first day of the month DateTime dayOfMonth = instance.AddDays(1 - instance.Day); // Find first dayOfWeek of this month; if (dayOfMonth.DayOfWeek > dayOfWeek) { dayOfMonth = dayOfMonth.AddDays(7 - (int)dayOfMonth.DayOfWeek + (int)dayOfWeek); } else { dayOfMonth = dayOfMonth.AddDays((int)dayOfWeek - (int)dayOfMonth.DayOfWeek); } // add 7 days per occurance dayOfMonth = dayOfMonth.AddDays(7 * (occurance - 1)); // make sure this occurance is within the original month result = dayOfMonth.Month == instance.Month; if (result) { dateOfMonth = dayOfMonth; } return result; } 

Resultados:

 DateTime myDate = new DateTime(2013, 1, 1) DateTime dateOfMonth; myDate.TryGetDayOfMonth(DayOfWeek.Sunday, 1, out dateOfMonth) // returns: true; dateOfMonth = Sunday, 1/6/2013 myDate.TryGetDayOfMonth(DayOfWeek.Sunday, 4, out dateOfMonth) // returns: true; dateOfMonth = Sunday, 1/27/2013 myDate.TryGetDayOfMonth(DayOfWeek.Sunday, 5, out dateOfMonth) // returns: false; myDate.TryGetDayOfMonth(DayOfWeek.Wednesday, 1, out dateOfMonth) // returns: true; dateOfMonth = Wednesday, 1/2/2013 myDate.TryGetDayOfMonth(DayOfWeek.Wednesday, 4, out dateOfMonth) // returns: true; dateOfMonth = Wednesday, 1/23/2013 myDate.TryGetDayOfMonth(DayOfWeek.Wednesday, 5, out dateOfMonth) // returns: true; dateOfMonth = Wednesday, 1/30/2013 // etc 

Post antigo, mas eu encontrei notavelmente poucas respostas decentes online para este problema certamente bastante comum! A resposta de Mark Ransom deve ser a última palavra neste algoritmo, mas aqui está uma class auxiliar C # (eu odeio extensões) para quem quer uma resposta rápida para os problemas comuns de “primeiro dia da semana no mês”, “xth day”. de semana no mês “e” último dia da semana no mês “.

Eu o modifiquei para retornar DateTime.MinValue se o Xth dia da semana ficar fora do mês fornecido, em vez de passar para o próximo mês, porque isso para mim parece mais útil.

Eu lancei em um programa de exemplo executável LINQPad também.

 void Main() { DayOfWeek dow = DayOfWeek.Friday; int y = 2014; int m = 2; String.Format("First {0}: {1}", new object[] { dow, DateHelper.FirstDayOfWeekInMonth(y, m, dow) }).Dump(); "".Dump(); String.Format("Last {0}: {1}", new object[] { dow, DateHelper.LastDayOfWeekInMonth(y, m, dow) }).Dump(); "".Dump(); for(int i = 1; i <= 6; i++) String.Format("{0} #{1}: {2}", new object[] { dow, i, DateHelper.XthDayOfWeekInMonth(y, m, dow, i) }).Dump(); } public class DateHelper { public static DateTime FirstDayOfWeekInMonth(int year, int month, DayOfWeek day) { DateTime res = new DateTime(year, month, 1); int offset = -(res.DayOfWeek - day); if (offset < 0) offset += 7; res = res.AddDays(offset); return res; } public static DateTime LastDayOfWeekInMonth(int year, int month, DayOfWeek day) { DateTime res = FirstDayOfWeekInMonth(year, month + 1, day); res = res.AddDays(-7); return res; } public static DateTime XthDayOfWeekInMonth(int year, int month, DayOfWeek day, int x) { DateTime res = DateTime.MinValue; if (x > 0) { res = FirstDayOfWeekInMonth(year, month, day); if (x > 1) res = res.AddDays((x - 1) * 7); res = res.Year == year && res.Month == month ? res : DateTime.MinValue; } return res; } } 

Impressões:

 First Friday: 07/02/2014 00:00:00 Last Friday: 28/02/2014 00:00:00 Friday #1: 07/02/2014 00:00:00 Friday #2: 14/02/2014 00:00:00 Friday #3: 21/02/2014 00:00:00 Friday #4: 28/02/2014 00:00:00 Friday #5: 01/01/0001 00:00:00 Friday #6: 01/01/0001 00:00:00 

Esta é uma versão que usa o LINQ e o estilo de functional programming.

Funciona assim.

Primeiro, pegue todos os dias do mês. Em seguida, selecione apenas os do dia certo (sexta-feira). Finalmente, pegue a enésima (terceira) input e retorne.

 // dt: The date to start from (usually DateTime.Now) // n: The nth occurance (3rd) // weekday: the day of the week to look for public DateTime GetNthWeekdayOfMonth(DateTime dt, int n, DayOfWeek weekday) { var days = Enumerable.Range(1, DateTime.DaysInMonth(dt.Year, dt.Month)).Select(day => new DateTime(dt.Year, dt.Month, day)); var weekdays = from day in days where day.DayOfWeek == weekday orderby day.Day ascending select day; int index = n - 1; if (index >= 0 && index < weekdays.Count()) return weekdays.ElementAt(index); else throw new InvalidOperationException("The specified day does not exist in this month!"); } 

Eu passo isso no DateTime para o começo do mês que estou olhando.

  private DateTime thirdSunday(DateTime timeFrom) { List days = new List(); DateTime testDate = timeFrom; while (testDate < timeFrom.AddMonths(1)) { if (testDate.DayOfWeek == DayOfWeek.Friday) { days.Add(testDate); } testDate = testDate.AddDays(1); } return days[2]; } 

Eu não conheço nenhuma maneira limpa / construída de fazer isso. Mas não é muito difícil de codificar:

  DateTime now = DateTime.Now; for (int i = 0; i < 7; ++i) { DateTime d = new DateTime(now.Year, now.Month, i+1); if (d.DayOfWeek == DayOfWeek.Friday) { return d.AddDays(14); } } 

Meu raciocínio é assim

  • a 15ª é a primeira “terceira sexta-feira” possível (1,8,15)
  • portanto, estamos procurando a primeira sexta-feira a partir do dia 15
  • DayOfWeek é uma enumeração começando com 0 para domingo
  • Portanto, você tem que adicionar um offet de 5-(int)baseDay.DayOfWeek para o dia 15
  • Só que o offset acima pode ser negativo, o que corrigimos adicionando 7, então fazendo o módulo 7.

Em código:

 public static DateTime GetThirdFriday(int year, int month) { DateTime baseDay = new DateTime(year, month, 15); int thirdfriday = 15 + ((12 - (int)baseDay.DayOfWeek) % 7); return new DateTime(year, month, thirdfriday); } 

Como existem apenas 7 resultados possíveis, você também pode fazer isso:

  private readonly static int[] thirdfridays = new int[] { 20, 19, 18, 17, 16, 15, 21 }; public static int GetThirdFriday(int year, int month) { DateTime baseDay = new DateTime(year, month, 15); return thirdfridays[(int)baseDay.DayOfWeek]; } 
  public DateTime GetThirdThursday(DateTime now) { DateTime ThirdThursday; now = DateTime.Now; string wkday; DateTime firstday = new DateTime(now.Year, now.Month, 1); ThirdThursday = firstday.AddDays(15); // ThirdThursday = now.AddDays((now.Day - 1) * -1).AddDays(14); wkday = ThirdThursday.DayOfWeek.ToString(); while (wkday.CompareTo("Thursday") < 0) { ThirdThursday.AddDays(1); } return ThirdThursday; } 
  int numday = 0; int dayofweek = 5; //friday DateTime thirdfriday; for (int i = 0; i < (date.AddMonths(1) - date).Days && numday <3; i++) { if ((int)date.AddDays(i).DayOfWeek == dayofweek) { numday++; } if (numday == 3) { thirdfriday = date.AddDays(i); } } 

Desculpe pular tarde nisso … Pode ajudar alguém.

Comece a falar: Loops, yuck. Muito código, eca. Não Genérico Suficiente, yuck.

Aqui está uma function simples com uma sobrecarga livre.

 public DateTime DateOfWeekOfMonth(int year, int month, DayOfWeek dayOfWeek, byte weekNumber) { DateTime tempDate = new DateTime(year, month, 1); tempDate = tempDate.AddDays(-(tempDate.DayOfWeek - dayOfWeek)); return tempDate.Day > (byte)DayOfWeek.Saturday ? tempDate.AddDays(7 * weekNumber) : tempDate.AddDays(7 * (weekNumber - 1)); } public DateTime DateOfWeekOfMonth(DateTime sender, DayOfWeek dayOfWeek, byte weekNumber) { return DateOfWeekOfMonth(sender.Year, sender.Month, dayOfWeek, weekNumber); } 

Seu uso:

 DateTime thirdFridayOfMonth = DateOfWeekOfMonth(DateTime.Now, DayOfWeek.Friday, 3); 

Aqui está meu algoritmo:

  1. Encontre o número de dias até a próxima sexta-feira.
  2. Inicialize um contador e defina-o como 1. Subtraia sete dias da data retornada de [1] e compare o mês a partir da data retornada com a data retornada de (1).
    1. Se os meses não forem iguais, retorne o contador de [2].
    2. Se os meses forem iguais, recrute em [2] e adicione 1 ao contador criado em [2].

O contador lhe dará a sexta-feira do mês para essa data (ou a sexta-feira seguinte).

A seguir funciona muito bem, nenhuma validação para a ocorrência é fornecida. Você pode encontrar qualquer nono dia para o mês da data indicada, seja do início ou do último. Forneça menos valor de ocorrência se você estiver procurando pelo último.

  public static DateTime GetDayOfMonth(DateTime dateValue, DayOfWeek dayOfWeek, int occurance) { List dayOfWeekRanges = new List(); //move to the first of th month DateTime startOfMonth = new DateTime(dateValue.Year, dateValue.Month, 1); //move startOfMonth to the dayOfWeek requested while (startOfMonth.DayOfWeek != dayOfWeek) startOfMonth = startOfMonth.AddDays(1); do { dayOfWeekRanges.Add(startOfMonth); startOfMonth = startOfMonth.AddDays(7); } while (startOfMonth.Month == dateValue.Month); bool fromLast = occurance < 0; if (fromLast) occurance = occurance * -1; if (fromLast) return dayOfWeekRanges[dayOfWeekRanges.Count - occurance]; else return dayOfWeekRanges[occurance - 1]; } 

Aqui estão meus dois centavos … Uma solução otimizada sem loops ou testes desnecessários:

 public static DateTime ThirdFridayOfMonth(DateTime dateTime) { int day = dateTime.Day; return dateTime.AddDays(21 - day - ((int)dateTime.DayOfWeek + 37 - day) % 7); }