Calcular fecha a partir del número de semana

Alguien sabe una manera fácil de obtener la fecha del primer día de la semana (el lunes aquí en Europa). Sé el año y el número de la semana? Voy a hacer esto en C #.

Tuve problemas con la solución de @HenkHolterman incluso con la solución de @RobinAndersson.

Leer el estándar ISO 8601 resuelve el problema muy bien. Use el primer jueves como objective y no el lunes. El código a continuación también funcionará para la 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); } 

Me gusta la solución provista por Henk Holterman. Pero para ser un poco más independiente de la cultura, debe obtener el primer día de la semana para la cultura actual (no siempre es lunes):

 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); } 

La forma más fácil es encontrar el primer lunes del año y luego agregar el número de semanas correspondiente. Aquí hay un código de muestra. Supone un número de semana que comienza en 1, por cierto:

 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); } } 

Personalmente, aprovecharía la información cultural para obtener el día de la semana y seguir el primer día de la cultura. No estoy seguro si lo estoy explicando correctamente, aquí hay un ejemplo:

  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 acuerdo con ISO 8601: 1988 que se utiliza en Suecia, la primera semana del año es la primera semana que tiene al menos cuatro días en el año nuevo.

Entonces, si su semana comienza el lunes, el primer jueves de cada año es dentro de la primera semana. Puede usar DateAdd o DateDiff de eso.

utilizando 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); 

La biblioteca gratuita Time Period para .NET incluye la clase de conformidad ISO 8601 Week :

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

Este funcionó para mí, también tiene la ventaja de esperar un cultureinfo como parámetro para probar la fórmula con diferentes culturas. Si está vacío, obtiene la información cultural actual … los valores válidos son como: “it”, “en-us”, “fr”, … ando etc. El truco consiste en restar el número de semana del primer día del año, que puede ser 1 para indicar que el primer día es dentro de la primera semana. Espero que esto ayude.

 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 

Aquí hay un método que es compatible con los números de la semana que Google Analytics, y también el mismo esquema de numeración que usamos internamente en Intel, y que estoy seguro también se usa en muchos otros 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); } 

Suponiendo que el número de semana comienza en 1

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

Esto debería darte el primer día de cualquier semana. No he hecho muchas pruebas al respecto, pero parece que funciona. Es una solución más pequeña que la mayoría de la que encontré en la web, por eso quería compartirla.

Cambió ligeramente el código de Mikael Svenson. Encontré la semana del primer lunes y cambio el número de la 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; } 

Probé algunos códigos arriba y algunos tienen pequeños errores, cuando intentes diferentes años con diferentes días iniciales de la semana los verás, tomé el código de Jon Skeet, lo corrigió y funciona, código muy simple.

 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 

¡Buenas noticias! Una solicitud de extracción que agrega System.Globalization.ISOWeek a .NET Core acaba de fusionarse y está actualmente progtwigda para la versión 3.0. Esperemos que se propague a las otras plataformas .NET en un futuro no muy lejano.

Debería poder usar el ISOWeek.ToDateTime(int year, int week, DayOfWeek dayOfWeek) para calcular esto.

Puedes encontrar el código fuente aquí .

La semana 1 se define como la semana que comienza un lunes y contiene el primer jueves del año.

Para convertir en ambas direcciones, consulte aquí: Artículo de Wikipedia sobre las fechas de la semana ISO

Mejore un poco en la solución de Thomas con una anulación:

  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; } */ 

De lo contrario, la fecha era anterior por una semana ..

Gracias Thomas, gran ayuda.

Usé una de las soluciones, pero me dio resultados incorrectos, simplemente porque cuenta el domingo como el primer día de la semana.

Cambié:

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

a:

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

y ahora está funcionando como un encanto.

La solución propuesta no está completa; solo funciona para CalendarWeekRule.FirstFullWeek. Otros tipos de reglas de la semana no funcionan. Esto se puede ver usando este caso de prueba:

 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); } } 

He hecho una versión refinada de la solución propuesta que es más simple y parametriza el primer día de la semana:

 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 es mi solución cuando queremos calcular una fecha dada año, semana número y día de la 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); } 

Simplifiqué el código proporcionado por Mikael Svensson, que es correcto para muchos países de 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)); } 

He escrito y probado el siguiente código y funciona perfectamente bien para mí. Por favor, avíseme si alguien tiene problemas con esto, también he publicado una pregunta para obtener la mejor respuesta posible. Alguien puede encontrarlo ú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; } 

Actualmente, no existe una clase C # que maneje correctamente los números ISO 8601week. Aunque puede instanciar una cultura, buscar lo más cercano y corregir eso, creo que es mejor hacer el cálculo completo usted mismo:

  ///  /// 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; }