试图编写一个正确的函数来返回给定年份的周数,但没有成功。
我正在寻找的功能示例:
int weeks = GetWeeksInYear ( 2012 )
应该返回 52 周 // 表示 2012 年只有 52 周。
ps:一年中可以是52、53、54周,51左右不确定
试图编写一个正确的函数来返回给定年份的周数,但没有成功。
我正在寻找的功能示例:
int weeks = GetWeeksInYear ( 2012 )
应该返回 52 周 // 表示 2012 年只有 52 周。
ps:一年中可以是52、53、54周,51左右不确定
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。(对于某些压光机,它可能会有所不同......)
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
}
}
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);
}
我不知道为什么会这样,但看起来日历说的数字不正确。正确的周数总是少于 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 };
当我将 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;
}