Calcular data do número da semana

Alguém sabe uma maneira fácil de obter a data do primeiro dia da semana (segunda-feira aqui na Europa). Eu sei o ano e o numero da semana? Eu vou fazer isso em c #.

Eu tive problemas com a solução de @HenkHolterman mesmo com a correção de @RobinAndersson.

A leitura do padrão ISO 8601 resolve bem o problema. Use a primeira quinta-feira como alvo e não segunda-feira. O código abaixo funcionará também para a semana 53 de 2009.

public static DateTime FirstDateOfWeekISO8601(int year, int weekOfYear) { DateTime jan1 = new DateTime(year, 1, 1); int daysOffset = DayOfWeek.Thursday - jan1.DayOfWeek; // Use first Thursday in January to get first week of the year as // it will never be in Week 52/53 DateTime firstThursday = jan1.AddDays(daysOffset); var cal = CultureInfo.CurrentCulture.Calendar; int firstWeek = cal.GetWeekOfYear(firstThursday, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); var weekNum = weekOfYear; // As we're adding days to a date in Week 1, // we need to subtract 1 in order to get the right date for week #1 if (firstWeek == 1) { weekNum -= 1; } // Using the first Thursday as starting week ensures that we are starting in the right year // then we add number of weeks multiplied with days var result = firstThursday.AddDays(weekNum * 7); // Subtract 3 days from Thursday to get Monday, which is the first weekday in ISO8601 return result.AddDays(-3); } 

Eu gosto da solução fornecida por Henk Holterman. Mas para ser um pouco mais independente da cultura, você tem que obter o primeiro dia da semana para a cultura atual (nem sempre é segunda-feira):

 using System.Globalization; static DateTime FirstDateOfWeek(int year, int weekOfYear) { DateTime jan1 = new DateTime(year, 1, 1); int daysOffset = (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek - (int)jan1.DayOfWeek; DateTime firstMonday = jan1.AddDays(daysOffset); int firstWeek = CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(jan1, CultureInfo.CurrentCulture.DateTimeFormat.CalendarWeekRule, CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek); if (firstWeek < = 1) { weekOfYear -= 1; } return firstMonday.AddDays(weekOfYear * 7); } 

A maneira mais fácil é provavelmente encontrar a primeira segunda-feira do ano e, em seguida, adicionar o número relevante de semanas. Aqui está um código de exemplo. Assume-se um número de semana a partir de 1, a propósito:

 using System; class Test { static void Main() { // Show the third Tuesday in 2009. Should be January 20th Console.WriteLine(YearWeekDayToDateTime(2009, DayOfWeek.Tuesday, 3)); } static DateTime YearWeekDayToDateTime(int year, DayOfWeek day, int week) { DateTime startOfYear = new DateTime (year, 1, 1); // The +7 and %7 stuff is to avoid negative numbers etc. int daysToFirstCorrectDay = (((int)day - (int)startOfYear.DayOfWeek) + 7) % 7; return startOfYear.AddDays(7 * (week-1) + daysToFirstCorrectDay); } } 

Pessoalmente, aproveito as informações sobre cultura para obter o dia da semana e vou até o primeiro dia da semana da cultura. Não tenho certeza se estou explicando corretamente, aqui está um exemplo:

  public DateTime GetFirstDayOfWeek(int year, int weekNumber) { return GetFirstDayOfWeek(year, weekNumber, Application.CurrentCulture); } public DateTime GetFirstDayOfWeek(int year, int weekNumber, System.Globalization.CultureInfo culture) { System.Globalization.Calendar calendar = culture.Calendar; DateTime firstOfYear = new DateTime(year, 1, 1, calendar); DateTime targetDay = calendar.AddWeeks(firstOfYear, weekNumber); DayOfWeek firstDayOfWeek = culture.DateTimeFormat.FirstDayOfWeek; while (targetDay.DayOfWeek != firstDayOfWeek) { targetDay = targetDay.AddDays(-1); } return targetDay; } 

De acordo com a ISO 8601: 1988, que é usado na Suécia, a primeira semana do ano é a primeira semana que tem pelo menos quatro dias no ano novo.

Portanto, se sua semana começar em uma segunda a primeira quinta-feira, qualquer ano será na primeira semana. Você pode DateAdd ou DateDiff a partir disso.

usando o Fluent DateTime http://fluentdatetime.codeplex.com/

  var year = 2009; var firstDayOfYear = new DateTime(year, 1, 1); var firstMonday = firstDayOfYear.Next(DayOfWeek.Monday); var weeksDateTime = 12.Weeks().Since(firstMonday); 

A biblioteca de período de tempo gratuita para .NET inclui a class de conformidade ISO 8601 Week :

 // ---------------------------------------------------------------------- public static DateTime GetFirstDayOfWeek( int year, int weekOfYear ) { return new Week( year, weekOfYear ).FirstDayStart; } // GetFirstDayOfWeek 

Esse trabalhou pra mim, também tem a vantagem de esperar um cultureinfo como parâmetro para testar a fórmula com diferentes culturas. Se vazio, obtém as informações da cultura atual … os valores válidos são: “it”, “en-us”, “fr”, … e assim por diante. O truque é subtrair o número da semana do primeiro dia do ano, que pode ser 1 para indicar que o primeiro dia está dentro da primeira semana. Espero que isto ajude.

 Public Shared Function FirstDayOfWeek(ByVal year As Integer, ByVal weekNumber As Integer, ByVal culture As String) As Date Dim cInfo As System.Globalization.CultureInfo If culture = "" Then cInfo = System.Globalization.CultureInfo.CurrentCulture Else cInfo = System.Globalization.CultureInfo.CreateSpecificCulture(culture) End If Dim calendar As System.Globalization.Calendar = cInfo.Calendar Dim firstOfYear As DateTime = New DateTime(year, 1, 1, calendar) Dim firstDayWeek As Integer = calendar.GetWeekOfYear(firstOfYear, cInfo.DateTimeFormat.CalendarWeekRule, cInfo.DateTimeFormat.FirstDayOfWeek) weekNumber -= firstDayWeek Dim targetDay As DateTime = calendar.AddWeeks(firstOfYear, weekNumber) Dim fDayOfWeek As DayOfWeek = cInfo.DateTimeFormat.FirstDayOfWeek While (targetDay.DayOfWeek <> fDayOfWeek) targetDay = targetDay.AddDays(-1) End While Return targetDay End Function 

Aqui está um método que é compatível com os números da semana que o Google Analytics, e também o mesmo esquema de numeração que usamos internamente na Intel, e que tenho certeza também é usado em muitos outros contextos.

 // Google Analytics does not follow ISO standards for date. // It numbers week 1 starting on Jan. 1, regardless what day of week it starts on. // It treats Sunday as the first day of the week. // The first and last weeks of a year are usually not complete weeks. public static DateTime GetStartDateTimeFromWeekNumberInYear(int year, uint weekOfYear) { if (weekOfYear == 0 || weekOfYear > 54) throw new ArgumentException("Week number must be between 1 and 54! (Yes, 54... Year 2000 had Jan. 1 on a Saturday plus 53 Sundays.)"); // January 1 -- first week. DateTime firstDayInWeek = new DateTime(year, 1, 1); if (weekOfYear == 1) return firstDayInWeek; // Get second week, starting on the following Sunday. do { firstDayInWeek = firstDayInWeek.AddDays(1); } while (firstDayInWeek.DayOfWeek != DayOfWeek.Sunday); if (weekOfYear == 2) return firstDayInWeek; // Now get the Sunday of whichever week we're looking for. return firstDayInWeek.AddDays((weekOfYear - 2)*7); } 

Assumindo que o número da semana começa em 1

 DateTime dt = new DateTime(YearNumber, 1, 1).AddDays((WeekNumber - 1) * 7 - (WeekNumber == 1 ? 0 : 1)); return dt.AddDays(-(int)dt.DayOfWeek); 

Isso deve lhe dar o primeiro dia em qualquer semana. Eu não fiz muitos testes, mas parece que funciona. É uma solução menor do que a maioria das outras que encontrei na web, então queria compartilhar.

Trocou de leve o código de Mikael Svenson. Eu encontrei a semana da primeira segunda-feira e alterei apropriadamente o número da semana.

  DateTime GetFirstWeekDay(int year, int weekNum) { Calendar calendar = CultureInfo.CurrentCulture.Calendar; DateTime jan1 = new DateTime(year, 1, 1); int daysOffset = DayOfWeek.Monday - jan1.DayOfWeek; DateTime firstMonday = jan1.AddDays(daysOffset); int firstMondayWeekNum = calendar.GetWeekOfYear(firstMonday, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); DateTime firstWeekDay = firstMonday.AddDays((weekNum-firstMondayWeekNum) * 7); return firstWeekDay; } 

Eu tentei alguns códigos acima e alguns têm pequenos erros, quando você tenta diferentes anos com diferentes dias iniciais da semana você os verá, eu peguei o código do Jon Skeet, consertei e ele funciona, código muito simples.

 Public Function YearWeekDayToDateTime(ByVal year As Integer, ByVal weekDay As Integer, ByVal week As Integer) As DateTime ' weekDay, day you want Dim startOfYear As New DateTime(year, 1, 1) Dim startOfYearFixDay As Integer If startOfYear.DayOfWeek <> DayOfWeek.Sunday Then startOfYearFixDay = startOfYear.DayOfWeek Else startOfYearFixDay = 7 End If Return startOfYear.AddDays((7 * (week)) - startOfYearFixDay + weekDay) End Function 

Boas notícias! Uma solicitação pull, que adiciona o System.Globalization.ISOWeek ao .NET Core, foi mesclada e atualmente está prevista para a versão 3.0. Espero que ele se propague para as outras plataformas .NET em um futuro não muito distante.

Você deve ser capaz de usar o ISOWeek.ToDateTime(int year, int week, DayOfWeek dayOfWeek) para calcular isso.

Você pode encontrar o código fonte aqui .

A semana 1 é definida como a semana que começa na segunda-feira e contém a primeira quinta-feira do ano.

Para converter em ambas as direções, veja aqui: Artigo da Wikipédia sobre datas da semana ISO

Eu melhorei um pouco na solução de Thomas com um override:

  public static DateTime FirstDateOfWeek(int year, int weekOfYear) { return Timer.FirstDateOfWeekOfMonth(year, 1, weekOfYear); } public static DateTime FirstDateOfWeekOfMonth(int year, int month, int weekOfYear) { DateTime dtFirstDayOfMonth = new DateTime(year, month, 1); //I also commented out this part: /* if (firstWeek < = 1) { weekOfYear -= 1; } */ 

Caso contrário, a data foi precedida por uma semana.

Obrigado Thomas, grande ajuda.

Eu usei uma das soluções, mas isso me deu resultados errados, simplesmente porque conta o domingo como o primeiro dia da semana.

Eu mudei:

 var firstDay = new DateTime(DateTime.Now.Year, 1, 1).AddDays((weekNumber - 1) * 7); var lastDay = firstDay.AddDays(6); 

para:

 var lastDay = new DateTime(DateTime.Now.Year, 1, 1).AddDays((weekNumber) * 7); var firstDay = lastDay.AddDays(-6); 

e agora está funcionando como um encanto.

A solução proposta não está completa – só funciona para CalendarWeekRule.FirstFullWeek. Outros tipos de regras de semana não funcionam. Isso pode ser visto usando este caso de teste:

 foreach (CalendarWeekRule rule in Enum.GetValues(typeof(CalendarWeekRule))) { for (int year = 1900; year < 2000; year++) { DateTime date = FirstDateOfWeek(year, 1, rule); Assert(CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(date, rule, DayOfWeek.Monday) == 1); Assert(CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(date.AddDays(-1), rule, DayOfWeek.Monday) != 1); } } 

Eu fiz uma versão refinada da solução proposta que é um mais simples e parametriza o primeiroDayOfWeek:

 public static DateTime GetFirstDayOfWeek(int year, int week, DayOfWeek firstDayOfWeek) { return GetWeek1Day1(year, firstDayOfWeek).AddDays(7 * (week - 1)); } public static DateTime GetWeek1Day1(int year, DayOfWeek firstDayOfWeek) { DateTime date = new DateTime(year, 1, 1); // Move towards firstDayOfWeek date = date.AddDays(firstDayOfWeek - date.DayOfWeek); // Either 1 or 52 or 53 int weekOfYear = CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFullWeek, firstDayOfWeek); // Move forwards 1 week if week is 52 or 53 date = date.AddDays(7 * System.Math.Sign(weekOfYear - 1)); return date; } 

Esta é a minha solução quando queremos calcular uma data, ano, semana e dia da semana.

 int Year = 2014; int Week = 48; int DayOfWeek = 4; DateTime FecIni = new DateTime(Year, 1, 1); FecIni = FecIni.AddDays(7 * (Week - 1)); if ((int)FecIni.DayOfWeek > DayOfWeek) { while ((int)FecIni.DayOfWeek != DayOfWeek) FecIni = FecIni.AddDays(-1); } else { while ((int)FecIni.DayOfWeek != DayOfWeek) FecIni = FecIni.AddDays(1); } 

Eu simplifiquei o código fornecido por Mikael Svensson, o que é correto para muitos países da Europa.

 public static DateTime FirstDateOfWeekIso8601(int year, int week) { var firstThursdayOfYear = new DateTime(year, 1, 1); while (firstThursdayOfYear.DayOfWeek != DayOfWeek.Thursday) { firstThursdayOfYear = firstThursdayOfYear.AddDays(1); } var startDateOfWeekOne = firstThursdayOfYear.AddDays(-(DayOfWeek.Thursday - DayOfWeek.Monday)); return startDateOfWeekOne.AddDays(7 * (week - 1)); } 

Eu escrevi e testei o seguinte código e está funcionando perfeitamente bem para mim. Por favor, deixe-me saber se alguém enfrentou problemas com isso, eu postei uma pergunta também, a fim de obter a melhor resposta possível. Alguém pode achar útil.

 public static DateTime GetFirstDateOfWeekByWeekNumber(int year, int weekNumber) { var date = new DateTime(year, 01, 01); var firstDayOfYear = date.DayOfWeek; var result = date.AddDays(weekNumber * 7); if (firstDayOfYear == DayOfWeek.Monday) return result.Date; if (firstDayOfYear == DayOfWeek.Tuesday) return result.AddDays(-1).Date; if (firstDayOfYear == DayOfWeek.Wednesday) return result.AddDays(-2).Date; if (firstDayOfYear == DayOfWeek.Thursday) return result.AddDays(-3).Date; if (firstDayOfYear == DayOfWeek.Friday) return result.AddDays(-4).Date; if (firstDayOfYear == DayOfWeek.Saturday) return result.AddDays(-5).Date; return result.AddDays(-6).Date; } 

Atualmente, não há nenhuma class C # que manipule corretamente os números da ISO 8601 por semana. Mesmo que você possa instanciar uma cultura, procure a coisa mais próxima e corrija isso, eu acho que é melhor fazer o cálculo completo sozinho:

  ///  /// Converts a date to a week number. /// ISO 8601 week 1 is the week that contains the first Thursday that year. ///  public static int ToIso8601Weeknumber(this DateTime date) { var thursday = date.AddDays(3 - date.DayOfWeek.DayOffset()); return (thursday.DayOfYear - 1) / 7 + 1; } ///  /// Converts a week number to a date. /// Note: Week 1 of a year may start in the previous year. /// ISO 8601 week 1 is the week that contains the first Thursday that year, so /// if December 28 is a Monday, December 31 is a Thursday, /// and week 1 starts January 4. /// If December 28 is a later day in the week, week 1 starts earlier. /// If December 28 is a Sunday, it is in the same week as Thursday January 1. ///  public static DateTime FromIso8601Weeknumber(int weekNumber, int? year = null, DayOfWeek day = DayOfWeek.Monday) { var dec28 = new DateTime((year ?? DateTime.Today.Year) - 1, 12, 28); var monday = dec28.AddDays(7 * weekNumber - dec28.DayOfWeek.DayOffset()); return monday.AddDays(day.DayOffset()); } ///  /// Iso8601 weeks start on Monday. This returns 0 for Monday. ///  private static int DayOffset(this DayOfWeek weekDay) { return ((int)weekDay + 6) % 7; }