How to Get the number of weeks in a given year

帅比萌擦擦* 提交于 2019-12-07 14:11:21

问题


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


回答1:


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




回答2:


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



回答3:


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

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



回答4:


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



来源:https://stackoverflow.com/questions/17391073/how-to-get-the-number-of-weeks-in-a-given-year

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!