Anyone know an easy way to get the date of the first day in the week (monday here in Europe). I know the year and the week number? I'm going to do this in C#.
-
Strongly related, perhaps duplicate: http://stackoverflow.com/questions/659183/how-do-i-get-the-month-number-from-the-year-and-week-number-in-c – John Rasch Mar 19 '09 at 14:20
-
Possible duplicate of [How do I get the month number from the year and week number in c#?](https://stackoverflow.com/questions/659183/how-do-i-get-the-month-number-from-the-year-and-week-number-in-c) – khellang Jun 19 '18 at 11:04
26 Answers
I had issues with the solution by @HenkHolterman even with the fix by @RobinAndersson.
Reading up on the ISO 8601 standard resolves the issue nicely. Use the first Thursday as the target and not Monday. The code below will work for Week 53 of 2009 as well.
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);
}

- 431
- 1
- 6
- 17

- 39,181
- 7
- 73
- 79
-
3I've tried almost every solution given here, this one is the only one that correctly works for me right now. Currently, it's the 7th of Feb, 2012. The week nr is #6. This code correctly gives me the 6th of Feb as the start date of the week. The other solutions all gave me the 13th of Feb, which is actually the start date of week #7. – HaukurHaf Feb 07 '12 at 09:25
-
1Works Like a charm.. tested a few data: http://pastebin.com/mfx8s1vq All work flawless! Thanks Mikael! – Mittchel Oct 08 '12 at 21:28
-
My fix apparantly sucked since it broke for 2013. Thanks for a proper fix. :) – Robin Andersson May 27 '13 at 12:32
-
1@RobinWassén-Andersson Good thing you revisited this question then :D 6 more votes and I'll tie with the "not" correct answer hehe. – Mikael Svenson May 27 '13 at 18:06
-
2Suggestion: Make "ISO8601" pert of the method name, as there simply is no universal 'correct' answer. – H H Apr 02 '14 at 07:00
-
Is it possible to rewrite this to SQL Server 2008 R2 or I have to use it as CLR assembly ? – Muflix Dec 14 '15 at 15:39
-
1@Muflix I don't know enough about SQL and dates/calendars to know - but doing CLR will work. – Mikael Svenson Dec 15 '15 at 08:42
-
1The only issue I found is that this function does not take into account the DST. time The result date contains `1 hour` in time part (for CET/CEST time zone). I think this amount of hours must be subtracted in result date. – BambinoUA Jul 15 '19 at 07:53
-
1Shouldn't you use CultureInfo.InvariantCulture.Calendar since we specify the first day of the week anyway. (because ISO 8601 requires Monday as the start of the week) – Bojidar Stanchev Nov 07 '19 at 16:26
-
-
I had used this method and it bit me in the rear. This method works if the 1st day of the year is Sunday, Monday, Tuesday, Wednesday or Thursday. 2021 started on a Friday and 2022 started on a Saturday. Both 2021 and 2022 return the wrong date. Simple fix (confirmed with unit tests) was to change the following: if (firstWeek == 1) to if (firstWeek == 1 || firstWeek >= 52) – faldeland Feb 23 '22 at 19:58
-
@faldeland can you explain a bite more? Passing in 2020-53, 2021-1, 2022-1, all return the correct date of the Monday for those weeks. – Mikael Svenson Feb 24 '22 at 19:51
Note
The below answer uses the .NET Calendar rules. It does not promise ISO8601 conformance. See some of the other answers here when you need that. Week numbering is a mess, always try to find out what rules you need to follow first.
The code below correctly puts the start of week 1, 2009 at 29-12-2008. The CalendarWeekRule probably should be a parameter.
Note that the weekNum should be >= 1
static DateTime FirstDateOfWeek(int year, int weekNum, CalendarWeekRule rule)
{
Debug.Assert(weekNum >= 1);
DateTime jan1 = new DateTime(year, 1, 1);
int daysOffset = DayOfWeek.Monday - jan1.DayOfWeek;
DateTime firstMonday = jan1.AddDays(daysOffset);
Debug.Assert(firstMonday.DayOfWeek == DayOfWeek.Monday);
var cal = CultureInfo.CurrentCulture.Calendar;
int firstWeek = cal.GetWeekOfYear(firstMonday, rule, DayOfWeek.Monday);
if (firstWeek <= 1)
{
weekNum -= 1;
}
DateTime result = firstMonday.AddDays(weekNum * 7);
return result;
}

