Рассчитать номера недель с годом, начиная с апреля

Я пытаюсь рассчитать номера недель в зависимости от конкретных правил. Пример правила, которое я ищу:

Неделя 1 = первая неделя в году, которая включает 1 апреля.

Пример данных:

1 неделя 27 марта 2017 г. 2 апреля 2017 г.

...

23 неделя 4 сентября 2017 г. 10 сентября 2017 г.

Я нашел похожий вопрос - получение номера недели в году, начиная с апреля, - и используя его в качестве руководства, я пришел к следующему, который работает на конкретную дату в будущем. Однако дата времени до отключения, но на текущей неделе, вызывает проблемы.

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

Текущий вопрос: если я перейду на 27/3/2017, то есть в течение 7 дней с 1-го числа, он все равно дает предыдущий год и неделю 52. Я предполагаю, что мне нужно как-то учитывать дни начала недели (?!).

1 ответ

Решение

То, как я подойду к этому, будет зависеть от того, что именно вам нужно сделать. В Noda Time 2.0 (и перенесен на 1.4) есть IWeekYearRule интерфейс, который вы могли бы реализовать, если вы хотите сделать это тщательно.

Если вам просто нужно вычислить номер года и недели и не нужно идти в обратном направлении, я бы сделал что-то вроде этого:

  • Найти начало недели-года, соответствующего данному календарному году
  • Проверьте, является ли дата, переданная в, на или после этого
    • Если так, сделайте расчет, используя тот год начала года
    • В противном случае вычислите начало предыдущей недели и используйте

Найти начало недели-года очень легко с DateAdjusters.PreviousOrSame, как вы можете просто сказать: "Это понедельник или непосредственно до 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)
Другие вопросы по тегам