Я хочу написать метод расширения для получения воскресной даты на основе weekOffset и текущей даты. Например, если значение weekOffset равно 1, это означает дату воскресенья следующей недели, а если weekOffset равно 2, то это означает дату следующего воскресенья следующей недели.
Я придумал код ниже
private static List<string> GetWeekRange(this DateTimeOffset date, int weekOffset = 0)
{
var sundayDate = new DateTimeOffset(date.Year, date.Month, date.Day, 0, 0, 0, date.Offset).AddDays(weekOffset * 7 - (int) new DateTimeOffset(date.Year, date.Month, date.Day, 0, 0, 0, date.Offset).DayOfWeek);
var saturdayDate = new DateTimeOffset(weekStartDate.Year, weekStartDate.Month, weekStartDate.Day, 0, 0, 0, weekStartDate.Offset).AddDays(7).AddMilliseconds(-1);
return new List<string> { weekStartDate.ToString("o"), weekEndDate.ToString("o") };
}
Мне было интересно, есть ли способ лучше?
2 ответа
Я думаю, ваш код мог бы быть более лаконичным и полезным (т.е. не возвращать строку), написанным как:
private static DateTimeOffset[] GetWeekRange(this DateTimeOffset d, int weekOffset = 0)
{
var weekStartDate = new DateTimeOffset(d.Date, d.Offset).AddDays(weekOffset * 7 - (int)d.DayOfWeek);
var weekEndDate = weekStartDate.AddDays(7);
return new [] { weekStartDate, weekEndDate };
}
Но тогда, учитывая, что конец так легко вычисляется с самого начала, может быть, просто верните начало, забудьте о массиве
В моих комментариях к OP упоминается, что в методе есть недостаток, если на рассматриваемой неделе есть переход на летнее время. Смещение UTC для DateTimeOffset
является постоянным для недели, то есть даты начала и окончания должны иметь одно и то же смещение по всемирному координированному времени, что может быть нежелательно. Если вы не учитываете часовой пояс, вам придется смириться с этим недостатком.
Я бы посоветовал вам сформулировать вопрос лучше. То же самое можно сказать и об именах переменных. Вы действительно не пытаетесь найти начало воскресенья. Скорее вы пытаетесь найти начало «недели». Если вы сдадите 1 для своего weekOffset
, то начало недели — понедельник, а не воскресенье. Таким образом, имя переменной sundayDate
действительно должно быть startDate
или что-то в этом роде, поскольку это не обязательно должно быть воскресенье.
Нет никаких ограничений на int weekOffset
параметр. Поскольку DateTimeOffset
также есть Offset
свойство (для смещения UTC), я сделал паузу и должен был медленно прочитать, чтобы увидеть, какой цели служит weekOffset
. Это очищено лучше в моей версии ниже, где я использую DayOfWeek
enum вместо этого. Как перечисление, он служит констрейтом, но также более прямым, поскольку он служит началом «недели».
Нет необходимости вычитать миллисекунду, чтобы получить дату окончания недели. Почему миллисекунда? Почему не 1 галочка? А еще лучше, зачем вообще беспокоиться? Обычно считается, что конец одной недели — это начало другой недели. Следовательно, по соглашению начало должно быть инклюзивным (т. Е. >=
) и Конец будет исключительным (т.е. <
), когда применяется фильтрация, чтобы увидеть, DateTime
попадает в эту «неделю».
Именование вашей переменной может во многом устранить любую путаницу. Возврат струн — относительная ошибка новичков. Как говорится в другом ответе, вы можете либо вернуть массив DateTimeOffset
или просто верните начало недели, так как вы знаете, что до конца этой недели осталось всего 7 дней. Пойдем дальше. Давайте вернем кортеж с именованными значениями, и пусть эти имена устранят путаницу.
public static (DateTimeOffset InclusiveStartDate, DateTimeOffset ExclusiveEndDate) GetWeekRange(this DateTimeOffset date, DayOfWeek weekStartingDay = DayOfWeek.Sunday)
{
date = new DateTimeOffset(date.Year, date.Month, date.Day, 0, 0, 0, date.Offset);
var offsetDays = ((int)weekStartingDay * 7) - (int)date.DayOfWeek;
var startDate = date.AddDays(offsetDays);
return (startDate, startDate.AddDays(7));
}
Любой разработчик, использующий это, ясно видит, что существует InclusiveStartDate
и ExclusiveEndDate
. Кроме того, вместо weekOffset
будучи int
, где можно было передать плохие значения, такие как -999
, Я прохожу через DayOfWeek
нумерованное значение.
Чтобы увидеть это в действии:
static void Main(string[] args)
{
var date = DateTimeOffset.Now;
DisplayWeekRange(date, DayOfWeek.Sunday);
DisplayWeekRange(date.AddDays(-7), DayOfWeek.Sunday);
Console.WriteLine("nPress ENTER key to close.");
Console.ReadLine();
}
private static void DisplayWeekRange(DateTimeOffset date, DayOfWeek weekStartingDay)
{
var weekRange = date.GetWeekRange(weekStartingDay);
Console.WriteLine($"Input Date: {date}");
Console.WriteLine($"Week Starting Day: {weekStartingDay}");
Console.WriteLine($" Inclusive Start: {weekRange.InclusiveStartDate}");
Console.WriteLine($" Exclusive End : {weekRange.ExclusiveEndDate}");
}
А вот пример вывода:
Input Date: 3/16/2021 8:47:24 AM -05:00
Week Starting Day: Sunday
Inclusive Start: 3/14/2021 12:00:00 AM -05:00
Exclusive End : 3/21/2021 12:00:00 AM -05:00
Input Date: 3/9/2021 8:47:24 AM -05:00
Week Starting Day: Sunday
Inclusive Start: 3/7/2021 12:00:00 AM -05:00
Exclusive End : 3/14/2021 12:00:00 AM -05:00
Press ENTER key to close.
Второй пример показывает недостаток перехода на летнее время. Я нахожусь в Центральной части США, и всего 3 дня назад у нас был весенний форвард на летнее время. Диапазон этой недели правильный. Однако диапазон прошлой недели действительно должен показывать смещение UTC на -06:00
с прошлой недели было стандартное время. Опять же, этот недостаток — не логическая ошибка, а ошибка дизайна. Не зная, какой часовой пояс я использую, я не могу учитывать переходы на летнее время. Так что будущая версия может включать это.
Кроме того, в любое время, когда возникает вопрос о часовых поясах, времени и т. Д., Я всегда рекомендую вам: