Calculer la date à partir du numéro de semaine

Tout le monde sait comment obtenir facilement la date du premier jour de la semaine (lundi ici en Europe). Je connais l’année et le numéro de la semaine? Je vais le faire en C #.

    J’ai eu des problèmes avec la solution de @HenkHolterman même avec le correctif de @RobinAndersson.

    La lecture de la norme ISO 8601 résout le problème. Utilisez le premier jeudi comme cible et non le lundi. Le code ci-dessous fonctionnera également pour la semaine 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); } 

    J’aime la solution fournie par Henk Holterman. Mais pour être un peu plus indépendant de la culture, il faut avoir le premier jour de la semaine pour la culture actuelle (ce n’est pas toujours lundi):

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

    Le plus simple est probablement de trouver le premier lundi de l’année, puis d’append le nombre de semaines correspondant. Voici un exemple de code. Cela suppose un numéro de semaine commençant à 1, soit dit en passant:

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

    Personnellement, je profite de l’info culturelle pour obtenir le jour de la semaine et faire le tour du premier jour de la semaine de la culture. Je ne sais pas si je l’explique correctement, voici un exemple:

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

    Selon la norme ISO 8601: 1988 utilisée en Suède, la première semaine de l’année correspond à la première semaine d’au moins quatre jours de la nouvelle année.

    Donc, si votre semaine commence un lundi le premier jeudi d’une année est dans la première semaine. Vous pouvez DateAdd ou DateDiff à partir de cela.

    en utilisant 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 bibliothèque de période de temps gratuite pour .NET inclut la semaine de classe conforme à la norme ISO 8601 :

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

    Celui-ci a fonctionné pour moi, il a également l’avantage d’attendre d’un cultureinfo comme paramètre pour tester la formule avec différentes cultures. S’il est vide, il obtient les informations de culture actuelles … les valeurs valides sont: “it”, “en-us”, “fr”, … et ainsi de suite. L’astuce consiste à soustraire le numéro de semaine du premier jour de l’année, qui peut être 1 pour indiquer que le premier jour est dans la première semaine. J’espère que cela t’aides.

     Public Shared Function FirstDayOfWeek(ByVal year As Integer, ByVal weekNumber As Integer, ByVal culture As Ssortingng) 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 

    Voici une méthode compatible avec les numéros de semaine de Google Analytics, ainsi que le même schéma de numérotation que celui que nous avons utilisé en interne chez Intel, et qui, j’en suis sûr, est également utilisé dans de nombreux autres contextes.

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

    En supposant que le numéro de la semaine commence à 1

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

    Cela devrait vous donner le premier jour d’une semaine donnée. Je n’ai pas fait beaucoup de tests, mais cela semble fonctionner. C’est une solution plus petite que la plupart des autres que j’ai trouvé sur le Web, alors je voulais partager.

    Légèrement changé le code de Mikael Svenson. J’ai trouvé la semaine du premier lundi et changer le numéro de la semaine.

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

    J’ai essayé quelques codes ci-dessus et certains ont de petites erreurs, lorsque vous essayez différentes années avec différents jours de début de semaine, vous les verrez, j’ai pris le code de Jon Skeet, le réparer et ça marche, code très 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 

    Bonnes nouvelles! Une requête d’extraction ajoutant System.Globalization.ISOWeek à .NET Core vient d’être fusionnée et est actuellement prévue pour la version 3.0. Espérons que cela se propagera aux autres plates-formes .NET dans un avenir pas trop lointain.

    Vous devriez pouvoir utiliser la ISOWeek.ToDateTime(int year, int week, DayOfWeek dayOfWeek) pour le calculer.

    Vous pouvez trouver le code source ici .

    La semaine 1 est définie comme étant la semaine commençant le lundi et contenant le premier jeudi de l’année.

    Pour convertir dans les deux sens, voir ici: Article de Wikipedia sur les dates de la semaine ISO

    J’ai amélioré un peu la solution de Thomas avec un remplacement:

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

    Sinon, la date précédait d'une semaine.

    Merci Thomas, aide précieuse.

    J’ai utilisé l’une des solutions mais cela m’a donné des résultats erronés, simplement parce que le dimanche est considéré comme le premier jour de la semaine.

    J’ai changé:

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

    à:

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

    et maintenant ça fonctionne comme un charme.

    La solution proposée n’est pas complète – elle ne fonctionne que pour CalendarWeekRule.FirstFullWeek. Les autres types de règles de la semaine ne fonctionnent pas. Cela peut être vu en utilisant ce cas de test:

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

    J’ai fait une version affinée de la solution proposée qui est plus simple et paramétre le firstDayOfWeek:

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

    C’est ma solution lorsque nous voulons calculer une date en fonction de l’année, du numéro de la semaine et du jour de la semaine.

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

    J’ai simplifié le code fourni par Mikael Svensson qui est correct pour de nombreux pays en Europe.

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

    J’ai écrit et testé le code suivant et fonctionne parfaitement bien pour moi. S’il vous plaît laissez-moi savoir si quelqu’un a des problèmes avec cela, j’ai également posté une question afin d’obtenir la meilleure réponse possible. Quelqu’un peut le trouver utile.

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

    Actuellement, aucune classe C # ne gère correctement les numéros ISO 8601week. Même si vous pouvez instancier une culture, recherchez la chose la plus proche et corrigez-la, je pense qu’il est préférable de faire le calcul complet vous-même:

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