I need to return year and week of a given date. Sounds simple. But to be right 2012-01-01 have to return 2011-52, because week 1 in 2012 starts January 2th.
To find the week, I use:
GregorianCalendar calw = new GregorianCalendar(GregorianCalendarTypes.Localized);
return calw.GetWeekOfYear(DateTime.Parse("2012-01-01"), CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday).ToString();
this return 52. (correct)
But how do I get the Year?
edit:
With the help from here: http://codebetter.com/petervanooijen/2005/09/26/iso-weeknumbers-of-a-date-a-c-implementation/
This seems to work:
private int weekYear(DateTime fromDate)
{
GregorianCalendar cal = new GregorianCalendar(GregorianCalendarTypes.Localized);
int week = weekNumber(fromDate);
int month = cal.GetMonth(fromDate);
int year = cal.GetYear(fromDate);
//week starts after 31st december
if (week > 50 && month == 1)
year = year - 1;
//week starts before 1st January
if (week < 5 && month == 12)
year = year + 1;
return year;
}
private int weekNumber(DateTime fromDate)
{
// Get jan 1st of the year
DateTime startOfYear = fromDate.AddDays(-fromDate.Day + 1).AddMonths(-fromDate.Month + 1);
// Get dec 31st of the year
DateTime endOfYear = startOfYear.AddYears(1).AddDays(-1);
// ISO 8601 weeks start with Monday
// The first week of a year includes the first Thursday
// DayOfWeek returns 0 for sunday up to 6 for saterday
int[] iso8601Correction = { 6, 7, 8, 9, 10, 4, 5 };
int nds = fromDate.Subtract(startOfYear).Days + iso8601Correction[(int)startOfYear.DayOfWeek];
int wk = nds / 7;
switch (wk)
{
case 0:
// Return weeknumber of dec 31st of the previous year
return weekNumber(startOfYear.AddDays(-1));
case 53:
// If dec 31st falls before thursday it is week 01 of next year
if (endOfYear.DayOfWeek < DayOfWeek.Thursday)
return 1;
else
return wk;
default: return wk;
}
}
Noda Time handles this for you very easily:
using System;
using NodaTime;
public class Test
{
static void Main()
{
LocalDate date = new LocalDate(2012, 1, 1);
Console.WriteLine($"WeekYear: {date.WeekYear}"); // 2011
Console.WriteLine($"WeekOfWeekYear: {date.WeekOfWeekYear}"); // 52
}
}
using System;
using NodaTime;
using NodaTime.Calendars;
public class Test
{
static void Main()
{
LocalDate date = new LocalDate(2012, 1, 1);
IWeekYearRule rule = WeekYearRules.Iso;
Console.WriteLine($"WeekYear: {rule.GetWeekYear(date)}"); // 2011
Console.WriteLine($"WeekOfWeekYear: {rule.GetWeekOfWeekYear(date)}"); // 52
}
}
That's using the ISO calendar system where the week year starts in the first week with at least 4 days in that year. (Like CalendarWeekRule.FirstFourDayWeek
.) If you want a different calendar system, specify it in the LocalDate
constructor. Week year rules are handled slightly differently between 1.x and 2.x.
EDIT: Note that this gives the right value for both this situation (where the week-year is less than the calendar year) and the situation at the other end of the year, where the week-year can be more than the calendar year. For example, December 31st 2012 is in week 1 of week-year 2013.
That's the beauty of having a library do this for you: its job is to understand this sort of thing. Your code shouldn't have to worry about it. You should just be able to ask for what you want.
You can get the weeknumber according to the CalendarWeekRule
in this way:
var d = new DateTime(2012, 01, 01);
System.Globalization.CultureInfo cul = System.Globalization.CultureInfo.CurrentCulture;
var firstDayWeek = cul.Calendar.GetWeekOfYear(
d,
System.Globalization.CalendarWeekRule.FirstDay,
DayOfWeek.Monday);
int weekNum = cul.Calendar.GetWeekOfYear(
d,
System.Globalization.CalendarWeekRule.FirstFourDayWeek,
DayOfWeek.Monday);
int year = weekNum >= 52 && d.Month == 1 ? d.Year - 1 : d.Year;
You probably want to compare CalendarWeekRule.FirstDay
with CalendarWeekRule.FirstFourDayWeek
. On this way you get the weeknumber and the year (DateTime.Year-1
if they differ).
CultureInfo.Calendar
PropertyCalendar.GetWeekOfYear
MethodIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With