- 263,252
- 30
- 330
- 514
-
6I don't think this is entirely correct. Using `CalendarWeekRule.FirstFourDayWeek` and year 2006 and week 32, the correct date to be returned is 2006, 7th of august. But it returns the 14th of august. I changed the GetWeekOfYear call to use firstMonday instead of jan1 and it seemed to work – Oskar Kjellin Sep 08 '11 at 12:53
-
1It doesn't work properly with the FirstDay rule; with this rule, week 1 should always start on the 1st of January. But `FirstDateOfWeek(2011, 1, CalendarWeekRule.FirstDay)` returns 27th of december 2010 – Thomas Levesque Nov 09 '11 at 16:43
-
3Not only the mayans that had problems with 2012. Code misbehaved with the first week of 2012, changed cal.GetWeekOfYear(jan1, rule, DayOfWeek.Monday); to cal.GetWeekOfYear(firstMonday, rule, DayOfWeek.Monday); which corrected it. – Robin Andersson Jan 04 '12 at 10:19
-
@RobinAndersson This change will make it fail for Week 53 - 2009 – Mikael Svenson Jan 30 '12 at 13:18
-
2Posted an answer with code which apparently work for all boundary special cases. – Mikael Svenson Jan 30 '12 at 13:56
-
-
This code works well in some parts of the World I guess, but not for Iso 8601 calendars, like the Swedish one. Year 2008, week 1 will return jan 7 2008 but should return dec 31 2007 according to Iso 8601, even if CalendarWeekRule.FirstFourDayWeek is used as rule. Calendar coding is interesting ;) – Johan Danforth Sep 25 '12 at 22:46
-
@Johan, see my answer and code below and you have working code for 2008, week 1 :) – Mikael Svenson Oct 09 '12 at 06:35
-
I've posted my answer that seems to work for even more boundary cases here I think I have an answer that works for all cultures. I had problems with all the other solutions proposed http://stackoverflow.com/questions/16553878/how-to-do-i-invert-the-week-returned-from-calendar-getweekofyear-back-to-a-datet/16553879#16553879 – Mark Lakata May 14 '13 at 22:33
-
This works great. I use CalendarWeek.FirstFourdayWeek and a small test dataset, all ok. In addition, I added a DayOfWeek dayOfWeek parameter and returned modified result : return result.AddDays(dayOfWeek == DayOfWeek.Sunday ? 6 : (int)dayOfWeek - 1); – barbara.post Aug 09 '22 at 07:06
UPDATE: .NET Core 3.0 and .NET Standard 2.1 has shipped with this type.
Good news! A pull request adding System.Globalization.ISOWeek
to .NET Core was just merged and is currently slated for the 3.0 release. Hopefully it will propagate to the other .NET platforms in a not-too-distant future.
You should be able to use the ISOWeek.ToDateTime(int year, int week, DayOfWeek dayOfWeek)
method to calculate this.
You can find the source code here.

- 17,550
- 6
- 64
- 84
I like the solution provided by Henk Holterman. But to be a little more culture independent, you have to get the first day of the week for the current culture ( it's not always monday ):
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);
}

- 389
- 3
- 2
-
I've added this to Mannex, as an extension method to Calendar and DateTimeFormatInfo. I've also cross-referenced to this answer for credit. – Atif Aziz Feb 15 '10 at 11:02
-
1It doesn't work properly on my machine. It shows a date with 0010 instead of 2010. I don't know if it is a problem in .net framework or in this function. Nice try, anyway... – Eduardo Xavier Jun 18 '10 at 16:12
-
6`firstMonday` is a bad variable name for something that might not be a Monday. =) – mflodin Nov 12 '12 at 13:53
The easiest way is probably to find the first Monday of the year, and then add the relevant number of weeks. Here's some sample code. It assumes a week number starting at 1, by the way:
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);
}
}

