Calcola data dal numero della settimana

Qualcuno sa un modo semplice per ottenere la data del primo giorno della settimana (lunedì qui in Europa). Conosco l’anno e il numero della settimana? Lo farò in C #.

Ho avuto problemi con la soluzione di @HenkHolterman anche con la correzione di @RobinAndersson.

La lettura dello standard ISO 8601 risolve bene il problema. Usa il primo giovedì come bersaglio e non il lunedì. Il codice seguente funzionerà anche per la settimana 53 del 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); } 

Mi piace la soluzione fornita da Henk Holterman. Ma per essere un po ‘più indipendenti dalla cultura, devi ottenere il primo giorno della settimana per la cultura attuale (non è sempre il lunedì):

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

Il modo più semplice è probabilmente quello di trovare il primo lunedì dell’anno, quindi aggiungere il numero di settimane pertinente. Ecco alcuni esempi di codice. A proposito, assume un numero di settimana che inizia a 1:

 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 mi piacerebbe sfruttare le informazioni sulla cultura per ottenere il giorno della settimana e andare al primo giorno della settimana della cultura. Non sono sicuro che lo spieghi correttamente, ecco un esempio:

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

Secondo la norma ISO 8601: 1988 utilizzata in Svezia, la prima settimana dell’anno è la prima settimana che ha almeno quattro giorni nel nuovo anno.

Quindi se la tua settimana inizia di lunedì il primo giovedì di ogni anno è entro la prima settimana. Puoi DateAdd o DateDiff da quello.

utilizzando 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 libreria del periodo di tempo gratuita per .NET include la settimana della class conforms ISO 8601 :

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

Questo ha funzionato per me, ha anche il vantaggio di aspettarsi un culturalinfo come parametro per testare la formula con culture diverse. Se vuoto, ottiene le informazioni sulla cultura corrente … valori validi sono come: “it”, “en-us”, “fr”, … e così via. Il trucco è sottrarre il numero della settimana del primo giorno dell’anno, che può essere 1 per indicare che il primo giorno è entro la prima settimana. Spero che questo ti aiuti.

 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 

Ecco un metodo che è compatibile con i numeri della settimana di Google Analytics, e anche lo stesso schema di numerazione che abbiamo usato internamente a Intel, e che sono sicuro sia utilizzato anche in molti altri contesti.

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

Supponendo che il numero della settimana inizi a 1

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

Questo dovrebbe darti il ​​primo giorno in una data settimana. Non ho fatto molti test su di esso, ma sembra che funzioni. È una soluzione più piccola rispetto alla maggior parte delle altre che ho trovato sul Web, quindi volevo condividere.

Mikael Svenson ha cambiato leggermente il codice. Ho trovato la settimana del primo lunedì e appropriato cambiare il numero della settimana.

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

Ho provato alcuni codici sopra e alcuni hanno piccoli errori, quando provi diversi anni con diversi giorni di inizio settimana li vedrai, ho preso il codice di Jon Skeet, lo aggiusto e funziona, codice molto semplice.

 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 

Buone notizie! Una richiesta pull che aggiunge System.Globalization.ISOWeek a .NET Core è stata appena unita e attualmente è prevista per la versione 3.0. Si spera che si propagherà alle altre piattaforms .NET in un futuro non troppo lontano.

Dovresti essere in grado di utilizzare il ISOWeek.ToDateTime(int year, int week, DayOfWeek dayOfWeek) per calcolare questo.

Puoi trovare il codice sorgente qui .

La settimana 1 è definita come la settimana che inizia il lunedì e contiene il primo giovedì dell’anno.

Per convertire in entrambe le direzioni, vedere qui: articolo di Wikipedia sulle date della settimana ISO

Ho migliorato un po ‘la soluzione di Thomas con un 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; } */ 

Altrimenti la data era precedente di una settimana ..

Grazie Thomas, un grande aiuto.

Ho usato una delle soluzioni ma mi ha dato risultati sbagliati, semplicemente perché conta domenica come primo giorno della settimana.

Ho cambiato:

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

e ora sta funzionando come un fascino.

La soluzione proposta non è completa, funziona solo con CalendarWeekRule.FirstFullWeek. Altri tipi di regole settimanali non funzionano. Questo può essere visto usando questo test case:

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

Ho realizzato una versione raffinata della soluzione proposta che è più semplice e parametrizza il 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; } 

questa è la mia soluzione quando vogliamo calcolare una data all’anno, il numero della settimana e il giorno della settimana.

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

Ho semplificato il codice fornito da Mikael Svensson che è corretto per molti paesi in 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)); } 

Ho scritto e testato il seguente codice e funziona perfettamente per me. Per favore fatemi sapere se qualcuno ha problemi con questo, ho inviato una domanda anche al fine di ottenere la migliore risposta ansible. Qualcuno potrebbe trovarlo 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; } 

Attualmente, non esiste una class C # che gestisca correttamente i numeri ISO 8601week. Anche se puoi istanziare una cultura, cercare la cosa più vicina e correggerla, penso che sia meglio fare da soli il calcolo completo:

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