计算从 4 月开始的年份的周数

Calculate week numbers with year starting in April

我正在尝试根据特定规则计算周数。我正在寻找的规则示例是:

Week 1 = first week of the year which containers 1st April.

示例数据:

Week 1 March 27, 2017 April 2, 2017

...

Week 23 September 4, 2017 September 10, 2017

我发现了一个类似的问题 - Getting Week number of year starting from April - 并以此为指导,我提出了以下在未来特定日期有效的问题。然而,截止时间早于当前一周的日期时间会导致问题。

LocalDate firstOne = LocalDate.FromDateTime(dateTime);

int targetYear = firstOne.Month > 4 || firstOne.Month == 4 && firstOne.Day >= 1 ? firstOne.Year : firstOne.Year - 1;

LocalDate start = new LocalDate(targetYear, 4, 1);

int days = Period.Between(start, firstOne, PeriodUnits.Days).Days;
int targetWeek = (days / 7) + 1;

if (targetWeek >= 52)
{
    // if we are greater than 52 then we are technically in week 1 of the following year; eg 31st March 2017.
    // Remove the "year" from the week count and move the year counter back to the correct year.
    targetWeek -= 52;
    targetYear++;
}

return (targetYear, targetWeek);   

当前的问题是,如果我在 2017 年 3 月 27 日通过,也就是 1 日之后的 7 天内,它仍然会给出前一年和第 52 周。我想我需要以某种方式考虑周开始日(?!).

我如何解决这个问题取决于您需要做什么。在 Noda Time 2.0(并向后移植到 1.4)中,有一个 IWeekYearRule 接口可以实现,如果你想彻底做到这一点。

如果你只是需要计算年和周数,而不需要相反的方向,我会这样做:

  • 找到与给定日历年对应的周年的开始
  • 检查传入的日期是否在当天或之后
    • 如果是这样,请使用该周开始的年份进行计算
    • 否则,计算前一周年的开始,并使用它

使用 DateAdjusters.PreviousOrSame 查找一周年的开始真的很容易,因为您可以说 "It's the Monday on or immediately before April 1st"(根据需要调整星期几)。

这是一个完整的示例,带有示例结果:

using System;
using NodaTime;

class Test
{
    static void Main()
    {
        ShowDate(2017, 1, 1);
        ShowDate(2017, 3, 27);
        ShowDate(2017, 9, 7);
    }

    private static void ShowDate(int year, int month, int day)
    {
        var date = new LocalDate(year, month, day);
        var result = GetWeekYearAndWeek(date);
        Console.WriteLine($"{date:uuuu-MM-dd} => {result}");
    }

    private static (int weekYear, int week) GetWeekYearAndWeek(LocalDate date)
    {
        // Initial guess...
        int weekYear = date.Year;
        var startOfWeekYear = GetStartOfWeekYear(weekYear);
        if (date < startOfWeekYear)
        {
            weekYear--;
            startOfWeekYear = GetStartOfWeekYear(weekYear);
        }

        int days = Period.Between(startOfWeekYear, date, PeriodUnits.Days).Days;
        int week = (days / 7) + 1;

        return (weekYear, week);
    }

    private const IsoDayOfWeek StartOfWeek = IsoDayOfWeek.Monday;

    private static LocalDate GetStartOfWeekYear(int weekYear) =>
        new LocalDate(weekYear, 4, 1).With(DateAdjusters.PreviousOrSame(StartOfWeek));
}

输出:

2017-01-01 => (2016, 40)
2017-03-27 => (2017, 1)
2017-09-07 => (2017, 24)