- 1,421,763
- 867
- 9,128
- 9,194
-
4Yep, but the first monday of the year could belong to week 52|53 of the previous year. – H H Mar 19 '09 at 14:24
-
2It depends how you want to define things. Unfortunately we don't have a lot of information to go on here... I'm hoping this is useful though. – Jon Skeet Mar 19 '09 at 14:26
using 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);

- 33,714
- 21
- 133
- 202
Here is a method that is compatible with the week numbers that Google Analytics, and also the same numbering scheme we used internally at Intel, and which I'm sure is also used in a lot of other contexts.
// 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);
}

- 683
- 7
- 16
Personally I'd take advantage of the culture info to get the day of the week and loop down to the culture's first day of the week. I'm not sure if I'm explaining it properly, here's an example:
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;
}

- 2,458
- 24
- 36
Lightly changed Mikael Svenson code. I found the week of the first monday and appropriate change the week number.
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;
}

- 101
- 4
This one worked for me, it also have the advantage of expecting a cultureinfo as parameter to test the formula with different cultures. If empty, it gets the current culture info... valid values are like: "it", "en-us", "fr", ... ando so on. The trick is to subtract the week number of the first day of the year, that may be 1 to indicate that the first day is within the first week. Hope this helps.
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

- 21
- 1
Assuming the week number starts at 1
DateTime dt = new DateTime(YearNumber, 1, 1).AddDays((WeekNumber - 1) * 7 - (WeekNumber == 1 ? 0 : 1));
return dt.AddDays(-(int)dt.DayOfWeek);
This should give you the first day in any given week. I haven't done a lot of testing on it, but looks like it works. It's smaller solution than most other's I found on the web, so wanted to share.

- 6,346
- 2
- 39
- 47
-
bad answer. Using DateTime.Parse is not required as DateTime has a constructor which takes year, month & day. `new DateTime(1,1,YearNumber)` – Jamiec Jul 14 '10 at 11:26
-
Updated the code to create a new DateTime instead of using parse. It was late. ;) – QuinnG Jul 20 '10 at 03:49
The free Time Period Library for .NET includes the ISO 8601 conform class Week:
// ----------------------------------------------------------------------
public static DateTime GetFirstDayOfWeek( int year, int weekOfYear )
{
return new Week( year, weekOfYear ).FirstDayStart;
} // GetFirstDayOfWeek
According to ISO 8601:1988 that is used in Sweden the first week of the year is the first week that has at least four days within the new year.
So if your week starts on a Monday the first Thursday any year is within the first week. You can DateAdd or DateDiff from that.

- 2,848
- 1
- 21
- 30
I tried some codes above and some have small mistakes, when you try different years with different starting days of week you will see them, I took the code of Jon Skeet, fix it and it works, very simple 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

- 7,582
- 28
- 53

- 21
- 1
I simplified the code Mikael Svensson provided which is correct for many countries in 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));
}

- 2,728
- 27
- 31
As suggested by khellang (sorry but I cannot add comments), with .NET Core is quite simple. This is my piece of code:
var today = DateTime.Today;
CultureInfo myCI = new CultureInfo("it-IT");
Calendar myCal = myCI.Calendar;
var weekNumber = myCal.GetWeekOfYear(today, CalendarWeekRule.FirstFullWeek, DayOfWeek.Monday);
var firstWeekDay = ISOWeek.ToDateTime(today.Year, weekNumber, DayOfWeek.Monday);

- 111
- 4
I used one of the solutions but it gave me wrong results, simply because it counts Sunday as a first day of the week.
I changed:
var firstDay = new DateTime(DateTime.Now.Year, 1, 1).AddDays((weekNumber - 1) * 7);
var lastDay = firstDay.AddDays(6);
to:
var lastDay = new DateTime(DateTime.Now.Year, 1, 1).AddDays((weekNumber) * 7);
var firstDay = lastDay.AddDays(-6);
and now it is working as a charm.

- 21
- 3
-
1But does this answer the OP's question? It's 1/1 plus a fixed number of days. No first day of the week concept. – Gert Arnold Aug 09 '12 at 19:08
The proposed solution is not complete - it only works for CalendarWeekRule.FirstFullWeek. Other types of week rules do not work. This can be seen using this 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);
}
}

