Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WeekNumber计算.NET中的错误?_C#_.net_Date Arithmetic - Fatal编程技术网

C# WeekNumber计算.NET中的错误?

C# WeekNumber计算.NET中的错误?,c#,.net,date-arithmetic,C#,.net,Date Arithmetic,我有一个很奇怪的问题。我住在丹麦,2013年的第一周(第1周)从2012年12月31日开始,持续7天——通常是几周:) 然而,根据.NET,12月30日是第52周,31日是第53周,1月1日是第1周 第53周仅持续一天,第1周持续6天。显然,这肯定是错误的(一周不到7天),在丹麦的情况下肯定是错误的。其中12月31日是第1周,而不是第53周 以下代码说明了该问题(CurrentCulture为“da DK”) static void Main(字符串[]args) { //星期一到 DayOfW

我有一个很奇怪的问题。我住在丹麦,2013年的第一周(第1周)从2012年12月31日开始,持续7天——通常是几周:)

然而,根据.NET,12月30日是第52周,31日是第53周,1月1日是第1周

第53周仅持续一天,第1周持续6天。显然,这肯定是错误的(一周不到7天),在丹麦的情况下肯定是错误的。其中12月31日是第1周,而不是第53周

以下代码说明了该问题(CurrentCulture为“da DK”)

