8

试图编写一个正确的函数来返回给定年份的周数,但没有成功。

我正在寻找的功能示例:

int weeks =  GetWeeksInYear ( 2012 )

应该返回 52 周 // 表示 2012 年只有 52 周。

ps:一年中可以是52、53、54周,51左右不确定

4

4 回答 4

25

请参阅Calendar.GetWeekOfYear方法

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

仔细找出与客户习惯的文化相匹配的日历的正确 CalendarWeekRule 和 FirstDayOfWeek。(对于某些压光机,它可能会有所不同......)

于 2013-06-30T14:06:55.430 回答
3

2019 年 10 月 14 日更新

如果您使用的是 .NET Core 3.0,并且想要获得符合 ISO 8601 的一年中的周数 - 您可以使用ISOWeek 的 GetWeeksInYear方法。

using System;
using System.Globalization;

public class Program
{
    public static void Main()
    {
        Console.WriteLine(ISOWeek.GetWeeksInYear(2009)); // returns 53
    }
}

工作示例:https ://dotnetfiddle.net/EpIbZQ

于 2019-10-14T21:25:32.070 回答
1

ps:一年中可以是52、53、54周,51左右不确定

1. 如果我们检查日历,我们将得到只有 53 或 54 周的结果。

2.这是不正确的结果(阅读我答案的结尾)

您可以使用以下应用程序进行检查:

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

并且只有 53 和 54 个值。

这意味着为了更快地工作方法,我们可以为这种情况提供预编码的功能。


没有 53 周的年份

在此处输入图像描述


没有 53 周和 54 周的年份:

在此处输入图像描述


所以在这种情况下,我们可以生成简单的年份数组,从 0 年到 4000 年有 54 周:

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

或者如果您不想预先计算数据:

    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:但是!看起来这是不正确的方式。

我不知道为什么会这样,但看起来日历说的数字不正确。正确的周数总是少于 1 周。您可以手动检查它:

让我们用 Calendar 计算接下来几年的天数:

2011+2012+2013:

53+54+53=160 周。

但是停下!

(365+366+365)/7 = 157。

所以最好的方法是对日历显示的值做-1

或者使用以下最快的方法:

//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 };
于 2019-01-02T22:24:33.307 回答
1

当我将 2018 分配给其他方法的年份参数时,我遇到了问题。我不知道也许有更快的代码,但我写了以下方法。

        //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;
        }
于 2018-08-02T13:00:47.600 回答