Trying to code a correct function that returns the number of weeks in a given year, but without success.
Example of the function I'm looking for :
int weeks = GetWeeksInYear ( 2012 )
should return 52 weeks // means there are only 52 weeks in 2012.
P.s.: in a year can be 52, 53, 54 weeks, not sure about 51
See the Calendar.GetWeekOfYear method
public int GetWeeksInYear(int year)
{
DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
DateTime date1 = new DateTime(year, 12, 31);
Calendar cal = dfi.Calendar;
return cal.GetWeekOfYear(date1, dfi.CalendarWeekRule,
dfi.FirstDayOfWeek);
}
Be carefull to figure out the correct CalendarWeekRule and FirstDayOfWeek for a Calendar that matches the culture your customers are used to. (for some calenders it might vary...)
Update 14 Oct 2019
If you're using .NET Core 3.0 and you want to get the number of weeks in a year conforming to ISO 8601 - you can use ISOWeek's GetWeeksInYear
method.
using System;
using System.Globalization;
public class Program
{
public static void Main()
{
Console.WriteLine(ISOWeek.GetWeeksInYear(2009)); // returns 53
}
}
Working example: https://dotnetfiddle.net/EpIbZQ
I had issue when i assign 2018 to year parameter of other methods. I do not know maybe there are codes that work faster but i wrote following methods.
//you can try like that
int weeks = DateHelper.GetWeeksInGivenYear(2018);
int weeks = DateHelper.GetWeeksInGivenYear(2020);
// This presumes that weeks start with Monday.
// Week 1 is the 1st week of the year with a Thursday in it.
public static int GetIso8601WeekOfYear(this DateTime time)
{
// Seriously cheat. If its Monday, Tuesday or Wednesday, then it'll
// be the same week# as whatever Thursday, Friday or Saturday are,
// and we always get those right
DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
{
time = time.AddDays(3);
}
// Return the week of our adjusted day
return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
//gets given year last week no
public static int GetWeeksInGivenYear(int year)
{
DateTime lastDate = new DateTime(year, 12, 31);
int lastWeek = GetIso8601WeekOfYear(lastDate);
while (lastWeek == 1)
{
lastDate = lastDate.AddDays(-1);
lastWeek = GetIso8601WeekOfYear(lastDate);
}
return lastWeek;
}
P.s.: in a year can be 52, 53, 54 weeks, not sure about 51
1. If we will check With Calendar we will get results that we can have only 53 or 54 weeks.
2. This is incorrect result (read the end of my answer)
You can check it with the following app:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Linq;
namespace TestConsoleApp
{
class Program
{
public static void Main(string[] args)
{
var b = CountWeeksForYearsRange(1, 4000);
var c = b.Where(a => a.Value != 53).ToDictionary(a=>a.Key, a=>a.Value);
}
static DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
static Calendar calendar = DateTimeFormatInfo.CurrentInfo.Calendar;
private static int CountWeeksInYear(int year)
{
DateTime date = new DateTime(year, 12, 31);
return calendar.GetWeekOfYear(date, dfi.CalendarWeekRule, dfi.FirstDayOfWeek);
}
private static Dictionary<int,int> CountWeeksForYearsRange(int yearStart, int yearEnd)
{
Dictionary<int, int> rez = new Dictionary<int, int>();
for (int i = yearStart; i <= yearEnd; i++)
{
rez.Add(i, CountWeeksInYear(i));
}
return rez;
}
}
}
and there will be only 53 and 54 values.
This means that for faster work of method we can have pre-coded function for such situation.
Years with not 53 weeks
Years with not 53 and not 54 weeks:
So in this case we can generate simple array of years that have 54 weeks from 0 to 4000 years:
12,40,68,96,108,136,164,192,204,232,260,288,328,356,384,412,440,468,496,508,536,564,592,604,632,660,688,728,756,784,812,840,868,896,908,936,964,992,1004,1032,1060,1088,1128,1156,1184,1212,1240,1268,1296,1308,1336,1364,1392,1404,1432,1460,1488,1528,1556,1584,1612,1640,1668,1696,1708,1736,1764,1792,1804,1832,1860,1888,1928,1956,1984,2012,2040,2068,2096,2108,2136,2164,2192,2204,2232,2260,2288,2328,2356,2384,2412,2440,2468,2496,2508,2536,2564,2592,2604,2632,2660,2688,2728,2756,2784,2812,2840,2868,2896,2908,2936,2964,2992,3004,3032,3060,3088,3128,3156,3184,3212,3240,3268,3296,3308,3336,3364,3392,3404,3432,3460,3488,3528,3556,3584,3612,3640,3668,3696,3708,3736,3764,3792,3804,3832,3860,3888,3928,3956,3984
//Works only with 1-4000 years range
public int CountWeeksInYearOptimized(int year)
{
return (_yearsWith54Weeks.IndexOf(year) == -1) ? 53 : 54;
}
private List<int> _yearsWith54Weeks = new List<int> { 12, 40, 68, 96, 108, 136, 164, 192,
204, 232, 260, 288, 328, 356, 384, 412, 440, 468, 496, 508, 536, 564,
592, 604, 632, 660, 688, 728, 756, 784, 812, 840, 868, 896, 908, 936,
964, 992, 1004, 1032, 1060, 1088, 1128, 1156, 1184, 1212, 1240, 1268,
1296, 1308, 1336, 1364, 1392, 1404, 1432, 1460, 1488, 1528, 1556, 1584,
1612, 1640, 1668, 1696, 1708, 1736, 1764, 1792, 1804, 1832, 1860, 1888,
1928, 1956, 1984, 2012, 2040, 2068, 2096, 2108, 2136, 2164, 2192, 2204,
2468, 2496, 2508, 2536, 2564, 2592, 2604, 2632, 2660, 2688, 2728, 2756,
2784, 2812, 2840, 2868, 2896, 2908, 2936, 2964, 2992, 3004, 3032, 3060,
3088, 3128, 3156, 3184, 3212, 3240, 3268, 3296, 3308, 3336, 3364, 3392,
3668, 3696, 3708, 3736, 3764, 3792, 3804, 3832, 3860, 3888, 3928, 3956,
3984 };
or if you don't want to pre-calculated data:
DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
Calendar calendar = DateTimeFormatInfo.CurrentInfo.Calendar;
private int CountWeeksInYear(int year)
{
DateTime date = new DateTime(year, 12, 31);
return calendar.GetWeekOfYear(date, dfi.CalendarWeekRule, dfi.FirstDayOfWeek);
}
I don't know why so, but looks like Calendar saying incorrect number. And correct count of weeks is always on less on 1 week. You can check it manually:
Let's calc days in the following years with Calendar:
2011+2012+2013:
53+54+53=160 weeks.
But stop!
(365+366+365)/7 = 157.
So best way will be to do -1 to the value that will be shown by calendar
Or to use the following fastest method:
//Works only with 1-4000 years range
public int CountWeeksInYearOptimized(int year)
{
return (_yearsWith54Weeks.IndexOf(year) == -1) ? 52 : 53;
}
private List<int> _yearsWith54Weeks = new List<int> { 12, 40, 68, 96, 108, 136, 164, 192,
204, 232, 260, 288, 328, 356, 384, 412, 440, 468, 496, 508, 536, 564,
592, 604, 632, 660, 688, 728, 756, 784, 812, 840, 868, 896, 908, 936,
964, 992, 1004, 1032, 1060, 1088, 1128, 1156, 1184, 1212, 1240, 1268,
1296, 1308, 1336, 1364, 1392, 1404, 1432, 1460, 1488, 1528, 1556, 1584,
1612, 1640, 1668, 1696, 1708, 1736, 1764, 1792, 1804, 1832, 1860, 1888,
1928, 1956, 1984, 2012, 2040, 2068, 2096, 2108, 2136, 2164, 2192, 2204,
2468, 2496, 2508, 2536, 2564, 2592, 2604, 2632, 2660, 2688, 2728, 2756,
2784, 2812, 2840, 2868, 2896, 2908, 2936, 2964, 2992, 3004, 3032, 3060,
3088, 3128, 3156, 3184, 3212, 3240, 3268, 3296, 3308, 3336, 3364, 3392,
3668, 3696, 3708, 3736, 3764, 3792, 3804, 3832, 3860, 3888, 3928, 3956,
3984 };
If 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