webentwicklung-frage-antwort-db.com.de

Berechnen Sie das Datum aus der Wochennummer

Jeder kennt einen einfachen Weg, um das Datum des ersten Tages in der Woche (Montag hier in Europa) zu erhalten. Ich kenne das Jahr und die Wochennummer? Ich mache das in C #.

125
Bobby

Ich hatte Probleme mit der Lösung von @HenkHolterman, auch mit der Lösung von @RobinAndersson.

Lesen Sie den ISO 8601-Standard durch, um das Problem zu lösen. Verwenden Sie den ersten Donnerstag als Ziel und nicht Montag. Der folgende Code funktioniert auch für Woche 53 von 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);
}       
225
Mikael Svenson

Mir gefällt die Lösung von Henk Holterman. Um jedoch ein bisschen kulturunabhängiger zu sein, muss der erste Wochentag für die aktuelle Kultur angegeben werden (dies ist nicht immer Montag):

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

Am einfachsten ist es wahrscheinlich, den ersten Montag des Jahres zu ermitteln und dann die entsprechende Anzahl von Wochen hinzuzufügen. Hier ist ein Beispielcode. Es geht übrigens von einer Wochennummer ab 1 aus:

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);
    }
}
9
Jon Skeet

Gute Nachrichten! Ein Pull-Anforderung Hinzufügen von System.Globalization.ISOWeek Zu .NET Core wurde gerade zusammengeführt und ist derzeit für die Version 3.0 vorgesehen. Hoffentlich wird es sich in nicht allzu ferner Zukunft auf den anderen .NET-Plattformen verbreiten.

Sie sollten in der Lage sein, die ISOWeek.ToDateTime(int year, int week, DayOfWeek dayOfWeek) -Methode zu verwenden, um dies zu berechnen.

Den Quellcode finden Sie hier .

4
khellang

Persönlich würde ich die Kulturinformationen nutzen, um den Wochentag zu ermitteln und zum ersten Wochentag der Kultur zu gelangen. Ich bin mir nicht sicher, ob ich es richtig erkläre. Hier ist ein Beispiel:

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

Gemäß ISO 8601: 1988 wird in Schweden verwendet Die erste Woche des Jahres ist die erste Woche, die mindestens vier Tage innerhalb des neuen Jahres hat.

Wenn Ihre Woche also an einem Montag beginnt, liegt der erste Donnerstag eines Jahres innerhalb der ersten Woche. Daraus können Sie DateAdd oder DateDiff auswählen.

2
idstam

Dieses hat für mich funktioniert, es hat auch den Vorteil, dass man eine Kulturinformation als Parameter erwartet, um die Formel mit verschiedenen Kulturen zu testen. Wenn leer, werden die aktuellen Kulturinformationen angezeigt. Gültige Werte lauten: "it", "en-us", "fr", ... und so weiter. Der Trick besteht darin, die Wochennummer des ersten Tages des Jahres zu subtrahieren, die 1 sein kann, um anzuzeigen, dass der erste Tag innerhalb der ersten Woche liegt. Hoffe das hilft.

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
2
Paolo Marani

Die kostenlose Time Period Library für .NET enthält die ISO 8601 konforme Klasse Woche :

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

Hier finden Sie eine Methode, die mit den Wochenzahlen von Google Analytics kompatibel ist, und dasselbe Nummerierungsschema, das wir intern bei Intel verwendet haben. Ich bin mir sicher, dass diese Methode auch in vielen anderen Kontexten verwendet wird.

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

Ich habe einige Codes oben ausprobiert und einige haben kleine Fehler. Wenn Sie verschiedene Jahre mit unterschiedlichen Starttagen der Woche ausprobieren, werden Sie sie sehen. Ich habe den Code von Jon Skeet genommen, ihn korrigiert und er funktioniert, sehr einfacher Code.

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
2
GEORGE BAXTER

verwenden von 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);
2
Simon

Angenommen, die Wochennummer beginnt bei 1

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

Dies sollte Ihnen den ersten Tag in einer bestimmten Woche geben. Ich habe nicht viel getestet, aber es sieht so aus, als ob es funktioniert. Es ist eine kleinere Lösung als die meisten anderen, die ich im Web gefunden habe und die ich deshalb teilen wollte.

1
QuinnG

Leicht geänderter Mikael Svenson Code. Ich fand die Woche vom ersten Montag und ändere die Wochennummer entsprechend.

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

Ich habe die Lösung von Thomas mit einem Override ein wenig verbessert:

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

Ansonsten lag das Datum eine Woche vor.

Danke Thomas, tolle Hilfe.

0
pasx

Woche 1 ist definiert als die Woche, die an einem Montag beginnt und den ersten Donnerstag des Jahres enthält.

0
amaca

Derzeit gibt es keine C # -Klasse, die ISO 8601-Wochennummern korrekt verarbeitet. Auch wenn Sie eine Kultur instanziieren, nach der nächsten suchen und diese korrigieren können, ist es meiner Meinung nach besser, die vollständige Berechnung selbst durchzuführen:

    /// <summary>
    /// Converts a date to a week number.
    /// ISO 8601 week 1 is the week that contains the first Thursday that year.
    /// </summary>
    public static int ToIso8601Weeknumber(this DateTime date)
    {
        var thursday = date.AddDays(3 - date.DayOfWeek.DayOffset());
        return (thursday.DayOfYear - 1) / 7 + 1;
    }

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

    /// <summary>
    /// Iso8601 weeks start on Monday. This returns 0 for Monday.
    /// </summary>
    private static int DayOffset(this DayOfWeek weekDay)
    {
        return ((int)weekDay + 6) % 7;
    }
0
realbart

Ich habe den folgenden Code geschrieben und getestet und für mich funktioniert er einwandfrei. Bitte lassen Sie mich wissen, wenn jemand Probleme damit hat. Ich habe auch eine Frage gestellt, um die bestmögliche Antwort zu erhalten. Jemand mag es nützlich finden.

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

Ich habe eine verfeinerte Version der vorgeschlagenen Lösung erstellt, die einfacher ist und das firstDayOfWeek parametrisiert:

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;
}
0
Colin Breame

Die vorgeschlagene Lösung ist nicht vollständig - sie funktioniert nur für CalendarWeekRule.FirstFullWeek. Andere Arten von Wochenregeln funktionieren nicht. Dies kann anhand dieses Testfalls festgestellt werden:

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);
    }
}
0
Colin Breame

Informationen zum Umrechnen in beide Richtungen finden Sie hier: Wikipedia-Artikel zu ISO-Wochentagen

0
Robert L

Ich habe eine der Lösungen verwendet, aber sie hat zu falschen Ergebnissen geführt, einfach weil der Sonntag als erster Tag der Woche zählt.

Ich habe mich verändert:

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

zu:

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

und jetzt wirkt es wie ein Zauber.

0
user1564287

Ich habe den Code von Mikael Svensson vereinfacht, der für viele Länder in Europa korrekt ist.

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));        
}
0
Oskar Sjöberg

dies ist meine Lösung, wenn wir ein Datum mit Jahr, Wochennummer und Wochentag berechnen möchten.

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