- 1,367
- 2
- 15
- 18
I have made a refined version of the proposed solution that is a simpler and parametrises the 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;
}

- 1,367
- 2
- 15
- 18
To convert in both directions, see here: Wikipedia article on ISO week dates

- 1,963
- 2
- 13
- 11
this is my solution when we want to calculate a date given year, week number and day of the week.
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);
}

- 12,242
- 4
- 52
- 53
I have written and tested the following code and is working perfectly fine for me. Please let me know if anyone face trouble with this, I have posted a question as well in order to get the best possible answer. Someone may find it useful.
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;
}

- 776
- 6
- 14
- 40
-
This is wrong - at least for a lot of European countries. `GetFirstDateOfWeekByWeekNumber(2020, 29)` for Week 29 of 2020 this returns `07/20/2020`. But first day of 29th week was `07/13/2020` – Matthias Burger Jul 17 '20 at 08:30
Currently, there is no C# class that correctly handles ISO 8601week numbers. Even though you can instantiate a culture, look for the closest thing and correct that, I think it is better to do the complete calculation yourself:
/// <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;
}

- 3,497
- 1
- 25
- 37
I improved a little on Thomas' solution with an 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;
}
*/
Otherwise the date was preceding by one week..
Thank you Thomas, great help.
One of the biggest problems I found was to convert from weeks to dates, and then from dates to weeks.
The main problem is when trying to get the correct week year from a date that belongs to a week of the previous year. Luckily System.Globalization.ISOWeek.GetYear
handles this.
Here is my solution:
public class WeekOfYear
{
public static (int Year, int Week) DateToWeekOfYear(DateTime date) =>
(ISOWeek.GetYear(date), ISOWeek.GetWeekOfYear(date));
public static bool ValidYearAndWeek(int year, int week) =>
year >= 1 && year <= 9999 && week >= 1 && week <= 53 // bounds of year/week
&& !(year <= 1 && week <= 1) && !(year >= 9999 && week >= 53); // bounds of DateTime
public int Year { get; }
public int Week { get; }
public virtual DateTime StartOfWeek { get; protected set; }
public virtual DateTime EndOfWeek { get; protected set; }
public virtual IEnumerable<DateTime> DaysInWeek =>
Enumerable.Range(1, 10).Select(i => StartOfWeek.AddDays(i));
public WeekOfYear(int year, int week)
{
if (!ValidYearAndWeek(year, week))
throw new ArgumentException($"DateTime can't represent {week} of year {year}.");
Year = year;
Week = week;
StartOfWeek = ISOWeek.ToDateTime(year, week, DayOfWeek.Monday);
EndOfWeek = ISOWeek.ToDateTime(year, week, DayOfWeek.Sunday).AddDays(1).AddTicks(-1);
}
public WeekOfYear((int Year, int Week) week) : this(week.Year, week.Week) { }
public WeekOfYear(DateTime date) : this(DateToWeekOfYear(date)) { }
}
The second biggest problem was the preference for weeks starting on Sundays in the US.
The solution I cam up with subclasses WeekOfYear
from above, and manages the offset of the in the constructor (which converts week to dates) and DateToWeekOfYear
(which converts from date to week).
public class UsWeekOfYear : WeekOfYear
{
public static new (int Year, int Week) DateToWeekOfYear(DateTime date)
{
// if date is a sunday, return the next week
if (date.DayOfWeek == DayOfWeek.Sunday) date = date.AddDays(1);
return WeekOfYear.DateToWeekOfYear(date);
}
public UsWeekOfYear(int year, int week) : base(year, week)
{
StartOfWeek = ISOWeek.ToDateTime(year, week, DayOfWeek.Monday).AddDays(-1);
EndOfWeek = ISOWeek.ToDateTime(year, week, DayOfWeek.Sunday).AddTicks(-1);
}
public UsWeekOfYear((int Year, int Week) week) : this(week.Year, week.Week) { }
public UsWeekOfYear(DateTime date) : this(DateToWeekOfYear(date)) { }
}
Here is some test code:
public static void Main(string[] args)
{
Console.WriteLine("== Last Week / First Week");
Log(new WeekOfYear(2020, 53));
Log(new UsWeekOfYear(2020, 53));
Log(new WeekOfYear(2021, 1));
Log(new UsWeekOfYear(2021, 1));
Console.WriteLine("\n== Year Crossover (iso)");
var start = new DateTime(2020, 12, 26);
var i = 0;
Log(start.AddDays(i), new WeekOfYear(start.AddDays(i++))); // 2020-12-26 - Sat
Log(start.AddDays(i), new WeekOfYear(start.AddDays(i++))); // 2020-12-27 - Sun
Log(start.AddDays(i), new WeekOfYear(start.AddDays(i++))); // 2020-12-28 - Mon
Log(start.AddDays(i), new WeekOfYear(start.AddDays(i++))); // 2020-12-29 - Tue
Log(start.AddDays(i), new WeekOfYear(start.AddDays(i++))); // 2020-12-30 - Wed
Log(start.AddDays(i), new WeekOfYear(start.AddDays(i++))); // 2020-12-30 - Thu
Log(start.AddDays(i), new WeekOfYear(start.AddDays(i++))); // 2021-01-01 - Fri
Log(start.AddDays(i), new WeekOfYear(start.AddDays(i++))); // 2021-01-02 - Sat
Log(start.AddDays(i), new WeekOfYear(start.AddDays(i++))); // 2021-01-03 - Sun
Log(start.AddDays(i), new WeekOfYear(start.AddDays(i++))); // 2021-01-04 - Mon
Log(start.AddDays(i), new WeekOfYear(start.AddDays(i++))); // 2021-01-05 - Tue
Log(start.AddDays(i), new WeekOfYear(start.AddDays(i++))); // 2021-01-06 - Wed
Console.WriteLine("\n== Year Crossover (us)");
i = 0;
Log(start.AddDays(i), new UsWeekOfYear(start.AddDays(i++))); // 2020-12-26 - Sat
Log(start.AddDays(i), new UsWeekOfYear(start.AddDays(i++))); // 2020-12-27 - Sun
Log(start.AddDays(i), new UsWeekOfYear(start.AddDays(i++))); // 2020-12-28 - Mon
Log(start.AddDays(i), new UsWeekOfYear(start.AddDays(i++))); // 2020-12-29 - Tue
Log(start.AddDays(i), new UsWeekOfYear(start.AddDays(i++))); // 2020-12-30 - Wed
Log(start.AddDays(i), new UsWeekOfYear(start.AddDays(i++))); // 2020-12-30 - Thu
Log(start.AddDays(i), new UsWeekOfYear(start.AddDays(i++))); // 2021-01-01 - Fri
Log(start.AddDays(i), new UsWeekOfYear(start.AddDays(i++))); // 2021-01-02 - Sat
Log(start.AddDays(i), new UsWeekOfYear(start.AddDays(i++))); // 2021-01-03 - Sun
Log(start.AddDays(i), new UsWeekOfYear(start.AddDays(i++))); // 2021-01-04 - Mon
Log(start.AddDays(i), new UsWeekOfYear(start.AddDays(i++))); // 2021-01-05 - Tue
Log(start.AddDays(i), new UsWeekOfYear(start.AddDays(i++))); // 2021-01-06 - Wed
var x = new UsWeekOfYear(2020, 53) as WeekOfYear;
}
public static void Log(WeekOfYear week)
{
Console.WriteLine($"{week} - {week.StartOfWeek:yyyy-MM-dd} ({week.StartOfWeek:ddd}) - {week.EndOfWeek:yyyy-MM-dd} ({week.EndOfWeek:ddd})");
}
public static void Log(DateTime date, WeekOfYear week)
{
Console.WriteLine($"{date:yyyy-MM-dd (ddd)} - {week} - {week.StartOfWeek:yyyy-MM-dd (ddd)} - {week.EndOfWeek:yyyy-MM-dd (ddd)}");
}

- 9,017
- 3
- 42
- 63
Week 1 is defined as being the week that starts on a Monday and contains the first Thursday of the year.

- 1,470
- 13
- 18
-
1
-
1ISO standard define week 1 as the week with the year's first Thursday in it. – RickardN Jan 18 '12 at 12:17