Jeder kennt eine einfache Möglichkeit, das Datum des ersten Tages in der Woche zu ermitteln (Montag hier in Europa). Ich kenne das Jahr und die Wochennummer? Ich werde das in C # machen.
Jeder kennt eine einfache Möglichkeit, das Datum des ersten Tages in der Woche zu ermitteln (Montag hier in Europa). Ich kenne das Jahr und die Wochennummer? Ich werde das in C # machen.
Antworten:
Ich hatte Probleme mit der Lösung von @HenkHolterman, sogar mit dem Fix von @RobinAndersson.
Das Lesen des ISO 8601-Standards löst das Problem gut. Verwenden Sie den ersten Donnerstag als Ziel und nicht den 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);
}
Ich mag die Lösung von Henk Holterman. Aber um ein bisschen kulturunabhängiger zu sein, muss man den ersten Tag der Woche für die aktuelle Kultur bekommen (es 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);
}
firstMonday
ist ein schlechter Variablenname für etwas, das möglicherweise kein Montag ist. =)
UPDATE : .NET Core 3.0 und .NET Standard 2.1 wurden mit diesem Typ ausgeliefert.
Gute Nachrichten! Eine Pull-Anfrage, die System.Globalization.ISOWeek
zu .NET Core hinzugefügt wurde , wurde gerade zusammengeführt und ist derzeit für die Version 3.0 vorgesehen. Hoffentlich wird es in nicht allzu ferner Zukunft auf die anderen .NET-Plattformen übertragen.
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 .
Am einfachsten ist es wahrscheinlich, den ersten Montag des Jahres zu finden und dann die entsprechende Anzahl von Wochen hinzuzufügen. Hier ist ein Beispielcode. Es wird übrigens eine Wochennummer angenommen, die bei 1 beginnt:
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);
}
}
Persönlich würde ich die Kulturinformationen nutzen, um den Wochentag zu ermitteln und zum ersten Wochentag der Kultur zurückzukehren. Ich bin mir nicht sicher, ob ich es richtig erkläre. Hier 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;
}
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);
Gemäß ISO 8601: 1988 , die in Schweden verwendet wird, ist die erste Woche des Jahres die erste Woche mit mindestens vier Tagen innerhalb des neuen Jahres.
Wenn Ihre Woche also an einem Montag beginnt, liegt der erste Donnerstag eines Jahres innerhalb der ersten Woche. Sie können DateAdd oder DateDiff daraus.
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, also wollte ich sie teilen.
new DateTime(1,1,YearNumber)
Die freie Zeitperiode Bibliothek für .NET enthält die ISO - 8601 - Klasse entsprechen Woche :
// ----------------------------------------------------------------------
public static DateTime GetFirstDayOfWeek( int year, int weekOfYear )
{
return new Week( year, weekOfYear ).FirstDayStart;
} // GetFirstDayOfWeek
Dieser hat bei mir funktioniert, er hat auch den Vorteil, dass er eine Kultur als Parameter erwartet, um die Formel mit verschiedenen Kulturen zu testen. Wenn leer, werden die aktuellen Kulturinformationen angezeigt. Gültige Werte sind: "it", "en-us", "fr", ... und so weiter. Der Trick besteht darin, die Wochennummer des ersten Tages des Jahres zu subtrahieren, dh 1, 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
Hier ist eine Methode, die mit den Wochenzahlen von Google Analytics kompatibel ist, sowie das gleiche Nummerierungsschema, das wir intern bei Intel verwendet haben und das sicher 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);
}
Ich habe einige der oben genannten Codes 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 behoben und es 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
Leicht geänderter Mikael Svenson Code. Ich fand die Woche des ersten Montags und änderte entsprechend die Wochennummer.
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;
}
Woche 1 ist definiert als die Woche, die an einem Montag beginnt und den ersten Donnerstag des Jahres enthält.
Informationen zum Konvertieren in beide Richtungen finden Sie hier: Wikipedia-Artikel zu ISO-Wochentagen
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 um eine Woche vor.
Danke Thomas, große Hilfe.
Ich habe eine der Lösungen verwendet, aber sie hat zu falschen Ergebnissen geführt, einfach weil der Sonntag als erster Tag der Woche gilt.
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.
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 gesehen 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);
}
}
Ich habe eine verfeinerte Version der vorgeschlagenen Lösung erstellt, die einfacher ist und den ersten Tag der Woche 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;
}
Dies ist meine Lösung, wenn wir ein Datum für ein bestimmtes Jahr, eine bestimmte Wochennummer und einen bestimmten 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);
}
Ich habe den von Mikael Svensson bereitgestellten Code 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));
}
Ich habe den folgenden Code geschrieben und getestet und funktioniert für mich 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 könnte 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;
}
GetFirstDateOfWeekByWeekNumber(2020, 29)
für Woche 29 von 2020 kehrt dies zurück 07/20/2020
. Aber der erste Tag der 29. Woche war07/13/2020
Derzeit gibt es keine C # -Klasse, die ISO 8601-Wochen-Nummern korrekt verarbeitet. Obwohl Sie eine Kultur instanziieren, nach dem nächsten suchen und das 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;
}