static void Main(字符串[]args)
{
//星期一到
DayOfWeek firstDayOfWeek=DateTimeFormatInfo.CurrentInfo.firstDayOfWeek;
//这是我每周的第四天
CalendarWeekRule-weekRule=DateTimeFormatInfo.CurrentInfo.CalendarWeekRule;
DateTime日期=新的日期时间(2012,12,30);

对于(int i=0;i1.1.2013是星期二,从第1周开始。2012年12月31日是星期一,属于2012年,因此是第53周。当然,你不能在12月有第1周,因为这意味着一年中有两个第1周,因此会导致各种各样的代码问题

没有规定一周必须正好是7天。

问题是该方法不符合ISO 8601,这正是您所期望的,但事实并非如此

请注意,当您使用
FirstFourDayWeek
时,会显示:

基于FirstFourDayWeek值的第一周可以有四到七天

这违反了ISO 8601的规定,即所有周必须有七天


根据ISO 8601,您可以使用以下方法获得正确的周数:

int weekNumber(DateTime fromDate)
{
    // Get jan 1st of the year
    DateTime startOfYear = fromDate.AddDays(- fromDate.Day + 1).AddMonths(- fromDate.Month +1);
    // Get dec 31st of the year
    DateTime endOfYear = startOfYear.AddYears(1).AddDays(-1);
    // ISO 8601 weeks start with Monday 
    // The first week of a year includes the first Thursday 
    // DayOfWeek returns 0 for sunday up to 6 for saterday
    int[] iso8601Correction = {6,7,8,9,10,4,5};
    int nds = fromDate.Subtract(startOfYear).Days  + iso8601Correction[(int)startOfYear.DayOfWeek];
    int wk = nds / 7;
    switch(wk)
    {
        case 0 : 
            // Return weeknumber of dec 31st of the previous year
            return weekNumber(startOfYear.AddDays(-1));
        case 53 : 
            // If dec 31st falls before thursday it is week 01 of next year
            if (endOfYear.DayOfWeek < DayOfWeek.Thursday)
                return 1;
            else
                return wk;
        default : return wk;
    }
}
int weekNumber(DateTime fromDate)
{
//获得每年的1月1日
DateTime startOfYear=fromDate.AddDays(-fromDate.Day+1)。AddMonths(-fromDate.Month+1);
//得到每年的12月31日
DateTime endOfYear=startOfYear.AddYears(1.AddDays(-1);
//ISO 8601周从周一开始
//一年的第一周包括第一个星期四
//DayOfWeek周日返回0,周六返回6
int[]ISO8601校正={6,7,8,9,10,4,5};
int nds=fromDate.Subtract(startOfYear).Days+ISO8601校正[(int)startOfYear.DayOfWeek];
int wk=nds/7;
开关(wk)
{
案例0:
//返回上一年12月31日的周数
返回周数(startOfYear.AddDays(-1));
案例53:
//如果12月31日在星期四之前,则是明年的第01周
if(endOfYear.DayOfWeek
(还有很多其他功能……)


因此,将循环更改为

for (int i = 0; i <= 10; i++)
{
    DateTime currentDate = date.AddDays(i);
    Console.WriteLine("Date: {0} WeekNumber: {1}: CorrectWeekNumber: {2}",
        currentDate.ToShortDateString(),
        CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(currentDate, weekRule, firstDayOfWeek),
        weekNumber(currentDate));
}

for(int i=0;i我对丹麦日历一无所知,但.NET的规则很明确,您的代码与这些规则完全对应。
CalendarWeekRule
枚举的MSDN文档仅供参考。总之:

NET将始终将12月31日视为“一年中的最后一周”

您说您得到的周规则值为
FirstFourDayWeek
。由于2013年1月1日是星期二,该周的剩余时间为六天(下一周从下一个星期一开始)。因此,2013年1月1日至6日被视为“第一周”如果您有该规则的
FirstFullWeek
,那么第1周将从第7周星期一开始

至于“显然这肯定是错的:”显然,根据其自身的规范,这是正确的。任何编程语言或API都不需要符合特定的期望;每个项目都定义了自己的需求。NET遵循我们可能认为意外的规则,但这些规则是有文档记录的,并且与文档保持一致


这是否有用是另一个问题…

Calendar.GetWeekOfYear不支持ISO8601规范,另请参阅

您可以使用以下的课程:


感谢所有的答案。我还搜索了更多,最后创建了两种C#方法来实现我想要的:

首先,在以下网站的一条评论中可以找到一个简明的评论:

Jon Senchyna还指出:

     public static int WeekNumber(this DateTime date)
    {
        Calendar cal = CultureInfo.InvariantCulture.Calendar;
        DayOfWeek day = cal.GetDayOfWeek(date);
        date = date.AddDays(4 - ((int)day == 0 ? 7 : (int)day));
        return cal.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
    }
还有一个:

public static int week number2(此日期时间日期)
{
INTA;
int b;
INTC;
int-s;
INTE;
int f;
如果(日期月(364+s))
返回1;
返回n/7+1;
}
都给了我想要的

我还编写了一个小单元测试,证明它们在日历的前3000年返回相同的周数

    [TestMethod]
    public void WeekNumbers_CorrectFor_3000Years()
    {
        var weekNumbersMethod1 = WeekNumbers3000Years(DateManipulation.WeekNumber).ToList();
        var weekNumbersMethod2 = WeekNumbers3000Years(DateManipulation.WeekNumber2).ToList();
        CollectionAssert.AreEqual(weekNumbersMethod1, weekNumbersMethod2);
    }

    private IEnumerable<int> WeekNumbers3000Years(Func<DateTime, int> weekNumberCalculator)
    {
        var startDate = new DateTime(1,1,1);
        var endDate = new DateTime(3000, 12, 31);
        for(DateTime date = startDate; date < endDate; date = date.AddDays(1))
            yield return weekNumberCalculator(date);
    }
[TestMethod]
公共无效周数更正为3000年()
{
var weekNumbersMethod1=weekNumbers3000年(DateManipulation.WeekNumber.ToList();
var weekNumberMethod2=weekNumber3000年(DateManipulation.WeekNumber2.ToList();
集合资产等于(周数方法1,周数方法2);
}
私人IEnumerable周数3000年(Func周数计算器)
{
var startDate=新日期时间(1,1,1);
var endDate=新的日期时间(3000,12,31);
对于(DateTime date=startDate;date
您可以使用以下代码来计算给定日期的周数:

    public static int GetWeekNumber(DateTime date)
    {
        var firstDayOfYear = new DateTime(date.Year, 1, 1);
        var lastDayOfYear = new DateTime(date.Year, 12, 31);
        var lastDayOfPreviousYear = new DateTime(date.Year - 1, 12, 31);

        var weekDayOfFirstDayOfYear = (int)firstDayOfYear.DayOfWeek + 1;
        var weekDayOfLastDayOfYear = (int)lastDayOfYear.DayOfWeek + 1;
        var days = (date - firstDayOfYear).Days;

        if (days <= 7 - weekDayOfFirstDayOfYear)  // My day fall in 1'st week of the year
        {
            if (weekDayOfFirstDayOfYear > 5)
                return GetWeekNumber(lastDayOfPreviousYear);
            return 1;
        }
        else // My day fall not on 1'st week of the year
        {
            // Number of weeks that pass from 1'st Sunday of 2'nd week of the year
            var weekNo = ((days - (8 - weekDayOfFirstDayOfYear)) / 7) + 1;

            if (weekDayOfFirstDayOfYear < 6)  // if Year start at Sun...Thursday the first week is added.
                weekNo++;

            // Check if Last week of the year belong to next year
            if (weekDayOfLastDayOfYear < 5) // if the year end in Sunday to Wednesday then it might belong to the 1'st week of the next year
            {
                if ((lastDayOfYear - date).Days < weekDayOfLastDayOfYear)
                {
                    return 1;
                }
            }

            return weekNo;
        }
    }
publicstaticintgetweeknumber(DateTime日期)
{
var firstDayOfYear=新的日期时间(date.Year,1,1);
var lastDayOfYear=新的日期时间(date.Year,12,31);
var LastDayOfPreousYear=新日期时间(date.Year-1,12,31);
var weekDayOfFirstDayOfYear=(int)firstDayOfYear.DayOfWeek+1;
var工作日
    public static int WeekNumber2(this DateTime date)
    {
        int a;
        int b;
        int c;
        int s;
        int e;
        int f;

        if (date.Month <= 2)
        {
            a = date.Year - 1;
            b = a / 4 - a / 100 + a / 400;
            c = (a - 1) / 4 - (a - 1) / 100 + (a - 1) / 400;
            s = b - c;
            e = 0;
            f = date.Day - 1 + 31 * (date.Month - 1);
        }
        else
        {
            a = date.Year;
            b = a / 4 - a / 100 + a / 400;
            c = (a - 1) / 4 - (a - 1) / 100 + (a - 1) / 400;
            s = b - c;
            e = s + 1;
            f = date.Day + ((153 * (date.Month - 3) + 2) / 5) + 58 + s;
        }

        int g = (a + b) % 7;
        int d = (f + g - e) % 7;
        int n = f + 3 - d;

        if (n < 0)
            return 53 - ((g - s) / 5);
        if (n > (364 + s))
            return 1;
        return n / 7 + 1;
    }
    [TestMethod]
    public void WeekNumbers_CorrectFor_3000Years()
    {
        var weekNumbersMethod1 = WeekNumbers3000Years(DateManipulation.WeekNumber).ToList();
        var weekNumbersMethod2 = WeekNumbers3000Years(DateManipulation.WeekNumber2).ToList();
        CollectionAssert.AreEqual(weekNumbersMethod1, weekNumbersMethod2);
    }

    private IEnumerable<int> WeekNumbers3000Years(Func<DateTime, int> weekNumberCalculator)
    {
        var startDate = new DateTime(1,1,1);
        var endDate = new DateTime(3000, 12, 31);
        for(DateTime date = startDate; date < endDate; date = date.AddDays(1))
            yield return weekNumberCalculator(date);
    }
    public static int GetWeekNumber(DateTime date)
    {
        var firstDayOfYear = new DateTime(date.Year, 1, 1);
        var lastDayOfYear = new DateTime(date.Year, 12, 31);
        var lastDayOfPreviousYear = new DateTime(date.Year - 1, 12, 31);

        var weekDayOfFirstDayOfYear = (int)firstDayOfYear.DayOfWeek + 1;
        var weekDayOfLastDayOfYear = (int)lastDayOfYear.DayOfWeek + 1;
        var days = (date - firstDayOfYear).Days;

        if (days <= 7 - weekDayOfFirstDayOfYear)  // My day fall in 1'st week of the year
        {
            if (weekDayOfFirstDayOfYear > 5)
                return GetWeekNumber(lastDayOfPreviousYear);
            return 1;
        }
        else // My day fall not on 1'st week of the year
        {
            // Number of weeks that pass from 1'st Sunday of 2'nd week of the year
            var weekNo = ((days - (8 - weekDayOfFirstDayOfYear)) / 7) + 1;

            if (weekDayOfFirstDayOfYear < 6)  // if Year start at Sun...Thursday the first week is added.
                weekNo++;

            // Check if Last week of the year belong to next year
            if (weekDayOfLastDayOfYear < 5) // if the year end in Sunday to Wednesday then it might belong to the 1'st week of the next year
            {
                if ((lastDayOfYear - date).Days < weekDayOfLastDayOfYear)
                {
                    return 1;
                }
            }

            return weekNo;
        }
    }