【问题标题】:Calculate week numbers with year starting in April计算从 4 月开始的年份的周数
【发布时间】:2017-09-07 16:53:54
【问题描述】:

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

第 1 周 = 一年中的第一周,其中包含 4 月 1 日。

示例数据:

2017 年 3 月 27 日第 1 周 2017 年 4 月 2 日

...

2017 年 9 月 4 日第 23 周 2017 年 9 月 10 日

我发现了一个类似的问题 - 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 周。我猜我需要以某种方式考虑周开始天(? !)。

【问题讨论】:

  • 只是检查一下,您认为什么是“周” - 周一到周日,还是其他?
  • @JonSkeet 我认为最初是周一到周日,但我认为我可能还必须使其可配置以满足未来的不同需求。
  • 好的。将在我的答案中指出在哪里设置。
  • @JonSkeet 完美,谢谢!
  • 在计算targetYear(第二行)时,不应该在firstOne 上加上7 天,看看4 月1 日是否在范围内?

标签: c# datetime nodatime


【解决方案1】:

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

如果您需要计算年份和周数,并且不需要反方向,我会做这样的事情:

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

使用DateAdjusters.PreviousOrSame 查找一周年的开始非常简单,因为您可以说“现在是 4 月 1 日或之前的星期一”(根据需要调整星期几)。

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

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)

【讨论】:

  • 然后如果/当我需要更改一周的开始时间(周一到周日或周三到周二等),可以适当设置属性“StartOfWeek”吗? IWeekYearRule 看起来很有趣!会调查。谢谢!
  • @WestDiscGolf:是的,你只需改变它。如果您愿意,您可以参数化 GetStartOfWeekYear,而不是将其作为常量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-06
  • 2020-12-01
  • 2010-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-25
相关资源
最近更新 更多