Рассчитать номера недель с годом, начиная с апреля
Я пытаюсь рассчитать номера недель в зависимости от конкретных правил. Пример правила, которое я ищу:
Неделя 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)