11

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

svick
  • 236,525
  • 50
  • 385
  • 514
illusion
  • 383
  • 2
  • 4
  • 9
  • 4
    the number of weeks is the same every year. (given the case you have an int...) the only difference (when using a double) would be leap years (where you have one day more) – Vogel612 Jun 30 '13 at 13:58
  • 1
    Isn't there always 52 whole weeks in a year (given that you are using an `int` and not a `double` / `decimal`) ? – Simon Belanger Jun 30 '13 at 13:58
  • Whole weeks? Weeks starting Sunday? 52 * 7 = 364 there were 366 days in 2012... – Tony Hopkinson Jun 30 '13 at 14:02
  • 6
    It entirely depends on what you mean by "week". If you're talking "week of ISO week year" then it can definitely vary between 52 and 53. If you mean something else, you'll need to be very specific. – Jon Skeet Jun 30 '13 at 14:03
  • 7
    @Vogel612: No, there really aren't. For one thing, you're assuming a Gregorian calendar. For another, you're assuming one meaning of "week" - and there are various different options available. The OP definitely needs to be clearer, but it's not as simple as "there are always 52 weeks". – Jon Skeet Jun 30 '13 at 14:04
  • there is always 52 weeks in a year, but you may want to count how many Sundays in a year ? – Hilmi Jun 30 '13 at 14:05
  • Depends on what standard you apply: ISO week starts on monday, the first week of a year has to contain at least four days. http://en.wikipedia.org/wiki/ISO_week_date – mbx Jun 30 '13 at 14:06
  • 1
    @JonSkeet Doesn't “2012” and no mention of “alternative” calendars in a question written in English clearly imply Gregorian calendar? – svick Jun 30 '13 at 14:26
  • 2
    @svick this is not a debate, he should be more specific next time, if a question has so many comments, and only 1 answer.. the question is not specific enough :) – ilansch Jun 30 '13 at 14:30
  • 1
    @svick: It's very likely that the OP is only interested in the Gregorian calendar - but my point is that the blanket statement is incorrect. Too many assumptions. – Jon Skeet Jun 30 '13 at 14:46
  • 1
    @JonSkeet How did you come to know I'm talking about earth not mars years? – illusion Jun 30 '13 at 15:35
  • 3
    @illusion: I don't, because you didn't put any details into your question. Hint hint. (54 weeks in a year must be in a calendar I haven't come across before, mind you.) – Jon Skeet Jun 30 '13 at 15:38
  • @JonSkeet I was replying on those who said in a year can be only 52 weeks, though it can be 54 as well Y2K)... rene though had enough logic to figure what I'm talking about. – illusion Jun 30 '13 at 15:58
  • 1
    @illusion: Well no - he *guessed*, and it's still not clear that his guess actually solves your problem. You still haven't said what sort of week you're talking about. As I said on the answer, if you're actually interested in ISO-8601 weeks, .NET classes don't provide that information themselves. – Jon Skeet Jun 30 '13 at 16:16
  • @JonSkeet you better tell me, in general,how many sorts of calendar standards are there ( where number of weeks in a year vary)? and do you have 3 different functions that can be the correct answer to my question? – illusion Jun 30 '13 at 16:45
  • @illusion: There are *lots* of different calendars, and different ways of measuring weeks. As for "3 different functions" - the one given by rene *might* be what you're after, but you might be after ISO-8601 week-years, in which case you might want to look at my Noda Time library. We don't know what your requirements are though. – Jon Skeet Jun 30 '13 at 16:49
  • Which week were 30 and 31/12/2012 in then? Seems to be the 53rd assuming Sunday is start of week. Last time I ran into all the assumptions around weeks in year, I managed to get the entire concept dropped, then they asked me for the number of months in a UK fiscal year 6/4/YYY to 5/4/YYYY at that point I started crying.... – Tony Hopkinson Jul 01 '13 at 23:00

5 Answers5

26

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...)

rene
  • 41,474
  • 78
  • 114
  • 152
  • And, just as importantly, the OP should decide for himself what he is really asking. – Tormod Jun 30 '13 at 14:24
  • 7
    And note that none of the CalendarWeekRule options in .NET match ISO-8601, if that's what the OP wants... – Jon Skeet Jun 30 '13 at 14:46
  • I wouldn't be surprised to have new Question of the OP that asks for an implementation of a calendar that follows the company rules...been there, done that... – rene Jun 30 '13 at 15:01
  • 2
    when i give 2018 to year parameter after method returns 53 but it is not correct end of this year week is 52. – Murat Can OĞUZHAN Aug 02 '18 at 12:28
  • 1
    @MuratCanOĞUZHAN That is then a bug in the implementation as none of the cultures return 52. It might be that the lack of a proper ISO-8601 implementation is causing this. You might want to look into NodaTime, the library that Jon wrote for date and time handling – rene Aug 02 '18 at 13:03
5

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

DalSoft
  • 10,673
  • 3
  • 42
  • 55
2

I had the issue when I assign 2018 to year parameter of other methods, so I extended the Code of Tim Schmelter. I do not know, maybe there are codes that work faster:

//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;
}
Christian Gollhardt
  • 16,510
  • 17
  • 74
  • 111
Murat Can OĞUZHAN
  • 735
  • 11
  • 19
  • 1
    Part of this answer seems to be copied from [here](https://stackoverflow.com/revisions/11155102/2) without proper attribution. – Christian Gollhardt Jun 23 '22 at 13:17
  • @ChristianGollhardt you are totally right I copied most of it inside somewhere in Stackoverflow. I'm gonna mention that one in the answer, I could also remove the answer but this answer fixed my problem in old wild times. – Murat Can OĞUZHAN Jun 23 '22 at 14:22
1

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

enter image description here


Years with not 53 and not 54 weeks:

enter image description here


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

And this is means that most optimized method will be:

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

UPD: BUT! Looks like this is incorrect way.

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 };
Community
  • 1
  • 1
Andrew_STOP_RU_WAR_IN_UA
  • 9,318
  • 5
  • 65
  • 101
0
//For ISO Calender(First Day Of Week : Monday)  

DateTime start = new DateTime(2020,1,1);
int total_weeks=0;  

//If a year starts on thursday or a leap year starts on wednesday then the year has 53 weeks

if((DateTime.IsLeapYear(start.Year) && start.ToString("dddd")=="Wednesday")||(start.ToString("dddd")=="Thursday")) 
{
    total_weeks=53;
}
else
{
    total_week=52;
}
Console.WriteLine(total_weeks.ToString());